Mercurial > ~dholland > hg > ag > index.cgi
comparison tests/agcl/oldagsrc/bcip.syn @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13d2b8934445 |
---|---|
1 {/* | |
2 bcip.syn Version 1.0 | |
3 | |
4 A simple byte code compiler | |
5 | |
6 Copyright (c) 1996-1999 Parsifal Software, All Rights Reserved. | |
7 | |
8 The expression syntax is borrowed from C but with the addition | |
9 of the FORTRAN exponentiation operator (**). | |
10 | |
11 The cast, increment, and decrement operators are not | |
12 implemented, nor are the following operations that are defined | |
13 only for integers: | |
14 Bitwise logical operators: &, |, ^, ~, &=, |=, ^= | |
15 Remainder operators: %, %= | |
16 Shift operators: <<, >>, >>=, <<= | |
17 | |
18 The supported operations are: | |
19 Assignment operators: =, +=, -=, *=, /= | |
20 Conditional expressions: ? : | |
21 Logical operators: !, &&, || | |
22 Comparison operators: ==, !=, <, <=, >, >= | |
23 Binary arithmetic operators: +, -, *, / | |
24 Exponentiation: ** | |
25 Unary arithmetic operators: +, - | |
26 Parentheses ( ) | |
27 Built-in functions log, exp, sqrt | |
28 | |
29 All arithmetic is double precision floating point. | |
30 | |
31 Statements may include expression statements, blocks, if/else | |
32 statements, while statements, do-while statements, or for | |
33 statements, following the rules of C. | |
34 | |
35 The statement syntax has been written to avoid the conventional | |
36 if/else ambiguity. | |
37 | |
38 There are no declarations. All variables are presumed to be | |
39 double. | |
40 | |
41 Input strings may contain any number of statements. White space | |
42 may be used freely, including both C and C++ style comments. | |
43 | |
44 The parser is invoked by the constructor for the virtual machine | |
45 to parse the source code and compile it into byte code. | |
46 | |
47 With this organization, it is possible to create various | |
48 virtual machine objects all of which use the same symbol dictionary, | |
49 so that all can operate on the same data array. Furthermore, if | |
50 there are multiple data arrays, all consistent with the same | |
51 symbol dictionary, then any virtual machine object created using the | |
52 given symbol dictionary can operate on any of the data arrays. | |
53 | |
54 Thus a given virtual machine may operate on different data | |
55 arrays at different times. The data array, of course, must be | |
56 consistent with the symbol dictionary used to initialize the virtual | |
57 machine. | |
58 | |
59 The symbol dictionary maps character strings to indices into the | |
60 data array, so that each unique variable name is assigned a | |
61 particular location in the data array. Different virtual | |
62 machines may be initialized with the same symbol dictionary. When | |
63 this is done, these virtual machines can all operate on the | |
64 same data array. | |
65 | |
66 An override for the SYNTAX_ERROR macro defined by AnaGram and | |
67 the definition of the ScriptMethod class are in the bci.h | |
68 file. bci.cpp has function definitons for the ScriptMethod | |
69 class. bcidemo.cpp demonstrates one way to use the virtual | |
70 machine. | |
71 | |
72 bcip.syn is compiled with the AnaGram parser generator yielding | |
73 bcip.h and bcip.cpp. | |
74 | |
75 To build bcidemo, compile bcip.cpp, bci.cpp, cntnrs.cpp and bcidemo.cpp | |
76 and link them with your C++ compiler. | |
77 | |
78 For information about AnaGram, visit http://www.parsifalsoft.com. | |
79 */ | |
80 | |
81 #include <math.h> | |
82 #include "bci.h" // defines external interface | |
83 | |
84 } | |
85 // -- CONFIGURATION SECTION ---------------------------- | |
86 [ | |
87 disregard white space | |
88 lexeme {real, name} | |
89 pointer input | |
90 parser name = bciParse | |
91 parser file name = "#.cpp" | |
92 reentrant parser | |
93 extend pcb { | |
94 AgStringDictionary *symbolDictionary; | |
95 AgStack<double> realList; // List of real constants | |
96 int compile(AgStringDictionary *, AgString); | |
97 CodeFragment code; | |
98 | |
99 AgCharStack charStack; // Stack to accumulate variable names | |
100 int locateVariable(int k); // Identify variable named on character stack | |
101 int stashReal(double); | |
102 CodeFragment codeIfElse(CodeFragment &, CodeFragment &, CodeFragment &); | |
103 CodeFragment codeWhile(CodeFragment &, CodeFragment &); | |
104 CodeFragment codeDoWhile(CodeFragment &, CodeFragment &); | |
105 CodeFragment codeFor(CodeFragment &, CodeFragment &, CodeFragment &, CodeFragment &); | |
106 } | |
107 wrapper {CodeFragment} | |
108 ] | |
109 | |
110 (CodeFragment) input string $ // specify grammar token | |
111 -> statements:x, eof =x.cat(HLT); | |
112 | |
113 (CodeFragment) statements | |
114 -> =CodeFragment(); | |
115 -> statements:x, statement:y =x.cat(y); | |
116 | |
117 (CodeFragment) statement | |
118 -> open statement | |
119 -> closed statement | |
120 | |
121 // Any statement that could be followed by an else is an open statement | |
122 (CodeFragment) open statement | |
123 -> if clause:x, statement:s =x.cat(BRF, s.size()).cat(s); | |
124 -> if clause:x, closed statement:s1, | |
125 "else", open statement:s2 =PCB.codeIfElse(x,s1,s2); | |
126 -> while clause:x, open statement:s =PCB.codeWhile(x,s); | |
127 -> "for", '(', expression:init, ';', expression:cond, ';', | |
128 expression:inc, ')', open statement:s =PCB.codeFor(init, cond, inc, s); | |
129 | |
130 // A statement that cannot be followed by "else" is a closed statement | |
131 (CodeFragment) closed statement | |
132 -> simple statement | |
133 -> if clause:x, closed statement:s1, "else", | |
134 closed statement:s2 =PCB.codeIfElse(x,s1,s2); | |
135 -> while clause:x, closed statement:s =PCB.codeWhile(x,s); | |
136 -> "do", statement:s, while clause:x, ';' =PCB.codeDoWhile(s,x); | |
137 -> "for", '(', expression:init, ';', expression:cond, ';', | |
138 expression:inc, ')', closed statement:s =PCB.codeFor(init, cond, inc, s); | |
139 | |
140 (CodeFragment) if clause | |
141 -> "if", '(', expression:x, ')' =x; | |
142 | |
143 (CodeFragment) while clause | |
144 -> "while", '(', expression:x, ')' =x; | |
145 | |
146 (CodeFragment) simple statement | |
147 -> expression:x, ';' =x.cat(POP); | |
148 -> ';' =CodeFragment(); | |
149 -> '{', statements:s, '}' =s; | |
150 | |
151 (CodeFragment) expression | |
152 -> assignment expression | |
153 -> expression:x, ',', assignment expression:y =x.cat(POP).cat(y); | |
154 | |
155 (CodeFragment) assignment expression | |
156 -> conditional expression | |
157 -> name:k, '=', assignment expression:x =x.cat(STORE, k); | |
158 -> name:k, "+=", assignment expression:x =x.cat(ADDM, k); | |
159 -> name:k, "-=", assignment expression:x =x.cat(SUBM, k); | |
160 -> name:k, "*=", assignment expression:x =x.cat(MULM,k); | |
161 -> name:k, "/=", assignment expression:x =x.cat(DIVM, k); | |
162 | |
163 (CodeFragment) conditional expression | |
164 -> logical or expression | |
165 -> logical or expression:c, '?', expression:x, | |
166 ':', conditional expression:y =PCB.codeIfElse(c, x, y); | |
167 | |
168 (CodeFragment) logical or expression | |
169 -> logical and expression | |
170 -> logical and expression:x, "||", | |
171 logical or expression:y =x.cat(OR, y.size()).cat(y); | |
172 | |
173 (CodeFragment) logical and expression | |
174 -> equality expression | |
175 -> equality expression:x, "&&", | |
176 logical and expression:y =x.cat(AND, y.size()).cat(y); | |
177 | |
178 (CodeFragment) equality expression | |
179 -> relational expression | |
180 -> equality expression:x, "==", relational expression:y =x.cat(y).cat(EQ); | |
181 -> equality expression:x, "!=", relational expression:y =x.cat(y).cat(NE); | |
182 | |
183 (CodeFragment) relational expression | |
184 -> additive expression | |
185 -> relational expression:x, '<', additive expression:y =x.cat(y).cat(LT); | |
186 -> relational expression:x, "<=", additive expression:y =x.cat(y).cat(LE); | |
187 -> relational expression:x, '>', additive expression:y =x.cat(y).cat(GT); | |
188 -> relational expression:x, ">=", additive expression:y =x.cat(y).cat(GE); | |
189 | |
190 (CodeFragment) additive expression | |
191 -> multiplicative expression | |
192 -> additive expression:x, '+', multiplicative expression:y =x.cat(y).cat(ADD); | |
193 -> additive expression:x, '-', multiplicative expression:y =x.cat(y).cat(SUB); | |
194 | |
195 (CodeFragment) multiplicative expression | |
196 -> unary expression | |
197 -> multiplicative expression:x, '*', unary expression:y =x.cat(y).cat(MUL); | |
198 -> multiplicative expression:x, '/', unary expression:y =x.cat(y).cat(DIV); | |
199 | |
200 (CodeFragment) unary expression | |
201 -> factor | |
202 -> '-', unary expression:x =x.cat(NEG); | |
203 -> '+', unary expression:x = x; | |
204 | |
205 (CodeFragment) factor | |
206 -> primary | |
207 -> primary:x, "**", unary expression:y =x.cat(y).cat(POW); | |
208 | |
209 (CodeFragment) primary | |
210 -> real:x =CodeFragment().cat(PUSHI, x); | |
211 -> name:k =CodeFragment().cat(PUSH, k); | |
212 -> "log", '(', assignment expression:x, ')' =x.cat(LOG); | |
213 -> "exp", '(', assignment expression:x, ')' =x.cat(EXP); | |
214 -> "sqrt", '(', assignment expression:x, ')' =x.cat(SQRT); | |
215 -> '(', expression:x, ')' =x; | |
216 -> '!', primary:x =x.cat(NOT); | |
217 | |
218 // -- LEXICAL UNITS ------------------------------------------------ | |
219 digit = '0-9' | |
220 eof = 0 | |
221 letter = 'a-z' + 'A-Z' + '_' | |
222 | |
223 (void) white space | |
224 -> ' ' + '\t' + '\f' + '\v' + '\r' + '\n' | |
225 -> "/*", ~eof?..., "*/" // C style comment | |
226 -> "//", ~(eof+'\n')?..., '\n' // C++ style comment | |
227 | |
228 (int) real | |
229 -> simple real:x =PCB.stashReal(x); | |
230 -> simple real:x, 'e'+'E', '+'?,exponent:e =PCB.stashReal(x*pow(10,e)); | |
231 -> simple real:x, 'e'+'E', '-',exponent:e =PCB.stashReal(x*pow(10,-e)); | |
232 | |
233 (double) simple real | |
234 -> integer part:i, '.', fraction part:f = i+f; | |
235 -> integer part, '.'? | |
236 -> '.', fraction part:f = f; | |
237 | |
238 (double) integer part | |
239 -> digit:d = d-'0'; | |
240 -> integer part:x, digit:d = 10*x + d-'0'; | |
241 | |
242 (double) fraction part | |
243 -> digit:d =(d-'0')/10.; | |
244 -> digit:d, fraction part:f =(d-'0' + f)/10.; | |
245 | |
246 (int) exponent | |
247 -> digit:d = d-'0'; | |
248 -> exponent:x, digit:d = 10*x + d-'0'; | |
249 | |
250 (int) name | |
251 -> name string =PCB.symbolDictionary->identify(PCB.charStack.popString()); | |
252 | |
253 name string | |
254 -> letter: c =PCB.charStack.push((char) c); | |
255 -> name string, letter+digit: c =PCB.charStack.push((char) c); | |
256 | |
257 { // Begin embedded C | |
258 | |
259 #define SYNTAX_ERROR | |
260 | |
261 int bciParse_pcb_struct::stashReal(double x) { | |
262 int n = realList.size(); | |
263 realList.push(x); | |
264 return n; | |
265 } | |
266 | |
267 CodeFragment bciParse_pcb_struct::codeIfElse(CodeFragment &condition, | |
268 CodeFragment &trueStatement, | |
269 CodeFragment &falseStatement) | |
270 { | |
271 return condition.cat(BRF, trueStatement.size() + 2) | |
272 .cat(trueStatement) | |
273 .cat(BR, falseStatement.size()) | |
274 .cat(falseStatement); | |
275 } | |
276 | |
277 CodeFragment bciParse_pcb_struct::codeWhile(CodeFragment &condition, | |
278 CodeFragment &statement) | |
279 { | |
280 // loop back distance is length of statement + length of condition + 2 branch instructions | |
281 int loopBackDistance = condition.size() + statement.size() + 4; | |
282 return condition.cat(BRF, statement.size() + 2) // size of statement +size of loopback | |
283 .cat(statement) | |
284 .cat(BR, -loopBackDistance); | |
285 } | |
286 | |
287 CodeFragment bciParse_pcb_struct::codeDoWhile(CodeFragment &statement, | |
288 CodeFragment &condition) | |
289 { | |
290 // loop back distance is | |
291 // length of statement + length of condition + 1 branch instruction | |
292 int loopBackDistance = statement.size() + condition.size() + 2; | |
293 return statement.cat(condition) | |
294 .cat(BRT, -loopBackDistance); | |
295 } | |
296 | |
297 CodeFragment bciParse_pcb_struct::codeFor(CodeFragment &initializer, | |
298 CodeFragment &condition, | |
299 CodeFragment &increment, | |
300 CodeFragment &statement) | |
301 { | |
302 // Calculate the length of the jump back at the bottom of the loop | |
303 // It consists of the length of the increment, condition and statement | |
304 // CodeFragments + 5 inserted Bytecodes: 1 Pop, and 2 each for each of | |
305 // two branches | |
306 int loopBackDistance = increment.size() + condition.size() + statement.size() + 5; | |
307 | |
308 // Put it all together | |
309 return initializer.cat(POP) // clear expression value from stack | |
310 .cat(BR, increment.size() + 1) // Skip increment on first time through | |
311 .cat(increment).cat(POP) // clear expresson value from stack | |
312 .cat(condition) | |
313 .cat(BRF, statement.size() + 2) // exit when condition is false | |
314 .cat(statement) | |
315 .cat(BR, -loopBackDistance); | |
316 } | |
317 | |
318 int bciParse_pcb_struct::compile(AgStringDictionary *s, AgString text) { | |
319 symbolDictionary = s; | |
320 charStack.reset(); | |
321 pointer = (unsigned char *) text.ptr(); | |
322 bciParse(this); | |
323 if(exit_flag != AG_SUCCESS_CODE) return 1; | |
324 code = bciParse_value(this); | |
325 return 0; | |
326 } | |
327 | |
328 } // End of embedded C | |
329 /********************* End of bcip.syn ************************/ | |
330 |