//
// File: hzNumexp.cpp
//
// Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
// The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
// Software Foundation, either version 3 of the License, or any later version.
//
// The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
//
// Implimentation of the hzNumexp (numeric expression) class and the hzNumexpTerm classes defined in hzNumexp.h
//
#include <fstream>
#include "hzTextproc.h"
#include "hzProcess.h"
#include "hzNumexp.h"
/*
** hzNumexpForm Functions
*/
double hzNumexpForm::Evaluate (void)
{
// Evaluate this expression (hzNumexpForm instance) to a single atomic value. A hzNumexpForm instance is created by an expression parser when the
// expression amounts to a 'term operator term' rather than only a single term. hzNumexpForm Evaluation is thus always a matter of evaluating
// both terms and applying the operator. Where the terms are themselves hzNumexpForm instances, this function recurses.
//
// Arguments: None
// Returns: Value - the numeric result
_hzfunc("hzNumexpForm::Evaluate_a") ;
double A ; // Term A
double B ; // Term B
A = m_pA->Evaluate() ;
B = m_pB->Evaluate() ;
switch (m_eBinary)
{
//case OP_ASSIGN: break ;
case OP_EQUAL: m_Result = (A == B) ; break ;
case OP_GT: m_Result = (A > B) ; break ;
case OP_LT: m_Result = (A < B) ; break ;
case OP_GTEQ: m_Result = (A >= B) ; break ;
case OP_LTEQ: m_Result = (A <= B) ; break ;
case OP_PLUS: m_Result = A ; m_Result += B ; break ;
case OP_MINUS: m_Result = A ; m_Result -= B ; break ;
case OP_MULT: m_Result = A ; m_Result *= B ; break ;
case OP_DIVIDE: m_Result = A ; m_Result /= B ; break ;
//case OP_AND: m_Result = A ; m_Result &= B ; break ;
//case OP_OR: m_Result = A ; m_Result |= B ; break ;
}
return m_Result ;
}
/*
** hzNumexp Functions
*/
double hzNumexp::Evaluate (void)
{
// Evaluate expression into single atomic value.
//
// Arguments: None
// Returns: Value - the numeric result
_hzfunc("hzNumexp::Evaluate_b") ;
if (m_pRoot)
return m_pRoot->Evaluate() ;
return m_Default ;
}
hzEcode hzNumexp::Parse (const char* pExp)
{
// Parses extression into a single operand or more generally, a tree of formulae that will evaluate to a single value.
//
// Arguments: 1) pExp Numeric expression
//
// Returns: E_SYNTAX If the expression could not be tokenized or could not be parsed.
// E_OK If the expression was parsed.
_hzfunc("hzNumexp::Parse_a") ;
hzEcode rc ; // Return code
// tokenize the expression
rc = TokenizeString(m_Tokens, pExp, TOK_MO_BOOL) ;
if (rc != E_OK)
return E_SYNTAX ;
m_pRoot = Parse() ;
if (!m_pRoot)
return E_SYNTAX ;
return E_OK ;
}
hzNumexpTerm* hzNumexp::Parse (void)
{
// convert text tokens into tree of hzNumexpForm, hzReference & hzNumexpValue
//
// Arguments: None
// Returns: Pointer to numeric expresssion term base class instance
_hzfunc("hzIdSetExp::Parse(hzTokenlist&)") ;
hzNumexpForm* pFormula = 0 ; // Pointer to a formula
hzNumexpValue* pConstant = 0 ; // Pointer to a constant
hzNumexpTerm* pOperand1 = 0 ; // Pointer to term A
hzNumexpTerm* pOperand2 = 0 ; // Pointer to term B
hzOperator binOp = OP_NULL ; // Binary op applicable to A and B
hzUnary unaOp = UOP_NULL ; // Unary op applicable to result
hzToken tok ; // Current token
double val ; // result value
tok = m_Tokens[m_tokIter] ;
if (!tok)
{
m_Error.Printf("No more tokens - returning null\n") ;
return 0 ;
}
/*
** Occupy first operand
*/
// Unary operators are permitted while expecting operand
if (tok == "!")
{
m_Error.Printf("Setting unary for first operand\n") ;
unaOp = UOP_NOT ;
m_tokIter++ ;
tok = m_Tokens[m_tokIter] ;
if (!tok)
{
m_Error.Printf("Expected an operand or '(' to follow unary") ;
return 0 ;
}
}
// Binary operators are not permitted here though
if (tok == "&&" || tok == "||")
{
m_Error.Printf("Expected an operand or '('. Got an operator") ;
return 0 ;
}
if (tok == "(")
{
// The operand can be a formula, recurse if it is
m_nParLevel++ ;
m_tokIter++ ;
tok = m_Tokens[m_tokIter] ;
pOperand1 = Parse() ;
}
else
{
// Token is not a unary or an open bracket. We assume token is a constant
m_Error.Printf("Set first operand as constant\n") ;
pConstant = new hzNumexpValue() ;
IsDouble(val, *tok.Value()) ;
*pConstant = val ; //tok.Value() ;
pOperand1 = pConstant ;
m_tokIter++ ;
tok = m_Tokens[m_tokIter] ;
}
/*
** Obtain the operator
*/
if (tok.Value())
{
m_Error.Printf("Processing token %s\n", *tok.Value()) ;
// we now expect an binary operator or a terminating )
if (tok == ")")
{
m_tokIter++ ;
tok = m_Tokens[m_tokIter] ;
return pOperand1 ;
}
// Test for operator
if (tok == "&&")
{
binOp = OP_AND ;
m_tokIter++ ;
tok = m_Tokens[m_tokIter] ;
}
else if (tok == "||")
{
binOp = OP_OR ;
m_tokIter++ ;
tok = m_Tokens[m_tokIter] ;
}
else if (tok == "(")
{
m_Error.Printf("Line %d: Expected an operator", tok.LineNo()) ;
return 0 ;
}
else
{
// Token is not an operator and not an open or a close. We assume it is another constant and thus there is an implied AND operator.
m_Error.Printf("asserting operator as AND\n") ;
binOp = OP_AND ;
}
}
/*
** Recurse to get second operand
*/
if (tok.Value())
{
m_Error.Printf("Recursing for 2nd operand\n") ;
m_nParLevel++ ;
pOperand2 = Parse() ;
m_nParLevel-- ;
if (pOperand2)
m_Error.Printf("Got 2nd operand\n") ;
else
m_Error.Printf("Got 2nd operand\n") ;
}
/*
** Decide if we return a constant or a formula
*/
if (!pOperand1)
{
m_Error.Printf("returning null (no first operand)\n") ;
return 0 ;
}
if (binOp == OP_NULL)
{
m_Error.Printf("returning single operand\n") ;
return pOperand1 ;
}
if (!pOperand2)
{
// report syntax error
m_Error.Printf("returning null (no second operand)\n") ;
return 0 ;
}
// Allocate a formula node
m_Error.Printf("returning double operand\n") ;
pFormula = new hzNumexpForm() ;
pFormula->AddOperand(pOperand1) ;
pFormula->AddOperand(pOperand2) ;
pFormula->SetUnaryOp(unaOp) ;
pFormula->SetOperator(binOp) ;
return pFormula ;
}