added doxygen docu to spirit X3 under tests.
This commit is contained in:
@@ -41,7 +41,19 @@
|
|||||||
namespace x3 = boost::spirit::x3;
|
namespace x3 = boost::spirit::x3;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// Constructor
|
/**
|
||||||
|
* @brief Constructs a PFunction by parsing the input expression.
|
||||||
|
*
|
||||||
|
* Parses the input string using the Boost.Spirit X3 grammar to extract
|
||||||
|
* the function assignment (FUN# = expression) and build the AST. The
|
||||||
|
* constructor validates the parse and stores the function number and
|
||||||
|
* expression tree for later evaluation.
|
||||||
|
*
|
||||||
|
* @param input Function assignment string (e.g., "FUN1 = PAR1 * COS(PAR2)")
|
||||||
|
* @param param Vector of parameter values for PAR# references
|
||||||
|
* @param map Vector of map indices for MAP# indirect references
|
||||||
|
* @param debug Enable debug output for parsing and evaluation
|
||||||
|
*/
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
PFunction::PFunction(const std::string& input, std::vector<double> param,
|
PFunction::PFunction(const std::string& input, std::vector<double> param,
|
||||||
std::vector<int> map, bool debug)
|
std::vector<int> map, bool debug)
|
||||||
@@ -85,7 +97,11 @@ PFunction::PFunction(const std::string& input, std::vector<double> param,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// Destructor
|
/**
|
||||||
|
* @brief Destructor - releases resources.
|
||||||
|
*
|
||||||
|
* Clears the parameter and map vectors to free memory.
|
||||||
|
*/
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
PFunction::~PFunction()
|
PFunction::~PFunction()
|
||||||
{
|
{
|
||||||
@@ -94,7 +110,15 @@ PFunction::~PFunction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// Eval
|
/**
|
||||||
|
* @brief Evaluates the parsed expression using current parameter values.
|
||||||
|
*
|
||||||
|
* Traverses the AST using the visitor pattern to compute the numeric
|
||||||
|
* result. The evaluation applies operators left-to-right with proper
|
||||||
|
* precedence as encoded in the AST structure.
|
||||||
|
*
|
||||||
|
* @return The computed value, or 0.0 if the function is invalid
|
||||||
|
*/
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
double PFunction::Eval()
|
double PFunction::Eval()
|
||||||
{
|
{
|
||||||
@@ -133,16 +157,38 @@ double PFunction::Eval()
|
|||||||
// EvalVisitor Implementation
|
// EvalVisitor Implementation
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a nil (empty) AST node.
|
||||||
|
*
|
||||||
|
* @return Always returns 0.0
|
||||||
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(const musrfit::ast::nil&) const
|
double PFunction::EvalVisitor::operator()(const musrfit::ast::nil&) const
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a numeric literal.
|
||||||
|
*
|
||||||
|
* @param val The literal value from the AST
|
||||||
|
* @return The literal value unchanged
|
||||||
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(double val) const
|
double PFunction::EvalVisitor::operator()(double val) const
|
||||||
{
|
{
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a constant (PI, GAMMA_MU, B, EN, T#).
|
||||||
|
*
|
||||||
|
* Converts symbolic constants to their numeric values. Supports:
|
||||||
|
* - PI: Mathematical constant π
|
||||||
|
* - GAMMA_MU: Muon gyromagnetic ratio
|
||||||
|
* - B, EN, T#: Not supported in test version (returns 0.0)
|
||||||
|
*
|
||||||
|
* @param c The constant AST node with type, sign, and optional index
|
||||||
|
* @return The constant's numeric value (with sign applied if negative)
|
||||||
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(const musrfit::ast::constant& c) const
|
double PFunction::EvalVisitor::operator()(const musrfit::ast::constant& c) const
|
||||||
{
|
{
|
||||||
double val = 0.0;
|
double val = 0.0;
|
||||||
@@ -171,6 +217,16 @@ double PFunction::EvalVisitor::operator()(const musrfit::ast::constant& c) const
|
|||||||
return c.sign ? -val : val;
|
return c.sign ? -val : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a parameter reference (PAR#).
|
||||||
|
*
|
||||||
|
* Looks up the parameter value from the fParam vector using the
|
||||||
|
* parameter number (1-based indexing in syntax, 0-based in vector).
|
||||||
|
* Validates bounds and applies sign.
|
||||||
|
*
|
||||||
|
* @param p The parameter AST node containing number and sign
|
||||||
|
* @return The parameter value (with sign applied), or 0.0 if out of bounds
|
||||||
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(const musrfit::ast::parameter& p) const
|
double PFunction::EvalVisitor::operator()(const musrfit::ast::parameter& p) const
|
||||||
{
|
{
|
||||||
int idx = p.number - 1;
|
int idx = p.number - 1;
|
||||||
@@ -184,6 +240,16 @@ double PFunction::EvalVisitor::operator()(const musrfit::ast::parameter& p) cons
|
|||||||
return p.sign ? -val : val;
|
return p.sign ? -val : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a map reference (MAP#) for indirect parameter lookup.
|
||||||
|
*
|
||||||
|
* Performs a two-level lookup: first looks up the map index in fMap,
|
||||||
|
* then uses that value to index into fParam. This allows for flexible
|
||||||
|
* parameter remapping. Validates both lookups and applies sign.
|
||||||
|
*
|
||||||
|
* @param m The map reference AST node containing map number and sign
|
||||||
|
* @return The indirectly referenced parameter value (with sign), or 0.0 if invalid
|
||||||
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(const musrfit::ast::map_ref& m) const
|
double PFunction::EvalVisitor::operator()(const musrfit::ast::map_ref& m) const
|
||||||
{
|
{
|
||||||
int mapIdx = m.number - 1;
|
int mapIdx = m.number - 1;
|
||||||
@@ -204,6 +270,16 @@ double PFunction::EvalVisitor::operator()(const musrfit::ast::map_ref& m) const
|
|||||||
return m.sign ? -val : val;
|
return m.sign ? -val : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a function call (COS, SIN, EXP, SQRT, etc.).
|
||||||
|
*
|
||||||
|
* Recursively evaluates the argument expression, then applies the
|
||||||
|
* specified mathematical function. Supports trigonometric, hyperbolic,
|
||||||
|
* inverse, exponential, and logarithmic functions.
|
||||||
|
*
|
||||||
|
* @param f The function call AST node with function ID and argument expression
|
||||||
|
* @return The result of applying the mathematical function to the argument
|
||||||
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(const musrfit::ast::function_call& f) const
|
double PFunction::EvalVisitor::operator()(const musrfit::ast::function_call& f) const
|
||||||
{
|
{
|
||||||
// Evaluate argument
|
// Evaluate argument
|
||||||
@@ -245,6 +321,16 @@ double PFunction::EvalVisitor::operator()(const musrfit::ast::function_call& f)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a power operation POW(base, exponent).
|
||||||
|
*
|
||||||
|
* Recursively evaluates both the base and exponent expressions,
|
||||||
|
* then computes base^exponent using std::pow. Uses absolute value
|
||||||
|
* of base to avoid complex number issues with negative bases.
|
||||||
|
*
|
||||||
|
* @param p The power call AST node with base and exponent expressions
|
||||||
|
* @return The result of raising the base to the exponent power
|
||||||
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(const musrfit::ast::power_call& p) const
|
double PFunction::EvalVisitor::operator()(const musrfit::ast::power_call& p) const
|
||||||
{
|
{
|
||||||
// Evaluate base
|
// Evaluate base
|
||||||
@@ -278,6 +364,19 @@ double PFunction::EvalVisitor::operator()(const musrfit::ast::power_call& p) con
|
|||||||
return std::pow(std::abs(base), exponent);
|
return std::pow(std::abs(base), exponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a complete expression with binary operators.
|
||||||
|
*
|
||||||
|
* Evaluates the first operand, then applies each operation in sequence
|
||||||
|
* from left to right. The AST structure encodes operator precedence,
|
||||||
|
* so this left-to-right evaluation produces correct results.
|
||||||
|
*
|
||||||
|
* Handles division by zero by checking if divisor magnitude is greater
|
||||||
|
* than 1e-20; otherwise returns 0.0 for that sub-expression.
|
||||||
|
*
|
||||||
|
* @param e The expression AST node with first operand and operation list
|
||||||
|
* @return The computed result of the expression
|
||||||
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(const musrfit::ast::expression& e) const
|
double PFunction::EvalVisitor::operator()(const musrfit::ast::expression& e) const
|
||||||
{
|
{
|
||||||
double result = boost::apply_visitor(*this, e.first);
|
double result = boost::apply_visitor(*this, e.first);
|
||||||
|
|||||||
@@ -41,47 +41,152 @@
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* \brief Test version of PFunction class - simplified without PMetaData.
|
* @brief Test version of PFunction class - simplified without PMetaData.
|
||||||
*
|
*
|
||||||
* This test version uses the same X3 grammar and AST but with a simpler
|
* This test version uses the same X3 grammar and AST but with a simpler
|
||||||
* interface for testing purposes. It does not support metadata (field,
|
* interface for testing purposes. It demonstrates the Boost.Spirit X3 parser
|
||||||
* energy, temperature).
|
* and AST-based expression evaluation without the complexity of experimental
|
||||||
|
* metadata integration.
|
||||||
|
*
|
||||||
|
* Key features:
|
||||||
|
* - Parses function assignments (FUN# = expression)
|
||||||
|
* - Supports arithmetic operators: +, -, *, /
|
||||||
|
* - Supports mathematical functions: cos, sin, tan, exp, log, sqrt, pow, etc.
|
||||||
|
* - Supports parameter references: PAR#
|
||||||
|
* - Supports map references: MAP# (indirect parameter lookup)
|
||||||
|
* - Supports constants: PI, GAMMA_MU
|
||||||
|
* - Evaluates expressions using the visitor pattern
|
||||||
|
*
|
||||||
|
* Limitations compared to production version:
|
||||||
|
* - No metadata support (field B, energy EN, temperature T#)
|
||||||
|
* - Simplified error handling
|
||||||
|
* - Test/demonstration purposes only
|
||||||
*/
|
*/
|
||||||
class PFunction {
|
class PFunction {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructs a PFunction by parsing and validating an input expression.
|
||||||
|
*
|
||||||
|
* @param input The function expression string to parse (e.g., "FUN1 = PAR1 * COS(PAR2)")
|
||||||
|
* @param param Vector of parameter values referenced by PAR# in expressions
|
||||||
|
* @param map Vector of map indices for indirect parameter references (MAP#)
|
||||||
|
* @param debug Enable debug output showing parse tree and evaluation steps
|
||||||
|
*/
|
||||||
PFunction(const std::string& input, std::vector<double> param, std::vector<int> map, bool debug = false);
|
PFunction(const std::string& input, std::vector<double> param, std::vector<int> map, bool debug = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor - cleans up parameter and map vectors.
|
||||||
|
*/
|
||||||
virtual ~PFunction();
|
virtual ~PFunction();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the function was successfully parsed and is valid.
|
||||||
|
*
|
||||||
|
* @return true if parsing succeeded and the function is ready for evaluation
|
||||||
|
*/
|
||||||
virtual bool IsValid() { return fValid; }
|
virtual bool IsValid() { return fValid; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the function number from the parsed assignment.
|
||||||
|
*
|
||||||
|
* @return The function number extracted from FUN# in the parsed expression
|
||||||
|
*/
|
||||||
virtual int GetFuncNo() { return fFuncNo; }
|
virtual int GetFuncNo() { return fFuncNo; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates the parsed expression with current parameter values.
|
||||||
|
*
|
||||||
|
* @return The numeric result of evaluating the expression, or 0.0 if invalid
|
||||||
|
*/
|
||||||
virtual double Eval();
|
virtual double Eval();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
musrfit::ast::expression fAst;
|
musrfit::ast::expression fAst; ///< Abstract syntax tree of the parsed expression
|
||||||
std::vector<double> fParam;
|
std::vector<double> fParam; ///< Parameter values for PAR# references
|
||||||
std::vector<int> fMap;
|
std::vector<int> fMap; ///< Map indices for MAP# indirect references
|
||||||
bool fValid;
|
bool fValid; ///< Validity flag indicating successful parsing
|
||||||
int fFuncNo;
|
int fFuncNo; ///< Function number extracted from FUN#
|
||||||
bool fDebug;
|
bool fDebug; ///< Debug mode flag for verbose output
|
||||||
|
|
||||||
// Simplified evaluation visitor (no metadata support)
|
/**
|
||||||
|
* @brief Visitor class for evaluating AST nodes to numeric values.
|
||||||
|
*
|
||||||
|
* Implements the visitor pattern using boost::static_visitor to traverse
|
||||||
|
* the AST and compute the result. Each operator() overload handles a
|
||||||
|
* different AST node type (literals, constants, parameters, operators, etc.).
|
||||||
|
*
|
||||||
|
* This simplified version does not support experimental metadata values.
|
||||||
|
*/
|
||||||
class EvalVisitor : public boost::static_visitor<double> {
|
class EvalVisitor : public boost::static_visitor<double> {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructs an evaluation visitor with parameter and map contexts.
|
||||||
|
*
|
||||||
|
* @param map Vector of map indices for MAP# lookups
|
||||||
|
* @param param Vector of parameter values for PAR# lookups
|
||||||
|
*/
|
||||||
EvalVisitor(const std::vector<int>& map, const std::vector<double>& param)
|
EvalVisitor(const std::vector<int>& map, const std::vector<double>& param)
|
||||||
: fMap(map), fParam(param) {}
|
: fMap(map), fParam(param) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a nil/empty AST node.
|
||||||
|
* @param AST nil node (unused)
|
||||||
|
* @return 0.0
|
||||||
|
*/
|
||||||
double operator()(const musrfit::ast::nil&) const;
|
double operator()(const musrfit::ast::nil&) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a numeric literal.
|
||||||
|
* @param val The literal value
|
||||||
|
* @return The literal value unchanged
|
||||||
|
*/
|
||||||
double operator()(double val) const;
|
double operator()(double val) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a constant (PI, GAMMA_MU, etc.).
|
||||||
|
* @param c The constant AST node
|
||||||
|
* @return The constant's numeric value with sign applied
|
||||||
|
*/
|
||||||
double operator()(const musrfit::ast::constant& c) const;
|
double operator()(const musrfit::ast::constant& c) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a parameter reference (PAR#).
|
||||||
|
* @param p The parameter AST node containing the parameter number
|
||||||
|
* @return The parameter value with sign applied
|
||||||
|
*/
|
||||||
double operator()(const musrfit::ast::parameter& p) const;
|
double operator()(const musrfit::ast::parameter& p) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a map reference (MAP#) for indirect parameter lookup.
|
||||||
|
* @param m The map reference AST node
|
||||||
|
* @return The parameter value indexed through the map with sign applied
|
||||||
|
*/
|
||||||
double operator()(const musrfit::ast::map_ref& m) const;
|
double operator()(const musrfit::ast::map_ref& m) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a function call (COS, SIN, EXP, etc.).
|
||||||
|
* @param f The function call AST node containing function ID and argument
|
||||||
|
* @return The result of applying the mathematical function
|
||||||
|
*/
|
||||||
double operator()(const musrfit::ast::function_call& f) const;
|
double operator()(const musrfit::ast::function_call& f) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a power operation POW(base, exponent).
|
||||||
|
* @param p The power call AST node with base and exponent expressions
|
||||||
|
* @return The result of base raised to the exponent power
|
||||||
|
*/
|
||||||
double operator()(const musrfit::ast::power_call& p) const;
|
double operator()(const musrfit::ast::power_call& p) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a complete expression with operators.
|
||||||
|
* @param e The expression AST node with operands and operations
|
||||||
|
* @return The result of evaluating the expression left-to-right
|
||||||
|
*/
|
||||||
double operator()(const musrfit::ast::expression& e) const;
|
double operator()(const musrfit::ast::expression& e) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<int>& fMap;
|
const std::vector<int>& fMap; ///< Reference to map vector for MAP# lookups
|
||||||
const std::vector<double>& fParam;
|
const std::vector<double>& fParam; ///< Reference to parameter vector for PAR# lookups
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2007-2025 by Andreas Suter *
|
* Copyright (C) 2007-2026 by Andreas Suter *
|
||||||
* andreas.suter@psi.ch *
|
* andreas.suter@psi.ch *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2007-2025 by Andreas Suter *
|
* Copyright (C) 2007-2026 by Andreas Suter *
|
||||||
* andreas.suter@psi.ch *
|
* andreas.suter@psi.ch *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
@@ -44,6 +44,17 @@
|
|||||||
|
|
||||||
namespace x3 = boost::spirit::x3;
|
namespace x3 = boost::spirit::x3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @namespace musrfit::grammar
|
||||||
|
* @brief Boost.Spirit X3 grammar definitions for parsing function expressions.
|
||||||
|
*
|
||||||
|
* This namespace contains the complete grammar for parsing msr-file FUNCTION
|
||||||
|
* block entries. The grammar supports arithmetic expressions with operator
|
||||||
|
* precedence, mathematical functions, constants, and parameter/map references.
|
||||||
|
*
|
||||||
|
* The grammar is header-only for maximum portability and uses X3's modern
|
||||||
|
* attribute propagation system to automatically build the AST during parsing.
|
||||||
|
*/
|
||||||
namespace musrfit { namespace grammar
|
namespace musrfit { namespace grammar
|
||||||
{
|
{
|
||||||
using x3::int_;
|
using x3::int_;
|
||||||
@@ -56,6 +67,12 @@ namespace musrfit { namespace grammar
|
|||||||
// Symbol tables - using inline to avoid multiple definition errors
|
// Symbol tables - using inline to avoid multiple definition errors
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Symbol table for additive operators (+ and -).
|
||||||
|
*
|
||||||
|
* Maps operator characters to their corresponding AST token types
|
||||||
|
* for addition and subtraction operations.
|
||||||
|
*/
|
||||||
struct additive_op_ : x3::symbols<ast::optoken>
|
struct additive_op_ : x3::symbols<ast::optoken>
|
||||||
{
|
{
|
||||||
additive_op_()
|
additive_op_()
|
||||||
@@ -64,8 +81,14 @@ namespace musrfit { namespace grammar
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline additive_op_ additive_op;
|
inline additive_op_ additive_op; ///< Global instance of additive operator symbol table
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Symbol table for multiplicative operators (* and /).
|
||||||
|
*
|
||||||
|
* Maps operator characters to their corresponding AST token types
|
||||||
|
* for multiplication and division operations.
|
||||||
|
*/
|
||||||
struct multiplicative_op_ : x3::symbols<ast::optoken>
|
struct multiplicative_op_ : x3::symbols<ast::optoken>
|
||||||
{
|
{
|
||||||
multiplicative_op_()
|
multiplicative_op_()
|
||||||
@@ -74,8 +97,15 @@ namespace musrfit { namespace grammar
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline multiplicative_op_ multiplicative_op;
|
inline multiplicative_op_ multiplicative_op; ///< Global instance of multiplicative operator symbol table
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Symbol table for mathematical function names.
|
||||||
|
*
|
||||||
|
* Maps uppercase function names (COS, SIN, EXP, etc.) to their
|
||||||
|
* corresponding AST function identifiers. Supports trigonometric,
|
||||||
|
* hyperbolic, inverse, exponential, and logarithmic functions.
|
||||||
|
*/
|
||||||
struct fun_tok_ : x3::symbols<ast::funid>
|
struct fun_tok_ : x3::symbols<ast::funid>
|
||||||
{
|
{
|
||||||
fun_tok_()
|
fun_tok_()
|
||||||
@@ -100,8 +130,14 @@ namespace musrfit { namespace grammar
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline fun_tok_ fun_tok;
|
inline fun_tok_ fun_tok; ///< Global instance of function name symbol table
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Symbol table for named constants.
|
||||||
|
*
|
||||||
|
* Maps constant names (PI, GAMMA_MU) to their corresponding
|
||||||
|
* AST constant type identifiers.
|
||||||
|
*/
|
||||||
struct const_tok_ : x3::symbols<ast::constant::type>
|
struct const_tok_ : x3::symbols<ast::constant::type>
|
||||||
{
|
{
|
||||||
const_tok_()
|
const_tok_()
|
||||||
@@ -110,35 +146,77 @@ namespace musrfit { namespace grammar
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const_tok_ const_tok;
|
inline const_tok_ const_tok; ///< Global instance of constant name symbol table
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Rules
|
// Grammar Rules - Forward Declarations
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Top-level rule: FUN# = expression
|
||||||
x3::rule<class assignment, ast::assignment> const assignment = "assignment";
|
x3::rule<class assignment, ast::assignment> const assignment = "assignment";
|
||||||
|
|
||||||
|
/// Expression with addition/subtraction (lowest precedence)
|
||||||
x3::rule<class expression, ast::expression> const expression = "expression";
|
x3::rule<class expression, ast::expression> const expression = "expression";
|
||||||
|
|
||||||
|
/// Term with multiplication/division (higher precedence)
|
||||||
x3::rule<class term, ast::expression> const term = "term";
|
x3::rule<class term, ast::expression> const term = "term";
|
||||||
|
|
||||||
|
/// Factor: literal, constant, parameter, function, or parenthesized expression (highest precedence)
|
||||||
x3::rule<class factor, ast::operand> const factor = "factor";
|
x3::rule<class factor, ast::operand> const factor = "factor";
|
||||||
|
|
||||||
|
/// Constant: PI, GAMMA_MU, B, EN, or T#
|
||||||
x3::rule<class constant, ast::constant> const constant = "constant";
|
x3::rule<class constant, ast::constant> const constant = "constant";
|
||||||
|
|
||||||
|
/// Parameter reference: PAR# or -PAR#
|
||||||
x3::rule<class parameter, ast::parameter> const parameter = "parameter";
|
x3::rule<class parameter, ast::parameter> const parameter = "parameter";
|
||||||
|
|
||||||
|
/// Map reference: MAP# or -MAP#
|
||||||
x3::rule<class map_ref, ast::map_ref> const map = "map";
|
x3::rule<class map_ref, ast::map_ref> const map = "map";
|
||||||
|
|
||||||
|
/// Function call: FUNC(expression)
|
||||||
x3::rule<class function_call, ast::function_call> const function = "function";
|
x3::rule<class function_call, ast::function_call> const function = "function";
|
||||||
|
|
||||||
|
/// Power operation: POW(base, exponent)
|
||||||
x3::rule<class power_call, ast::power_call> const power = "power";
|
x3::rule<class power_call, ast::power_call> const power = "power";
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Rule definitions
|
// Grammar Rule Definitions
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Assignment rule: FUN# = expression
|
||||||
|
*
|
||||||
|
* Parses a function assignment statement, extracting the function number
|
||||||
|
* and the expression to evaluate.
|
||||||
|
*/
|
||||||
auto const assignment_def =
|
auto const assignment_def =
|
||||||
lit("FUN") >> int_ >> '=' >> expression;
|
lit("FUN") >> int_ >> '=' >> expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Expression rule: term ((+|-) term)*
|
||||||
|
*
|
||||||
|
* Handles addition and subtraction with left-associative evaluation.
|
||||||
|
* Lower precedence than multiplication/division.
|
||||||
|
*/
|
||||||
auto const expression_def =
|
auto const expression_def =
|
||||||
term >> *(additive_op >> term);
|
term >> *(additive_op >> term);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Term rule: factor ((*|/) factor)*
|
||||||
|
*
|
||||||
|
* Handles multiplication and division with left-associative evaluation.
|
||||||
|
* Higher precedence than addition/subtraction.
|
||||||
|
*/
|
||||||
auto const term_def =
|
auto const term_def =
|
||||||
factor >> *(multiplicative_op >> factor);
|
factor >> *(multiplicative_op >> factor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Factor rule: the atomic elements of expressions.
|
||||||
|
*
|
||||||
|
* Matches numeric literals, constants, parameters, maps, function calls,
|
||||||
|
* power operations, or parenthesized sub-expressions. Parentheses allow
|
||||||
|
* overriding operator precedence.
|
||||||
|
*/
|
||||||
auto const factor_def =
|
auto const factor_def =
|
||||||
double_
|
double_
|
||||||
| constant
|
| constant
|
||||||
@@ -148,6 +226,12 @@ namespace musrfit { namespace grammar
|
|||||||
| power
|
| power
|
||||||
| ('(' >> expression >> ')');
|
| ('(' >> expression >> ')');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constant rule: PI | GAMMA_MU | B | -B | EN | -EN | T# | -T#
|
||||||
|
*
|
||||||
|
* Parses symbolic constants, optionally with negation. Temperature
|
||||||
|
* constants include an index number (T0, T1, T2, etc.).
|
||||||
|
*/
|
||||||
auto const constant_def =
|
auto const constant_def =
|
||||||
(const_tok >> attr(false) >> attr(0))
|
(const_tok >> attr(false) >> attr(0))
|
||||||
| (lit("B") >> attr(ast::constant::field) >> attr(false) >> attr(0))
|
| (lit("B") >> attr(ast::constant::field) >> attr(false) >> attr(0))
|
||||||
@@ -157,20 +241,51 @@ namespace musrfit { namespace grammar
|
|||||||
| (lit('T') >> attr(ast::constant::temp) >> attr(false) >> int_)
|
| (lit('T') >> attr(ast::constant::temp) >> attr(false) >> int_)
|
||||||
| (lit("-T") >> attr(ast::constant::temp) >> attr(true) >> int_);
|
| (lit("-T") >> attr(ast::constant::temp) >> attr(true) >> int_);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parameter rule: PAR# | -PAR#
|
||||||
|
*
|
||||||
|
* Parses parameter references with 1-based indexing. The lexeme directive
|
||||||
|
* for -PAR# ensures the minus sign is treated as part of the token,
|
||||||
|
* not as a separate operator.
|
||||||
|
*/
|
||||||
auto const parameter_def =
|
auto const parameter_def =
|
||||||
(lexeme[lit("-PAR") >> int_] >> attr(true))
|
(lexeme[lit("-PAR") >> int_] >> attr(true))
|
||||||
| (lit("PAR") >> int_ >> attr(false));
|
| (lit("PAR") >> int_ >> attr(false));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Map rule: MAP# | -MAP#
|
||||||
|
*
|
||||||
|
* Parses map references for indirect parameter lookup with 1-based indexing.
|
||||||
|
* The lexeme directive for -MAP# ensures the minus sign is part of the token.
|
||||||
|
*/
|
||||||
auto const map_def =
|
auto const map_def =
|
||||||
(lexeme[lit("-MAP") >> int_] >> attr(true))
|
(lexeme[lit("-MAP") >> int_] >> attr(true))
|
||||||
| (lit("MAP") >> int_ >> attr(false));
|
| (lit("MAP") >> int_ >> attr(false));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function rule: FUNC(expression)
|
||||||
|
*
|
||||||
|
* Parses mathematical function calls. The function name is matched by
|
||||||
|
* fun_tok and the argument is a full expression.
|
||||||
|
*/
|
||||||
auto const function_def =
|
auto const function_def =
|
||||||
fun_tok >> '(' >> expression >> ')';
|
fun_tok >> '(' >> expression >> ')';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Power rule: POW(base, exponent)
|
||||||
|
*
|
||||||
|
* Parses power operations with two expression arguments separated by comma.
|
||||||
|
* Both base and exponent can be arbitrary expressions.
|
||||||
|
*/
|
||||||
auto const power_def =
|
auto const power_def =
|
||||||
lit("POW") >> '(' >> expression >> ',' >> expression >> ')';
|
lit("POW") >> '(' >> expression >> ',' >> expression >> ')';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Links rule names to their definitions.
|
||||||
|
*
|
||||||
|
* Required by Boost.Spirit X3 to connect the forward-declared rules
|
||||||
|
* with their actual parsing logic.
|
||||||
|
*/
|
||||||
BOOST_SPIRIT_DEFINE(
|
BOOST_SPIRIT_DEFINE(
|
||||||
assignment,
|
assignment,
|
||||||
expression,
|
expression,
|
||||||
@@ -185,8 +300,25 @@ namespace musrfit { namespace grammar
|
|||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @namespace musrfit
|
||||||
|
* @brief Top-level namespace for musrfit components.
|
||||||
|
*/
|
||||||
namespace musrfit {
|
namespace musrfit {
|
||||||
// Accessor for the top-level rule
|
/**
|
||||||
|
* @brief Provides access to the top-level grammar rule.
|
||||||
|
*
|
||||||
|
* Returns a reference to the assignment rule, which is the entry point
|
||||||
|
* for parsing complete function assignment statements (FUN# = expression).
|
||||||
|
* Use this function to obtain the grammar for parsing with Spirit X3.
|
||||||
|
*
|
||||||
|
* @return Constant reference to the assignment grammar rule
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* auto const& grammar = musrfit::function_grammar();
|
||||||
|
* bool success = x3::phrase_parse(iter, end, grammar, x3::space, result);
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
inline auto const& function_grammar()
|
inline auto const& function_grammar()
|
||||||
{
|
{
|
||||||
return grammar::assignment;
|
return grammar::assignment;
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
Author: Andreas Suter
|
Author: Andreas Suter
|
||||||
e-mail: andreas.suter@psi.ch
|
e-mail: andreas.suter@psi.ch
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2007 by Andreas Suter *
|
* Copyright (C) 2007-2026 by Andreas Suter *
|
||||||
* andreas.suter@psi.c *
|
* andreas.suter@psi.c *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
@@ -38,14 +36,19 @@
|
|||||||
|
|
||||||
#include "PFunctionHandler.h"
|
#include "PFunctionHandler.h"
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// Constructor
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Constructs a PFunctionHandler from a file.
|
||||||
*
|
*
|
||||||
* \param fln
|
* Reads the specified file to extract parameter values (PAR block),
|
||||||
|
* map indices (MAP block), and function definitions (FUNCTIONS block).
|
||||||
|
* Validates that all required blocks are present and that map indices
|
||||||
|
* are within parameter bounds.
|
||||||
|
*
|
||||||
|
* @param fln Filename containing the function definitions
|
||||||
|
* @param debug Enable debug output showing parsing details
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
PFunctionHandler::PFunctionHandler(char *fln, bool debug) : fDebug(debug), fFileName(fln)
|
PFunctionHandler::PFunctionHandler(char *fln, bool debug) : fDebug(debug), fFileName(fln)
|
||||||
{
|
{
|
||||||
fValid = true;
|
fValid = true;
|
||||||
@@ -58,14 +61,18 @@ PFunctionHandler::PFunctionHandler(char *fln, bool debug) : fDebug(debug), fFile
|
|||||||
fValid = MapsAreValid();
|
fValid = MapsAreValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// Constructor
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Constructs a PFunctionHandler from a vector of input lines.
|
||||||
*
|
*
|
||||||
* \param lines
|
* Parses the provided lines to extract PAR, MAP, and FUNCTIONS blocks.
|
||||||
|
* This constructor is useful for testing or when input comes from
|
||||||
|
* sources other than files. Validates that all required blocks are
|
||||||
|
* present and that map indices are within parameter bounds.
|
||||||
|
*
|
||||||
|
* @param lines Vector of strings containing the input (PAR, MAP, FUNCTIONS blocks)
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
PFunctionHandler::PFunctionHandler(std::vector<std::string> lines)
|
PFunctionHandler::PFunctionHandler(std::vector<std::string> lines)
|
||||||
{
|
{
|
||||||
fValid = true;
|
fValid = true;
|
||||||
@@ -152,13 +159,13 @@ PFunctionHandler::PFunctionHandler(std::vector<std::string> lines)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// Destructor
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Destructor - releases all resources.
|
||||||
*
|
*
|
||||||
|
* Clears parameter, map, line, and function vectors to free memory.
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
PFunctionHandler::~PFunctionHandler()
|
PFunctionHandler::~PFunctionHandler()
|
||||||
{
|
{
|
||||||
std::cout << std::endl << "in ~PFunctionHandler()" << std::endl << std::endl;
|
std::cout << std::endl << "in ~PFunctionHandler()" << std::endl << std::endl;
|
||||||
@@ -169,13 +176,19 @@ PFunctionHandler::~PFunctionHandler()
|
|||||||
fFuncs.clear();
|
fFuncs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// DoParse (public)
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Parses all function definitions using the X3 grammar.
|
||||||
*
|
*
|
||||||
|
* Iterates through all function lines, parsing each with the Spirit X3
|
||||||
|
* grammar to create PFunction objects. Performs validation checks:
|
||||||
|
* - All functions parse successfully
|
||||||
|
* - Parameter and map indices are within bounds
|
||||||
|
* - Function numbers are unique (no duplicates)
|
||||||
|
*
|
||||||
|
* @return true if all functions parsed and validated successfully
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
bool PFunctionHandler::DoParse()
|
bool PFunctionHandler::DoParse()
|
||||||
{
|
{
|
||||||
std::cout << std::endl << "in PFunctionHandler::DoParse() ...";
|
std::cout << std::endl << "in PFunctionHandler::DoParse() ...";
|
||||||
@@ -236,14 +249,17 @@ bool PFunctionHandler::DoParse()
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// Eval (public)
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Evaluates a function by its function number.
|
||||||
*
|
*
|
||||||
* \param i
|
* Looks up the function in the internal vector using its function number
|
||||||
|
* (from the FUN# declaration) and evaluates it with current parameter values.
|
||||||
|
*
|
||||||
|
* @param i Function number to evaluate
|
||||||
|
* @return The evaluation result, or 0.0 if function not found
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
double PFunctionHandler::Eval(int i)
|
double PFunctionHandler::Eval(int i)
|
||||||
{
|
{
|
||||||
if (GetFuncIndex(i) == -1) {
|
if (GetFuncIndex(i) == -1) {
|
||||||
@@ -254,14 +270,14 @@ double PFunctionHandler::Eval(int i)
|
|||||||
return fFuncs[GetFuncIndex(i)].Eval();
|
return fFuncs[GetFuncIndex(i)].Eval();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// GetFuncNo (public)
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Gets the function number of the i-th parsed function.
|
||||||
*
|
*
|
||||||
* \param i
|
* @param i Index into the internal function vector (0-based)
|
||||||
|
* @return The function number (from FUN#), or -1 if index out of bounds
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
unsigned int PFunctionHandler::GetFuncNo(unsigned int i)
|
unsigned int PFunctionHandler::GetFuncNo(unsigned int i)
|
||||||
{
|
{
|
||||||
if (i > fFuncs.size())
|
if (i > fFuncs.size())
|
||||||
@@ -270,13 +286,22 @@ unsigned int PFunctionHandler::GetFuncNo(unsigned int i)
|
|||||||
return fFuncs[i].GetFuncNo();
|
return fFuncs[i].GetFuncNo();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// ReadFile (private)
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Reads and parses the input file.
|
||||||
*
|
*
|
||||||
|
* Opens the file specified in fFileName and extracts:
|
||||||
|
* - PAR block: parameter values (up to 10 per line)
|
||||||
|
* - MAP block: map indices (up to 10 per line)
|
||||||
|
* - FUNCTIONS block: function definition lines
|
||||||
|
*
|
||||||
|
* Lines starting with # are treated as comments and ignored.
|
||||||
|
* Processing stops when END tag is encountered.
|
||||||
|
* Converts all input to uppercase for case-insensitive parsing.
|
||||||
|
*
|
||||||
|
* @return true if file was successfully read and all required blocks found
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
bool PFunctionHandler::ReadFile()
|
bool PFunctionHandler::ReadFile()
|
||||||
{
|
{
|
||||||
std::cout << std::endl << "in ~PFunctionHandler::ReadFile()";
|
std::cout << std::endl << "in ~PFunctionHandler::ReadFile()";
|
||||||
@@ -377,13 +402,17 @@ bool PFunctionHandler::ReadFile()
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// MapsAreValid (private)
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Validates that all map indices are within parameter bounds.
|
||||||
*
|
*
|
||||||
|
* Checks that each value in the MAP block is a valid parameter index.
|
||||||
|
* Map values use 1-based indexing, so valid values are 1 to fParam.size().
|
||||||
|
* This validation prevents out-of-bounds access during function evaluation.
|
||||||
|
*
|
||||||
|
* @return true if all map indices are valid, false otherwise
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
bool PFunctionHandler::MapsAreValid()
|
bool PFunctionHandler::MapsAreValid()
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
@@ -399,14 +428,18 @@ bool PFunctionHandler::MapsAreValid()
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// GetFuncIndex (private)
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>
|
* @brief Finds the internal vector index for a function by its number.
|
||||||
*
|
*
|
||||||
* \param funcNo
|
* Searches the fFuncs vector for a function with the specified function
|
||||||
|
* number. This maps from the user-visible function number (FUN#) to the
|
||||||
|
* internal 0-based vector index.
|
||||||
|
*
|
||||||
|
* @param funcNo Function number to search for (from FUN# declaration)
|
||||||
|
* @return Index in fFuncs vector (0-based), or -1 if not found
|
||||||
*/
|
*/
|
||||||
|
//-------------------------------------------------------------
|
||||||
int PFunctionHandler::GetFuncIndex(int funcNo)
|
int PFunctionHandler::GetFuncIndex(int funcNo)
|
||||||
{
|
{
|
||||||
int index = -1;
|
int index = -1;
|
||||||
|
|||||||
@@ -37,33 +37,137 @@
|
|||||||
#include "PFunctionGrammar.h"
|
#include "PFunctionGrammar.h"
|
||||||
#include "PFunction.h"
|
#include "PFunction.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Manages parsing and evaluation of multiple function definitions.
|
||||||
|
*
|
||||||
|
* This class handles the complete workflow for processing function blocks
|
||||||
|
* from msr files or direct input. It:
|
||||||
|
* - Reads function definitions from file or vector of strings
|
||||||
|
* - Parses parameter (PAR) and map (MAP) blocks
|
||||||
|
* - Validates map indices against parameter bounds
|
||||||
|
* - Creates PFunction objects for each function definition
|
||||||
|
* - Provides evaluation interface for functions by number
|
||||||
|
*
|
||||||
|
* Input format:
|
||||||
|
* @code
|
||||||
|
* PAR <par1> <par2> ... <parN>
|
||||||
|
* MAP <map1> <map2> ... <mapM>
|
||||||
|
* FUNCTIONS
|
||||||
|
* FUN1 = expression1
|
||||||
|
* FUN2 = expression2
|
||||||
|
* ...
|
||||||
|
* END
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
class PFunctionHandler
|
class PFunctionHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructs handler by reading function definitions from a file.
|
||||||
|
*
|
||||||
|
* @param fln Filename containing PAR, MAP, and FUNCTIONS blocks
|
||||||
|
* @param debug Enable debug output during parsing and evaluation
|
||||||
|
*/
|
||||||
PFunctionHandler(char *fln, bool debug);
|
PFunctionHandler(char *fln, bool debug);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructs handler from a vector of input lines.
|
||||||
|
*
|
||||||
|
* Useful for testing or when input comes from sources other than files.
|
||||||
|
*
|
||||||
|
* @param lines Vector of strings containing PAR, MAP, and FUNCTIONS blocks
|
||||||
|
*/
|
||||||
PFunctionHandler(std::vector<std::string> lines);
|
PFunctionHandler(std::vector<std::string> lines);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor - cleans up resources.
|
||||||
|
*/
|
||||||
virtual ~PFunctionHandler();
|
virtual ~PFunctionHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if initialization was successful.
|
||||||
|
*
|
||||||
|
* Returns false if file reading failed, required blocks are missing,
|
||||||
|
* or map validation failed.
|
||||||
|
*
|
||||||
|
* @return true if the handler is ready to parse and evaluate functions
|
||||||
|
*/
|
||||||
virtual bool IsValid() { return fValid; }
|
virtual bool IsValid() { return fValid; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parses all function definitions and validates them.
|
||||||
|
*
|
||||||
|
* Creates PFunction objects for each function line, validates that
|
||||||
|
* all functions parsed successfully, and ensures function numbers
|
||||||
|
* are unique.
|
||||||
|
*
|
||||||
|
* @return true if all functions parsed successfully and are valid
|
||||||
|
*/
|
||||||
virtual bool DoParse();
|
virtual bool DoParse();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates a function by its function number.
|
||||||
|
*
|
||||||
|
* @param i Function number (from FUN# in the definition)
|
||||||
|
* @return The evaluated result, or 0.0 if function not found
|
||||||
|
*/
|
||||||
virtual double Eval(int i);
|
virtual double Eval(int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the function number of the i-th parsed function.
|
||||||
|
*
|
||||||
|
* @param i Index into the internal function vector (0-based)
|
||||||
|
* @return The function number, or -1 if index out of bounds
|
||||||
|
*/
|
||||||
virtual unsigned int GetFuncNo(unsigned int i);
|
virtual unsigned int GetFuncNo(unsigned int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the total number of successfully parsed functions.
|
||||||
|
*
|
||||||
|
* @return Number of functions in the handler
|
||||||
|
*/
|
||||||
virtual unsigned int GetNoOfFuncs() { return fFuncs.size(); }
|
virtual unsigned int GetNoOfFuncs() { return fFuncs.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fDebug;
|
bool fDebug; ///< Debug mode flag for verbose output
|
||||||
bool fValid;
|
bool fValid; ///< Validity flag indicating successful initialization
|
||||||
|
|
||||||
std::string fFileName;
|
std::string fFileName; ///< Input filename (empty if constructed from lines)
|
||||||
|
|
||||||
std::vector<double> fParam;
|
std::vector<double> fParam; ///< Parameter values from PAR block
|
||||||
std::vector<int> fMap;
|
std::vector<int> fMap; ///< Map indices from MAP block
|
||||||
std::vector<std::string> fLines;
|
std::vector<std::string> fLines; ///< Function definition lines from FUNCTIONS block
|
||||||
|
|
||||||
std::vector<PFunction> fFuncs;
|
std::vector<PFunction> fFuncs; ///< Parsed function objects
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads and parses the input file.
|
||||||
|
*
|
||||||
|
* Extracts PAR, MAP, and FUNCTIONS blocks from the file. Lines starting
|
||||||
|
* with # are treated as comments. Processing stops at END tag.
|
||||||
|
*
|
||||||
|
* @return true if file was read and all required blocks found
|
||||||
|
*/
|
||||||
virtual bool ReadFile();
|
virtual bool ReadFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates that all map indices are within parameter bounds.
|
||||||
|
*
|
||||||
|
* Ensures each MAP# value is a valid parameter index (1-based),
|
||||||
|
* preventing out-of-bounds access during evaluation.
|
||||||
|
*
|
||||||
|
* @return true if all map indices are valid
|
||||||
|
*/
|
||||||
virtual bool MapsAreValid();
|
virtual bool MapsAreValid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finds the internal index for a function by its function number.
|
||||||
|
*
|
||||||
|
* Maps from function number (FUN#) to the 0-based index in fFuncs vector.
|
||||||
|
*
|
||||||
|
* @param funcNo Function number to search for
|
||||||
|
* @return Index in fFuncs vector, or -1 if not found
|
||||||
|
*/
|
||||||
virtual int GetFuncIndex(int funcNo);
|
virtual int GetFuncIndex(int funcNo);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,50 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
spirit_fcn_test.cpp
|
||||||
|
|
||||||
|
Author: Andreas Suter
|
||||||
|
e-mail: andreas.suter@psi.ch
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2007-2026 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file spirit_fcn_test.cpp
|
||||||
|
* @brief Test program for the Boost.Spirit X3 function parser.
|
||||||
|
*
|
||||||
|
* This program demonstrates and tests the Spirit X3-based parser for
|
||||||
|
* mathematical function expressions used in musrfit. It supports both
|
||||||
|
* interactive mode and file-based input.
|
||||||
|
*
|
||||||
|
* Features:
|
||||||
|
* - Parses PAR (parameter), MAP, and FUNCTIONS blocks
|
||||||
|
* - Evaluates mathematical expressions with operators and functions
|
||||||
|
* - Supports debug mode to inspect AST without evaluation
|
||||||
|
* - Interactive input mode for testing expressions
|
||||||
|
*
|
||||||
|
* @author Andreas Suter
|
||||||
|
* @date 2025
|
||||||
|
*/
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -6,6 +53,12 @@
|
|||||||
#include "PFunctionHandler.h"
|
#include "PFunctionHandler.h"
|
||||||
|
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @brief Displays command-line usage information.
|
||||||
|
*
|
||||||
|
* Prints help text showing available command-line options and
|
||||||
|
* their descriptions.
|
||||||
|
*/
|
||||||
void syntax()
|
void syntax()
|
||||||
{
|
{
|
||||||
std::cout << std::endl << "spirit_fcn_test [--file <filename> [--debug]] | [--help]";
|
std::cout << std::endl << "spirit_fcn_test [--file <filename> [--debug]] | [--help]";
|
||||||
@@ -17,6 +70,23 @@ void syntax()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @brief Handles interactive input from the user.
|
||||||
|
*
|
||||||
|
* Prompts the user to enter PAR, MAP, and FUNCTIONS blocks line by line.
|
||||||
|
* Input continues until the user types ".q" to quit. This mode is useful
|
||||||
|
* for quick testing without creating input files.
|
||||||
|
*
|
||||||
|
* Expected input format:
|
||||||
|
* - PAR <par1> <par2> ... <parN>
|
||||||
|
* - MAP <map1> <map2> ... <mapM>
|
||||||
|
* - FUNCTIONS
|
||||||
|
* - FUN# = <expression>
|
||||||
|
* - ...
|
||||||
|
* - END
|
||||||
|
*
|
||||||
|
* @param lines Reference to vector where input lines will be stored
|
||||||
|
*/
|
||||||
void handle_input(std::vector<std::string> &lines)
|
void handle_input(std::vector<std::string> &lines)
|
||||||
{
|
{
|
||||||
std::cout << std::endl << "will handle input ...";
|
std::cout << std::endl << "will handle input ...";
|
||||||
@@ -46,6 +116,26 @@ void handle_input(std::vector<std::string> &lines)
|
|||||||
} while (!done);
|
} while (!done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------
|
||||||
|
/**
|
||||||
|
* @brief Main entry point for the spirit_fcn_test program.
|
||||||
|
*
|
||||||
|
* Parses command-line arguments to determine operating mode:
|
||||||
|
* - No arguments: Interactive mode (prompts user for input)
|
||||||
|
* - --file <filename>: Reads input from specified file
|
||||||
|
* - --debug: Enables debug output (AST inspection without evaluation)
|
||||||
|
* - --help: Shows usage information
|
||||||
|
*
|
||||||
|
* Workflow:
|
||||||
|
* 1. Parse command-line arguments
|
||||||
|
* 2. Create PFunctionHandler from file or interactive input
|
||||||
|
* 3. Parse all function definitions
|
||||||
|
* 4. If not in debug mode, evaluate all functions and display results
|
||||||
|
*
|
||||||
|
* @param argc Argument count
|
||||||
|
* @param argv Argument vector
|
||||||
|
* @return 1 on success, 0 on error or help display
|
||||||
|
*/
|
||||||
//-----------------------------------------------------
|
//-----------------------------------------------------
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user