Mercurial > ~dholland > hg > ag > index.cgi
comparison tests/agcl/oldagsrc/asiwdp.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 /* | |
3 asiwdp.syn | |
4 | |
5 ASI -- A Simple Interpreter | |
6 Copyright (c) 1999 Parsifal Software, All Rights Reserved. | |
7 | |
8 This implementation of ASI uses C++ and was developed | |
9 as part of the ASI Windows Demonstration program to | |
10 illustrate the use of the "reentrant parser" switch | |
11 and the "extend pcb" statement to create a thread-safe | |
12 parser. The example program uses a Microsoft Foundation | |
13 Class program to demonstrate multiple instances of an | |
14 AnaGram parser running concurrently on separate threads. | |
15 | |
16 The expression syntax is borrowed from C but with the | |
17 addition of the FORTRAN exponentiation operator (**). | |
18 | |
19 The cast, increment, and decrement operators are not | |
20 implemented, nor are operations that are defined only | |
21 for integers: | |
22 Bitwise logical operators: &, |, ^, ~, &=, |=, ^= | |
23 Remainder operators: %, %= | |
24 Shift operators: <<, >>, >>=, <<= | |
25 | |
26 The supported operations are: | |
27 Assignment operators: =, +=, -=, *=, /= | |
28 Conditional expressions: ? : | |
29 Logical operators: !, &&, || | |
30 Comparison operators: ==, !=, <, <=, >, >= | |
31 Binary arithmetic operators: +, -, *, / | |
32 Exponentiation: ** | |
33 Unary arithmetic operators: +, - | |
34 Parentheses | |
35 Function calls | |
36 | |
37 All arithmetic is double precision floating point. | |
38 | |
39 Statements may include expression statements, blocks, if/else statements | |
40 or while statements, following the rules of C. | |
41 | |
42 The statement syntax has been written to avoid the conventional | |
43 if/else ambiguity. | |
44 | |
45 There are no declarations. All variables are presumed to be double. | |
46 | |
47 Input strings may contain any number of statements. White space may be | |
48 used freely, including both C and C++ style comments. | |
49 | |
50 asiwd uses the following classes, defined in asiwdef.h: | |
51 CharStack // Used to accumulate variable names | |
52 SymbolTable // Maintains variable names and values | |
53 WhileStack // Maintains state of active while loops | |
54 Location // Records location in source text | |
55 | |
56 The AnaGram parser generator uses asiwdp.syn as a specification to | |
57 create a C++ parser file asiwdp.cpp and a companion header file, | |
58 asiwdp.h. | |
59 | |
60 For information about AnaGram, visit http://www.parsifalsoft.com. | |
61 */ | |
62 | |
63 #include "asiwdef.h" | |
64 | |
65 } | |
66 // -- CONFIGURATION SECTION ---------------------------- | |
67 [ | |
68 default token type = double | |
69 disregard white space // Skip over white space | |
70 lexeme {real, name} // No white space in reals or names | |
71 pointer input // Take input from array in memory | |
72 parser name = asi // Name parser function | |
73 parser file name = "#.cpp" // Name parser file | |
74 line numbers // Generate #line directives | |
75 reentrant parser // Make parser reentrant | |
76 extend pcb { // Add declarations to parser control block | |
77 CharStack charStack; // Stack to accumulate variable names | |
78 WhileStack whileStack; // Stack of active while loops | |
79 SymbolTable *symbolTable; // Pointer to external symbol table | |
80 | |
81 void pushChar(int c); // Add character to character stack | |
82 double *locateValue(int k); // Identify variable named on character stack | |
83 void stackLoop(const Location &c); // Provide for nested while loops | |
84 Location location(); // Capture current location of parse | |
85 void setLocation(const Location &l); // Set location of parse | |
86 void loopContinue(); // Set location to continue current while loop | |
87 void loopExit(); // Set location to exit current while loop | |
88 double checkZero(double value); // Check for zero divisor | |
89 | |
90 // External interface to the parser | |
91 int interpret(char *text, SymbolTable *s); // Parse instructions in text, using variables defined in s | |
92 } | |
93 ] | |
94 | |
95 (void) input string $ // specify grammar token | |
96 -> statements?, eof | |
97 | |
98 (void) statements | |
99 -> statement | |
100 -> statements, statement | |
101 | |
102 /* | |
103 Syntax to skip over statements without executing them. | |
104 This syntax is required for if statements and while loops. | |
105 | |
106 The skip logic is used to do a preliminary scan of while | |
107 statements to identify the location of the while condition and | |
108 the exit point. Then, by manipulating the pointer field of the | |
109 parser control block, the while loop can be scanned as | |
110 many times as is necessary. | |
111 | |
112 This syntax also shows the bare bones of the technique for | |
113 handling the conventional if/else ambiguity correctly, without | |
114 recourse to methods of less than complete rigor. | |
115 | |
116 To deal with the if/else problem, we classify statements into | |
117 two classes: those which contain a dangling if clause and those | |
118 thatdon't. We call the former "open statements" and the | |
119 latter "closed statements". | |
120 | |
121 Note that one effect of this classification is that we must | |
122 implement the while statment twice: once controlling a | |
123 closed statement and once controlling an open statement. | |
124 */ | |
125 | |
126 (void) skip statement | |
127 -> skip open statement | |
128 -> skip closed statement | |
129 | |
130 (void) skip closed statement | |
131 -> statement text?, ';' | |
132 -> balanced braces | |
133 -> "if", balanced parens, skip closed statement, "else", skip closed statement | |
134 -> "while", balanced parens, skip closed statement | |
135 | |
136 skip open statement | |
137 -> "if", balanced parens, skip statement | |
138 -> "if", balanced parens, skip closed statement, "else", skip open statement | |
139 -> "while", balanced parens, skip open statement | |
140 | |
141 /* | |
142 The syntax for statements is essentially the same as for skipping | |
143 statements. The primary difference is that expressions are actually | |
144 evaluated, rather than skipped, and the conditions in if statements | |
145 are evaluated and acted upon. | |
146 */ | |
147 | |
148 (void) statement | |
149 -> open statement | |
150 -> closed statement | |
151 | |
152 (void) closed statement | |
153 -> expression, ';' | |
154 -> ';' | |
155 -> '{', '}' | |
156 -> '{', statements, '}' | |
157 -> true if condition, closed statement, "else", skip closed statement | |
158 -> false if condition, skip closed statement, "else", closed statement | |
159 -> closed while, execute while | |
160 | |
161 /* | |
162 The following syntax uses a semantically determined production | |
163 to separate if conditions into true and false conditions. | |
164 */ | |
165 | |
166 (void) open statement | |
167 -> true if condition, statement | |
168 -> false if condition, skip statement | |
169 -> true if condition, closed statement, "else", skip open statement | |
170 -> false if condition, skip closed statement, "else", open statement | |
171 -> open while, execute while | |
172 | |
173 (void) true if condition, false if condition | |
174 -> "if", '(', expression:x, ')' ={if (x == 0) CHANGE_REDUCTION(false_if_condition);} | |
175 | |
176 (void) closed while | |
177 -> while:c, balanced parens, skip closed statement =PCB.stackLoop(c); | |
178 | |
179 (void) open while | |
180 -> while:c, balanced parens, skip open statement =PCB.stackLoop(c); | |
181 | |
182 (Location) while | |
183 -> "while" =PCB.location(); | |
184 | |
185 /* | |
186 The "execute while" syntax does not actually occur in the | |
187 input file. It is actually the implementation of the while | |
188 loop. The "closed while" productions identify and stack | |
189 the locations of the while condition and the exit location in | |
190 the script file. The "while loop" productions reset the input | |
191 pointer to the while condition. On encountering a false | |
192 condition, the "execute while" production restores the input | |
193 pointer to the end of the while loop so that normal parsing | |
194 can then continue. | |
195 */ | |
196 | |
197 (void) execute while | |
198 -> while loop, false while condition =PCB.loopExit(); | |
199 | |
200 (void) while loop | |
201 -> | |
202 -> while loop, true while condition, statement =PCB.loopContinue(); | |
203 | |
204 // Semantically determined production to control parsing of while loop | |
205 | |
206 (void) true while condition, false while condition | |
207 -> '(', expression:x, ')' =x == 0 ? CHANGE_REDUCTION(false_while_condition) : 0; | |
208 | |
209 /* | |
210 The following expression syntax is essentially that of C/C++. | |
211 An exponentiation operator, similar to that in Fortran has | |
212 been added. Note that the right hand operand of the && and || | |
213 operators is evaluated whether it needs to be or not. | |
214 */ | |
215 | |
216 expression | |
217 -> conditional expression | |
218 -> name:pointer, '=', expression:x =*pointer = x; | |
219 -> name:pointer, "+=", expression:x =*pointer += x; | |
220 -> name:pointer, "-=", expression:x =*pointer -= x; | |
221 -> name:pointer, "*=", expression:x =*pointer *= x; | |
222 -> name:pointer, "/=", expression:x =*pointer /= x; | |
223 | |
224 conditional expression | |
225 -> logical or expression | |
226 -> logical or expression:c, '?', | |
227 expression:x, ':', conditional expression:y =c ? x : y; | |
228 | |
229 logical or expression | |
230 -> logical and expression | |
231 -> logical or expression:x, "||", logical and expression:y = x ? x : y; | |
232 | |
233 logical and expression | |
234 -> equality expression | |
235 -> logical and expression:x, "&&", equality expression:y =x ? y : x; | |
236 | |
237 equality expression | |
238 -> relational expression | |
239 -> equality expression:x, "==", relational expression:y =x == y; | |
240 -> equality expression:x, "!=", relational expression:y =x != y; | |
241 | |
242 relational expression | |
243 -> additive expression | |
244 -> relational expression:x, '<', additive expression:y =x < y; | |
245 -> relational expression:x, "<=", additive expression:y =x <= y; | |
246 -> relational expression:x, '>', additive expression:y =x > y; | |
247 -> relational expression:x, ">=", additive expression:y =x >= y; | |
248 | |
249 additive expression | |
250 -> multiplicative expression | |
251 -> additive expression:x, '+', multiplicative expression:y =x + y; | |
252 -> additive expression:x, '-', multiplicative expression:y =x - y; | |
253 | |
254 multiplicative expression | |
255 -> unary expression | |
256 -> multiplicative expression:x, '*', unary expression:y =x * y; | |
257 -> multiplicative expression:x, '/', unary expression:y =x/PCB.checkZero(y); | |
258 | |
259 unary expression | |
260 -> factor | |
261 -> '-', unary expression:x =-x; | |
262 -> '+', unary expression:x =x; | |
263 | |
264 factor | |
265 -> primary | |
266 -> primary:x, "**", unary expression:y =pow(x,y); | |
267 | |
268 primary | |
269 -> real | |
270 -> name:valuePointer =*valuePointer; | |
271 -> "log", '(', expression:x, ')' =log(x); | |
272 -> "exp", '(', expression:x, ')' =exp(x); | |
273 -> "sin", '(', expression:x, ')' =sin(x); | |
274 -> "cos", '(', expression:x, ')' =cos(x); | |
275 -> "tan", '(', expression:x, ')' =tan(x); | |
276 -> '(', expression:x, ')' =x; | |
277 -> '!', primary:x = x == 0; | |
278 | |
279 // -- LEXICAL UNITS ------------------------------------------------ | |
280 blank = ' ' + '\t' + '\f' + '\v' + '\r' + '\n' | |
281 digit = '0-9' | |
282 eof = 0 | |
283 letter = 'a-z' + 'A-Z' + '_' | |
284 statement char = 32..126 - blank - ';' - '(' - ')' - '{' - '}' | |
285 | |
286 (void) white space | |
287 -> blank | |
288 -> "/*", ~eof?..., "*/" // C style comment | |
289 -> "//", ~(eof+'\n')?..., '\n' // C++ style comment | |
290 | |
291 // Productions for use skipping over statements | |
292 | |
293 statement text | |
294 -> statement char | |
295 -> balanced parens | |
296 -> statement text, statement char | |
297 -> statement text, balanced parens | |
298 -> statement text, balanced braces | |
299 | |
300 balanced parens | |
301 -> '(', statement text?, ')' | |
302 | |
303 balanced braces | |
304 -> '{', [statement text?, ';']..., '}' | |
305 -> '{', balanced braces, '}' | |
306 | |
307 /* | |
308 Identifying variable names | |
309 | |
310 Characters in a name string are pushed onto the character | |
311 stack. The integer value of the name string token is the | |
312 length of the string on the stack. | |
313 | |
314 The locate function returns a pointer to the value of the | |
315 named variable. If the variable has not been previously | |
316 referenced, its value is initialized to zero. | |
317 */ | |
318 | |
319 (int) name string | |
320 -> letter: c =PCB.charStack.push(c), 1; | |
321 -> name string:k, letter+digit: c =PCB.charStack.push(c), k+1; | |
322 | |
323 (double *) name | |
324 -> name string:k =PCB.locateValue(k); | |
325 | |
326 // Parsing and evaluating numeric constants | |
327 | |
328 real | |
329 -> simple real | |
330 -> simple real:x, 'e'+'E', '+'?,exponent:e =x*pow(10,e); | |
331 -> simple real:x, 'e'+'E', '-',exponent:e =x*pow(10,-e); | |
332 | |
333 simple real | |
334 -> integer part:i, '.', fraction part:f = i+f; | |
335 -> integer part, '.'? | |
336 -> '.', fraction part:f = f; | |
337 | |
338 integer part | |
339 -> digit:d = d-'0'; | |
340 -> integer part:x, digit:d = 10*x + d-'0'; | |
341 | |
342 fraction part | |
343 -> digit:d =(d-'0')/10.; | |
344 -> digit:d, fraction part:f =(d-'0' + f)/10.; | |
345 | |
346 (int) exponent | |
347 -> digit:d = d-'0'; | |
348 -> exponent:x, digit:d = 10*x + d-'0'; | |
349 | |
350 | |
351 { // begin embedded C | |
352 | |
353 #include <math.h> | |
354 | |
355 // Check for division by zero | |
356 double asi_pcb_type::checkZero(double value) { | |
357 if (value) return value; | |
358 error_message = "Divide by Zero"; | |
359 exit_flag = AG_SEMANTIC_ERROR_CODE; | |
360 return 1; | |
361 } | |
362 | |
363 // external interface to the parser | |
364 int asi_pcb_type::interpret(char *text, SymbolTable *st) { | |
365 symbolTable = st; | |
366 charStack.reset(); | |
367 pointer = (unsigned char *) text; | |
368 asi(this); | |
369 return exit_flag != AG_SUCCESS_CODE; | |
370 } | |
371 | |
372 /* | |
373 locate value of variable whose name is given by the top k characters on the | |
374 character stack. | |
375 Return a pointer so the value can be either fetched or stored | |
376 */ | |
377 | |
378 double *asi_pcb_type::locateValue(int k) { | |
379 double *pointer = &symbolTable->locate(charStack.popString(k)).value; | |
380 if (symbolTable->overflow()) { | |
381 error_message = "Symbol table overflow"; | |
382 exit_flag = AG_SEMANTIC_ERROR_CODE; | |
383 } | |
384 return pointer; | |
385 } | |
386 | |
387 // Encapsulate current location in source text | |
388 Location asi_pcb_type::location() { | |
389 return Location(pointer, line, column); | |
390 } | |
391 | |
392 // Set source file location for loop continuation | |
393 void asi_pcb_type::loopContinue() { | |
394 setLocation(whileStack.continueLocation()); | |
395 } | |
396 | |
397 // Set source file location for loop exit | |
398 void asi_pcb_type::loopExit() { | |
399 setLocation(whileStack.exitLocation()); | |
400 whileStack.pop(); | |
401 } | |
402 | |
403 // Push character onto character stack | |
404 void asi_pcb_type::pushChar(int c) { | |
405 if (charStack.push(c)) { | |
406 error_message = "Name is too long"; | |
407 exit_flag = AG_SEMANTIC_ERROR_CODE; | |
408 } | |
409 } | |
410 | |
411 // Set parse location in source text | |
412 void asi_pcb_type::setLocation(const Location &l) { | |
413 pointer = l.pointer; | |
414 line = l.line; | |
415 column = l.column; | |
416 } | |
417 | |
418 // Save currently active loop, if any, and init nested loop | |
419 void asi_pcb_type::stackLoop(const Location &c) { | |
420 // Current source location is exit location for loop | |
421 // c is the continue location | |
422 if (whileStack.push(c, location())) { | |
423 error_message = "While stack overflow"; | |
424 exit_flag = AG_SEMANTIC_ERROR_CODE; | |
425 } | |
426 setLocation(c); // Set location to loop condition | |
427 } | |
428 | |
429 } // end of embedded C |