// rpinterpreter.h // Copyright (c) Menno Rubingh 2016. Web: [http://rubinghsoftware.de] // // MR Mar 2016. // // Simple general-purpose interpreter for Reverse Polish expression for // floating-point arithmetic. // Scans RP expression from input string to an internal representation, // and evaluates this later on variables that are set (prior to evaluation) // and read (after evaluation) by the client code. // //--- // Design notes: // - Input and output to/from the interpreter goes via variables 'a'...'z'. // The client code determines which variables are input and output. // A variable not used as in/output can be used as a local/temporary variable // in the expression. // - The operations (+ - * ...) in the expression do not clip. Any clipping // of the output variables to an interval is done by the client code after // reading the output variable values. // #ifndef _RPINTERPRETER_H_ #define _RPINTERPRETER_H_ #include <stdio.h> //FILE. //------------------------------------------------------------------------------------- // Class RPInterpreter. //------------------------------------------------------------------------------------- class RPInterpreter { void * m_exprdata; //Parsed expression data. Implementation is hidden. void * m_vardata; //Values of the variables. Implementation is hidden. public: // // Class function: // Return a help text about the syntax of the RP input string // accepted by 'scanFromString()'. // static char const * helptxt( void ) { return "Syntax of the Reverse Polish expression string: \n" " - Single lower-case letter 'a'..'z' NOT preceded by equals sign means PUSH \n" " the value of the variable onto stack. \n" " - Single lower-case letter preceded by equals sign \"=a\"..\"=z\" means POP \n" " a value from stack and copy it into the variable. \n" " - Decimal floating-point number without sign (e.g. 2, 0.25, .5) means PUSH \n" " this nonnegative constant value onto stack. \n" " - Operators: There are only binary operators, namely \n" " '+' (add) \n" " '-' (subtract, \"ab-\" means a - b) \n" " '*' (multiply). \n" " '/' (divide, \"ab/\" means a / b) \n" " '^' (exponentiate, \"ab^\" means a ^ b) \n" " Each of these POPS two values from stack, computes, and PUSHES the result.\n" " - At character ';' the interpreter checks whether the stack is empty at \n" " that point, and generates an error if not. \n" " - Space characters are allowed in the input string between lexical elements \n" " (but tab or newline characters are not allowed). \n" ""; } // Print contents of parsed expression to FILE. void dump( FILE * oF ) const; // Initializes parsed expression to empty, and variable values to 0.0. RPInterpreter( void ); ~RPInterpreter( void ); // Clear parsed expression to empty and clear all variables to 0.0. void reinit( void ); // Clear the values of all variables to 0.0. void clearVars( void ); // // Set and read the value of a variable. // The variable is identified by the parameter iC which is one lower-case ASCII // character 'a'-'z'. (An assertion fails if iC is out of range.) // // The function 'getVar()' returns false when the value of the variable is a NaN, // which means that a DOMAIN ERROR occurred during the evaluate() call. It returns // true if the variable is not a NaN (in this case the variable can still be // + or - HUGE_VAL). // For more info see the text file 'rpinterpreter_doc_floatingPointErrors.txt' // which should be contained among the sources. // bool getVar( char iC , double * oValue ) const; void putVar( char iC, double iValue ); // // Scan RP expression from string. // And then, test evaluation of the expression on dummy variable values (to // test for expression well-formedness, i.e. no stack under/overflows, and // stacksize is 0 at the end and at any ';' character). // // The input string as a whole must consist of the RP expression only, // with no other characters. // // Converts the string into an executable representation of the expression, // stored internally in the RPInterpreter object, which can be executed later // by calling 'evaluate()'. // // Assumes that at the time of calling, the internal parsed-expression data // is empty (an assertion fails if this assumption is violated). // // On error, prints to stderr and returns false. // bool scanFromString( char const * iStr ); // // Evaluate the internally stored parsed expression for the current values of // the variables, overwriting variables as specified in the expresssion. // The operations (+ - * ...) in the expression do not clip. // // Assumes that the parsed expression is well-formed (as checked by scanFromString(), // i.e. no stack under/overflows, and stacksize is 0 at the end and at any ';' // character). An assertion fails if this assumption is violated. // // The evaluate() function does NOT check internally for floating-point errors; // see the text file 'rpinterpreter_doc_floatingPointErrors.txt' which should be // contained among the sources. // The client code can detect DOMAIN ERRORS by checking the return value of the // getVal() function, or alternatively by bracketing a (series of) evaluate() // call(s) between feclearexcept() and fetestexcept(FE_INVALID). // void evaluate( void ); }; #endif //_RPINTERPRETER_H_