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