home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Programming Contest / ~Solutions Submitted / Problem 10 - Three and One / Solution.cp < prev    next >
Encoding:
Text File  |  1998-06-19  |  7.2 KB  |  389 lines  |  [TEXT/CWIE]

  1. /*
  2. Problem 10 - Interpreter
  3.  
  4. Write an interpreter for this simple 32-bit integer language with 26 registers
  5. labeled A-Z.
  6.  
  7. type RegisterArray = array[0..25] of SInt32;
  8.  
  9. procedure Interpret( source: Handle; var result: RegisterArray );
  10.  
  11. source consists of a number of lines of the form:
  12.  
  13. [<label>:][<tab><instruction><tab><operand-list>]<cr>
  14.  
  15. <label> is a sequence of at least two alphanumerics (0-9a-zA-Z_)
  16. (casesensitive).
  17. <operand-list> is a sequence of operators seperated by commas
  18. other than the tabs and crs, no white space is allowed.
  19.  
  20. <instruction> (and appropriate operands are:
  21.  
  22. MOVE    <value>,<register>            (set <register> to <value>)
  23. ADD     <value1>,<value2>,<register>  (set <register> to <value1>+<value2>)
  24. SUB     <value1>,<value2>,<register>  (set <register> to <value1>-<value2>)
  25. JMP     <label>                       (jump to line labeled with <label>)
  26. JEQ     <value1>,<value2>,<label>     (jump to <label> if <value1> = <value2>)
  27. JLE     <value1>,<value2>,<label>     (jump to <label> if <value1> <= <value2>)
  28. JSR     <label>                       (jump to subroutine at <label>)
  29. RTS                                   (return from subroutine)
  30. PUSH    <value>                       (push value on to stack)
  31. POP     <register>                    (pop value from stack)
  32.  
  33. <register> is a single uppercase letter in the range A..Z
  34. <number> is an optional minus sign followed by decimal digits
  35. <value> is a <register> or a <number>
  36.  
  37. Note that the data stack and subroutine stack are independent stacks.  A RTS is
  38. used to stop the program (that is, consider that you have JSRed to the initial
  39. line of the source handle).  For example:
  40.  
  41.     PUSH    10
  42.     JSR    setA
  43.     JSE setB
  44.     RTS
  45. setA:
  46.     POP    A
  47.     RTS
  48. setB:    MOVE    A,B
  49.     RTS
  50.     
  51. Interpret takes the source handle and JSRs to it, presetting the registers
  52. according to the register array.  When the code returns, the register array is
  53. set to the final value of all the registers.  Both subroutine and data stacks
  54. should be large (at least 1000 entries each).
  55. */
  56.  
  57. #include "Solution.h"
  58. #include <map>
  59. #include <string>
  60. #include <vector>
  61. #include <sstream>
  62. #include <iostream>
  63. #include <stack>
  64. #include <ctype.h>
  65.  
  66. // Fill in your solution and then submit this folder
  67.  
  68. // Team Name: Three and One!
  69.  
  70. struct Instruction {
  71.     virtual void Execute() const = 0;
  72. };
  73.  
  74. __MSL_FIX_ITERATORS__(Instruction*);
  75.  
  76. std::map<std::string, int instruction> labels;
  77. std::vector<Instruction*> program;
  78. RegisterArray registers;
  79. int pc;
  80. std::stack<int> callStack;
  81. std::stack<int> valueStack;
  82. bool done;
  83.  
  84. struct Value {
  85.     int Evaluate() const;
  86.     bool reg;
  87.     int valueOrRegister;
  88. };
  89.  
  90. void
  91. SkipCommasSpacesTabs(std::istream& s)
  92. {
  93.     while (1) {
  94.         char character = s.get();
  95.         if (character != ',' && character != ' ' && character != 9) {
  96.             s.putback(character);
  97.             return;
  98.         }
  99.     }
  100. }
  101.  
  102. int
  103. ReadRegister(std::istream& s)
  104. {
  105.     SkipCommasSpacesTabs(s);
  106.     return toupper(s.get()) - 'A';
  107. }
  108.  
  109. std::string
  110. ReadLabel(std::istream& s)
  111. {
  112.     SkipCommasSpacesTabs(s);
  113.     std::string label;
  114.     s >> label;
  115.     return label;
  116. }
  117.  
  118. Value
  119. ReadValue(std::istream& s)
  120. {
  121.     SkipCommasSpacesTabs(s);
  122.  
  123.     Value v;
  124.     
  125.     char character = toupper(s.get());
  126.     if (character >= 'A' && character <= 'Z') {
  127.         v.valueOrRegister = character - 'A';
  128.         v.reg = true;
  129.         return v;
  130.     }
  131.     
  132.     s.putback(character);
  133.     s >> v.valueOrRegister;
  134.     v.reg = false;
  135.     return v;
  136. }
  137.  
  138. int
  139. Value::Evaluate() const
  140. {
  141.     if (!reg)
  142.         return valueOrRegister;
  143.     return registers[valueOrRegister];
  144. }
  145.  
  146. struct MOVE : Instruction {
  147.     MOVE(istream&);
  148.     virtual void Execute() const;
  149.     Value value;
  150.     int reg;
  151. };
  152.  
  153. struct ADD : Instruction {
  154.     ADD(istream&);
  155.     virtual void Execute() const;
  156.     Value value1;
  157.     Value value2;
  158.     int reg;
  159. };
  160.  
  161. struct SUB : Instruction {
  162.     SUB(istream&);
  163.     virtual void Execute() const;
  164.     Value value1;
  165.     Value value2;
  166.     int reg;
  167. };
  168.  
  169. struct JMP : Instruction {
  170.     JMP(istream&);
  171.     virtual void Execute() const;
  172.     std::string label;
  173. };
  174.  
  175. struct JEQ : Instruction {
  176.     JEQ(istream&);
  177.     virtual void Execute() const;
  178.     Value value1;
  179.     Value value2;
  180.     std::string label;
  181. };
  182.  
  183. struct JLE : Instruction {
  184.     JLE(istream&);
  185.     virtual void Execute() const;
  186.     Value value1;
  187.     Value value2;
  188.     std::string label;
  189. };
  190.  
  191. struct JSR : Instruction {
  192.     JSR(istream&);
  193.     virtual void Execute() const;
  194.     std::string label;
  195. };
  196.  
  197. struct RTS : Instruction {
  198.     RTS();
  199.     virtual void Execute() const;
  200. };
  201.  
  202. struct PUSH : Instruction {
  203.     PUSH(istream&);
  204.     virtual void Execute() const;
  205.     Value value;
  206. };
  207.  
  208. struct POP : Instruction {
  209.     POP(istream&);
  210.     virtual void Execute() const;
  211.     int reg;
  212. };
  213.  
  214. MOVE::MOVE(istream& s)
  215. {
  216.     value = ReadValue(s);
  217.     reg = ReadRegister(s);
  218. }
  219.         
  220. void MOVE::Execute() const
  221. {
  222.     registers[reg] = value.Evaluate();
  223. }
  224.         
  225. ADD::ADD(istream& s)
  226. {
  227.     value1 = ReadValue(s);
  228.     value2 = ReadValue(s);
  229.     reg = ReadRegister(s);
  230. }
  231.         
  232. void ADD::Execute() const
  233. {
  234.     registers[reg] = value1.Evaluate() + value2.Evaluate();
  235. }
  236.         
  237. SUB::SUB(istream& s)
  238. {
  239.     value1 = ReadValue(s);
  240.     value2 = ReadValue(s);
  241.     reg = ReadRegister(s);
  242. }
  243.         
  244. void SUB::Execute() const
  245. {
  246.     registers[reg] = value1.Evaluate() - value2.Evaluate();
  247. }
  248.         
  249. JMP::JMP(istream& s)
  250. {
  251.     label = ReadLabel(s);
  252. }
  253.         
  254. void JMP::Execute() const
  255. {
  256.     pc = labels[label];
  257. }
  258.         
  259. JEQ::JEQ(istream& s)
  260. {
  261.     value1 = ReadValue(s);
  262.     value2 = ReadValue(s);
  263.     label = ReadLabel(s);
  264. }
  265.         
  266. void JEQ::Execute() const
  267. {
  268.     if (value1.Evaluate() == value2.Evaluate())
  269.         pc = labels[label];
  270. }
  271.         
  272. JLE::JLE(istream& s)
  273. {
  274.     value1 = ReadValue(s);
  275.     value2 = ReadValue(s);
  276.     label = ReadLabel(s);
  277. }
  278.         
  279. void JLE::Execute() const
  280. {
  281.     if (value1.Evaluate() <= value2.Evaluate())
  282.         pc = labels[label];
  283. }
  284.         
  285. JSR::JSR(istream& s)
  286. {
  287.     label = ReadLabel(s);
  288. }
  289.         
  290. void JSR::Execute() const
  291. {
  292.     callStack.push(pc);
  293.     pc = labels[label];
  294. }
  295.         
  296. RTS::RTS()
  297. {
  298. }
  299.         
  300. void RTS::Execute() const
  301. {
  302.     if (callStack.empty())
  303.         done = true;
  304.     else {
  305.         pc = callStack.top();
  306.         callStack.pop();
  307.     }
  308. }
  309.         
  310. PUSH::PUSH(istream& s)
  311. {
  312.     value = ReadValue(s);
  313. }
  314.         
  315. void PUSH::Execute() const
  316. {
  317.     valueStack.push(value.Evaluate());
  318. }
  319.  
  320. POP::POP(istream& s)
  321. {
  322.     reg = ReadRegister(s);
  323. }
  324.         
  325. void POP::Execute() const
  326. {
  327.     registers[reg] = valueStack.top();
  328.     valueStack.pop();
  329. }
  330.  
  331. pascal void Interpret( Handle s,  RegisterArray result )
  332. {
  333.     labels.clear();
  334.     program.clear();
  335.     callStack = stack<int>();
  336.     valueStack = stack<int>();
  337.     BlockMove(result, registers, sizeof(registers));
  338.  
  339.     HLock(s);
  340.     int size = GetHandleSize(s);
  341.     std::string source(*s, size);
  342.     HUnlock(s);
  343.     std::istringstream in(source);
  344.     
  345.     // read a line
  346.     std::string line;
  347.     char macNL = 13;
  348.     while (getline(in, line, macNL)) {
  349.         std::istringstream l(line);
  350.         std::string opcode;
  351.         l >> opcode;
  352.         if (opcode[opcode.length() - 1] == ':') {
  353.             // label
  354.             opcode.erase(opcode.length() - 1);
  355.             labels[opcode] = program.size();
  356.             l >> opcode;
  357.         }
  358.         
  359.         if (opcode == "MOVE")
  360.             program.push_back(new MOVE(l));
  361.         else if (opcode == "ADD")
  362.             program.push_back(new ADD(l));
  363.         else if (opcode == "SUB")
  364.             program.push_back(new SUB(l));
  365.         else if (opcode == "JMP")
  366.             program.push_back(new JMP(l));
  367.         else if (opcode == "JEQ")
  368.             program.push_back(new JEQ(l));
  369.         else if (opcode == "JLE")
  370.             program.push_back(new JLE(l));
  371.         else if (opcode == "JSR")
  372.             program.push_back(new JSR(l));
  373.         else if (opcode == "RTS")
  374.             program.push_back(new RTS());
  375.         else if (opcode == "PUSH")
  376.             program.push_back(new PUSH(l));
  377.         else if (opcode == "POP")
  378.             program.push_back(new POP(l));
  379.     }
  380.     
  381.     pc = 0;
  382.     done = false;
  383.     
  384.     while (!done)
  385.         program[pc++]->Execute();
  386.     
  387.     BlockMove(registers, result, sizeof(registers));
  388. }
  389.