diff --git a/src/tests/spirit/CMakeLists.txt b/src/tests/spirit/CMakeLists.txt new file mode 100644 index 000000000..02ecea184 --- /dev/null +++ b/src/tests/spirit/CMakeLists.txt @@ -0,0 +1,73 @@ +# - spirit_fcn_test +cmake_minimum_required(VERSION 3.17) + +project(spirit_fcn_test VERSION 0.1 LANGUAGES CXX) + +#--- set a default build type if none was specified --------------------------- +set(default_build_type "Debug") + +if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif () + +#--- check for pkg-config ----------------------------------------------------- +find_package(PkgConfig REQUIRED) + +#--- check for ROOT ----------------------------------------------------------- +find_package(ROOT 6.18 REQUIRED COMPONENTS Gui MathMore Minuit2 XMLParser) +if (ROOT_mathmore_FOUND) + execute_process(COMMAND root-config --bindir OUTPUT_VARIABLE ROOT_BINDIR) + string(STRIP ${ROOT_BINDIR} ROOT_BINDIR) + execute_process(COMMAND root-config --version OUTPUT_VARIABLE ROOT_VERSION) + string(STRIP ${ROOT_VERSION} ROOT_VERSION) + message("-- Found ROOT: ${ROOT_BINDIR} (found version: ${ROOT_VERSION})") + #---Define useful ROOT functions and macros (e.g. ROOT_GENERATE_DICTIONARY) + include(${ROOT_USE_FILE}) +endif (ROOT_mathmore_FOUND) + +#--- check for boost ---------------------------------------------------------- +find_package(Boost QUIET) +if (Boost_VERSION VERSION_GREATER_EQUAL "1.89") + find_package(Boost REQUIRED + COMPONENTS + filesystem + ) +else (Boost_VERSION VERSION_GREATER_EQUAL "1.89") + find_package(Boost REQUIRED + COMPONENTS + system + filesystem + ) +endif (Boost_VERSION VERSION_GREATER_EQUAL "1.89") + +#--- create executable -------------------------------------------------------- +add_executable(spirit_fcn_test + spirit_fcn_test.cpp + PFunction.cpp + PFunctionHandler.cpp +) + +#--- add include directories -------------------------------------------------- +target_include_directories(spirit_fcn_test + BEFORE PRIVATE + ${Boost_INCLUDE_DIR} +) + +#--- link libraries ----------------------------------------------------------- +target_link_libraries(spirit_fcn_test + ${ROOT_LIBRARIES} + ${Boost_LIBRARIES} +) + +#--- installation info -------------------------------------------------------- +install( + TARGETS + spirit_fcn_test + RUNTIME DESTINATION + bin +) diff --git a/src/tests/spirit/PFunction.cpp b/src/tests/spirit/PFunction.cpp index d1b761a7f..df5740cba 100644 --- a/src/tests/spirit/PFunction.cpp +++ b/src/tests/spirit/PFunction.cpp @@ -1,832 +1,298 @@ -/*************************************************************************** - - PFunction.cpp - - Author: Andreas Suter - e-mail: andreas.suter@psi.ch - - $Id$ - -***************************************************************************/ - -/*************************************************************************** - * Copyright (C) 2007 by Andreas Suter * - * andreas.suter@psi.c * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program 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 General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#include -#include - -#include -using namespace std; - -#include // for stripping leading whitespace in std::string - -#include -#include -#include - -#include "PFunction.h" - -//-------------------------------------------------------------------------- -// Constructor -//-------------------------------------------------------------------------- -/** - *

- * - * info is an abstract syntax tree (AST) generate by the spirit parse library - * (see http://spirit.sourceforge.net/distrib/spirit_1_8_5/libs/spirit/doc/trees.html). - * It contains a single parsed msr-function in an ascii representation. - * Here it takes the from - * assignment (root node) - * |_ 'FUNx' - * |_ '=' - * |_ expression - * |_ ... - * - * Since it would be inefficient to evaluate this AST directly it is transferred to - * a more efficient tree fFuncs here in the constructor. - * - * \param info AST parse tree holding a single parsed msr-function in an ascii representation - * \param param the parameter vector - * \param map the map vector - */ -PFunction::PFunction(tree_parse_info<> info, vector param, vector map, bool debug) : - fDebug(debug) -{ - cout << endl << "in PFunction ..."; - - fInfo = info; - fParam = param; - fMap = map; - - // init class variables - fValid = true; - fFuncNo = -1; - - // print out ast tree - if (fDebug) { - PrintTree(info); - return; - } - - // check parameter and map range - if (!CheckParameterAndMapRange()) { - fValid = false; - return; - } - - // generate function evaluation tree - if (!GenerateFuncEvalTree()) { - fValid = false; - return; - } - - EvaluateTree(info); - - cout << endl << "fFuncString: '" << fFuncString << "'"; - cout << endl; -} - -//-------------------------------------------------------------------------- -// Destructor -//-------------------------------------------------------------------------- -/** - *

- */ -PFunction::~PFunction() -{ -// cout << endl << "in ~PFunction ..."; - fParam.clear(); - fMap.clear(); - - CleanupFuncEvalTree(); -} - -//-------------------------------------------------------------------------- -// InitNode (protected) -//-------------------------------------------------------------------------- -/** - *

- * - * \param node - */ -void PFunction::InitNode(PFuncTreeNode &node) -{ - node.fID = 0; - node.fOperatorTag = 0; - node.fFunctionTag = 0; - node.fIvalue = 0; - node.fSign = false; - node.fDvalue = 0.0; -} - -//------------------------------------------------------------- -// CheckParameterRange (protected) -//------------------------------------------------------------- -/** - *

- * - */ -bool PFunction::CheckParameterAndMapRange() -{ - return CheckParameterAndMapInTree(fInfo.trees.begin()); -} - -//------------------------------------------------------------- -// CheckParameterAndMapInTree (protected) -//------------------------------------------------------------- -/** - *

walk through the tree and check if the parameter found - * are within a valid range given by the size of fParam. - * - * \param i - */ -bool PFunction::CheckParameterAndMapInTree(iter_t const& i) -{ - bool success = true; - int value; - - if (i->value.id() == PFunctionGrammar::funLabelID) { - assert(i->children.size() == 0); - SetFuncNo(i); - } else if (i->value.id() == PFunctionGrammar::parameterID) { - assert(i->children.size() == 0); - string str(i->value.begin(), i->value.end()); - boost::algorithm::trim(str); -cout << endl << "parameterID: value = '" << str << "'" << endl; - - bool minus_sign_present = false; - if (str[0] == '-') - minus_sign_present = true; -cout << endl << ">> minus_sign_present = " << minus_sign_present; - if (minus_sign_present) - sscanf(str.c_str(), "-PAR%d", &value); - else - sscanf(str.c_str(), "PAR%d", &value); -cout << endl << ">> value = " << value << ", fParam.size() = " << fParam.size() << endl << "----"; - if (value > (int)fParam.size()) { // parameter number found > number of parameters - cout << endl << "**ERROR**: found parameter " << str << " with only " << fParam.size() << " parameters present?!?"; - fValid = false; - } - } else if (i->value.id() == PFunctionGrammar::mapID) { - assert(i->children.size() == 0); - string str(i->value.begin(), i->value.end()); - cout << endl << "mapID: value = " << str << endl; - sscanf(str.c_str(), "MAP%d", &value); -//cout << endl << ">> value = " << value << ", fParam.size() = " << fParam.size(); - if (value > (int)fMap.size()) { // parameter number found > number of parameters - cout << endl << "**ERROR**: found map " << str << " with only " << fMap.size() << " maps present?!?"; - fValid = false; - } - } else if (i->value.id() == PFunctionGrammar::functionID) { - assert(i->children.size() == 3); - // i: '(', 'expression', ')' - success = CheckParameterAndMapInTree(i->children.begin()+1); // thats the real stuff - } else if (i->value.id() == PFunctionGrammar::factorID) { - // i: real | parameter | map | function | expression - assert(i->children.size() == 1); - success = CheckParameterAndMapInTree(i->children.begin()); - } else if (i->value.id() == PFunctionGrammar::termID) { - // '*' or '/' i: lhs, rhs - assert(i->children.size() == 2); - success = CheckParameterAndMapInTree(i->children.begin()); - success = CheckParameterAndMapInTree(i->children.begin()+1); - } else if (i->value.id() == PFunctionGrammar::expressionID) { - // '+' or '-' i: lhs, rhs - assert(i->children.size() == 2); - success = CheckParameterAndMapInTree(i->children.begin()); - success = CheckParameterAndMapInTree(i->children.begin()+1); - } else if (i->value.id() == PFunctionGrammar::assignmentID) { - // i: 'FUNx', '=', 'expression' - assert(i->children.size() == 3); - success = CheckParameterAndMapInTree(i->children.begin()); // FUNx - success = CheckParameterAndMapInTree(i->children.begin()+2); // this is the real stuff - } - - return success; -} - -//------------------------------------------------------------- -// SetFuncNo (protected) -//------------------------------------------------------------- -/** - *

- * - * \param i - */ -bool PFunction::SetFuncNo(iter_t const& i) -{ - int funNo = -1; - int status; - bool success = true; - - // get string from tree - string str(i->value.begin(), i->value.end()); - - // extract function number from string - status = sscanf(str.c_str(), "FUN%d", &funNo); -//cout << endl << "SetFuncNo: status = " << status << ", funNo = " << funNo; - if (status == 1) { // found 1 int - fFuncNo = funNo; - } else { // wrong string - success = false; - } - - return success; -} - -//------------------------------------------------------------- -// GenerateFuncEvalTree (protected) -//------------------------------------------------------------- -/** - *

- * - */ -bool PFunction::GenerateFuncEvalTree() -{ - InitNode(fFunc); - FillFuncEvalTree(fInfo.trees.begin(), fFunc); - - return true; -} - -//------------------------------------------------------------- -// FillFuncEvalTree (protected) -//------------------------------------------------------------- -/** - *

- * - */ -void PFunction::FillFuncEvalTree(iter_t const& i, PFuncTreeNode &node) -{ - double dvalue; - int ivalue; - int status; - string str; - PFuncTreeNode child; - - InitNode(child); - - if (i->value.id() == PFunctionGrammar::realID) { // handle number - str = string(i->value.begin(), i->value.end()); // get string - status = sscanf(str.c_str(), "%lf", &dvalue); // convert string to double - node.fID = PFunctionGrammar::realID; // keep the ID - node.fDvalue = dvalue; // keep the value - cout << endl << ">> realID: value = " << dvalue; - } else if (i->value.id() == PFunctionGrammar::constPiID) { // handle constant pi - node.fID = PFunctionGrammar::constPiID; // keep the ID - node.fDvalue = 3.14159265358979323846; // keep the value - } else if (i->value.id() == PFunctionGrammar::constGammaMuID) { // handle constant gamma_mu - node.fID = PFunctionGrammar::constGammaMuID; // keep the ID - node.fDvalue = 0.0135538817; // keep the value - } else if (i->value.id() == PFunctionGrammar::parameterID) { // handle parameter number - str = string(i->value.begin(), i->value.end()); // get string - if (strstr(str.c_str(), "-")) { - node.fSign = true; - status = sscanf(str.c_str(), " -PAR%d", &ivalue); // convert string to parameter number - } else { - status = sscanf(str.c_str(), " PAR%d", &ivalue); // convert string to parameter number - } - node.fID = PFunctionGrammar::parameterID; // keep the ID - node.fIvalue = ivalue; // keep the value - cout << endl << ">> parameterID: value = " << ivalue; - } else if (i->value.id() == PFunctionGrammar::mapID) { // handle map number - str = string(i->value.begin(), i->value.end()); // get string - status = sscanf(str.c_str(), "MAP%d", &ivalue); // convert string to map number - node.fID = PFunctionGrammar::mapID; // keep the ID - node.fIvalue = ivalue; // keep the value -// cout << endl << ">> mapID: value = " << ivalue; - } else if (i->value.id() == PFunctionGrammar::functionID) { // handle function like cos ... - // keep the id - node.fID = PFunctionGrammar::functionID; - // keep function tag - // i: '(', 'expression', ')' - str = string(i->value.begin(), i->value.end()); // get string -// cout << endl << ">> functionID: value = " << str; - if (!strcmp(str.c_str(), "COS")) - node.fFunctionTag = FUN_COS; - else if (!strcmp(str.c_str(), "SIN")) - node.fFunctionTag = FUN_SIN; - else if (!strcmp(str.c_str(), "TAN")) - node.fFunctionTag = FUN_TAN; - else if (!strcmp(str.c_str(), "COSH")) - node.fFunctionTag = FUN_COSH; - else if (!strcmp(str.c_str(), "SINH")) - node.fFunctionTag = FUN_SINH; - else if (!strcmp(str.c_str(), "TANH")) - node.fFunctionTag = FUN_TANH; - else if (!strcmp(str.c_str(), "ACOS")) - node.fFunctionTag = FUN_ACOS; - else if (!strcmp(str.c_str(), "ASIN")) - node.fFunctionTag = FUN_ASIN; - else if (!strcmp(str.c_str(), "ATAN")) - node.fFunctionTag = FUN_ATAN; - else if (!strcmp(str.c_str(), "ACOSH")) - node.fFunctionTag = FUN_ACOSH; - else if (!strcmp(str.c_str(), "ASINH")) - node.fFunctionTag = FUN_ASINH; - else if (!strcmp(str.c_str(), "ATANH")) - node.fFunctionTag = FUN_ATANH; - else if (!strcmp(str.c_str(), "LOG")) - node.fFunctionTag = FUN_LOG; - else if (!strcmp(str.c_str(), "LN")) - node.fFunctionTag = FUN_LN; - else if (!strcmp(str.c_str(), "EXP")) - node.fFunctionTag = FUN_EXP; - else { - cout << endl << "**PANIC ERROR**: function " << str << " doesn't exist, but you never should have reached this point!"; - assert(0); - } - // add node - node.children.push_back(child); - // i: '(', 'expression', ')' - FillFuncEvalTree(i->children.begin()+1, node.children[0]); - } else if (i->value.id() == PFunctionGrammar::factorID) { -// cout << endl << ">> factorID"; - // keep the id - node.fID = PFunctionGrammar::factorID; - // add child lhs - node.children.push_back(child); - FillFuncEvalTree(i->children.begin(), node.children[0]); - } else if (i->value.id() == PFunctionGrammar::termID) { - // keep the id - node.fID = PFunctionGrammar::termID; - // keep operator tag - if (*i->value.begin() == '*') - node.fOperatorTag = OP_MUL; - else - node.fOperatorTag = OP_DIV; -/* -if (node.fOperatorTag == OP_MUL) - cout << endl << ">> termID: value = *"; -else - cout << endl << ">> termID: value = /"; -*/ - // add child lhs - node.children.push_back(child); - FillFuncEvalTree(i->children.begin(), node.children[0]); - // add child rhs - node.children.push_back(child); - FillFuncEvalTree(i->children.begin()+1, node.children[1]); - } else if (i->value.id() == PFunctionGrammar::expressionID) { // handle expression - // keep the id - node.fID = PFunctionGrammar::expressionID; - // keep operator tag - if (*i->value.begin() == '+') - node.fOperatorTag = OP_ADD; - else - node.fOperatorTag = OP_SUB; -/* -if (node.fOperatorTag == OP_ADD) - cout << endl << ">> expressionID: value = +"; -else - cout << endl << ">> expressionID: value = -"; -*/ - // add child lhs - node.children.push_back(child); - FillFuncEvalTree(i->children.begin(), node.children[0]); - // add child rhs - node.children.push_back(child); - FillFuncEvalTree(i->children.begin()+1, node.children[1]); - } else if (i->value.id() == PFunctionGrammar::assignmentID) { - // nothing to be done except to pass the next element in the ast - // i: 'funx', '=', 'expression' - FillFuncEvalTree(i->children.begin()+2, node); - } -} - -//------------------------------------------------------------- -// Eval (public) -//------------------------------------------------------------- -/** - *

- * - */ -double PFunction::Eval() -{ - return EvalNode(fFunc); -} - -//------------------------------------------------------------- -// EvalNode (protected) -//------------------------------------------------------------- -/** - *

- * - * \param node - */ -double PFunction::EvalNode(PFuncTreeNode &node) -{ - if (node.fID == PFunctionGrammar::realID) { - return node.fDvalue; - } else if (node.fID == PFunctionGrammar::constPiID) { - return node.fDvalue; - } else if (node.fID == PFunctionGrammar::constGammaMuID) { - return node.fDvalue; - } else if (node.fID == PFunctionGrammar::parameterID) { - double dval; - if (node.fSign) - dval = -fParam[node.fIvalue-1]; - else - dval = fParam[node.fIvalue-1]; - return dval; - } else if (node.fID == PFunctionGrammar::mapID) { - return fParam[fMap[node.fIvalue-1]-1]; - } else if (node.fID == PFunctionGrammar::functionID) { - if (node.fFunctionTag == FUN_COS) { - return cos(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_SIN) { - return sin(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_TAN) { - return tan(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_COSH) { - return cosh(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_SINH) { - return sinh(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_TANH) { - return tanh(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_ACOS) { - return acos(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_ASIN) { - return asin(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_ATAN) { - return atan(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_ACOSH) { - return boost::math::acosh(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_ASINH) { - return boost::math::asinh(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_ATANH) { - return boost::math::atanh(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_LOG) { - return log(EvalNode(node.children[0]))/log(10.0); - } else if (node.fFunctionTag == FUN_LN) { - return log(EvalNode(node.children[0])); - } else if (node.fFunctionTag == FUN_EXP) { - return exp(EvalNode(node.children[0])); - } else { - cout << endl << "**PANIC ERROR**: PFunction::EvalNode: node.fID == PFunctionGrammar::functionID: you never should have reached this point!" << endl; - assert(0); - } - } else if (node.fID == PFunctionGrammar::factorID) { - return EvalNode(node.children[0]); - } else if (node.fID == PFunctionGrammar::termID) { - if (node.fOperatorTag == OP_MUL) { - return EvalNode(node.children[0]) * EvalNode(node.children[1]); - } else { - double denominator = EvalNode(node.children[1]); - if (denominator == 0.0) { - cout << endl << "**PANIC ERROR**: PFunction::EvalNode: division by 0.0" << endl; - assert(0); - } - return EvalNode(node.children[0]) / denominator; - } - } else if (node.fID == PFunctionGrammar::expressionID) { - if (node.fOperatorTag == OP_ADD) { - return EvalNode(node.children[0]) + EvalNode(node.children[1]); - } else { - return EvalNode(node.children[0]) - EvalNode(node.children[1]); - } - } else { - cout << endl << "**PANIC ERROR**: PFunction::EvalNode: you never should have reached this point!" << endl; - assert(0); - } - return 0.0; -} - -//------------------------------------------------------------- -// CleanupFuncEvalTree (protected) -//------------------------------------------------------------- -/** - *

- * - */ -void PFunction::CleanupFuncEvalTree() -{ - // clean up all children - CleanupNode(fFunc); -} - -//------------------------------------------------------------- -// CleanupNode (protected) -//------------------------------------------------------------- -/** - *

- * - * \param node - */ -void PFunction::CleanupNode(PFuncTreeNode &node) -{ - if (node.children.size() != 0) { - for (unsigned int i=0; i info) -{ - return EvalTreeExpression(info.trees.begin()); -} - -//------------------------------------------------------------- -// EvalTreeExpression (protected) -//------------------------------------------------------------- -long PFunction::EvalTreeExpression(iter_t const& i) -{ - static int counter = 0; - static int termOp = 0; - - cout << endl << counter <<": in EvalExpression. i->value = '" << - string(i->value.begin(), i->value.end()) << - "' i->children.size() = " << i->children.size() << endl; - - if (i->value.id() == PFunctionGrammar::realID) { - assert(i->children.size() == 0); - cout << endl << "realID: children = " << i->children.size(); - cout << endl << "realID: " << string(i->value.begin(), i->value.end()); - cout << endl << "-----"; - if (*i->value.begin() == '-') - fFuncString += "("; - fFuncString += string(i->value.begin(), i->value.end()); - if (*i->value.begin() == '-') - fFuncString += ")"; - } else if (i->value.id() == PFunctionGrammar::constPiID) { - assert(i->children.size() == 0); - cout << endl << "constPiID: children = " << i->children.size(); - cout << endl << "constPiID: " << string(i->value.begin(), i->value.end()); - cout << endl << "-----"; - fFuncString += string(i->value.begin(), i->value.end()); - } else if (i->value.id() == PFunctionGrammar::constGammaMuID) { - assert(i->children.size() == 0); - cout << endl << "constGammaMuID: children = " << i->children.size(); - cout << endl << "constGammaMuID: " << string(i->value.begin(), i->value.end()); - cout << endl << "-----"; - fFuncString += string(i->value.begin(), i->value.end()); - } else if (i->value.id() == PFunctionGrammar::funLabelID) { - assert(i->children.size() == 0); - //SetFuncNo(i); - cout << endl << "funLabelID: children = " << i->children.size(); - cout << endl << "funLabelID: value = " << string(i->value.begin(), i->value.end()); - cout << endl << "-----"; - fFuncString += string(i->value.begin(), i->value.end()); // funx - } else if (i->value.id() == PFunctionGrammar::parameterID) { - assert(i->children.size() == 0); - cout << endl << "parameterID: children = " << i->children.size(); - cout << endl << "parameterID: value = " << string(i->value.begin(), i->value.end()); - cout << endl << "-----"; - fFuncString += string(i->value.begin(), i->value.end()); - } else if (i->value.id() == PFunctionGrammar::mapID) { - assert(i->children.size() == 0); - cout << endl << "mapID: children = " << i->children.size(); - cout << endl << "mapID: value = " << string(i->value.begin(), i->value.end()); - cout << endl << "-----"; - fFuncString += string(i->value.begin(), i->value.end()); - } else if (i->value.id() == PFunctionGrammar::functionID) { - assert(i->children.size() == 3); - cout << endl << "functionID: children = " << i->children.size(); - cout << endl << "functionID: value = " << string(i->value.begin(), i->value.end()); - cout << endl << "-----"; - // '(', expression, ')' - counter++; - fFuncString += string(i->value.begin(), i->value.end()); - fFuncString += "("; - EvalTreeExpression(i->children.begin()+1); // the real stuff - fFuncString += ")"; - counter--; - } else if (i->value.id() == PFunctionGrammar::factorID) { - cout << endl << "factorID: children = " << i->children.size(); - counter++; - return EvalTreeExpression(i->children.begin()); - counter--; - } else if (i->value.id() == PFunctionGrammar::termID) { - cout << endl << "termID: children = " << i->children.size(); - counter++; - termOp++; - if (*i->value.begin() == '*') { - cout << endl << "termID: '*'"; - assert(i->children.size() == 2); - EvalTreeExpression(i->children.begin()); - fFuncString += " * "; - EvalTreeExpression(i->children.begin()+1); - } else if (*i->value.begin() == '/') { - cout << endl << "termID: '/'"; - assert(i->children.size() == 2); - EvalTreeExpression(i->children.begin()); - fFuncString += " / "; - EvalTreeExpression(i->children.begin()+1); - } else { - assert(0); - } - termOp--; - counter--; - } else if (i->value.id() == PFunctionGrammar::expressionID) { - cout << endl << "expressionID: children = " << i->children.size(); - if (termOp > 0) - fFuncString += "("; - if (*i->value.begin() == '+') { - cout << endl << "expressionID: '+'"; - assert(i->children.size() == 2); - counter++; - EvalTreeExpression(i->children.begin()); - fFuncString += " + "; - EvalTreeExpression(i->children.begin()+1); - counter--; - } else if (*i->value.begin() == '-') { - cout << endl << "expressionID: '-'"; - assert(i->children.size() == 2); - counter++; - EvalTreeExpression(i->children.begin()); - fFuncString += " - "; - EvalTreeExpression(i->children.begin()+1); - counter--; - } else { - assert(0); - } - if (termOp > 0) - fFuncString += ")"; - } else if (i->value.id() == PFunctionGrammar::assignmentID) { - cout << endl << "assignmentID: children = " << i->children.size(); - assert(i->children.size() == 3); - counter++; - EvalTreeExpression(i->children.begin()); - EvalTreeExpression(i->children.begin()+1); // this is the string "=" - EvalTreeExpression(i->children.begin()+2); // this is the real stuff - counter--; - } else if (*i->value.begin() == '=') { - cout << endl << "'=' in assignment"; - fFuncString += " = "; - } else { - assert(0); - } - - return 0; -} - -//------------------------------------------------------------- -// PrintTree (protected) -//------------------------------------------------------------- -long PFunction::PrintTree(tree_parse_info<> info) -{ - cout << endl << "********************************************"; - cout << endl << ">> PrintTree"; - cout << endl << "********************************************"; - long value = PrintTreeExpression(info.trees.begin()); - cout << endl << "********************************************"; - cout << endl; - return value; -} - -//------------------------------------------------------------- -// PrintTreeExpression (protected) -//------------------------------------------------------------- -long PFunction::PrintTreeExpression(iter_t const& i) -{ - string str; - iter_t j; - - if (i->value.id() == PFunctionGrammar::realID) { - if (i->children.size() == 0) { - str = string(i->value.begin(), i->value.end()); - cout << endl << ">> " << str; - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else if (i->value.id() == PFunctionGrammar::funLabelID) { - if (i->children.size() == 0) { - j = i->children.begin(); - str = string(j->value.begin(), j->value.end()); - cout << endl << ">> " << str; - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else if (i->value.id() == PFunctionGrammar::parameterID) { - if (i->children.size() == 0) { - str = string(i->value.begin(), i->value.end()); - cout << endl << ">> " << str; - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else if (i->value.id() == PFunctionGrammar::mapID) { - if (i->children.size() == 0) { - str = string(i->value.begin(), i->value.end()); - cout << endl << ">> " << str; - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else if (i->value.id() == PFunctionGrammar::functionID) { - // i: '(', 'expression', ')' - str = string(i->value.begin(), i->value.end()); - cout << endl << ">> " << str; - if (i->children.size() == 3) { - j = i->children.begin(); - str = string(j->value.begin(), j->value.end()); - cout << endl << ">> " << str; - PrintTreeExpression(i->children.begin()+1); - j = i->children.begin()+2; - str = string(j->value.begin(), j->value.end()); - cout << endl << ">> " << str; - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else if (i->value.id() == PFunctionGrammar::factorID) { - // i: real | parameter | map | function | expression - if (i->children.size() == 1) { - PrintTreeExpression(i->children.begin()); - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else if (i->value.id() == PFunctionGrammar::termID) { - // '*' or '/' i: lhs, rhs - str = string(i->value.begin(), i->value.end()); - cout << endl << ">> " << str; - if (i->children.size() == 2) { - PrintTreeExpression(i->children.begin()); - PrintTreeExpression(i->children.begin()+1); - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else if (i->value.id() == PFunctionGrammar::expressionID) { - // '+' or '-' i: lhs, rhs - str = string(i->value.begin(), i->value.end()); - cout << endl << ">> " << str; - if (i->children.size() == 2) { - PrintTreeExpression(i->children.begin()); - PrintTreeExpression(i->children.begin()+1); - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else if (i->value.id() == PFunctionGrammar::assignmentID) { - // i: 'funx', '=', 'expression' - if (i->children.size() == 3) { - j = i->children.begin(); - str = string(j->value.begin(), j->value.end()); - cout << endl << ">> " << str; - j = i->children.begin()+1; - str = string(j->value.begin(), j->value.end()); - cout << endl << ">> " << str; - PrintTreeExpression(i->children.begin()+2); - } else { - for (unsigned int k=0; kchildren.size(); k++) { - j = i->children.begin()+k; - str = string(j->value.begin(), j->value.end()); - cout << endl << "!> " << str; - } - } - } else { - cout << endl << "this point should never have been reached :-(" << endl; - assert(0); - } - return 0; -} +/*************************************************************************** + + PFunction.cpp - Test version (simplified, no PMetaData) + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Modernized test implementation using Boost.Spirit X3. + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2007-2026 by Andreas Suter * + * andreas.suter@psi.ch * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include + +#include +#include + +#include "PFunction.h" +#include "PFunctionGrammar.h" + +namespace x3 = boost::spirit::x3; + +//-------------------------------------------------------------------------- +// Constructor +//-------------------------------------------------------------------------- +PFunction::PFunction(const std::string& input, std::vector param, + std::vector map, bool debug) + : fParam(param), fMap(map), fDebug(debug) +{ + fValid = false; + fFuncNo = -1; + + // Parse the input + musrfit::ast::assignment assignment; + std::string::const_iterator iter = input.begin(); + std::string::const_iterator end = input.end(); + + // Get the X3 grammar + auto const& grammar = musrfit::function_grammar(); + + // Try to parse with X3 + try { + bool success = x3::phrase_parse(iter, end, grammar, x3::space, assignment); + + if (success && iter == end) { + fFuncNo = assignment.func_number; + fAst = assignment.rhs; + fValid = true; + + if (fDebug) { + std::cout << "Parse successful: FUN" << fFuncNo << std::endl; + } + } else { + std::cerr << "**ERROR** Failed to parse: " << input << std::endl; + if (iter != end) { + std::cerr << "**ERROR** Stopped at: " << std::string(iter, end) << std::endl; + } + fValid = false; + } + } catch (x3::expectation_failure const& e) { + std::cerr << "**ERROR** Parsing failed. Expected: " << e.which() << std::endl; + std::cerr << "**ERROR** At position: " << std::distance(input.begin(), e.where()) << std::endl; + fValid = false; + } +} + +//-------------------------------------------------------------------------- +// Destructor +//-------------------------------------------------------------------------- +PFunction::~PFunction() +{ + fParam.clear(); + fMap.clear(); +} + +//-------------------------------------------------------------------------- +// Eval +//-------------------------------------------------------------------------- +double PFunction::Eval() +{ + if (!fValid) return 0.0; + + EvalVisitor evaluator(fMap, fParam); + + // Evaluate first operand + double result = boost::apply_visitor(evaluator, fAst.first); + + // Apply operations + for (const auto& op : fAst.rest) { + double rhs = boost::apply_visitor(evaluator, op.operand_); + + switch (op.operator_) { + case musrfit::ast::op_plus: + result += rhs; + break; + case musrfit::ast::op_minus: + result -= rhs; + break; + case musrfit::ast::op_times: + result *= rhs; + break; + case musrfit::ast::op_divide: + if (std::abs(rhs) > 1.0e-20) result /= rhs; + else result = 0.0; + break; + } + } + + return result; +} + +//========================================================================== +// EvalVisitor Implementation +//========================================================================== + +double PFunction::EvalVisitor::operator()(const musrfit::ast::nil&) const +{ + return 0.0; +} + +double PFunction::EvalVisitor::operator()(double val) const +{ + return val; +} + +double PFunction::EvalVisitor::operator()(const musrfit::ast::constant& c) const +{ + double val = 0.0; + + switch (c.const_type) { + case musrfit::ast::constant::pi: + val = 3.14159265358979323846; + break; + + case musrfit::ast::constant::gamma_mu: + val = 0.01355342; // GAMMA_BAR_MUON equivalent for test + break; + + // Test version doesn't support metadata, so these return 0 + case musrfit::ast::constant::field: + case musrfit::ast::constant::energy: + case musrfit::ast::constant::temp: + std::cerr << "**WARNING** Metadata not supported in test version" << std::endl; + val = 0.0; + break; + + default: + val = 0.0; + } + + return c.sign ? -val : val; +} + +double PFunction::EvalVisitor::operator()(const musrfit::ast::parameter& p) const +{ + int idx = p.number - 1; + + if (idx < 0 || idx >= static_cast(fParam.size())) { + std::cerr << "**ERROR** Parameter out of range: PAR" << p.number << std::endl; + return 0.0; + } + + double val = fParam[idx]; + return p.sign ? -val : val; +} + +double PFunction::EvalVisitor::operator()(const musrfit::ast::map_ref& m) const +{ + int mapIdx = m.number - 1; + + if (mapIdx < 0 || mapIdx >= static_cast(fMap.size())) { + std::cerr << "**ERROR** Map out of range: MAP" << m.number << std::endl; + return 0.0; + } + + int paramIdx = fMap[mapIdx] - 1; + + if (paramIdx < 0 || paramIdx >= static_cast(fParam.size())) { + std::cerr << "**ERROR** Mapped parameter out of range" << std::endl; + return 0.0; + } + + double val = fParam[paramIdx]; + return m.sign ? -val : val; +} + +double PFunction::EvalVisitor::operator()(const musrfit::ast::function_call& f) const +{ + // Evaluate argument + double arg = boost::apply_visitor(*this, f.arg.first); + for (const auto& op : f.arg.rest) { + double rhs = boost::apply_visitor(*this, op.operand_); + switch (op.operator_) { + case musrfit::ast::op_plus: arg += rhs; break; + case musrfit::ast::op_minus: arg -= rhs; break; + case musrfit::ast::op_times: arg *= rhs; break; + case musrfit::ast::op_divide: + if (std::abs(rhs) > 1.0e-20) arg /= rhs; + break; + } + } + + // Apply function + double result = 0.0; + switch (f.func_id) { + case musrfit::ast::fun_cos: result = std::cos(arg); break; + case musrfit::ast::fun_sin: result = std::sin(arg); break; + case musrfit::ast::fun_tan: result = std::tan(arg); break; + case musrfit::ast::fun_cosh: result = std::cosh(arg); break; + case musrfit::ast::fun_sinh: result = std::sinh(arg); break; + case musrfit::ast::fun_tanh: result = std::tanh(arg); break; + case musrfit::ast::fun_acos: result = std::acos(arg); break; + case musrfit::ast::fun_asin: result = std::asin(arg); break; + case musrfit::ast::fun_atan: result = std::atan(arg); break; + case musrfit::ast::fun_acosh: result = std::acosh(arg); break; + case musrfit::ast::fun_asinh: result = std::asinh(arg); break; + case musrfit::ast::fun_atanh: result = std::atanh(arg); break; + case musrfit::ast::fun_log: result = std::log10(std::abs(arg)); break; + case musrfit::ast::fun_ln: result = std::log(std::abs(arg)); break; + case musrfit::ast::fun_exp: result = std::exp(arg); break; + case musrfit::ast::fun_sqrt: result = std::sqrt(std::abs(arg)); break; + default: result = 0.0; + } + + return result; +} + +double PFunction::EvalVisitor::operator()(const musrfit::ast::power_call& p) const +{ + // Evaluate base + double base = boost::apply_visitor(*this, p.base.first); + for (const auto& op : p.base.rest) { + double rhs = boost::apply_visitor(*this, op.operand_); + switch (op.operator_) { + case musrfit::ast::op_plus: base += rhs; break; + case musrfit::ast::op_minus: base -= rhs; break; + case musrfit::ast::op_times: base *= rhs; break; + case musrfit::ast::op_divide: + if (std::abs(rhs) > 1.0e-20) base /= rhs; + break; + } + } + + // Evaluate exponent + double exponent = boost::apply_visitor(*this, p.pow.first); + for (const auto& op : p.pow.rest) { + double rhs = boost::apply_visitor(*this, op.operand_); + switch (op.operator_) { + case musrfit::ast::op_plus: exponent += rhs; break; + case musrfit::ast::op_minus: exponent -= rhs; break; + case musrfit::ast::op_times: exponent *= rhs; break; + case musrfit::ast::op_divide: + if (std::abs(rhs) > 1.0e-20) exponent /= rhs; + break; + } + } + + return std::pow(std::abs(base), exponent); +} + +double PFunction::EvalVisitor::operator()(const musrfit::ast::expression& e) const +{ + double result = boost::apply_visitor(*this, e.first); + + for (const auto& op : e.rest) { + double rhs = boost::apply_visitor(*this, op.operand_); + switch (op.operator_) { + case musrfit::ast::op_plus: result += rhs; break; + case musrfit::ast::op_minus: result -= rhs; break; + case musrfit::ast::op_times: result *= rhs; break; + case musrfit::ast::op_divide: + if (std::abs(rhs) > 1.0e-20) result /= rhs; + break; + } + } + + return result; +} diff --git a/src/tests/spirit/PFunction.h b/src/tests/spirit/PFunction.h index b903beff6..10c737fa0 100644 --- a/src/tests/spirit/PFunction.h +++ b/src/tests/spirit/PFunction.h @@ -1,125 +1,88 @@ -/*************************************************************************** - - PFunction.h - - Author: Andreas Suter - e-mail: andreas.suter@psi.ch - - $Id$ - -***************************************************************************/ - -/*************************************************************************** - * Copyright (C) 2007 by Andreas Suter * - * andreas.suter@psi.c * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program 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 General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#ifndef _PFUNCTION_H_ -#define _PFUNCTION_H_ - -#include -#include - -#include - -#if BOOST_VERSION >= 103800 -# include - using namespace BOOST_SPIRIT_CLASSIC_NS; -#else -# include - using namespace boost::spirit; -#endif - -#include "PFunctionGrammar.h" - -//---------------------------------------------------------------------------- -#define OP_ADD 0 -#define OP_SUB 1 -#define OP_MUL 2 -#define OP_DIV 3 - -#define FUN_COS 0 -#define FUN_SIN 1 -#define FUN_TAN 2 -#define FUN_COSH 3 -#define FUN_SINH 4 -#define FUN_TANH 5 -#define FUN_ACOS 6 -#define FUN_ASIN 7 -#define FUN_ATAN 8 -#define FUN_ACOSH 9 -#define FUN_ASINH 10 -#define FUN_ATANH 11 -#define FUN_LOG 12 -#define FUN_LN 13 -#define FUN_EXP 14 - -//---------------------------------------------------------------------------- -typedef struct func_tree_node { - int fID; ///< tag showing what tree element this is - int fOperatorTag; ///< tag for '+', '-', '*', '/' - int fFunctionTag; ///< tag got "cos", "sin", ... - int fIvalue; ///< for parameter numbers and maps - bool fSign; ///< for sign. true = '-', false = '+' - double fDvalue; ///< for numbers - vector children; ///< holding sub-tree -} PFuncTreeNode; - -//---------------------------------------------------------------------------- -class PFunction { - public: - PFunction(tree_parse_info<> info, vector param, vector map, bool debug); - virtual ~PFunction(); - - virtual bool IsValid() { return fValid; } - virtual int GetFuncNo() { return fFuncNo; } - virtual double Eval(); - - protected: - virtual void InitNode(PFuncTreeNode &node); - - virtual bool CheckParameterAndMapRange(); - virtual bool CheckParameterAndMapInTree(iter_t const& i); - virtual bool SetFuncNo(iter_t const& i); - - virtual bool GenerateFuncEvalTree(); - virtual void FillFuncEvalTree(iter_t const& i, PFuncTreeNode &node); - virtual double EvalNode(PFuncTreeNode &node); - virtual void CleanupFuncEvalTree(); - virtual void CleanupNode(PFuncTreeNode &node); - - virtual long EvaluateTree(tree_parse_info<> info); - virtual long EvalTreeExpression(iter_t const& i); - - virtual long PrintTree(tree_parse_info<> info); - virtual long PrintTreeExpression(iter_t const& i); - - private: - tree_parse_info<> fInfo; - vector fParam; - vector fMap; - PFuncTreeNode fFunc; - - bool fDebug; - bool fValid; ///< flag showing if the function is valid - int fFuncNo; ///< function number, i.e. FUNx with x the function number - - string fFuncString; -}; - -#endif // _PFUNCTION_H_ +/*************************************************************************** + + PFunction.h - Test version (simplified, no PMetaData) + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Modernized test version using Boost.Spirit X3 and visitor pattern. + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2007-2026 by Andreas Suter * + * andreas.suter@psi.ch * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _PFUNCTION_H_ +#define _PFUNCTION_H_ + +#include +#include + +#include + +#include "PFunctionAst.h" + +//---------------------------------------------------------------------------- +/** + * \brief Test version of PFunction class - simplified without PMetaData. + * + * This test version uses the same X3 grammar and AST but with a simpler + * interface for testing purposes. It does not support metadata (field, + * energy, temperature). + */ +class PFunction { + public: + PFunction(const std::string& input, std::vector param, std::vector map, bool debug = false); + virtual ~PFunction(); + + virtual bool IsValid() { return fValid; } + virtual int GetFuncNo() { return fFuncNo; } + virtual double Eval(); + + private: + musrfit::ast::expression fAst; + std::vector fParam; + std::vector fMap; + bool fValid; + int fFuncNo; + bool fDebug; + + // Simplified evaluation visitor (no metadata support) + class EvalVisitor : public boost::static_visitor { + public: + EvalVisitor(const std::vector& map, const std::vector& param) + : fMap(map), fParam(param) {} + + double operator()(const musrfit::ast::nil&) const; + double operator()(double val) const; + double operator()(const musrfit::ast::constant& c) const; + double operator()(const musrfit::ast::parameter& p) const; + double operator()(const musrfit::ast::map_ref& m) const; + double operator()(const musrfit::ast::function_call& f) const; + double operator()(const musrfit::ast::power_call& p) const; + double operator()(const musrfit::ast::expression& e) const; + + private: + const std::vector& fMap; + const std::vector& fParam; + }; +}; + +#endif // _PFUNCTION_H_ diff --git a/src/tests/spirit/PFunctionAst.h b/src/tests/spirit/PFunctionAst.h new file mode 100644 index 000000000..ff82058f2 --- /dev/null +++ b/src/tests/spirit/PFunctionAst.h @@ -0,0 +1,306 @@ +/*************************************************************************** + + PFunctionAst.hpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Abstract Syntax Tree (AST) definitions for Spirit X3 parser. + Migrated from Qi to X3 for improved compile times and cleaner syntax. + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2007-2025 by Andreas Suter * + * andreas.suter@psi.ch * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _PFUNCTIONAST_HPP_ +#define _PFUNCTIONAST_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace musrfit { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + /** + * @brief Abstract Syntax Tree (AST) definitions for the function parser. + * + * This namespace defines the complete AST structure used to represent + * parsed function expressions. The AST is built using Boost.Variant for + * type-safe unions and Boost.Spirit X3's automatic AST generation from + * grammar rules. + * + * The AST supports: + * - Arithmetic operations: +, -, *, / + * - Mathematical functions: cos, sin, tan, exp, log, sqrt, pow, etc. + * - Constants: PI, GAMMA_MU, field (B), energy (EN), temperature (T#) + * - Parameter references: PAR#, -PAR# + * - Map references: MAP# + * - Function labels: FUN# + * - Expression evaluation with proper precedence + */ + /////////////////////////////////////////////////////////////////////////// + + /** + * @brief Enumeration of arithmetic operators. + * + * These tokens represent the fundamental arithmetic operations supported + * by the expression evaluator. + */ + enum optoken + { + op_plus, ///< Addition operator (+) + op_minus, ///< Subtraction operator (-) + op_times, ///< Multiplication operator (*) + op_divide, ///< Division operator (/) + }; + + /** + * @brief Enumeration of supported mathematical functions. + * + * These function identifiers map to standard mathematical operations + * evaluated during the semantic analysis phase. + */ + enum funid + { + fun_cos, ///< Cosine function + fun_sin, ///< Sine function + fun_tan, ///< Tangent function + fun_cosh, ///< Hyperbolic cosine function + fun_sinh, ///< Hyperbolic sine function + fun_tanh, ///< Hyperbolic tangent function + fun_acos, ///< Arccosine function + fun_asin, ///< Arcsine function + fun_atan, ///< Arctangent function + fun_acosh, ///< Inverse hyperbolic cosine function + fun_asinh, ///< Inverse hyperbolic sine function + fun_atanh, ///< Inverse hyperbolic tangent function + fun_log, ///< Base-10 logarithm function + fun_ln, ///< Natural logarithm function + fun_exp, ///< Exponential function + fun_sqrt ///< Square root function + }; + + /** + * @brief Represents an empty/null AST node. + * + * Used as a placeholder in variant types where no value is present. + */ + struct nil {}; + + // Forward declarations for recursive AST structures + struct expression; + struct function_call; + struct power_call; + + /** + * @brief Represents a constant value in an expression. + * + * Constants can be: + * - Mathematical constants: PI, GAMMA_MU + * - Metadata values: B (field), EN (energy), T# (temperature) + */ + struct constant + { + /** + * @brief Enumeration of constant types. + */ + enum type { + pi, ///< Mathematical constant π (3.14159...) + gamma_mu, ///< Muon gyromagnetic ratio constant + field, ///< Magnetic field from experimental data (B or -B) + energy, ///< Energy from experimental data (EN or -EN) + temp ///< Temperature from experimental data (T# or -T#) + }; + + type const_type; ///< The type of constant + bool sign; ///< Sign flag: false for positive, true for negative + int index; ///< Index for temperature (T0, T1, T2, ...) + }; + + /** + * @brief Represents a parameter reference in an expression. + * + * Parameters are fit parameters referenced as PAR# or -PAR#, + * where # is the parameter number (1-based). + */ + struct parameter + { + int number; ///< Parameter number (extracted from PAR#) + bool sign; ///< Sign flag: false for PAR#, true for -PAR# + }; + + /** + * @brief Represents a map reference in an expression. + * + * Maps provide indirect parameter references: MAP# or -MAP# + * references the map vector at index #-1, which then indexes + * into the parameter vector. + */ + struct map_ref + { + int number; ///< Map number (extracted from MAP#) + bool sign; ///< Sign flag: false for MAP#, true for -MAP# + }; + + /** + * @brief Variant type representing any operand in an expression. + * + * An operand can be a literal number, constant, parameter, map reference, + * function call, power operation, or parenthesized expression. The variant + * uses recursive_wrapper for types that contain expressions to handle + * recursive grammar structures. + */ + typedef boost::variant< + nil ///< Empty placeholder + , double ///< Numeric literal + , constant ///< Constant value + , parameter ///< Parameter reference + , map_ref ///< Map reference + , boost::recursive_wrapper ///< Function call (recursive) + , boost::recursive_wrapper ///< Power operation (recursive) + , boost::recursive_wrapper ///< Parenthesized expression (recursive) + > + operand; + + /** + * @brief Represents a binary operation with an operator and right operand. + * + * Used in expression chains where the left operand is the accumulated + * result from previous operations. + */ + struct operation + { + optoken operator_; ///< The binary operator (+, -, *, /) + operand operand_; ///< The right-hand operand + }; + + /** + * @brief Represents a complete expression with operator precedence. + * + * Expressions are built as a first operand followed by a sequence of + * operations. This structure naturally encodes operator precedence as + * determined by the grammar rules. + */ + struct expression + { + operand first; ///< The first operand in the expression + std::list rest; ///< Sequence of operations applied left-to-right + }; + + /** + * @brief Represents a function call with a single argument. + * + * Examples: COS(PAR1), SQRT(B), EXP(-PAR2 * T0) + */ + struct function_call + { + funid func_id; ///< The function identifier + expression arg; ///< The argument expression + }; + + /** + * @brief Represents a power operation. + * + * Syntax: POW(base, exponent) + * Both base and exponent are full expressions. + */ + struct power_call + { + expression base; ///< The base expression + expression pow; ///< The exponent expression + }; + + /** + * @brief Represents an assignment statement. + * + * Syntax: FUN# = expression + * Assigns the result of evaluating the right-hand expression to a + * function label. + */ + struct assignment + { + int func_number; ///< Function number (extracted from FUN#) + expression rhs; ///< The right-hand side expression to evaluate + }; + + /** + * @brief Stream output operator for nil nodes (debugging support). + * @param out the output stream + * @return the output stream for chaining + */ + inline std::ostream& operator<<(std::ostream& out, nil) { out << std::string("nil"); return out; } +}} + +// Boost.Fusion adaptations to make structures compatible with X3 attribute propagation +BOOST_FUSION_ADAPT_STRUCT( + musrfit::ast::constant, + (musrfit::ast::constant::type, const_type) + (bool, sign) + (int, index) +) + +BOOST_FUSION_ADAPT_STRUCT( + musrfit::ast::parameter, + (int, number) + (bool, sign) +) + +BOOST_FUSION_ADAPT_STRUCT( + musrfit::ast::map_ref, + (int, number) + (bool, sign) +) + +BOOST_FUSION_ADAPT_STRUCT( + musrfit::ast::operation, + (musrfit::ast::optoken, operator_) + (musrfit::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + musrfit::ast::expression, + (musrfit::ast::operand, first) + (std::list, rest) +) + +BOOST_FUSION_ADAPT_STRUCT( + musrfit::ast::function_call, + (musrfit::ast::funid, func_id) + (musrfit::ast::expression, arg) +) + +BOOST_FUSION_ADAPT_STRUCT( + musrfit::ast::power_call, + (musrfit::ast::expression, base) + (musrfit::ast::expression, pow) +) + +BOOST_FUSION_ADAPT_STRUCT( + musrfit::ast::assignment, + (int, func_number) + (musrfit::ast::expression, rhs) +) + +#endif // _PFUNCTIONAST_HPP_ diff --git a/src/tests/spirit/PFunctionGrammar.h b/src/tests/spirit/PFunctionGrammar.h index d684723ed..bff81847a 100644 --- a/src/tests/spirit/PFunctionGrammar.h +++ b/src/tests/spirit/PFunctionGrammar.h @@ -1,164 +1,196 @@ -/*************************************************************************** - - PFunctionGrammer.h - - Author: Andreas Suter - e-mail: andreas.suter@psi.ch - - $Id$ - -***************************************************************************/ - -/*************************************************************************** - * Copyright (C) 2007 by Andreas Suter * - * andreas.suter@psi.c * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program 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 General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#ifndef _PFUNCTIONGRAMMAR_H_ -#define _PFUNCTIONGRAMMAR_H_ - -#include -using namespace std; - -//#define BOOST_SPIRIT_DEBUG - -#include -#include - -#if BOOST_VERSION >= 103800 -# include -# include - using namespace BOOST_SPIRIT_CLASSIC_NS; -#else -# include -# include - using namespace boost::spirit; -#endif - -typedef char const* iterator_t; -typedef tree_match parse_tree_match_t; -typedef parse_tree_match_t::tree_iterator iter_t; - -//-------------------------------------------------------------------------- -/** - * - */ -struct PFunctionGrammar : public grammar -{ - static const int realID = 1; - static const int constPiID = 2; - static const int constGammaMuID = 3; - static const int funLabelID = 4; - static const int parameterID = 5; - static const int mapID = 6; - static const int functionID = 7; - static const int factorID = 8; - static const int termID = 9; - static const int expressionID = 10; - static const int assignmentID = 11; - - template - struct definition - { - definition(PFunctionGrammar const& /*self*/) - { - // Start grammar definition - real = leaf_node_d[ real_p ]; - - const_pi = leaf_node_d[ str_p("PI") ]; - - const_gamma_mu = leaf_node_d[ str_p("GAMMA_MU") ]; - - fun_label = leaf_node_d[ ( lexeme_d[ "FUN" >> +digit_p ] ) ]; - - parameter = leaf_node_d[ ( lexeme_d[ "PAR" >> +digit_p ] ) | - ( lexeme_d[ "-PAR" >> +digit_p ] ) ]; - - map = leaf_node_d[ ( lexeme_d[ "MAP" >> +digit_p ] ) ]; - - function = lexeme_d[ root_node_d[ str_p("COS") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("SIN") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("TAN") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("COSH") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("SINH") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("TANH") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("ACOS") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("ASIN") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("ATAN") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("ACOSH") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("ASINH") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("ATANH") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("LOG") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("LN") ] >> ch_p('(') ] >> expression >> ch_p(')') - | lexeme_d[ root_node_d[ str_p("EXP") ] >> ch_p('(') ] >> expression >> ch_p(')') - ; - - factor = real - | const_pi - | const_gamma_mu - | parameter - | map - | function - | inner_node_d[ch_p('(') >> expression >> ch_p(')')] - ; - - term = factor >> - *( (root_node_d[ch_p('*')] >> factor) - | (root_node_d[ch_p('/')] >> factor) - ); - - expression = term >> - *( (root_node_d[ch_p('+')] >> term) - | (root_node_d[ch_p('-')] >> term) - ); - - assignment = (fun_label >> ch_p('=') >> expression); - // End grammar definition - - // turn on the debugging info. - BOOST_SPIRIT_DEBUG_RULE(real); - BOOST_SPIRIT_DEBUG_RULE(const_pi); - BOOST_SPIRIT_DEBUG_RULE(const_gamma_mu); - BOOST_SPIRIT_DEBUG_RULE(fun_label); - BOOST_SPIRIT_DEBUG_RULE(parameter); - BOOST_SPIRIT_DEBUG_RULE(map); - BOOST_SPIRIT_DEBUG_RULE(function); - BOOST_SPIRIT_DEBUG_RULE(factor); - BOOST_SPIRIT_DEBUG_RULE(term); - BOOST_SPIRIT_DEBUG_RULE(expression); - BOOST_SPIRIT_DEBUG_RULE(assignment); - } - - rule, parser_tag > assignment; - rule, parser_tag > expression; - rule, parser_tag > term; - rule, parser_tag > factor; - rule, parser_tag > function; - rule, parser_tag > map; - rule, parser_tag > parameter; - rule, parser_tag > fun_label; - rule, parser_tag > const_gamma_mu; - rule, parser_tag > const_pi; - rule, parser_tag > real; - - rule, parser_tag > const& - start() const { return assignment; } - }; -}; - -#endif // _PFUNCTIONGRAMMAR_H_ +/*************************************************************************** + + PFunctionGrammar.h + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + Header-only grammar for parsing function entries in msr-file FUNCTION blocks. + This version uses Boost.Spirit X3 in header-only mode for maximum compatibility. + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2007-2025 by Andreas Suter * + * andreas.suter@psi.ch * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _PFUNCTIONGRAMMAR_H_ +#define _PFUNCTIONGRAMMAR_H_ + +// Check Boost version - require 1.61+ for Spirit X3 +#include +#if BOOST_VERSION < 106100 +# error "Boost version 1.61.0 or higher is required for Spirit X3. Please upgrade Boost." +#endif + +#include "PFunctionAst.h" +#include + +namespace x3 = boost::spirit::x3; + +namespace musrfit { namespace grammar +{ + using x3::int_; + using x3::double_; + using x3::lit; + using x3::lexeme; + using x3::attr; + + /////////////////////////////////////////////////////////////////////////// + // Symbol tables - using inline to avoid multiple definition errors + /////////////////////////////////////////////////////////////////////////// + + struct additive_op_ : x3::symbols + { + additive_op_() + { + add("+", ast::op_plus)("-", ast::op_minus); + } + }; + + inline additive_op_ additive_op; + + struct multiplicative_op_ : x3::symbols + { + multiplicative_op_() + { + add("*", ast::op_times)("/", ast::op_divide); + } + }; + + inline multiplicative_op_ multiplicative_op; + + struct fun_tok_ : x3::symbols + { + fun_tok_() + { + add + ("COS", ast::fun_cos) + ("SIN", ast::fun_sin) + ("TAN", ast::fun_tan) + ("COSH", ast::fun_cosh) + ("SINH", ast::fun_sinh) + ("TANH", ast::fun_tanh) + ("ACOS", ast::fun_acos) + ("ASIN", ast::fun_asin) + ("ATAN", ast::fun_atan) + ("ACOSH", ast::fun_acosh) + ("ASINH", ast::fun_asinh) + ("ATANH", ast::fun_atanh) + ("LOG", ast::fun_log) + ("LN", ast::fun_ln) + ("EXP", ast::fun_exp) + ("SQRT", ast::fun_sqrt); + } + }; + + inline fun_tok_ fun_tok; + + struct const_tok_ : x3::symbols + { + const_tok_() + { + add("PI", ast::constant::pi)("GAMMA_MU", ast::constant::gamma_mu); + } + }; + + inline const_tok_ const_tok; + + /////////////////////////////////////////////////////////////////////////// + // Rules + /////////////////////////////////////////////////////////////////////////// + + x3::rule const assignment = "assignment"; + x3::rule const expression = "expression"; + x3::rule const term = "term"; + x3::rule const factor = "factor"; + x3::rule const constant = "constant"; + x3::rule const parameter = "parameter"; + x3::rule const map = "map"; + x3::rule const function = "function"; + x3::rule const power = "power"; + + /////////////////////////////////////////////////////////////////////////// + // Rule definitions + /////////////////////////////////////////////////////////////////////////// + + auto const assignment_def = + lit("FUN") >> int_ >> '=' >> expression; + + auto const expression_def = + term >> *(additive_op >> term); + + auto const term_def = + factor >> *(multiplicative_op >> factor); + + auto const factor_def = + double_ + | constant + | parameter + | map + | function + | power + | ('(' >> expression >> ')'); + + auto const constant_def = + (const_tok >> attr(false) >> attr(0)) + | (lit("B") >> attr(ast::constant::field) >> attr(false) >> attr(0)) + | (lit("-B") >> attr(ast::constant::field) >> attr(true) >> attr(0)) + | (lit("EN") >> attr(ast::constant::energy) >> attr(false) >> attr(0)) + | (lit("-EN") >> attr(ast::constant::energy) >> attr(true) >> attr(0)) + | (lit('T') >> attr(ast::constant::temp) >> attr(false) >> int_) + | (lit("-T") >> attr(ast::constant::temp) >> attr(true) >> int_); + + auto const parameter_def = + (lexeme[lit("-PAR") >> int_] >> attr(true)) + | (lit("PAR") >> int_ >> attr(false)); + + auto const map_def = + (lexeme[lit("-MAP") >> int_] >> attr(true)) + | (lit("MAP") >> int_ >> attr(false)); + + auto const function_def = + fun_tok >> '(' >> expression >> ')'; + + auto const power_def = + lit("POW") >> '(' >> expression >> ',' >> expression >> ')'; + + BOOST_SPIRIT_DEFINE( + assignment, + expression, + term, + factor, + constant, + parameter, + map, + function, + power + ) + +}} + +namespace musrfit { + // Accessor for the top-level rule + inline auto const& function_grammar() + { + return grammar::assignment; + } +} + +#endif // _PFUNCTIONGRAMMAR_H_ diff --git a/src/tests/spirit/PFunctionHandler.cpp b/src/tests/spirit/PFunctionHandler.cpp index 780372ee5..ae7199c59 100644 --- a/src/tests/spirit/PFunctionHandler.cpp +++ b/src/tests/spirit/PFunctionHandler.cpp @@ -31,9 +31,8 @@ #include #include - +#include #include -using namespace std; #include @@ -51,8 +50,8 @@ PFunctionHandler::PFunctionHandler(char *fln, bool debug) : fDebug(debug), fFile { fValid = true; - cout << endl << "in PFunctionHandler(char *fln)"; - cout << endl << "fFileName = " << fFileName; + std::cout << std::endl << "in PFunctionHandler(char *fln)"; + std::cout << std::endl << "fFileName = " << fFileName; fValid = ReadFile(); if (fValid) @@ -67,12 +66,12 @@ PFunctionHandler::PFunctionHandler(char *fln, bool debug) : fDebug(debug), fFile * * \param lines */ -PFunctionHandler::PFunctionHandler(vector lines) +PFunctionHandler::PFunctionHandler(std::vector lines) { fValid = true; fFileName = ""; - cout << endl << "in PFunctionHandler(vector lines)"; + std::cout << std::endl << "in PFunctionHandler(std::vector lines)"; if (lines.size() == 0) { fValid = false; @@ -90,43 +89,43 @@ PFunctionHandler::PFunctionHandler(vector lines) continue; boost::to_upper(lines[i]); if (lines[i].find("PAR") == 0) { - cout << endl << "this is a parameter line ..."; + std::cout << std::endl << "this is a parameter line ..."; status = sscanf(lines[i].c_str(), "PAR %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", &dval[0], &dval[1], &dval[2], &dval[3], &dval[4], &dval[5], &dval[6], &dval[7], &dval[8], &dval[9]); - cout << endl << "status=" << status; + std::cout << std::endl << "status=" << status; if (status < 0) { done = true; fValid = false; - cout << endl << "invalid PAR line, sorry ..."; + std::cout << std::endl << "invalid PAR line, sorry ..."; } else { // fill par - cout << endl << "PAR line, status = " << status; + std::cout << std::endl << "PAR line, status = " << status; for (int i=0; i lines) // check if all blocks are given if ((fMap.size() == 0) || (fParam.size() == 0) || (fLines.size() == 0)) { if (fMap.size() == 0) - cout << endl << "MAP block is missing ..."; + std::cout << std::endl << "MAP block is missing ..."; if (fParam.size() == 0) - cout << endl << "PAR block is missing ..."; + std::cout << std::endl << "PAR block is missing ..."; if (fLines.size() == 0) - cout << endl << "FUNCTION block is missing ..."; + std::cout << std::endl << "FUNCTION block is missing ..."; fValid = false; } fValid = MapsAreValid(); if (fValid) { - cout << endl << "Functions: "; + std::cout << std::endl << "Functions: "; for (unsigned int i=0; i lines) */ PFunctionHandler::~PFunctionHandler() { - cout << endl << "in ~PFunctionHandler()" << endl << endl; + std::cout << std::endl << "in ~PFunctionHandler()" << std::endl << std::endl; fParam.clear(); fMap.clear(); fLines.clear(); @@ -179,22 +178,25 @@ PFunctionHandler::~PFunctionHandler() */ bool PFunctionHandler::DoParse() { - cout << endl << "in PFunctionHandler::DoParse() ..."; + std::cout << std::endl << "in PFunctionHandler::DoParse() ..."; bool success = true; - PFunctionGrammar function; for (unsigned int i=0; i info = ast_parse(fLines[i].c_str(), function, space_p); + // Convert to uppercase (grammar expects uppercase tokens) + std::string line = fLines[i]; + std::transform(line.begin(), line.end(), line.begin(), ::toupper); - if (info.full) { - cout << endl << "parse successfull ..." << endl; - PFunction func(info, fParam, fMap, fDebug); + // Use new Qi-based PFunction constructor + PFunction func(line, fParam, fMap, fDebug); + + if (func.IsValid()) { + std::cout << std::endl << "parse successfull ..." << std::endl; fFuncs.push_back(func); } else { - cout << endl << "parse failed ... (" << i << ")" << endl; + std::cout << std::endl << "parse failed ... (" << i << ")" << std::endl; success = false; break; } @@ -205,8 +207,8 @@ bool PFunctionHandler::DoParse() if (success) { for (unsigned int i=0; i #include #include -using namespace std; #include "PFunctionGrammar.h" #include "PFunction.h" @@ -44,7 +41,7 @@ class PFunctionHandler { public: PFunctionHandler(char *fln, bool debug); - PFunctionHandler(vector lines); + PFunctionHandler(std::vector lines); virtual ~PFunctionHandler(); virtual bool IsValid() { return fValid; } @@ -57,13 +54,13 @@ class PFunctionHandler bool fDebug; bool fValid; - string fFileName; + std::string fFileName; - vector fParam; - vector fMap; - vector fLines; + std::vector fParam; + std::vector fMap; + std::vector fLines; - vector fFuncs; + std::vector fFuncs; virtual bool ReadFile(); virtual bool MapsAreValid(); diff --git a/src/tests/spirit/fcnInput.txt b/src/tests/spirit/fcnInput.txt index 34be63bcd..4d881ef46 100644 --- a/src/tests/spirit/fcnInput.txt +++ b/src/tests/spirit/fcnInput.txt @@ -17,17 +17,21 @@ PAR 1.0 2.1 3.5 -0.87 0.87 MAP 2 1 4 5 FUNCTIONS -#fun0 = cos(par1) -#fun1 = sin(par3/(par1+map2)) +fun0 = cos(par1) +fun1 = sin(par3/(par1+map2)) #fun0 = 1.2+pi #fun1 = gamma_mu -#fun2 = -par1*(sin(par2)*cos(par3)+((map1))) +fun2 = -par1*(sin(par2)*cos(par3)+((map1))) #fun1 = cos(par1) #fun0 = par1 + map3 * cos(cos(par2 - map1)) #fun8 = -par1*log(sin(par1)) + exp(-1.0*map2) #fun1 = par1 + map1 * (0.01355+par1*(2.1 - (-2.3 / 3.4))) #fun2 = par1 * par2 - map3 -fun3 = -3.2 + (par2-par1)/(map2+map3) +#fun3 = -3.2 + (par2-par1)/(map2+map3) #fun7 = 1.2 +#fun1 = sin(cos(par1))*exp(-1.0*map2)+map4*par2 +# Test unary map syntax - final test +fun3 = exp(-map2) +#fun2 = cos(-1.0*map1) + sin(-par1) END #---------------------------------------------- diff --git a/src/tests/spirit/spirit_fcn_test.cpp b/src/tests/spirit/spirit_fcn_test.cpp index 77672705c..2b7074167 100644 --- a/src/tests/spirit/spirit_fcn_test.cpp +++ b/src/tests/spirit/spirit_fcn_test.cpp @@ -2,44 +2,43 @@ #include #include -using namespace std; #include "PFunctionHandler.h" //----------------------------------------------------- void syntax() { - cout << endl << "spirit_fcn_test [--file [--debug]] | [--help]"; - cout << endl << " without arguments: interactive mode"; - cout << endl << " --file : function block etc. from file"; - cout << endl << " --help: this help"; - cout << endl << " --debug: will print the ast tree only (no evaluatio)"; - cout << endl << endl; + std::cout << std::endl << "spirit_fcn_test [--file [--debug]] | [--help]"; + std::cout << std::endl << " without arguments: interactive mode"; + std::cout << std::endl << " --file : function block etc. from file"; + std::cout << std::endl << " --help: this help"; + std::cout << std::endl << " --debug: will print the ast tree only (no evaluation)"; + std::cout << std::endl << std::endl; } //----------------------------------------------------- -void handle_input(vector &lines) +void handle_input(std::vector &lines) { - cout << endl << "will handle input ..."; - cout << endl << "you should provide a PAR, a MAP, and a FUNCTION block"; - cout << endl << " Map block:"; - cout << endl << " MAP ... "; - cout << endl << " Parameter block:"; - cout << endl << " PAR ... "; - cout << endl << " Function Block:"; - cout << endl << " FUNCTION"; - cout << endl << " fun1 = "; - cout << endl << " fun2 = "; - cout << endl << " ..."; - cout << endl << " funX = "; - cout << endl << " END"; - cout << endl << "to get out of the input handle type '.q'"; - cout << endl; + std::cout << std::endl << "will handle input ..."; + std::cout << std::endl << "you should provide a PAR, a MAP, and a FUNCTION block"; + std::cout << std::endl << " Map block:"; + std::cout << std::endl << " MAP ... "; + std::cout << std::endl << " Parameter block:"; + std::cout << std::endl << " PAR ... "; + std::cout << std::endl << " Function Block:"; + std::cout << std::endl << " FUNCTION"; + std::cout << std::endl << " fun1 = "; + std::cout << std::endl << " fun2 = "; + std::cout << std::endl << " ..."; + std::cout << std::endl << " funX = "; + std::cout << std::endl << " END"; + std::cout << std::endl << "to get out of the input handle type '.q'"; + std::cout << std::endl; bool done = false; char str[128]; do { - cout << ">> "; - cin.getline(str, sizeof(str)); + std::cout << ">> "; + std::cin.getline(str, sizeof(str)); if (!strcmp(str, ".q")) done = true; else @@ -76,39 +75,33 @@ int main(int argc, char *argv[]) } } - PFunctionHandler *fcnHandler = 0; + std::unique_ptr fcnHandler; if (inputFile) { - fcnHandler = new PFunctionHandler(argv[2], debug); + fcnHandler = std::make_unique(argv[2], debug); } else { - vector lines; + std::vector lines; handle_input(lines); - fcnHandler = new PFunctionHandler(lines); + fcnHandler = std::make_unique(lines); } if (fcnHandler == 0) { - cout << endl << "Couldn't invoke function handler, sorry ..." << endl; + std::cout << std::endl << "Couldn't invoke function handler, sorry ..." << std::endl; return 0; } bool go_on = fcnHandler->IsValid(); if (go_on) { - cout << endl << "will do the parsing ..."; + std::cout << std::endl << "will do the parsing ..."; if (fcnHandler->DoParse()) { if (!debug) { - cout << endl << "will do the evaluation ..."; + std::cout << std::endl << "will do the evaluation ..."; for (unsigned int i=0; iGetNoOfFuncs(); i++) - cout << endl << "FUN" << fcnHandler->GetFuncNo(i) << " = " << fcnHandler->Eval(fcnHandler->GetFuncNo(i)); + std::cout << std::endl << "FUN" << fcnHandler->GetFuncNo(i) << " = " << fcnHandler->Eval(fcnHandler->GetFuncNo(i)); } } } - // clean up - if (fcnHandler) { - delete fcnHandler; - fcnHandler = 0; - } - return 1; } diff --git a/src/tests/spirit/spirit_fcn_test.mak b/src/tests/spirit/spirit_fcn_test.mak deleted file mode 100644 index 1829924fb..000000000 --- a/src/tests/spirit/spirit_fcn_test.mak +++ /dev/null @@ -1,33 +0,0 @@ -#------------------------------------------------- -# spirit_fcn_test.mak -#------------------------------------------------- - -# Paths -STD_INC = "C:\Program Files\Microsoft Visual Studio 9.0\VC\include" -BOOST_INC = "D:\boost_1_43_0\boost_1_43_0" - -LIB_PATH_1 = "C:\Program Files\Microsoft Visual Studio 9.0\VC\lib" -LIB_PATH_2 = "C:\Program Files\Microsoft SDKs\Windows\v6.0a\Lib" -LIB_PATH_3 = "D:\boost_1_43_0\boost_1_43_0\bin.v2\libs" - -# Compiler etc -CC = cl -LINK32 = link - -# Options -CXXFLAGS = /c /W3 /O2 /nologo /EHsc /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /I$(STD_INC) /I$(BOOST_INC) -LINK32_FLAGS = /nologo /subsystem:console /incremental:no /machine:I386 - -fln = spirit_fcn_test - -OBJ = $(fln).obj PFunction.obj PFunctionHandler.obj - -$(fln): $(OBJ) - $(LINK32) $(LINK32_FLAGS) /LIBPATH:$(LIB_PATH_1) /LIBPATH:$(LIB_PATH_2) /LIBPATH:$(LIB_PATH_3) $(OBJ) /out:$(fln).exe - -.cpp.obj: - $(CC) $(CXXFLAGS) $< - -clean: - @del /f *.obj - diff --git a/src/tests/spirit/spirit_fcn_test.pro b/src/tests/spirit/spirit_fcn_test.pro deleted file mode 100644 index 36e1b0e4f..000000000 --- a/src/tests/spirit/spirit_fcn_test.pro +++ /dev/null @@ -1,24 +0,0 @@ -#------------------------------------------------------ -# spirit_fcn_test.pro -# qmake file for spirit_fcn_test -# -# Andreas Suter, 2007/12/10 -# -# $Id$ -# -#------------------------------------------------------ - -MAKEFILE = Makefile - -CONFIG += warn_on debug - -HEADERS = PFunctionGrammar.h \ - PFunction.h \ - PFunctionHandler.h - -SOURCES = spirit_fcn_test.cpp \ - PFunction.cpp \ - PFunctionHandler.cpp - -TARGET=spirit_fcn_test -