Mercurial > ~dholland > hg > ag > index.cgi
view tests/agcl/oldagsrc/asiwdp.syn @ 8:ec2b657edf13
Add explicit lint-comment-style fallthrough annotations.
GCC now assumes that if you don't have these you're making a mistake,
which is annoying.
XXX: This changeset updates the AG output files only (by hand) and is
XXX: abusive - rebuilding them will erase the change. However, I need
XXX: to get things to build before I can try to get AG to issue the
XXX: annotations itself, so this seems like a reasonable expedient.
author | David A. Holland |
---|---|
date | Mon, 30 May 2022 23:51:43 -0400 |
parents | 13d2b8934445 |
children |
line wrap: on
line source
{ /* 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