1 /*=============================================================================
2     Copyright (c) 1998-2003 Joel de Guzman
3     http://spirit.sourceforge.net/
4 
5     Use, modification and distribution is subject to the Boost Software
6     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7     http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 ////////////////////////////////////////////////////////////////////////////
10 //
11 //  The calculator using a simple virtual machine and compiler.
12 //
13 //  Ported to v1.5 from the original v1.0 code by JDG
14 //  [ JDG 9/18/2002 ]
15 //
16 ////////////////////////////////////////////////////////////////////////////
17 #include <boost/spirit/include/classic_core.hpp>
18 #include <iostream>
19 #include <vector>
20 #include <string>
21 
22 ////////////////////////////////////////////////////////////////////////////
23 using namespace std;
24 using namespace BOOST_SPIRIT_CLASSIC_NS;
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 //  The VMachine
29 //
30 ///////////////////////////////////////////////////////////////////////////////
31 enum ByteCodes
32 {
33     OP_NEG,     //  negate the top stack entry
34     OP_ADD,     //  add top two stack entries
35     OP_SUB,     //  subtract top two stack entries
36     OP_MUL,     //  multiply top two stack entries
37     OP_DIV,     //  divide top two stack entries
38     OP_INT,     //  push constant integer into the stack
39     OP_RET      //  return from the interpreter
40 };
41 
42 class vmachine
43 {
44 public:
vmachine(unsigned stackSize=1024)45                 vmachine(unsigned stackSize = 1024)
46                 :   stack(new int[stackSize]),
47                     stackPtr(stack) {}
~vmachine()48                 ~vmachine() { delete [] stack; }
top() const49     int         top() const { return stackPtr[-1]; };
50     void        execute(int code[]);
51 
52 private:
53 
54     int*        stack;
55     int*        stackPtr;
56 };
57 
58 void
execute(int code[])59 vmachine::execute(int code[])
60 {
61     int const*  pc = code;
62     bool        running = true;
63     stackPtr = stack;
64 
65     while (running)
66     {
67         switch (*pc++)
68         {
69             case OP_NEG:
70                 stackPtr[-1] = -stackPtr[-1];
71                 break;
72 
73             case OP_ADD:
74                 stackPtr--;
75                 stackPtr[-1] += stackPtr[0];
76                 break;
77 
78             case OP_SUB:
79                 stackPtr--;
80                 stackPtr[-1] -= stackPtr[0];
81                 break;
82 
83             case OP_MUL:
84                 stackPtr--;
85                 stackPtr[-1] *= stackPtr[0];
86                 break;
87 
88             case OP_DIV:
89                 stackPtr--;
90                 stackPtr[-1] /= stackPtr[0];
91                 break;
92 
93             case OP_INT:
94                 // Check stack overflow here!
95                 *stackPtr++ = *pc++;
96                 break;
97 
98             case OP_RET:
99                 running = false;
100                 break;
101         }
102     }
103 }
104 
105 ///////////////////////////////////////////////////////////////////////////////
106 //
107 //  The Compiler
108 //
109 ///////////////////////////////////////////////////////////////////////////////
110 struct push_int
111 {
push_intpush_int112     push_int(vector<int>& code_)
113     : code(code_) {}
114 
operator ()push_int115     void operator()(char const* str, char const* /*end*/) const
116     {
117         using namespace std;
118         int n = strtol(str, 0, 10);
119         code.push_back(OP_INT);
120         code.push_back(n);
121         cout << "push\t" << int(n) << endl;
122     }
123 
124     vector<int>& code;
125 };
126 
127 struct push_op
128 {
push_oppush_op129     push_op(int op_, vector<int>& code_)
130     : op(op_), code(code_) {}
131 
operator ()push_op132     void operator()(char const*, char const*) const
133     {
134         code.push_back(op);
135 
136         switch (op) {
137 
138             case OP_NEG:
139                 cout << "neg\n";
140                 break;
141 
142             case OP_ADD:
143                 cout << "add\n";
144                 break;
145 
146             case OP_SUB:
147                 cout << "sub\n";
148                 break;
149 
150             case OP_MUL:
151                 cout << "mul\n";
152                 break;
153 
154             case OP_DIV:
155                 cout << "div\n";
156                 break;
157         }
158     }
159 
160     int op;
161     vector<int>& code;
162 };
163 
164 template <typename GrammarT>
165 static bool
compile(GrammarT const & calc,char const * expr)166 compile(GrammarT const& calc, char const* expr)
167 {
168     cout << "\n/////////////////////////////////////////////////////////\n\n";
169 
170     parse_info<char const*>
171         result = parse(expr, calc, space_p);
172 
173     if (result.full)
174     {
175         cout << "\t\t" << expr << " Parses OK\n\n\n";
176         calc.code.push_back(OP_RET);
177         return true;
178     }
179     else
180     {
181         cout << "\t\t" << expr << " Fails parsing\n";
182         cout << "\t\t";
183         for (int i = 0; i < (result.stop - expr); i++)
184             cout << " ";
185         cout << "^--Here\n\n\n";
186         return false;
187     }
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////
191 //
192 //  Our calculator grammar
193 //
194 ////////////////////////////////////////////////////////////////////////////
195 struct calculator : public grammar<calculator>
196 {
calculatorcalculator197     calculator(vector<int>& code_)
198     : code(code_) {}
199 
200     template <typename ScannerT>
201     struct definition
202     {
definitioncalculator::definition203         definition(calculator const& self)
204         {
205             integer =
206                 lexeme_d[ (+digit_p)[push_int(self.code)] ]
207                 ;
208 
209             factor =
210                     integer
211                 |   '(' >> expression >> ')'
212                 |   ('-' >> factor)[push_op(OP_NEG, self.code)]
213                 |   ('+' >> factor)
214                 ;
215 
216             term =
217                 factor
218                 >> *(   ('*' >> factor)[push_op(OP_MUL, self.code)]
219                     |   ('/' >> factor)[push_op(OP_DIV, self.code)]
220                     )
221                     ;
222 
223             expression =
224                 term
225                 >> *(   ('+' >> term)[push_op(OP_ADD, self.code)]
226                     |   ('-' >> term)[push_op(OP_SUB, self.code)]
227                     )
228                     ;
229         }
230 
231         rule<ScannerT> expression, term, factor, integer;
232 
233         rule<ScannerT> const&
startcalculator::definition234         start() const { return expression; }
235     };
236 
237     vector<int>& code;
238 };
239 
240 ////////////////////////////////////////////////////////////////////////////
241 //
242 //  Main program
243 //
244 ////////////////////////////////////////////////////////////////////////////
245 int
main()246 main()
247 {
248     cout << "/////////////////////////////////////////////////////////\n\n";
249     cout << "\t\tA simple virtual machine...\n\n";
250     cout << "/////////////////////////////////////////////////////////\n\n";
251     cout << "Type an expression...or [q or Q] to quit\n\n";
252 
253     vmachine    mach;       //  Our virtual machine
254     vector<int> code;       //  Our VM code
255     calculator  calc(code); //  Our parser
256 
257     string str;
258     while (getline(cin, str))
259     {
260         if (str.empty() || str[0] == 'q' || str[0] == 'Q')
261             break;
262 
263         code.clear();
264         if (compile(calc, str.c_str()))
265         {
266             mach.execute(&*code.begin());
267             cout << "\n\nresult = " << mach.top() << "\n\n";
268         }
269     }
270 
271     cout << "Bye... :-) \n\n";
272     return 0;
273 }
274 
275 
276