]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/classic/example/fundamental/more_calculators/vmachine_calc.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / spirit / classic / example / fundamental / more_calculators / vmachine_calc.cpp
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:
45 vmachine(unsigned stackSize = 1024)
46 : stack(new int[stackSize]),
47 stackPtr(stack) {}
48 ~vmachine() { delete [] stack; }
49 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
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 {
112 push_int(vector<int>& code_)
113 : code(code_) {}
114
115 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 {
129 push_op(int op_, vector<int>& code_)
130 : op(op_), code(code_) {}
131
132 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
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 {
197 calculator(vector<int>& code_)
198 : code(code_) {}
199
200 template <typename ScannerT>
201 struct definition
202 {
203 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&
234 start() const { return expression; }
235 };
236
237 vector<int>& code;
238 };
239
240 ////////////////////////////////////////////////////////////////////////////
241 //
242 // Main program
243 //
244 ////////////////////////////////////////////////////////////////////////////
245 int
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