Mercurial > ~dholland > hg > ag > index.cgi
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/agcl/oldagsrc/asiwdp.syn Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,429 @@ +{ +/* + asiwdp.syn + + ASI -- A Simple Interpreter + Copyright (c) 1999 Parsifal Software, All Rights Reserved. + + This implementation of ASI uses C++ and was developed + as part of the ASI Windows Demonstration program to + illustrate the use of the "reentrant parser" switch + and the "extend pcb" statement to create a thread-safe + parser. The example program uses a Microsoft Foundation + Class program to demonstrate multiple instances of an + AnaGram parser running concurrently on separate threads. + + The expression syntax is borrowed from C but with the + addition of the FORTRAN exponentiation operator (**). + + The cast, increment, and decrement operators are not + implemented, nor are operations that are defined only + for integers: + Bitwise logical operators: &, |, ^, ~, &=, |=, ^= + Remainder operators: %, %= + Shift operators: <<, >>, >>=, <<= + + The supported operations are: + Assignment operators: =, +=, -=, *=, /= + Conditional expressions: ? : + Logical operators: !, &&, || + Comparison operators: ==, !=, <, <=, >, >= + Binary arithmetic operators: +, -, *, / + Exponentiation: ** + Unary arithmetic operators: +, - + Parentheses + Function calls + + All arithmetic is double precision floating point. + + Statements may include expression statements, blocks, if/else statements + or while statements, following the rules of C. + + The statement syntax has been written to avoid the conventional + if/else ambiguity. + + There are no declarations. All variables are presumed to be double. + + Input strings may contain any number of statements. White space may be + used freely, including both C and C++ style comments. + + asiwd uses the following classes, defined in asiwdef.h: + CharStack // Used to accumulate variable names + SymbolTable // Maintains variable names and values + WhileStack // Maintains state of active while loops + Location // Records location in source text + + The AnaGram parser generator uses asiwdp.syn as a specification to + create a C++ parser file asiwdp.cpp and a companion header file, + asiwdp.h. + + For information about AnaGram, visit http://www.parsifalsoft.com. +*/ + +#include "asiwdef.h" + +} +// -- CONFIGURATION SECTION ---------------------------- +[ + default token type = double + disregard white space // Skip over white space + lexeme {real, name} // No white space in reals or names + pointer input // Take input from array in memory + parser name = asi // Name parser function + parser file name = "#.cpp" // Name parser file + line numbers // Generate #line directives + reentrant parser // Make parser reentrant + extend pcb { // Add declarations to parser control block + CharStack charStack; // Stack to accumulate variable names + WhileStack whileStack; // Stack of active while loops + SymbolTable *symbolTable; // Pointer to external symbol table + + void pushChar(int c); // Add character to character stack + double *locateValue(int k); // Identify variable named on character stack + void stackLoop(const Location &c); // Provide for nested while loops + Location location(); // Capture current location of parse + void setLocation(const Location &l); // Set location of parse + void loopContinue(); // Set location to continue current while loop + void loopExit(); // Set location to exit current while loop + double checkZero(double value); // Check for zero divisor + + // External interface to the parser + int interpret(char *text, SymbolTable *s); // Parse instructions in text, using variables defined in s + } +] + +(void) input string $ // specify grammar token + -> statements?, eof + +(void) statements + -> statement + -> statements, statement + +/* + Syntax to skip over statements without executing them. + This syntax is required for if statements and while loops. + + The skip logic is used to do a preliminary scan of while + statements to identify the location of the while condition and + the exit point. Then, by manipulating the pointer field of the + parser control block, the while loop can be scanned as + many times as is necessary. + + This syntax also shows the bare bones of the technique for + handling the conventional if/else ambiguity correctly, without + recourse to methods of less than complete rigor. + + To deal with the if/else problem, we classify statements into + two classes: those which contain a dangling if clause and those + thatdon't. We call the former "open statements" and the + latter "closed statements". + + Note that one effect of this classification is that we must + implement the while statment twice: once controlling a + closed statement and once controlling an open statement. +*/ + +(void) skip statement + -> skip open statement + -> skip closed statement + +(void) skip closed statement + -> statement text?, ';' + -> balanced braces + -> "if", balanced parens, skip closed statement, "else", skip closed statement + -> "while", balanced parens, skip closed statement + +skip open statement + -> "if", balanced parens, skip statement + -> "if", balanced parens, skip closed statement, "else", skip open statement + -> "while", balanced parens, skip open statement + +/* + The syntax for statements is essentially the same as for skipping + statements. The primary difference is that expressions are actually + evaluated, rather than skipped, and the conditions in if statements + are evaluated and acted upon. +*/ + +(void) statement + -> open statement + -> closed statement + +(void) closed statement + -> expression, ';' + -> ';' + -> '{', '}' + -> '{', statements, '}' + -> true if condition, closed statement, "else", skip closed statement + -> false if condition, skip closed statement, "else", closed statement + -> closed while, execute while + +/* + The following syntax uses a semantically determined production + to separate if conditions into true and false conditions. +*/ + +(void) open statement + -> true if condition, statement + -> false if condition, skip statement + -> true if condition, closed statement, "else", skip open statement + -> false if condition, skip closed statement, "else", open statement + -> open while, execute while + +(void) true if condition, false if condition + -> "if", '(', expression:x, ')' ={if (x == 0) CHANGE_REDUCTION(false_if_condition);} + +(void) closed while + -> while:c, balanced parens, skip closed statement =PCB.stackLoop(c); + +(void) open while + -> while:c, balanced parens, skip open statement =PCB.stackLoop(c); + +(Location) while + -> "while" =PCB.location(); + +/* + The "execute while" syntax does not actually occur in the + input file. It is actually the implementation of the while + loop. The "closed while" productions identify and stack + the locations of the while condition and the exit location in + the script file. The "while loop" productions reset the input + pointer to the while condition. On encountering a false + condition, the "execute while" production restores the input + pointer to the end of the while loop so that normal parsing + can then continue. +*/ + +(void) execute while + -> while loop, false while condition =PCB.loopExit(); + +(void) while loop + -> + -> while loop, true while condition, statement =PCB.loopContinue(); + +// Semantically determined production to control parsing of while loop + +(void) true while condition, false while condition + -> '(', expression:x, ')' =x == 0 ? CHANGE_REDUCTION(false_while_condition) : 0; + +/* + The following expression syntax is essentially that of C/C++. + An exponentiation operator, similar to that in Fortran has + been added. Note that the right hand operand of the && and || + operators is evaluated whether it needs to be or not. +*/ + +expression + -> conditional expression + -> name:pointer, '=', expression:x =*pointer = x; + -> name:pointer, "+=", expression:x =*pointer += x; + -> name:pointer, "-=", expression:x =*pointer -= x; + -> name:pointer, "*=", expression:x =*pointer *= x; + -> name:pointer, "/=", expression:x =*pointer /= x; + +conditional expression + -> logical or expression + -> logical or expression:c, '?', + expression:x, ':', conditional expression:y =c ? x : y; + +logical or expression + -> logical and expression + -> logical or expression:x, "||", logical and expression:y = x ? x : y; + +logical and expression + -> equality expression + -> logical and expression:x, "&&", equality expression:y =x ? y : x; + +equality expression + -> relational expression + -> equality expression:x, "==", relational expression:y =x == y; + -> equality expression:x, "!=", relational expression:y =x != y; + +relational expression + -> additive expression + -> relational expression:x, '<', additive expression:y =x < y; + -> relational expression:x, "<=", additive expression:y =x <= y; + -> relational expression:x, '>', additive expression:y =x > y; + -> relational expression:x, ">=", additive expression:y =x >= y; + +additive expression + -> multiplicative expression + -> additive expression:x, '+', multiplicative expression:y =x + y; + -> additive expression:x, '-', multiplicative expression:y =x - y; + +multiplicative expression + -> unary expression + -> multiplicative expression:x, '*', unary expression:y =x * y; + -> multiplicative expression:x, '/', unary expression:y =x/PCB.checkZero(y); + +unary expression + -> factor + -> '-', unary expression:x =-x; + -> '+', unary expression:x =x; + +factor + -> primary + -> primary:x, "**", unary expression:y =pow(x,y); + +primary + -> real + -> name:valuePointer =*valuePointer; + -> "log", '(', expression:x, ')' =log(x); + -> "exp", '(', expression:x, ')' =exp(x); + -> "sin", '(', expression:x, ')' =sin(x); + -> "cos", '(', expression:x, ')' =cos(x); + -> "tan", '(', expression:x, ')' =tan(x); + -> '(', expression:x, ')' =x; + -> '!', primary:x = x == 0; + +// -- LEXICAL UNITS ------------------------------------------------ +blank = ' ' + '\t' + '\f' + '\v' + '\r' + '\n' +digit = '0-9' +eof = 0 +letter = 'a-z' + 'A-Z' + '_' +statement char = 32..126 - blank - ';' - '(' - ')' - '{' - '}' + +(void) white space + -> blank + -> "/*", ~eof?..., "*/" // C style comment + -> "//", ~(eof+'\n')?..., '\n' // C++ style comment + +// Productions for use skipping over statements + +statement text + -> statement char + -> balanced parens + -> statement text, statement char + -> statement text, balanced parens + -> statement text, balanced braces + +balanced parens + -> '(', statement text?, ')' + + balanced braces + -> '{', [statement text?, ';']..., '}' + -> '{', balanced braces, '}' + +/* + Identifying variable names + + Characters in a name string are pushed onto the character + stack. The integer value of the name string token is the + length of the string on the stack. + + The locate function returns a pointer to the value of the + named variable. If the variable has not been previously + referenced, its value is initialized to zero. +*/ + +(int) name string + -> letter: c =PCB.charStack.push(c), 1; + -> name string:k, letter+digit: c =PCB.charStack.push(c), k+1; + +(double *) name + -> name string:k =PCB.locateValue(k); + +// Parsing and evaluating numeric constants + +real + -> simple real + -> simple real:x, 'e'+'E', '+'?,exponent:e =x*pow(10,e); + -> simple real:x, 'e'+'E', '-',exponent:e =x*pow(10,-e); + +simple real + -> integer part:i, '.', fraction part:f = i+f; + -> integer part, '.'? + -> '.', fraction part:f = f; + +integer part + -> digit:d = d-'0'; + -> integer part:x, digit:d = 10*x + d-'0'; + +fraction part + -> digit:d =(d-'0')/10.; + -> digit:d, fraction part:f =(d-'0' + f)/10.; + +(int) exponent + -> digit:d = d-'0'; + -> exponent:x, digit:d = 10*x + d-'0'; + + +{ // begin embedded C + +#include <math.h> + +// Check for division by zero +double asi_pcb_type::checkZero(double value) { + if (value) return value; + error_message = "Divide by Zero"; + exit_flag = AG_SEMANTIC_ERROR_CODE; + return 1; +} + +// external interface to the parser +int asi_pcb_type::interpret(char *text, SymbolTable *st) { + symbolTable = st; + charStack.reset(); + pointer = (unsigned char *) text; + asi(this); + return exit_flag != AG_SUCCESS_CODE; +} + +/* + locate value of variable whose name is given by the top k characters on the + character stack. + Return a pointer so the value can be either fetched or stored +*/ + +double *asi_pcb_type::locateValue(int k) { + double *pointer = &symbolTable->locate(charStack.popString(k)).value; + if (symbolTable->overflow()) { + error_message = "Symbol table overflow"; + exit_flag = AG_SEMANTIC_ERROR_CODE; + } + return pointer; +} + +// Encapsulate current location in source text +Location asi_pcb_type::location() { + return Location(pointer, line, column); +} + +// Set source file location for loop continuation +void asi_pcb_type::loopContinue() { + setLocation(whileStack.continueLocation()); +} + +// Set source file location for loop exit +void asi_pcb_type::loopExit() { + setLocation(whileStack.exitLocation()); + whileStack.pop(); +} + +// Push character onto character stack +void asi_pcb_type::pushChar(int c) { + if (charStack.push(c)) { + error_message = "Name is too long"; + exit_flag = AG_SEMANTIC_ERROR_CODE; + } +} + +// Set parse location in source text +void asi_pcb_type::setLocation(const Location &l) { + pointer = l.pointer; + line = l.line; + column = l.column; +} + +// Save currently active loop, if any, and init nested loop +void asi_pcb_type::stackLoop(const Location &c) { + // Current source location is exit location for loop + // c is the continue location + if (whileStack.push(c, location())) { + error_message = "While stack overflow"; + exit_flag = AG_SEMANTIC_ERROR_CODE; + } + setLocation(c); // Set location to loop condition +} + +} // end of embedded C