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