view tests/agcl/oldagsrc/bciastp.syn @ 21:1c9dac05d040

Add lint-style FALLTHROUGH annotations to fallthrough cases. (in the parse engine and thus the output code) Document this, because the old output causes warnings with gcc10.
author David A. Holland
date Mon, 13 Jun 2022 00:04:38 -0400
parents 13d2b8934445
children
line wrap: on
line source

{
/*
 BCIAST.SYN

 Compiler for Byte Code Interpreter (using parse tree)
 Copyright (c) 1997 Parsifal Software, All Rights Reserved.

 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
   Built-in functions           LOG, EXP

 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.

 vmParse makes the following external calls:
   void pushChar(int character);
     Push the specified character onto a character stack.

   int locateVariable(int nameLength);
     Pop the last nameLength characters from the character stack
     and, treating them as the name of a variable, return an
     index into the variable array.

 Overrides for macros defined by AnaGram, such as SYNTAX_ERROR
 are included in VMDEFS.H

 VMPT.SYN is compiled with the AnaGram parser generator
 yielding VMPT.H and VMPT.CPP.

 To build VMPT, compile and link VMPT.CPP, VMDEMO.CPP and PTREE.CPP
 with your C++ compiler.

 For information about AnaGram, visit http://www.parsifalsoft.com.
*/

#include "bciast.h"
#include "agstk.h"             // Defines AgStack<Object>
#include "agstr.h"             // Defines AgString et al
#include <math.h>              // for pow()
#include "ptree.h"

//typedef AgStack<Statement *> StatementList;

}
// -- CONFIGURATION SECTION ----------------------------
[
  disregard white space
  lexeme {real, name}
  pointer input
  parser name = astParse
  parser file name = "#.cpp"
  reentrant parser

  wrapper {AgStack<Statement *>, AgString}

  // Put the following in the parser control block for use during parsing
  extend pcb {
    // Maps symbol names to variables
    // AgSharedStringDictionary symbolDictionary;
    AbstractSyntaxTree *ast;

    // Temporary space to accumulate identifiers while parsing
    AgString charStack;
  }
]

/*
 * Mark input string with $ to indicate it is the "grammar token",
 * that is, the whole of the input we're intending to parse.
 */
(Program *) input string $
 -> statements:s, eof                         = PCB.ast->makeProgram(s);

/*
 * Zero or more statements. Generate a list of pointers to
 * statement descriptors.
 */
(AgStack<Statement *>) statements
 ->                                            =AgStack<Statement *>();
 -> statements:s, statement:x                  =s.push(x);

/*
 * A single statement.
 *
 * Here, an "open" statement is a statement that can legally be
 * followed by an "else" keyword. A "closed" statement is one that
 * cannot.
 *
 * This resolves the common if-then-else ambiguity. See ifelse.html for
 * a discussion of the ambiguity and this technique for resolving it.
 */
(Statement *) statement
 -> closed statement
 -> open statement

/*
 Any statement than can accept a dengling else clause
 is an open statement
*/

(Statement *) open statement
 -> "if", '(', expression:x, ')',
      statement:s                            = PCB.ast->makeIfStatement(x, s);
 -> "if", '(', expression:x, ')',
      closed statement:s1,
    "else",
      open statement:s2                      = PCB.ast->makeIfElseStatement(x,s1,s2);
 -> "while", '(', expression:x, ')',
      open statement:s                       = PCB.ast->makeWhileStatement(x,s);
 -> "for", '(',
      expression:init, ';',
      expression:cond, ';',
      expression:inc, ')', open statement:s  = PCB.ast->makeForStatement(init, cond, inc, s);

(Statement *) closed statement
 -> "if", '(', expression:x, ')', closed statement:s1,
    "else", closed statement:s2              = PCB.ast->makeIfElseStatement(x,s1,s2);
 -> "while", '(', expression:x, ')',
      closed statement:s                     = PCB.ast->makeWhileStatement(x,s);
 -> "for", '(',
      expression:init, ';',
      expression:cond, ';',
      expression:inc, ')', closed statement:s = PCB.ast->makeForStatement(init, cond, inc, s);
 -> simple statement:x                        = x;

/*
 * Statements that do not end with other statements. These all behave the
 * same way with respect to the closed statement/open statement construct
 * above, and are therefore factored out to PCB.ast->make it clearer.
 *
 * The bare expression appendss a pop instruction so that the resulting
 * byte code will discard the expression's value. (This is not an
 * optimizing compiler.)
 */
(Statement *) simple statement
 -> "do", statement:s,
    "while", '(', expression:x, ')', ';'      = PCB.ast->makeDoStatement(s,x);
 -> expression:x, ';'                         = PCB.ast->makeExpressionStatement(x);
 -> ';'                                       = PCB.ast->makeStatement();
 -> '{', statements:s, '}'                    = PCB.ast->makeStatementBlock(s);

// General expression. As in C, comma expression has the lowest precedence.
(Expression *) expression
 -> assignment expression
 -> expression:x, ',', assignment expression:y = PCB.ast->makeCommaExpression(x,y);

/*
 * Next precedence: assignments. Again, as in C, except we don't
 * support quite all the operators.
 */
