Parsifal Software - Home | AnaGram trial copy | Example download
{ /* EVALKERN.SYN Version 1.1 evaluateExpression: A Simple Expression Evaluator Copyright (c) 1996 - 1999 Parsifal Software, All Rights Reserved. evaluateExpression is an example program for evaluating C-style expressions which demonstrates some of the capabilities of the AnaGram parser generator. EVALKERN.SYN is the kernel of the example, consisting of the definition of the expression parser itself. Support functions are defined in EVALWRAP.C. A test program is defined in EVALDEMO.C. Global declarations are contained in EVALDEFS.H. EVALKERN.SYN is an AnaGram syntax (.SYN) file which describes, in this case, the syntax of expressions. It is written in the AnaGram language, which is a variang of BNF (Backus-Naur Form) with additional constructs to allow more concise descriptions and greater analytical power. AnaGram analyzes a syntax file containing a grammar and produces a parser in C or C++. The vital part of a syntax file consists of its productions, each of which takes the form: p -> p1, p2, p3, ... pn Productions describe the grammatical elements to be recognized by the parser. This rule says that the grammatical element p consists of a single instance each of the elements p1, p2, p3, ... pn in order. You will notice that a production may have some C code at its right end following an equals sign. This code constitutes a "reduction procedure", which will be executed automatically when the grammatical element specified by the production is identified in the input to the parser. AnaGram analyzes EVALKERN.SYN and produces the parser file EVALKERN.C and a header file EVALKERN.H. The parse function defined in EVALKERN.SYN is called evalKernel. All communication with evalKernel is via the parser control block (PCB). The wrapper function, evaluateExpression, defined in EVALWRAP.C, provides a more convenient interface for the parse function. 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 Function calls All arithmetic is double precision floating point. Input strings may contain any number of expressions, separated by commas or semicolons. White space may be used freely, including both C and C++ style comments. evalKernel() makes the following external calls: ------------------------------------------------ void pushChar(int character); Push the specified character onto a character stack. double *locateVariable(int nameLength); Pop the last nameLength characters from the character stack and, treating them as the name of a variable, return a pointer to the location where the value of the variable is stored. void pushArg(double value); Push the specified value onto an argument stack. double callFunction(nameLength, int argCount); Pop the last nameLength characters from the character stack and, treating them as the name of a function, identify the function and invoke it with argCount arguments popped from the argument stack. double checkZero(double value); Verify that value is not zero. Overrides for macros defined by AnaGram, such as SYNTAX_ERROR should be included in EVALDEFS.H For information about AnaGram, contact Parsifal Software http://www.parsifalsoft.com info@parsifalsoft.com 1-800-879-2755, Voice/Fax 1-508-358-2564 P.O. Box 219 Wayland, MA 01778 */ #include <math.h> #include "evaldefs.h" // defines external interface } // -- CONFIGURATION SECTION ---------------------------- [ default token type = double disregard white space lexeme {real, name} pointer input parser name = evalKernel ] //------------------------------------------------------ (void) input string $ // specify grammar token -> expressions, eof (void) expressions -> expression? -> expressions, ',' + ';', expression? expression -> conditional expression -> name:k, '=', expression:x =*locateVariable(k) = x; -> name:k, "+=", expression:x =*locateVariable(k) += x; -> name:k, "-=", expression:x =*locateVariable(k) -= x; -> name:k, "*=", expression:x =*locateVariable(k) *= x; -> name:k, "/=", expression:x =*locateVariable(k) /= 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||y; logical and expression -> equality expression -> logical and expression:x, "&&", equality expression:y =x&&y; 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/checkZero(y); unary expression -> factor:x = x; -> '-', unary expression:x =-x; -> '+', unary expression:x = x; factor -> primary -> primary:x, "**", unary expression:y = pow(x,y); primary -> real -> name:k =*locateVariable(k); -> '(', expression:x, ')' =x; -> '!', primary:x =!x; /**** Function calls **********************************************/ /* The following productions have been added to make the grammar */ /* handle function calls with any number of arguments. Note how */ /* easy it is to change the grammar - this is all you have to do */ /* to handle function calls. Arguments may be expressions. */ primary -> name:k, '(', arguments:n, ')' =callFunction(k,n); (int) arguments //value of arguments is number of args -> =0; -> argument list //argument count passes automatically (int) argument list //value of argument list is number of args -> expression:x =pushArg(x), 1; -> argument list:k, ',', expression:x =pushArg(x), k+1; /******************************************************************/ // -- 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 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'; (int) name //value of name token is length of name string -> letter: c =pushChar(c), 1; -> name:k, letter+digit: c =pushChar(c), k+1; /********************* End of EVALKERN.SYN ************************/
Comments or questions? support@parsifalsoft.com