Commit 356b3461 authored by Lynn Garren's avatar Lynn Garren
Browse files

Improve the logic so that unary plus and minus work as expected.

parent a67ab489
2010-06-29 Mark Fischler <mf@fnal.gov>
* src/Evaluator.cc: Improve the logic so that unary plus and minus
work as expected. See bug report #66214.
2010-06-28 Lynn Garren <garren@fnal.gov>
* Evaluator/Evaluator.h: Add error_name() method to return
the error as a string
* test/testBug66214.cc: Test unary operator bug (report #66214)
==============================
16.06.10 Release CLHEP-2.1.0.0.b01
==============================
......
// -*- C++ -*-
// $Id: Evaluator.h,v 1.1.1.1 2003/07/15 20:15:05 garren Exp $
// $Id: Evaluator.h,v 1.2 2010/07/20 17:00:49 garren Exp $
// ---------------------------------------------------------------------------
#ifndef HEP_EVALUATOR_H
#define HEP_EVALUATOR_H
#include <string>
namespace HepTool {
/**
......@@ -87,6 +89,10 @@ class Evaluator {
* Prints error message if status() is an ERROR.
*/
void print_error() const;
/**
* get a string defining the error name
*/
std::string error_name() const;
/**
* Adds to the dictionary a variable with given value.
......
// -*- C++ -*-
// $Id: Evaluator.cc,v 1.3 2010/06/16 14:46:50 garren Exp $
// $Id: Evaluator.cc,v 1.4 2010/07/20 17:00:49 garren Exp $
// ---------------------------------------------------------------------------
#include "CLHEP/Evaluator/defs.h"
#include "CLHEP/Evaluator/Evaluator.h"
#include <iostream>
#include <sstream>
#include <cmath> // for pow()
#include "stack.src"
#include "string.src"
......@@ -64,7 +65,7 @@ for(;;pointer++) { \
static const char sss[MAX_N_PAR+2] = "012345";
enum { ENDL, LBRA, OR, AND, EQ, NE, GE, GT, LE, LT,
PLUS, MINUS, MULT, DIV, POW, RBRA, VALUE };
PLUS, MINUS, UNARY_PLUS, UNARY_MINUS, MULT, DIV, POW, RBRA, VALUE };
static int engine(pchar, pchar, double &, pchar &, const dic_type &);
......@@ -328,6 +329,12 @@ static int maker(int op, stack<double> & val)
errno = 0;
val.top() = pow(val1,val2);
if (errno == 0) return EVAL::OK;
case UNARY_PLUS: // unary operator '+'
val.top() = val1 + val2; // val1 is zero
return EVAL::OK;
case UNARY_MINUS: // unary operator '-'
val.top() = val1 - val2; // val1 is zero
return EVAL::OK;
default:
return EVAL::ERROR_CALCULATION_ERROR;
}
......@@ -352,43 +359,61 @@ static int maker(int op, stack<double> & val)
static int engine(pchar begin, pchar end, double & result,
pchar & endp, const dic_type & dictionary)
{
static const int SyntaxTable[17][17] = {
//E ( || && == != >= > <= < + - * / ^ ) V - current token
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 1 }, // E - previous
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 1 }, // ( token
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // ||
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // &&
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // ==
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // !=
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // >=
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // >
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // <=
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // <
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // +
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // -
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // *
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // /
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // ^
{ 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, // )
{ 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 } // V = {.,N,C}
enum SyntaxTableEntry {
SyntaxError = 0,
NumberVariableOrFunction = 1,
UnaryPlusOrMinus = 2,
AnyOperator = 3
};
static const int SyntaxTable[19][19] = {
//E ( || && == != >= > <= < + - u+ u- * / ^ ) V - current token
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // E - previous
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // ( token
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // ||
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // &&
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // ==
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // !=
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // >=
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // >
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // <=
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // <
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // +
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // -
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // unary +
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // unary -
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // *
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // /
{ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // ^
{ 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, // )
{ 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 } // V = {.,N,C}
};
static const int ActionTable[15][16] = {
//E ( || && == != >= > <= < + - * / ^ ) - current operator
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1 }, // E - top operator
{-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 }, // ( in stack
{ 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // ||
{ 4, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // &&
{ 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // ==
{ 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // !=
{ 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 4 }, // >=
{ 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 4 }, // >
{ 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 4 }, // <=
{ 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 4 }, // <
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 4 }, // +
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 4 }, // -
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 4 }, // *
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 4 }, // /
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 } // ^
enum ActionTableEntry {
UnbalancedParentheses = -1,
ExpressionCompleted = 0,
HigherPrecedenceOperator = 1,
SamePrecedenceOperator = 2,
CloseProcessedParenthesesOrExpression = 3,
LowerPrecedenceOperator = 4
};
static const int ActionTable[17][18] = {
//E ( || && == != >= > <= < + - u+ u- * / ^ ) - current operator
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1 }, // E - top operator
{-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 }, // ( in stack
{ 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // ||
{ 4, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // &&
{ 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // ==
{ 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // !=
{ 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // >=
{ 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // >
{ 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // <=
{ 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // <
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 1, 1, 4 }, // +
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 1, 1, 4 }, // -
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 4, 4 }, // unary +
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 4, 4 }, // unary -
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 2, 2, 1, 4 }, // *
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 2, 2, 1, 4 }, // /
{ 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 4, 4 } // ^
};
stack<int> op; // operator stack
......@@ -462,7 +487,7 @@ static int engine(pchar begin, pchar end, double & result,
iWhat = SyntaxTable[iPrev][iCur];
iPrev = iCur;
switch (iWhat) {
case 0: // systax error
case 0: // syntax error
EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer );
case 1: // operand: number, variable, function
EVAL_STATUS = operand(pointer, end, value, pointer, dictionary);
......@@ -471,6 +496,10 @@ static int engine(pchar begin, pchar end, double & result,
continue;
case 2: // unary + or unary -
val.push(0.0);
if (iCur == PLUS) iCur = UNARY_PLUS;
if (iCur == MINUS) iCur = UNARY_MINUS;
// Note that for syntax purposes, ordinary + or - are fine.
// Thus iPrev need not change when we encounter a unary minus or plus.
case 3: default: // next operator
break;
}
......@@ -611,37 +640,48 @@ int Evaluator::error_position() const {
//---------------------------------------------------------------------------
void Evaluator::print_error() const {
Struct * s = (Struct *) p;
if(s->theStatus != OK) {
std::cerr << error_name() << std::endl;
}
return;
}
//---------------------------------------------------------------------------
std::string Evaluator::error_name() const
{
char prefix[] = "Evaluator : ";
std::ostringstream errn;
Struct * s = (Struct *) p;
switch (s->theStatus) {
case ERROR_NOT_A_NAME:
std::cerr << prefix << "invalid name" << std::endl;
return;
errn << prefix << "invalid name";
break;
case ERROR_SYNTAX_ERROR:
std::cerr << prefix << "systax error" << std::endl;
return;
errn << prefix << "syntax error";
break;
case ERROR_UNPAIRED_PARENTHESIS:
std::cerr << prefix << "unpaired parenthesis" << std::endl;
return;
errn << prefix << "unpaired parenthesis";
break;
case ERROR_UNEXPECTED_SYMBOL:
std::cerr << prefix << "unexpected symbol" << std::endl;
return;
errn << prefix << "unexpected symbol";
break;
case ERROR_UNKNOWN_VARIABLE:
std::cerr << prefix << "unknown variable" << std::endl;
return;
errn << prefix << "unknown variable";
break;
case ERROR_UNKNOWN_FUNCTION:
std::cerr << prefix << "unknown function" << std::endl;
return;
errn << prefix << "unknown function";
break;
case ERROR_EMPTY_PARAMETER:
std::cerr << prefix << "empty parameter in function call"
<< std::endl;
return;
errn << prefix << "empty parameter in function call";
break;
case ERROR_CALCULATION_ERROR:
std::cerr << prefix << "calculation error" << std::endl;
return;
errn << prefix << "calculation error";
break;
default:
return;
errn << " ";
}
return errn.str();
}
//---------------------------------------------------------------------------
......
......@@ -27,40 +27,36 @@ CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
# Identify executables needed during testing:
check_PROGRAMS = \
testEvaluator
testEvaluator testBug66214
check_SCRIPTS = \
testEvaluator.sh
# Identify test(s) to run when 'make check' is requested:
TESTS = \
testEvaluator.sh
testEvaluator.sh testBug66214
# Identify the test(s) for which failure is the intended outcome:
XFAIL_TESTS =
# Identify the dependencies on a per-test basis:
testEvaluator_SOURCES = testEvaluator.cc
testBug66214_SOURCES = testBug66214.cc
# Identify input data file(s) and prototype output file(s):
EXTRA_DIST = \
testEvaluator.input testEvaluator.output
# Identify generated file(s) to be removed when 'make clean' is requested:
CLEANFILES =
CLEANFILES = testEvaluator.sh testBug66214.cout
# supply our own suffix rule
.cc.obj:
if BUILD_VISUAL
# $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c $(OUTFLAG) `$(CYGPATH_W) '$<'`
# mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
source='$<' object='$@' libtool=no \
DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
$(CXXCOMPILE) -c $(OUTFLAG) `$(CYGPATH_W) '$<'`
else
if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c $(OUTFLAG) `$(CYGPATH_W) '$<'`; \
then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
# source='$<' object='$@' libtool=no \
# DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
# $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
endif
// ---------------------------------------------------------------------------
//
// This file is a part of the CLHEP - a Class Library for High Energy Physics.
//
// This is a test for bug report 66214 in the Evaluator class.
//
#include <iostream>
#include <fstream>
#include <CLHEP/Evaluator/Evaluator.h>
double eval( std::string expr, int& numbad, std::ofstream& os)
{
static HepTool::Evaluator *ev=0;
if(ev == 0) ev = new HepTool::Evaluator();
ev->setStdMath(); // set standard constants and functions
ev->setSystemOfUnits(); // set SI units
double v = ev->evaluate(expr.data());
os << "CALC> " << expr << ": ";
if(ev->status() != HepTool::Evaluator::OK) {
os << ev->error_name() << std::endl;
++numbad;
} else {
os << v << std::endl;
}
return v;
}
int main()
{
int numbad = 0;
double result;
// many of these expressions fail in releases prior to 2.0.4.7
std::string exp[38] = { " +1", " -1", "1 + 1", "1 + -1","1 + (-1)",
"1 + +1","1 + (+1)", "1 * -1","1 * (-1)", "-1 * 1",
"10^-1", "10^(-1)", "9*4", "9 * -4","9 * (-4)",
"4*---2","4*(---2)","4*(-(--2))","4*(--(-2))","4*(-(-(-2)))",
"4*--2", "4*(--2)", "4*(-(-2))", "-5^2", "9*4+2",
"231/-11","231/-11+10","231/-11/3","(231/-11)+10",
"100/5^2","100/+5^2","100/-5^2", "9*4+30", "9*4+-30",
"-9*4+30","9*-4+30","9*(-4)+30","(9*-4)+30" };
double res[38] = { 1., -1., 2., 0., 0.,
2., 2., -1., -1., -1.,
0.1, 0.1, 36., -36., -36.,
-8., -8., -8., -8., -8.,
8., 8., 8., 25., 38.,
-21., -11., -7., -11.,
4., 4., 4., 66., 6.,
-6., -6., -6., -6. };
std::string exp2[3] = { "sin(45*deg)", "sin(45*pi/-180)", "232/22" };
std::ofstream os("testBug66214.cout");
for(int i=0; i<38; ++i ) {
result=eval(exp[i],numbad,os);
if( result != res[i] ) {
++numbad;
os << "ERROR: expected " << res[i] << " got " << result << std::endl;
os << std::endl;
}
}
// inspect these by hand
// return values: 0.707107, -0.707107, 10.5455
for(int i=0; i<3; ++i ) {
eval(exp2[i],numbad,os);
}
return numbad;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment