view tests/agcl/oldagsrc/bcip.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 source

{/*
 bcip.syn  Version 1.0

 A simple byte code compiler

 Copyright (c) 1996-1999 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 the following 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, sqrt

 All arithmetic is double precision floating point.

 Statements may include expression statements, blocks, if/else
 statements, while statements, do-while statements, or for
 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.

 The parser is invoked by the constructor for the virtual machine
 to parse the source code and compile it into byte code.

 With this organization, it is possible to create various
 virtual machine objects all of which use the same symbol dictionary,
 so that all can operate on the same data array. Furthermore, if
 there are multiple data arrays, all consistent with the same
 symbol dictionary, then any virtual machine object created using the
 given symbol dictionary can operate on any of the data arrays.

 Thus a given virtual machine may operate on different data
 arrays at different times. The data array, of course, must be
 consistent with the symbol dictionary used to initialize the virtual
 machine.

 The symbol dictionary maps character strings to indices into the
 data array, so that each unique variable name is assigned a
 particular location in the data array. Different virtual
 machines may be initialized with the same symbol dictionary. When
 this is done, these virtual machines can all operate on the
 same data array.

 An override for the SYNTAX_ERROR macro defined by AnaGram and
 the definition of the ScriptMethod class are in the bci.h
 file. bci.cpp has function definitons for the ScriptMethod
 class. bcidemo.cpp demonstrates one way to use the virtual
 machine.

 bcip.syn is compiled with the AnaGram parser generator yielding
 bcip.h and bcip.cpp.

 To build bcidemo, compile bcip.cpp, bci.cpp, cntnrs.cpp and bcidemo.cpp
 and link them with your C++ compiler.

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

#include <math.h>
#include "bci.h"                  // defines external interface

}
// -- CONFIGURATION SECTION ----------------------------
[
  disregard white space
  lexeme {real, name}
  pointer input
  parser name = bciParse
  parser file name = "#.cpp"
  reentrant parser
  extend pcb {
    AgStringDictionary *symbolDictionary;
    AgStack<double> realList;                         // List of real constants
    int compile(AgStringDictionary *, AgString);
    CodeFragment code;

    AgCharStack charStack;           // Stack to accumulate variable names
    int locateVariable(int k);    // Identify variable named on character stack
    int stashReal(double);
    CodeFragment codeIfElse(CodeFragment &, CodeFragment &, CodeFragment &);
    CodeFragment codeWhile(CodeFragment &, CodeFragment &);
    CodeFragment codeDoWhile(CodeFragment &, CodeFragment &);
    CodeFragment codeFor(CodeFragment &, CodeFragment &, CodeFragment &, CodeFragment &);
  }
  wrapper {CodeFragment}
]

(CodeFragment) input string $                          // specify grammar token
 -> statements:x, eof                                              =x.cat(HLT);

(CodeFragment) statements
 ->                                                            =CodeFragment();
 -> statements:x, statement:y                                        =x.cat(y);

(CodeFragment) statement
 -> open statement
 -> closed statement

 // Any statement that could be followed by an else is an open statement
(CodeFragment) open statement
 -> if clause:x, statement:s                      =x.cat(BRF, s.size()).cat(s);
 -> if clause:x, closed statement:s1,
      "else", open statement:s2                       =PCB.codeIfElse(x,s1,s2);
 -> while clause:x, open statement:s                       =PCB.codeWhile(x,s);
 -> "for", '(', expression:init, ';', expression:cond, ';',
      expression:inc, ')', open statement:s   =PCB.codeFor(init, cond, inc, s);

 // A statement that cannot be followed by "else" is a closed statement
(CodeFragment) closed statement
 -> simple statement
 -> if clause:x, closed statement:s1, "else",
      closed statement:s2                             =PCB.codeIfElse(x,s1,s2);
 -> while clause:x, closed statement:s                     =PCB.codeWhile(x,s);
 -> "do", statement:s, while clause:x, ';'               =PCB.codeDoWhile(s,x);
 -> "for", '(', expression:init, ';', expression:cond, ';',
      expression:inc, ')', closed statement:s =PCB.codeFor(init, cond, inc, s);

(CodeFragment) if clause
 -> "if", '(', expression:x, ')'                                            =x;

(CodeFragment) while clause
 -> "while", '(', expression:x, ')'                                         =x;

(CodeFragment) simple statement
 -> expression:x, ';'                                              =x.cat(POP);
 -> ';'                                                        =CodeFragment();
 -> '{', statements:s, '}'                                                  =s;

(CodeFragment) expression
 -> assignment expression
 -> expression:x, ',', assignment expression:y              =x.cat(POP).cat(y);

(CodeFragment) assignment expression
 -> conditional expression
 -> name:k, '=',  assignment expression:x                     =x.cat(STORE, k);
 -> name:k, "+=", assignment expression:x                      =x.cat(ADDM, k);
 -> name:k, "-=", assignment expression:x                      =x.cat(SUBM, k);
 -> name:k, "*=", assignment expression:x                       =x.cat(MULM,k);
 -> name:k, "/=", assignment expression:x                      =x.cat(DIVM, k);

(CodeFragment) conditional expression
 -> logical or expression
 -> logical or expression:c, '?', expression:x,
      ':', conditional expression:y                   =PCB.codeIfElse(c, x, y);

(CodeFragment) logical or expression
 -> logical and expression
 -> logical and expression:x, "||",
      logical or expression:y                      =x.cat(OR, y.size()).cat(y);

(CodeFragment) logical and expression
 -> equality expression
 -> equality expression:x, "&&",
      logical and expression:y                    =x.cat(AND, y.size()).cat(y);

(CodeFragment) equality expression
 -> relational expression
 -> equality expression:x, "==", relational expression:y     =x.cat(y).cat(EQ);
 -> equality expression:x, "!=", relational expression:y     =x.cat(y).cat(NE);

(CodeFragment) relational expression
 -> additive expression
 -> relational expression:x, '<',  additive expression:y     =x.cat(y).cat(LT);
 -> relational expression:x, "<=", additive expression:y     =x.cat(y).cat(LE);
 -> relational expression:x, '>',  additive expression:y     =x.cat(y).cat(GT);
 -> relational expression:x, ">=", additive expression:y     =x.cat(y).cat(GE);

(CodeFragment) additive expression
 -> multiplicative expression
 -> additive expression:x, '+', multiplicative expression:y =x.cat(y).cat(ADD);
 -> additive expression:x, '-', multiplicative expression:y =x.cat(y).cat(SUB);

(CodeFragment) multiplicative expression
 -> unary expression
 -> multiplicative expression:x, '*', unary expression:y    =x.cat(y).cat(MUL);
 -> multiplicative expression:x, '/', unary expression:y    =x.cat(y).cat(DIV);

(CodeFragment) unary expression
 -> factor
 -> '-', unary expression:x                                        =x.cat(NEG);
 -> '+', unary expression:x                                                = x;

(CodeFragment) factor
 -> primary
 -> primary:x, "**", unary expression:y                     =x.cat(y).cat(POW);

(CodeFragment) primary
 -> real:x                                       =CodeFragment().cat(PUSHI, x);
 -> name:k                                        =CodeFragment().cat(PUSH, k);
 -> "log", '(', assignment expression:x, ')'                       =x.cat(LOG);
 -> "exp", '(', assignment expression:x, ')'                       =x.cat(EXP);
 -> "sqrt", '(', assignment expression:x, ')'                     =x.cat(SQRT);
 -> '(', expression:x, ')'                                                  =x;
 -> '!', primary:x                                                 =x.cat(NOT);

// -- 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

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

(double) simple real
 -> integer part:i, '.', fraction part:f                                 = i+f;
 -> integer part, '.'?
 -> '.', 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';

(int) name
 -> name string     =PCB.symbolDictionary->identify(PCB.charStack.popString());

name string
 -> letter: c                                    =PCB.charStack.push((char) c);
 -> name string, letter+digit: c                 =PCB.charStack.push((char) c);

{ // Begin embedded C

#define SYNTAX_ERROR

int bciParse_pcb_struct::stashReal(double x) {
  int n = realList.size();
  realList.push(x);
  return n;
}

CodeFragment bciParse_pcb_struct::codeIfElse(CodeFragment &condition,
                                             CodeFragment &trueStatement,
                                             CodeFragment &falseStatement)
{
  return condition.cat(BRF, trueStatement.size() + 2)
                  .cat(trueStatement)
                  .cat(BR, falseStatement.size())
                  .cat(falseStatement);
}

CodeFragment bciParse_pcb_struct::codeWhile(CodeFragment &condition,
                                            CodeFragment &statement)
{
  // loop back distance is length of statement + length of condition + 2 branch instructions
  int loopBackDistance = condition.size() + statement.size() + 4;
  return condition.cat(BRF, statement.size() + 2)       // size of statement +size of loopback
                  .cat(statement)
                  .cat(BR, -loopBackDistance);
}

CodeFragment bciParse_pcb_struct::codeDoWhile(CodeFragment &statement,
                                              CodeFragment &condition)
{
  // loop back distance is
  //    length of statement + length of condition + 1 branch instruction
  int loopBackDistance = statement.size() + condition.size() + 2;
  return statement.cat(condition)
                  .cat(BRT, -loopBackDistance);
}

CodeFragment bciParse_pcb_struct::codeFor(CodeFragment &initializer,
                                          CodeFragment &condition,
                                          CodeFragment &increment,
                                          CodeFragment &statement)
{
  // Calculate the length of the jump back at the bottom of the loop
  // It consists of the length of the increment, condition and statement
  // CodeFragments + 5 inserted Bytecodes: 1 Pop, and 2 each for each of
  // two branches
  int loopBackDistance = increment.size() + condition.size() + statement.size() + 5;

  // Put it all together
  return initializer.cat(POP)                           // clear expression value from stack
                    .cat(BR, increment.size() + 1)      // Skip increment on first time through
                    .cat(increment).cat(POP)            // clear expresson value from stack
                    .cat(condition)
                    .cat(BRF, statement.size() + 2)     // exit when condition is false
                    .cat(statement)
                    .cat(BR, -loopBackDistance);
}

int bciParse_pcb_struct::compile(AgStringDictionary *s, AgString text) {
  symbolDictionary = s;
  charStack.reset();
  pointer = (unsigned char *) text.ptr();
  bciParse(this);
  if(exit_flag != AG_SUCCESS_CODE) return 1;
  code = bciParse_value(this);
  return 0;
}

} // End of embedded C
/********************* End of bcip.syn ************************/