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