(Expression *) assignment expression
 -> conditional expression
 -> name:k, '=',  assignment expression:x    =PCB.ast->makeSimpleAssignment(k, x);
 -> name:k, "+=", assignment expression:x    =PCB.ast->makeAddMemory(k, x);
 -> name:k, "-=", assignment expression:x    =PCB.ast->makeSubMemory(k, x);
 -> name:k, "*=", assignment expression:x    =PCB.ast->makeMulMemory(k, x);
 -> name:k, "/=", assignment expression:x    =PCB.ast->makeDivMemory(k, x);

 // Conditional expression (ternary operator)
(Expression *) conditional expression
 -> logical or expression
 -> logical or expression:c, '?',
      expression:x, ':', conditional expression:y  =PCB.ast->makeConditionalExpression(c,x,y);

// Logical expressions with short-cut evaluation, as in C.
(Expression *) logical or expression
 -> logical and expression
 -> logical or expression:x, "||",
      logical and expression:y                    =PCB.ast->makeLogicalOrExpression(x, y);

(Expression *) logical and expression
 -> equality expression
 -> logical and expression:x, "&&",
      equality expression:y                       =PCB.ast->makeLogicalAndExpression(x,y);

// Arithmetic expressions, in operator precedence order.
(Expression *) equality expression
 -> relational expression
 -> equality expression:x, "==", relational expression:y    =PCB.ast->makeEqExpression(x,y);
 -> equality expression:x, "!=", relational expression:y    =PCB.ast->makeNeExpression(x,y);

(Expression *) relational expression
 -> additive expression
 -> relational expression:x, '<',  additive expression:y    =PCB.ast->makeLtExpression(x,y);
 -> relational expression:x, "<=", additive expression:y    =PCB.ast->makeLeExpression(x,y);
 -> relational expression:x, '>',  additive expression:y    =PCB.ast->makeGtExpression(x,y);
 -> relational expression:x, ">=", additive expression:y    =PCB.ast->makeGeExpression(x,y);

(Expression *) additive expression
 -> multiplicative expression
 -> additive expression:x, '+',
      multiplicative expression:y                          =PCB.ast->makeAddExpression(x,y);
 -> additive expression:x, '-',
      multiplicative expression:y                          =PCB.ast->makeSubExpression(x,y);

(Expression *) multiplicative expression
 -> unary expression
 -> multiplicative expression:x, '*', unary expression:y   =PCB.ast->makeMulExpression(x,y);
 -> multiplicative expression:x, '/', unary expression:y   =PCB.ast->makeDivExpression(x,y);

(Expression *) unary expression
 -> factor
 -> '-', unary expression:x                                =PCB.ast->makeNegExpression(x);
 -> '+', unary expression:x                                =x;
 -> '!', unary expression:x                                =PCB.ast->makeNotExpression(x);

/*
 * Syntactically, we can use ** for exponentiation because we don't have
 * pointers. (In C, ** could be confused with pointer indirection.)
 * Note that the precedence of ** is inserted between unary +/- and unary !.
 */
(Expression *) factor
 -> primary
 -> primary:x, "**", unary expression:y                   =PCB.ast->makePowExpression(x,y);

/*
 * Primary expression - bottom level of expression syntax.
 * Variable references, constants, the builtin functions.
 * Also, another expression in parentheses. (This is how you make
 * parentheses work the way they're supposed to.)
 */
(Expression *) primary
 -> real:x                                                =PCB.ast->makeConstant(x);
 -> name:k                                                =PCB.ast->makeVariable(k);
 -> "log", '(', expression:x, ')'                         =PCB.ast->makeLogExpression(x);
 -> "exp", '(', expression:x, ')'                         =PCB.ast->makeExpExpression(x);
 -> "sqrt", '(', assignment expression:x, ')'             =PCB.ast->makeSqrtExpression(x);
 -> '(', expression:x, ')'                                =x;

// -- LEXICAL UNITS ------------------------------------------------
digit   = '0-9'
eof     = 0
letter  = 'a-z' + 'A-Z' + '_'

(void) white space
 -> ' ' + '\t' + '\f' + '\v' + '\r' + '\n'
 -> "/*", ~eof?..., "*/"                          // C style comment
 -> "//", ~(eof+'\n')?..., '\n'                 // C++ style comment

(double) real
 -> simple real:x                                                =x;
 -> simple real:x, 'e'+'E', '+'?,exponent:e            =x*pow(10,e);
 -> simple real:x, 'e'+'E', '-',exponent:e            =x*pow(10,-e);

(double) simple real
 -> integer part:i, '.', fraction part:f                      = i+f;
 -> integer part:i, '.'?                                        = i;
 -> '.', fraction part:f                                        = f;

(double) integer part
 -> digit:d                                                 = d-'0';
 -> integer part:x, digit:d                          = 10*x + d-'0';

(double) 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';

(AgString) name
 -> letter: c                                       =AgString().concat(c);
 -> name:s, letter+digit: c                         =s.concat(c);

{ // begin embedded C

void ag_delete_wrappers(astParse_pcb_struct *);

void parseStatements(AbstractSyntaxTree *tree, char *text) {
  astParse_pcb_struct pcb;
  pcb.ast = tree;
  pcb.pointer = (unsigned char *) text;
  astParse(&pcb);
  if (pcb.exit_flag == AG_SUCCESS_CODE)  tree->setRoot(astParse_value(&pcb));
  else ag_delete_wrappers(&pcb);
}
} // end of embedded C
/********************* End of bciast.syn ************************/