1- /*
2-
3- MIT License
4-
5- Copyright (c) 2023 Max Goren
6-
7- Permission is hereby granted, free of charge, to any person obtaining a copy
8- of this software and associated documentation files (the "Software"), to deal
9- in the Software without restriction, including without limitation the rights
10- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11- copies of the Software, and to permit persons to whom the Software is
12- furnished to do so, subject to the following conditions:
13-
14- The above copyright notice and this permission notice shall be included in all
15- copies or substantial portions of the Software.
16-
17- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23- SOFTWARE.
24-
25- */
26-
271#ifndef STACKMACHINE_HPP
282#define STACKMACHINE_HPP
293#include < iostream>
@@ -34,6 +8,7 @@ typedef int OPSTAT;
348const OPSTAT OP_SUCCESS = 1 ;
359const OPSTAT OP_ERROR = -1 ;
3610const OPSTAT OP_BRANCH = 2 ;
11+ const OPSTAT OP_HALT = 3 ;
3712
3813class StackMachine {
3914 private:
@@ -48,7 +23,7 @@ class StackMachine {
4823 int rets[255 ]; // return stack
4924 OPSTAT pushr ();
5025 OPSTAT popr ();
51- // alu
26+ // arithmetic logic unit.
5227 OPSTAT ALU (string op, string arg);
5328 int tosr; // top of stack register
5429 OPSTAT cmpl ();
@@ -71,13 +46,18 @@ class StackMachine {
7146 OPSTAT jmpz (int addr); // jump to addr if top of stack IS zero
7247 OPSTAT call (); // call to
7348 OPSTAT retf (); // return from
74- void halt (); // end program.
49+ OPSTAT halt (); // end program.
50+ OPSTAT nop (); // no operation (you'd be surprised)
7551 vector<string> smtokenizer (string expr, char DELIM);
7652 int programCounter;
7753 int memoryAddrReg;
7854 int randomAccessMemory[255 ];
55+ bool debugMode;
56+ bool stepping;
7957 public:
80- StackMachine () {
58+ StackMachine (bool dbmode = false , bool smode = false ) {
59+ debugMode = dbmode;
60+ stepping = smode;
8161 top = 0 ;
8262 tosr = 0 ;
8363 rtop = 0 ;
@@ -88,15 +68,21 @@ class StackMachine {
8868};
8969
9070OPSTAT StackMachine::cmpl () {
91- return push (data[top-2 ] < data[top - 1 ]);
71+ if (data[top-1 ] < data[top - 2 ])
72+ return push (1 );
73+ return push (0 );
9274}
9375
9476OPSTAT StackMachine::cmpg () {
95- return push (data[top-2 ] > data[top - 1 ]);
77+ if (data[top-1 ] > data[top - 2 ])
78+ return push (1 );
79+ return push (0 );
9680}
9781
9882OPSTAT StackMachine::cmpeq () {
99- return push (data[top-2 ] == data[top - 1 ]);
83+ if (data[top-2 ] == data[top - 1 ])
84+ return push (1 );
85+ return push (0 );
10086}
10187
10288// / @brief bitwise AND top two items on data stack
@@ -173,7 +159,7 @@ OPSTAT StackMachine::store() {
173159// / @return
174160OPSTAT StackMachine::jmpnz (int addr) {
175161 if (data[top-1 ] != 0 ) {
176- push (programCounter); // put current address on data stack
162+ push (programCounter+ 1 ); // put address of next instruction (ret addr) on data stack
177163 pushr (); // move address from data stack to return stack
178164 programCounter = addr; // set to jump point
179165 return OP_BRANCH; // signal next instruction is result of branching.
@@ -185,12 +171,11 @@ OPSTAT StackMachine::jmpnz(int addr) {
185171// / Opposite behavior to above.
186172OPSTAT StackMachine::jmpz (int addr) {
187173 if (data[top-1 ] == 0 ) {
188- push (programCounter); // put current address on data stack
174+ push (programCounter+ 1 ); // put current address on data stack
189175 pushr (); // move address from data stack to return stack
190176 programCounter = addr; // set to jump point
191177 return OP_BRANCH; // signal next instruction is result of branching.
192178 }
193- tosr = data[top-1 ]; // Otherwise proceed as normal
194179 return pop ();
195180}
196181
@@ -211,6 +196,14 @@ OPSTAT StackMachine::retf() {
211196 return OP_BRANCH;
212197}
213198
199+ OPSTAT StackMachine::halt () {
200+ return OP_HALT;
201+ }
202+
203+ OPSTAT StackMachine::nop () {
204+ return OP_SUCCESS;
205+ }
206+
214207// / @brief converts string to int and pushes onto data stack
215208// / @param arg
216209// / @return
@@ -235,14 +228,28 @@ int StackMachine::pop() {
235228
236229// / @brief pops data stack and pushes result to return stack
237230// / @return
238- OPSTAT StackMachine::pushr () {
231+ OPSTAT StackMachine::pushr () {
232+ if (debugMode) {
233+ cout<<" [" <<programCounter<<" ] pushr Stack: [" ;
234+ for (int i = top-1 ; i >= 0 ; i--) cout<<data[i]<<" " ;
235+ cout<<" ] raddr Stack: [" ;
236+ for (int i = rtop-1 ; i >= 0 ; i--) cout<<rets[i]<<" " ;
237+ cout<<" ]\n " ;
238+ }
239239 rets[rtop++] = pop ();
240240 return OP_SUCCESS;
241241}
242242
243243// / @brief pops data of return stack and pushes result to data stack
244244// / @return
245- OPSTAT StackMachine::popr () {
245+ OPSTAT StackMachine::popr () {
246+ if (debugMode) {
247+ cout<<" [" <<programCounter<<" ] popr Stack: [" ;
248+ for (int i = top-1 ; i >= 0 ; i--) cout<<data[i]<<" " ;
249+ cout<<" ] raddr Stack: [" ;
250+ for (int i = rtop-1 ; i >= 0 ; i--) cout<<rets[i]<<" " ;
251+ cout<<" ]\n " ;
252+ }
246253 return push (rets[--rtop]);
247254}
248255
@@ -299,7 +306,7 @@ OPSTAT StackMachine::mod() {
299306
300307// show top item on stack.
301308OPSTAT StackMachine::show () {
302- cout<<" [TOP ]" <<data[top-1 ]<<" \n " ;
309+ cout<<" [- ]" <<data[top-1 ]<<" \n " ;
303310 return OP_SUCCESS;
304311}
305312
@@ -323,6 +330,15 @@ int StackMachine::ALU(string op, string arg) {
323330 return over ();
324331 }
325332
333+ // equality
334+ if (op == " cmpl" ) {
335+ return cmpl ();
336+ } else if (op == " cmpg" ) {
337+ return cmpg ();
338+ } else if (op == " cmpeq" ) {
339+ return cmpeq ();
340+ }
341+
326342 // bitwise ops
327343 if (op == " AND" ) {
328344 return bwAnd ();
@@ -360,6 +376,10 @@ int StackMachine::ALU(string op, string arg) {
360376 return jmpnz (atoi (arg.c_str ()));
361377 } else if (op == " jmpz" ) {
362378 return jmpz (atoi (arg.c_str ()));
379+ } else if (op == " halt" ) {
380+ return halt ();
381+ } else if (op == " nop" ) {
382+ return nop ();
363383 }
364384
365385 return OP_ERROR;
@@ -374,23 +394,32 @@ void StackMachine::run(vector<string>& program) {
374394 vector<string> tokens = smtokenizer (instr, ' ' ); // break the expression
375395 op = tokens[0 ]; // down into operation and argument
376396 arg = (tokens.size () > 1 ) ? tokens[1 ]:" " ;
377- // for debugging:
378- cout<<" [" <<programCounter<<" ] " <<op<<" " <<arg<<" \n " ;
397+ if (debugMode) {
398+ cout<<" [" <<programCounter<<" ] " <<op<<" " <<arg<<" , Stack: [" ;
399+ for (int i = top-1 ; i >= 0 ; i--) cout<<data[i]<<" " ;
400+ cout<<" ]\n " ;
401+ }
379402 // pass the instruction to the arithmetic and logic unit
380403 OPSTAT stat = ALU (op, arg);
381404 switch (stat) {
382405 case OP_SUCCESS:
383406 programCounter += 1 ;
384407 break ;
408+ case OP_HALT:
409+ programCounter = program.size () + 1 ;
410+ break ;
385411 case OP_BRANCH:
386- cout<<" [" <<stat<<" ] [BRANCHING TO: " <<programCounter<<" ]\n " ;
412+ if (debugMode)
413+ cout<<" [" <<stat<<" ] [BRANCHING TO: " <<programCounter<<" ]\n " ;
387414 break ;
388415 case OP_ERROR:
389416 default :
390- cout<< " [ " <<stat<< " ] " ;
391- cout<<" [LAST INSTRUCTION FAILED.]\n " ;
417+ if (debugMode)
418+ cout<<" [ " <<stat<< " ] [LAST INSTRUCTION FAILED.]\n " ;
392419 programCounter += 1 ;
393- }
420+ }
421+ char k;
422+ if (stepping) cin>>k;
394423 }
395424}
396425
@@ -414,4 +443,4 @@ vector<string> StackMachine::smtokenizer(string expr, char DELIM) {
414443 return tokens;
415444}
416445
417- #endif
446+ #endif
0 commit comments