Mercurial > ~dholland > hg > ag > index.cgi
view tests/agcl/oldagsrc/bcip.syn @ 10:5b21f127e957
silence random gcc warning
author | David A. Holland |
---|---|
date | Mon, 30 May 2022 23:58:14 -0400 |
parents | 13d2b8934445 |
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 ************************/