Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ce1bc1583b | |||
| 4adf66cb26 | |||
| 8a86351674 | |||
| 418ca6b0a1 | |||
| 73aff4ec69 | |||
| 7ce0926fd9 |
@@ -232,13 +232,16 @@ install(
|
|||||||
|
|
||||||
#--- install headers ----------------------------------------------------------
|
#--- install headers ----------------------------------------------------------
|
||||||
install(
|
install(
|
||||||
FILES ${MUSRFIT_INC}/PFitterFcn.h
|
FILES ${MUSRFIT_INC}/PFindRun.h
|
||||||
|
${MUSRFIT_INC}/PFitterFcn.h
|
||||||
${MUSRFIT_INC}/PFitter.h
|
${MUSRFIT_INC}/PFitter.h
|
||||||
${MUSRFIT_INC}/PFourierCanvas.h
|
${MUSRFIT_INC}/PFourierCanvas.h
|
||||||
${MUSRFIT_INC}/PFourier.h
|
${MUSRFIT_INC}/PFourier.h
|
||||||
|
${MUSRFIT_INC}/PFunctionAst.h
|
||||||
${MUSRFIT_INC}/PFunctionGrammar.h
|
${MUSRFIT_INC}/PFunctionGrammar.h
|
||||||
${MUSRFIT_INC}/PFunction.h
|
${MUSRFIT_INC}/PFunction.h
|
||||||
${MUSRFIT_INC}/PFunctionHandler.h
|
${MUSRFIT_INC}/PFunctionHandler.h
|
||||||
|
${MUSRFIT_INC}/PMsgBox.h
|
||||||
${MUSRFIT_INC}/PMsr2Data.h
|
${MUSRFIT_INC}/PMsr2Data.h
|
||||||
${MUSRFIT_INC}/PMsrHandler.h
|
${MUSRFIT_INC}/PMsrHandler.h
|
||||||
${MUSRFIT_INC}/PMusrCanvas.h
|
${MUSRFIT_INC}/PMusrCanvas.h
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -30,8 +30,12 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <boost/spirit/home/x3.hpp>
|
||||||
|
|
||||||
#include "PFunctionHandler.h"
|
#include "PFunctionHandler.h"
|
||||||
|
|
||||||
|
namespace x3 = boost::spirit::x3;
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
// Constructor
|
// Constructor
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
@@ -67,7 +71,6 @@ PFunctionHandler::~PFunctionHandler()
|
|||||||
Bool_t PFunctionHandler::DoParse()
|
Bool_t PFunctionHandler::DoParse()
|
||||||
{
|
{
|
||||||
Bool_t success = true;
|
Bool_t success = true;
|
||||||
PFunctionGrammar function;
|
|
||||||
TString line;
|
TString line;
|
||||||
|
|
||||||
// feed the function block into the parser. Start with i=1, since i=0 is FUNCTIONS
|
// feed the function block into the parser. Start with i=1, since i=0 is FUNCTIONS
|
||||||
@@ -89,14 +92,32 @@ Bool_t PFunctionHandler::DoParse()
|
|||||||
}
|
}
|
||||||
line.ToUpper();
|
line.ToUpper();
|
||||||
|
|
||||||
// do parsing
|
// do parsing with X3
|
||||||
tree_parse_info<> info = ast_parse(line.Data(), function, space_p);
|
musrfit::ast::assignment assignment;
|
||||||
|
std::string str(line.Data());
|
||||||
|
auto iter = str.begin();
|
||||||
|
auto end = str.end();
|
||||||
|
|
||||||
if (info.full) { // parsing successful
|
// Get the X3 grammar
|
||||||
PFunction func(info); // generate an evaluation function object based on the AST tree
|
auto const& grammar = musrfit::function_grammar();
|
||||||
fFuncs.push_back(func); // feeds it to the functions vector
|
|
||||||
} else {
|
try {
|
||||||
|
bool parseSuccess = x3::phrase_parse(iter, end, grammar, x3::space, assignment);
|
||||||
|
|
||||||
|
if (parseSuccess && iter == end) { // parsing successful
|
||||||
|
PFunction func(assignment); // generate an evaluation function object based on the AST
|
||||||
|
fFuncs.push_back(func); // feeds it to the functions vector
|
||||||
|
} else {
|
||||||
|
std::cerr << std::endl << "**ERROR**: FUNCTIONS parse failed in line " << fLines[i].fLineNo << std::endl;
|
||||||
|
if (iter != end) {
|
||||||
|
std::cerr << "**ERROR**: Stopped at: " << std::string(iter, end) << std::endl;
|
||||||
|
}
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (x3::expectation_failure<std::string::iterator> const& e) {
|
||||||
std::cerr << std::endl << "**ERROR**: FUNCTIONS parse failed in line " << fLines[i].fLineNo << std::endl;
|
std::cerr << std::endl << "**ERROR**: FUNCTIONS parse failed in line " << fLines[i].fLineNo << std::endl;
|
||||||
|
std::cerr << "**ERROR**: Expected: " << e.which() << std::endl;
|
||||||
success = false;
|
success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,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 *
|
||||||
@@ -33,85 +33,23 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/version.hpp>
|
#include <boost/version.hpp>
|
||||||
|
#include <boost/variant/static_visitor.hpp>
|
||||||
#if BOOST_VERSION >= 103800
|
#include <boost/variant/apply_visitor.hpp>
|
||||||
# include <boost/spirit/include/classic_ast.hpp>
|
|
||||||
using namespace BOOST_SPIRIT_CLASSIC_NS;
|
|
||||||
#else
|
|
||||||
# include <boost/spirit/tree/ast.hpp>
|
|
||||||
using namespace boost::spirit;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <TString.h>
|
#include <TString.h>
|
||||||
|
|
||||||
#include "PMusr.h"
|
#include "PMusr.h"
|
||||||
|
#include "PFunctionAst.h"
|
||||||
#include "PFunctionGrammar.h"
|
#include "PFunctionGrammar.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
// Operator tags for arithmetic operations
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
#define OP_ADD 0 ///< Addition operator tag
|
|
||||||
#define OP_SUB 1 ///< Subtraction operator tag
|
|
||||||
#define OP_MUL 2 ///< Multiplication operator tag
|
|
||||||
#define OP_DIV 3 ///< Division operator tag
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
// Function tags for mathematical functions
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
#define FUN_COS 0 ///< Cosine function tag
|
|
||||||
#define FUN_SIN 1 ///< Sine function tag
|
|
||||||
#define FUN_TAN 2 ///< Tangent function tag
|
|
||||||
#define FUN_COSH 3 ///< Hyperbolic cosine function tag
|
|
||||||
#define FUN_SINH 4 ///< Hyperbolic sine function tag
|
|
||||||
#define FUN_TANH 5 ///< Hyperbolic tangent function tag
|
|
||||||
#define FUN_ACOS 6 ///< Inverse cosine (arccos) function tag
|
|
||||||
#define FUN_ASIN 7 ///< Inverse sine (arcsin) function tag
|
|
||||||
#define FUN_ATAN 8 ///< Inverse tangent (arctan) function tag
|
|
||||||
#define FUN_ACOSH 9 ///< Inverse hyperbolic cosine function tag
|
|
||||||
#define FUN_ASINH 10 ///< Inverse hyperbolic sine function tag
|
|
||||||
#define FUN_ATANH 11 ///< Inverse hyperbolic tangent function tag
|
|
||||||
#define FUN_LOG 12 ///< Base-10 logarithm function tag
|
|
||||||
#define FUN_LN 13 ///< Natural logarithm function tag
|
|
||||||
#define FUN_EXP 14 ///< Exponential function tag
|
|
||||||
#define FUN_SQRT 15 ///< Square root function tag
|
|
||||||
#define FUN_POW 16 ///< Power function tag (base^exponent)
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* \brief Tree node structure for efficient function evaluation.
|
|
||||||
*
|
|
||||||
* This structure represents a node in the evaluation tree used to compute
|
|
||||||
* function values. The abstract syntax tree (AST) generated by the parser
|
|
||||||
* is converted into this more efficient tree structure for faster evaluation.
|
|
||||||
*
|
|
||||||
* Each node can represent:
|
|
||||||
* - A leaf node (constant, parameter, map reference)
|
|
||||||
* - An operator node (arithmetic operation)
|
|
||||||
* - A function node (mathematical function)
|
|
||||||
*
|
|
||||||
* The tree is evaluated recursively by traversing from the root to the leaves.
|
|
||||||
*
|
|
||||||
* \see PFunction::EvalNode for the recursive evaluation algorithm
|
|
||||||
*/
|
|
||||||
typedef struct func_tree_node {
|
|
||||||
Int_t fID; ///< Node type identifier (from PFunctionGrammar constants)
|
|
||||||
Int_t fOperatorTag; ///< Operator type: OP_ADD, OP_SUB, OP_MUL, OP_DIV
|
|
||||||
Int_t fFunctionTag; ///< Function type: FUN_COS, FUN_SIN, FUN_EXP, etc.
|
|
||||||
Int_t fIvalue; ///< Integer value for parameter numbers, map indices, or temperature indices
|
|
||||||
Bool_t fSign; ///< Sign flag: true for negative, false for positive
|
|
||||||
Double_t fDvalue; ///< Numeric value for constants and real number literals
|
|
||||||
std::vector<func_tree_node> children; ///< Child nodes forming the sub-tree
|
|
||||||
} PFuncTreeNode;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* \brief Class for parsing and evaluating mathematical functions from msr-file FUNCTIONS blocks.
|
* \brief Class for parsing and evaluating mathematical functions from msr-file FUNCTIONS blocks.
|
||||||
*
|
*
|
||||||
* This class handles the complete lifecycle of a function definition:
|
* This class handles the complete lifecycle of a function definition:
|
||||||
* 1. Parses the function string using PFunctionGrammar into an AST
|
* 1. Parses the function string using PFunctionGrammar into an AST
|
||||||
* 2. Converts the AST into an efficient evaluation tree
|
* 2. Validates parameter and map references
|
||||||
* 3. Validates parameter and map references
|
* 3. Evaluates the function with given parameters and metadata using the visitor pattern
|
||||||
* 4. Evaluates the function with given parameters and metadata
|
|
||||||
*
|
*
|
||||||
* Functions can reference:
|
* Functions can reference:
|
||||||
* - Fit parameters (PAR1, PAR2, ...)
|
* - Fit parameters (PAR1, PAR2, ...)
|
||||||
@@ -126,7 +64,7 @@ typedef struct func_tree_node {
|
|||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
* \see PFunctionGrammar for the grammar definition
|
* \see PFunctionGrammar for the grammar definition
|
||||||
* \see PFuncTreeNode for the evaluation tree structure
|
* \see musrfit::ast for the AST structure
|
||||||
*/
|
*/
|
||||||
class PFunction {
|
class PFunction {
|
||||||
public:
|
public:
|
||||||
@@ -134,13 +72,13 @@ class PFunction {
|
|||||||
/**
|
/**
|
||||||
* \brief Constructor that parses and prepares a function for evaluation.
|
* \brief Constructor that parses and prepares a function for evaluation.
|
||||||
*
|
*
|
||||||
* \param info Abstract syntax tree (AST) from parsing a function expression
|
* \param assignment Abstract syntax tree (AST) from parsing a function expression
|
||||||
*/
|
*/
|
||||||
PFunction(tree_parse_info<> info);
|
PFunction(const musrfit::ast::assignment& assignment);
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* \brief Destructor that cleans up the evaluation tree.
|
* \brief Destructor that cleans up resources.
|
||||||
*/
|
*/
|
||||||
virtual ~PFunction();
|
virtual ~PFunction();
|
||||||
|
|
||||||
@@ -202,101 +140,72 @@ class PFunction {
|
|||||||
protected:
|
protected:
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* \brief Initializes all fields of an evaluation tree node to default values.
|
* \brief Recursively validates parameter and map references in the AST.
|
||||||
*
|
*
|
||||||
* \param node Node to initialize
|
* \param operand Current operand being checked
|
||||||
*/
|
|
||||||
virtual void InitNode(PFuncTreeNode &node);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* \brief Extracts the function number from the AST.
|
|
||||||
*
|
|
||||||
* Parses the function label (FUN#) to extract the numeric identifier.
|
|
||||||
*
|
|
||||||
* \return true if successful, false otherwise
|
|
||||||
*/
|
|
||||||
virtual Bool_t SetFuncNo();
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* \brief Recursively validates parameter and map references in the tree.
|
|
||||||
*
|
|
||||||
* \param node Current node being checked
|
|
||||||
* \param mapSize Number of available map entries
|
* \param mapSize Number of available map entries
|
||||||
* \param paramSize Number of available fit parameters
|
* \param paramSize Number of available fit parameters
|
||||||
* \return true if all references are valid, false otherwise
|
* \return true if all references are valid, false otherwise
|
||||||
*/
|
*/
|
||||||
virtual Bool_t FindAndCheckMapAndParamRange(PFuncTreeNode &node, UInt_t mapSize, UInt_t paramSize);
|
virtual Bool_t FindAndCheckMapAndParamRange(const musrfit::ast::operand& operand,
|
||||||
|
UInt_t mapSize, UInt_t paramSize);
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* \brief Initiates the conversion from AST to evaluation tree.
|
* \brief Generates a human-readable string representation of the AST.
|
||||||
*
|
*
|
||||||
* \return true if successful, false otherwise
|
* \param expr Expression AST to convert to string
|
||||||
|
* \return Formatted string representation
|
||||||
*/
|
*/
|
||||||
virtual Bool_t GenerateFuncEvalTree();
|
virtual TString GenerateString(const musrfit::ast::expression& expr);
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* \brief Recursively builds the evaluation tree from the AST.
|
* \brief Generates a string representation of an operand.
|
||||||
*
|
*
|
||||||
* \param i Iterator pointing to current AST node
|
* \param operand Operand AST to convert to string
|
||||||
* \param node Evaluation tree node to fill
|
* \return Formatted string representation
|
||||||
*/
|
*/
|
||||||
virtual void FillFuncEvalTree(iter_t const& i, PFuncTreeNode &node);
|
virtual TString GenerateStringOperand(const musrfit::ast::operand& operand);
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* \brief Recursively evaluates an evaluation tree node.
|
|
||||||
*
|
|
||||||
* \param node Node to evaluate
|
|
||||||
* \return Computed value for this node and its subtree
|
|
||||||
*/
|
|
||||||
virtual Double_t EvalNode(PFuncTreeNode &node);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* \brief Initiates cleanup of the evaluation tree.
|
|
||||||
*/
|
|
||||||
virtual void CleanupFuncEvalTree();
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* \brief Recursively cleans up evaluation tree nodes and their children.
|
|
||||||
*
|
|
||||||
* \param node Node to clean up
|
|
||||||
*/
|
|
||||||
virtual void CleanupNode(PFuncTreeNode &node);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tree_parse_info<> fInfo; ///< AST parse tree from Boost.Spirit parser
|
|
||||||
std::vector<Double_t> fParam; ///< Current fit parameter values for evaluation
|
|
||||||
std::vector<Int_t> fMap; ///< Map vector for indirect parameter references
|
|
||||||
PFuncTreeNode fFunc; ///< Root node of the evaluation tree
|
|
||||||
|
|
||||||
Bool_t fValid; ///< Validity flag: true if function parsed and initialized successfully
|
|
||||||
Int_t fFuncNo; ///< Function number extracted from label (x in FUNx)
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
/**
|
/**
|
||||||
* \brief Initiates generation of human-readable function string.
|
* \brief Visitor class for evaluating the AST.
|
||||||
*
|
*
|
||||||
* \param info AST parse tree to convert to string
|
* This visitor traverses the AST and computes the numeric value of the expression.
|
||||||
|
* It uses the visitor pattern with boost::static_visitor to handle different
|
||||||
|
* AST node types.
|
||||||
*/
|
*/
|
||||||
virtual void EvalTreeForString(tree_parse_info<> info);
|
class EvalVisitor : public boost::static_visitor<Double_t>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EvalVisitor(const std::vector<Int_t>& map,
|
||||||
|
const std::vector<Double_t>& param,
|
||||||
|
const PMetaData& metaData)
|
||||||
|
: fMap(map), fParam(param), fMetaData(metaData) {}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
Double_t operator()(const musrfit::ast::leer&) const;
|
||||||
/**
|
Double_t operator()(double val) const;
|
||||||
* \brief Recursively generates formatted function string from AST.
|
Double_t operator()(const musrfit::ast::constant& c) const;
|
||||||
*
|
Double_t operator()(const musrfit::ast::parameter& p) const;
|
||||||
* \param i Iterator pointing to current AST node
|
Double_t operator()(const musrfit::ast::map_ref& m) const;
|
||||||
* \param funcFlag Flag indicating if currently inside a function call
|
Double_t operator()(const musrfit::ast::function_call& f) const;
|
||||||
*/
|
Double_t operator()(const musrfit::ast::power_call& p) const;
|
||||||
virtual void EvalTreeForStringExpression(iter_t const& i, bool funcFlag=false);
|
Double_t operator()(const musrfit::ast::expression& expr) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::vector<Int_t>& fMap;
|
||||||
|
const std::vector<Double_t>& fParam;
|
||||||
|
const PMetaData& fMetaData;
|
||||||
|
};
|
||||||
|
|
||||||
|
musrfit::ast::expression fAst; ///< Abstract syntax tree for the expression
|
||||||
|
std::vector<Double_t> fParam; ///< Current fit parameter values for evaluation
|
||||||
|
std::vector<Int_t> fMap; ///< Map vector for indirect parameter references
|
||||||
|
|
||||||
|
Bool_t fValid; ///< Validity flag: true if function parsed and initialized successfully
|
||||||
|
Int_t fFuncNo; ///< Function number extracted from label (x in FUNx)
|
||||||
TString fFuncString; ///< Formatted, human-readable function representation
|
TString fFuncString; ///< Formatted, human-readable function representation
|
||||||
|
|
||||||
PMetaData fMetaData; ///< Metadata from experimental data (field, energy, temperature, etc.)
|
PMetaData fMetaData; ///< Metadata from experimental data (field, energy, temperature, etc.)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
306
src/include/PFunctionAst.h
Normal file
306
src/include/PFunctionAst.h
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
PFunctionAst.h
|
||||||
|
|
||||||
|
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-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 _PFUNCTIONAST_H_
|
||||||
|
#define _PFUNCTIONAST_H_
|
||||||
|
|
||||||
|
#include <boost/config/warning_disable.hpp>
|
||||||
|
#include <boost/variant/recursive_variant.hpp>
|
||||||
|
#include <boost/fusion/include/adapt_struct.hpp>
|
||||||
|
#include <boost/fusion/include/io.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
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 leer {};
|
||||||
|
|
||||||
|
// 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<
|
||||||
|
leer ///< Empty placeholder
|
||||||
|
, double ///< Numeric literal
|
||||||
|
, constant ///< Constant value
|
||||||
|
, parameter ///< Parameter reference
|
||||||
|
, map_ref ///< Map reference
|
||||||
|
, boost::recursive_wrapper<function_call> ///< Function call (recursive)
|
||||||
|
, boost::recursive_wrapper<power_call> ///< Power operation (recursive)
|
||||||
|
, boost::recursive_wrapper<expression> ///< 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<operation> 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 leer nodes (debugging support).
|
||||||
|
* @param out the output stream
|
||||||
|
* @return the output stream for chaining
|
||||||
|
*/
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, leer) { out << std::string("leer"); 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<musrfit::ast::operation>, 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_H_
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
|
||||||
PFunctionGrammer.h
|
PFunctionGrammar.h
|
||||||
|
|
||||||
Author: Andreas Suter
|
Author: Andreas Suter
|
||||||
e-mail: andreas.suter@psi.ch
|
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 *
|
* 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 *
|
||||||
@@ -30,223 +33,296 @@
|
|||||||
#ifndef _PFUNCTIONGRAMMAR_H_
|
#ifndef _PFUNCTIONGRAMMAR_H_
|
||||||
#define _PFUNCTIONGRAMMAR_H_
|
#define _PFUNCTIONGRAMMAR_H_
|
||||||
|
|
||||||
//#define BOOST_SPIRIT_DEBUG
|
// Check Boost version - require 1.61+ for Spirit X3
|
||||||
|
|
||||||
#include <boost/version.hpp>
|
#include <boost/version.hpp>
|
||||||
|
#if BOOST_VERSION < 106100
|
||||||
#if BOOST_VERSION >= 103800
|
# error "Boost version 1.61.0 or higher is required for Spirit X3. Please upgrade Boost."
|
||||||
# include <boost/spirit/include/classic_core.hpp>
|
|
||||||
# include <boost/spirit/include/classic_ast.hpp>
|
|
||||||
using namespace BOOST_SPIRIT_CLASSIC_NS;
|
|
||||||
#else
|
|
||||||
# include <boost/spirit/core.hpp>
|
|
||||||
# include <boost/spirit/tree/ast.hpp>
|
|
||||||
using namespace boost::spirit;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
#include "PFunctionAst.h"
|
||||||
/**
|
#include <boost/spirit/home/x3.hpp>
|
||||||
* \brief Iterator type for parsing characters.
|
|
||||||
*/
|
|
||||||
typedef char const* iterator_t;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
namespace x3 = boost::spirit::x3;
|
||||||
/**
|
|
||||||
* \brief Type for parse tree matching results.
|
|
||||||
*/
|
|
||||||
typedef tree_match<iterator_t> parse_tree_match_t;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
/**
|
/**
|
||||||
* \brief Iterator type for traversing the parse tree.
|
* @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.
|
||||||
*/
|
*/
|
||||||
typedef parse_tree_match_t::tree_iterator iter_t;
|
namespace musrfit { namespace grammar
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* \brief EBNF-like grammar definition for parsing function entries in msr-file FUNCTION blocks.
|
|
||||||
*
|
|
||||||
* This grammar defines the syntax for parsing mathematical function expressions in msr-files.
|
|
||||||
* It supports:
|
|
||||||
* - Basic arithmetic operations (+, -, *, /)
|
|
||||||
* - Mathematical functions (trigonometric, hyperbolic, logarithmic, exponential, etc.)
|
|
||||||
* - Constants (PI, GAMMA_MU, field B, energy EN, temperature T)
|
|
||||||
* - Parameters (PAR) and maps (MAP)
|
|
||||||
* - Function references (FUN)
|
|
||||||
*
|
|
||||||
* The grammar follows an EBNF-like structure with the following hierarchy:
|
|
||||||
* \verbatim
|
|
||||||
* assignment = fun_label '=' expression
|
|
||||||
* expression = term { ('+' | '-') term }
|
|
||||||
* term = factor { ('*' | '/') factor }
|
|
||||||
* factor = real | constant | parameter | map | function | power | '(' expression ')'
|
|
||||||
* \endverbatim
|
|
||||||
*
|
|
||||||
* \see PFunction for the class that uses this grammar to evaluate parsed expressions
|
|
||||||
*/
|
|
||||||
struct PFunctionGrammar : public grammar<PFunctionGrammar>
|
|
||||||
{
|
{
|
||||||
static const int realID = 1; ///< Identifier for real number literals
|
using x3::int_;
|
||||||
static const int constPiID = 2; ///< Identifier for PI constant
|
using x3::double_;
|
||||||
static const int constGammaMuID = 3; ///< Identifier for GAMMA_MU constant (muon gyromagnetic ratio)
|
using x3::lit;
|
||||||
static const int constFieldID = 4; ///< Identifier for magnetic field constant (B or -B)
|
using x3::lexeme;
|
||||||
static const int constEnergyID = 5; ///< Identifier for energy constant (EN or -EN)
|
using x3::attr;
|
||||||
static const int constTempID = 6; ///< Identifier for temperature constant (T# or -T#)
|
|
||||||
static const int funLabelID = 7; ///< Identifier for function label (FUN#)
|
|
||||||
static const int parameterID = 8; ///< Identifier for parameter reference (PAR# or -PAR#)
|
|
||||||
static const int mapID = 9; ///< Identifier for map reference (MAP#)
|
|
||||||
static const int functionID = 10; ///< Identifier for mathematical functions (cos, sin, exp, etc.)
|
|
||||||
static const int powerID = 11; ///< Identifier for power function (POW)
|
|
||||||
static const int factorID = 12; ///< Identifier for factor in expression
|
|
||||||
static const int termID = 13; ///< Identifier for term in expression
|
|
||||||
static const int expressionID = 14; ///< Identifier for expression
|
|
||||||
static const int assignmentID = 15; ///< Identifier for assignment statement
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/**
|
// Symbol tables - using inline to avoid multiple definition errors
|
||||||
* \brief Inner template structure defining the grammar rules.
|
///////////////////////////////////////////////////////////////////////////
|
||||||
*
|
|
||||||
* This template structure contains the actual grammar rule definitions
|
/**
|
||||||
* using Boost.Spirit syntax. It defines how the parser should recognize
|
* @brief Symbol table for additive operators (+ and -).
|
||||||
* and build an abstract syntax tree (AST) for function expressions.
|
*
|
||||||
*
|
* Maps operator characters to their corresponding AST token types
|
||||||
* \tparam ScannerT Scanner type used by Boost.Spirit for parsing
|
* for addition and subtraction operations.
|
||||||
*/
|
*/
|
||||||
template <typename ScannerT>
|
struct additive_op_ : x3::symbols<ast::optoken>
|
||||||
struct definition
|
{
|
||||||
|
additive_op_()
|
||||||
{
|
{
|
||||||
//--------------------------------------------------------------------
|
add("+", ast::op_plus)("-", ast::op_minus);
|
||||||
/**
|
}
|
||||||
* \brief Constructor that defines all grammar rules.
|
};
|
||||||
*
|
|
||||||
* Sets up the complete grammar hierarchy for parsing function expressions:
|
|
||||||
* - Terminals: real numbers, constants (PI, GAMMA_MU, B, EN, T), parameters (PAR), maps (MAP)
|
|
||||||
* - Functions: trigonometric (cos, sin, tan), hyperbolic (cosh, sinh, tanh),
|
|
||||||
* inverse trigonometric (acos, asin, atan), inverse hyperbolic (acosh, asinh, atanh),
|
|
||||||
* logarithmic (log, ln), exponential (exp), square root (sqrt), power (pow)
|
|
||||||
* - Operators: addition (+), subtraction (-), multiplication (*), division (/)
|
|
||||||
* - Expressions: Hierarchical structure following operator precedence
|
|
||||||
*
|
|
||||||
* \param self Reference to the enclosing PFunctionGrammar (unused but required by Boost.Spirit)
|
|
||||||
*/
|
|
||||||
definition(PFunctionGrammar const& /*self*/)
|
|
||||||
{
|
|
||||||
// Start grammar definition
|
|
||||||
real = leaf_node_d[ real_p ];
|
|
||||||
|
|
||||||
const_pi = leaf_node_d[ str_p("PI") ];
|
inline additive_op_ additive_op; ///< Global instance of additive operator symbol table
|
||||||
|
|
||||||
const_gamma_mu = leaf_node_d[ str_p("GAMMA_MU") ];
|
/**
|
||||||
|
* @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>
|
||||||
|
{
|
||||||
|
multiplicative_op_()
|
||||||
|
{
|
||||||
|
add("*", ast::op_times)("/", ast::op_divide);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const_field = leaf_node_d[ str_p("B") ] |
|
inline multiplicative_op_ multiplicative_op; ///< Global instance of multiplicative operator symbol table
|
||||||
leaf_node_d[ str_p("-B") ];
|
|
||||||
|
|
||||||
const_energy = leaf_node_d[ str_p("EN") ] |
|
/**
|
||||||
leaf_node_d[ str_p("-EN") ];
|
* @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>
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const_temp = leaf_node_d[ ( lexeme_d[ "T" >> +digit_p ] ) ] |
|
inline fun_tok_ fun_tok; ///< Global instance of function name symbol table
|
||||||
leaf_node_d[ ( lexeme_d[ "-T" >> +digit_p ] ) ];
|
|
||||||
|
|
||||||
fun_label = leaf_node_d[ ( lexeme_d[ "FUN" >> +digit_p ] ) ];
|
/**
|
||||||
|
* @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>
|
||||||
|
{
|
||||||
|
const_tok_()
|
||||||
|
{
|
||||||
|
add("PI", ast::constant::pi)("GAMMA_MU", ast::constant::gamma_mu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
parameter = leaf_node_d[ ( lexeme_d[ "PAR" >> +digit_p ] ) |
|
inline const_tok_ const_tok; ///< Global instance of constant name symbol table
|
||||||
( lexeme_d[ "-PAR" >> +digit_p ] ) ];
|
|
||||||
|
|
||||||
map = leaf_node_d[ ( lexeme_d[ "MAP" >> +digit_p ] ) ];
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Grammar Rules - Forward Declarations
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
function = lexeme_d[ root_node_d[ str_p("COS") ] >> ch_p('(') ] >> expression >> ch_p(')')
|
/// Top-level rule: FUN# = expression
|
||||||
| lexeme_d[ root_node_d[ str_p("SIN") ] >> ch_p('(') ] >> expression >> ch_p(')')
|
x3::rule<class assignment, ast::assignment> const assignment = "assignment";
|
||||||
| 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(')')
|
|
||||||
| lexeme_d[ root_node_d[ str_p("SQRT") ] >> ch_p('(') ] >> expression >> ch_p(')')
|
|
||||||
;
|
|
||||||
|
|
||||||
power = lexeme_d[ root_node_d[ str_p("POW") ] >> ch_p('(') ] >> expression >> ch_p(',') >> expression >> ch_p(')')
|
/// Expression with addition/subtraction (lowest precedence)
|
||||||
;
|
x3::rule<class expression, ast::expression> const expression = "expression";
|
||||||
|
|
||||||
factor = real
|
/// Term with multiplication/division (higher precedence)
|
||||||
| const_pi
|
x3::rule<class term, ast::expression> const term = "term";
|
||||||
| const_gamma_mu
|
|
||||||
| const_field
|
|
||||||
| const_energy
|
|
||||||
| const_temp
|
|
||||||
| parameter
|
|
||||||
| map
|
|
||||||
| function
|
|
||||||
| power
|
|
||||||
| inner_node_d[ch_p('(') >> expression >> ch_p(')')]
|
|
||||||
;
|
|
||||||
|
|
||||||
term = factor >>
|
/// Factor: literal, constant, parameter, function, or parenthesized expression (highest precedence)
|
||||||
*( (root_node_d[ch_p('*')] >> factor)
|
x3::rule<class factor, ast::operand> const factor = "factor";
|
||||||
| (root_node_d[ch_p('/')] >> factor)
|
|
||||||
);
|
|
||||||
|
|
||||||
expression = term >>
|
/// Constant: PI, GAMMA_MU, B, EN, or T#
|
||||||
*( (root_node_d[ch_p('+')] >> term)
|
x3::rule<class constant, ast::constant> const constant = "constant";
|
||||||
| (root_node_d[ch_p('-')] >> term)
|
|
||||||
);
|
|
||||||
|
|
||||||
assignment = (fun_label >> ch_p('=') >> expression);
|
/// Parameter reference: PAR# or -PAR#
|
||||||
// End grammar definition
|
x3::rule<class parameter, ast::parameter> const parameter = "parameter";
|
||||||
|
|
||||||
// turn on the debugging info.
|
/// Map reference: MAP# or -MAP#
|
||||||
BOOST_SPIRIT_DEBUG_RULE(real);
|
x3::rule<class map_ref, ast::map_ref> const map = "map";
|
||||||
BOOST_SPIRIT_DEBUG_RULE(const_pi);
|
|
||||||
BOOST_SPIRIT_DEBUG_RULE(const_gamma_mu);
|
|
||||||
BOOST_SPIRIT_DEBUG_RULE(const_field);
|
|
||||||
BOOST_SPIRIT_DEBUG_RULE(const_energy);
|
|
||||||
BOOST_SPIRIT_DEBUG_RULE(const_temp);
|
|
||||||
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(power);
|
|
||||||
BOOST_SPIRIT_DEBUG_RULE(factor);
|
|
||||||
BOOST_SPIRIT_DEBUG_RULE(term);
|
|
||||||
BOOST_SPIRIT_DEBUG_RULE(expression);
|
|
||||||
BOOST_SPIRIT_DEBUG_RULE(assignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<assignmentID> > assignment; ///< Rule for assignment: FUN# = expression
|
/// Function call: FUNC(expression)
|
||||||
rule<ScannerT, parser_context<>, parser_tag<expressionID> > expression; ///< Rule for expression: term { ('+' | '-') term }
|
x3::rule<class function_call, ast::function_call> const function = "function";
|
||||||
rule<ScannerT, parser_context<>, parser_tag<termID> > term; ///< Rule for term: factor { ('*' | '/') factor }
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<factorID> > factor; ///< Rule for factor: operand or parenthesized expression
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<functionID> > function; ///< Rule for mathematical functions
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<powerID> > power; ///< Rule for power function POW(base, exponent)
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<mapID> > map; ///< Rule for map reference MAP#
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<parameterID> > parameter; ///< Rule for parameter reference PAR# or -PAR#
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<funLabelID> > fun_label; ///< Rule for function label FUN#
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<constTempID> > const_temp; ///< Rule for temperature constant T# or -T#
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<constEnergyID> > const_energy; ///< Rule for energy constant EN or -EN
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<constFieldID> > const_field; ///< Rule for field constant B or -B
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<constGammaMuID> > const_gamma_mu;///< Rule for muon gyromagnetic ratio constant
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<constPiID> > const_pi; ///< Rule for PI constant
|
|
||||||
rule<ScannerT, parser_context<>, parser_tag<realID> > real; ///< Rule for real number literals
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
/// Power operation: POW(base, exponent)
|
||||||
/**
|
x3::rule<class power_call, ast::power_call> const power = "power";
|
||||||
* \brief Returns the starting rule for the grammar.
|
|
||||||
*
|
///////////////////////////////////////////////////////////////////////////
|
||||||
* The parser begins by matching the assignment rule, which represents
|
// Grammar Rule Definitions
|
||||||
* a complete function definition (e.g., FUN1 = PAR1 * cos(PAR2 * PI)).
|
///////////////////////////////////////////////////////////////////////////
|
||||||
*
|
|
||||||
* \return Reference to the assignment rule as the grammar entry point
|
/**
|
||||||
*/
|
* @brief Assignment rule: FUN# = expression
|
||||||
rule<ScannerT, parser_context<>, parser_tag<assignmentID> > const&
|
*
|
||||||
start() const { return assignment; }
|
* Parses a function assignment statement, extracting the function number
|
||||||
};
|
* and the expression to evaluate.
|
||||||
};
|
*/
|
||||||
|
auto const assignment_def =
|
||||||
|
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 =
|
||||||
|
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 =
|
||||||
|
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 =
|
||||||
|
double_
|
||||||
|
| constant
|
||||||
|
| parameter
|
||||||
|
| map
|
||||||
|
| function
|
||||||
|
| power
|
||||||
|
| ('(' >> 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 =
|
||||||
|
(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_);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 =
|
||||||
|
(lexeme[lit("-PAR") >> int_] >> attr(true))
|
||||||
|
| (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 =
|
||||||
|
(lexeme[lit("-MAP") >> int_] >> attr(true))
|
||||||
|
| (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 =
|
||||||
|
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 =
|
||||||
|
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(
|
||||||
|
assignment,
|
||||||
|
expression,
|
||||||
|
term,
|
||||||
|
factor,
|
||||||
|
constant,
|
||||||
|
parameter,
|
||||||
|
map,
|
||||||
|
function,
|
||||||
|
power
|
||||||
|
)
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @namespace musrfit
|
||||||
|
* @brief Top-level namespace for musrfit components.
|
||||||
|
*/
|
||||||
|
namespace musrfit {
|
||||||
|
/**
|
||||||
|
* @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()
|
||||||
|
{
|
||||||
|
return grammar::assignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // _PFUNCTIONGRAMMAR_H_
|
#endif // _PFUNCTIONGRAMMAR_H_
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace mupp
|
|||||||
* handler to pinpoint the exact location of errors in the source text.
|
* handler to pinpoint the exact location of errors in the source text.
|
||||||
*
|
*
|
||||||
* The annotation is performed after successful parsing but before semantic
|
* The annotation is performed after successful parsing but before semantic
|
||||||
* analysis, using Boost.Phoenix function objects integrated with the parser.
|
* analysis, integrated with the Spirit X3 parser.
|
||||||
*
|
*
|
||||||
* @tparam Iterator the iterator type for traversing the source code (typically std::string::const_iterator)
|
* @tparam Iterator the iterator type for traversing the source code (typically std::string::const_iterator)
|
||||||
*/
|
*/
|
||||||
@@ -59,9 +59,6 @@ namespace mupp
|
|||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
struct PAnnotation
|
struct PAnnotation
|
||||||
{
|
{
|
||||||
/// Result type specification required by Boost.Phoenix function protocol
|
|
||||||
template <typename, typename>
|
|
||||||
struct result { typedef void type; };
|
|
||||||
|
|
||||||
std::vector<Iterator>& iters; ///< Reference to vector storing iterator positions indexed by AST node IDs
|
std::vector<Iterator>& iters; ///< Reference to vector storing iterator positions indexed by AST node IDs
|
||||||
|
|
||||||
@@ -79,8 +76,6 @@ namespace mupp
|
|||||||
*/
|
*/
|
||||||
struct set_id
|
struct set_id
|
||||||
{
|
{
|
||||||
typedef void result_type; ///< Return type for Boost.Phoenix compatibility
|
|
||||||
|
|
||||||
int id; ///< The ID to assign to tagged AST nodes
|
int id; ///< The ID to assign to tagged AST nodes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace mupp
|
|||||||
*
|
*
|
||||||
* This error handler logs detailed error information to a file, including
|
* This error handler logs detailed error information to a file, including
|
||||||
* the error message, line number, source line, and a visual pointer to the
|
* the error message, line number, source line, and a visual pointer to the
|
||||||
* error position. It integrates with the Boost.Spirit parser error handling
|
* error position. It integrates with the Boost.Spirit X3 parser error handling
|
||||||
* mechanism and works in conjunction with the PAnnotation handler to map
|
* mechanism and works in conjunction with the PAnnotation handler to map
|
||||||
* AST node IDs back to source positions.
|
* AST node IDs back to source positions.
|
||||||
*
|
*
|
||||||
@@ -58,9 +58,6 @@ namespace mupp
|
|||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
struct PErrorHandler
|
struct PErrorHandler
|
||||||
{
|
{
|
||||||
/// Result type specification required by Boost.Phoenix function protocol
|
|
||||||
template <typename, typename, typename>
|
|
||||||
struct result { typedef void type; };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructor that stores the source code range.
|
* @brief Constructor that stores the source code range.
|
||||||
|
|||||||
@@ -33,21 +33,12 @@
|
|||||||
#ifndef _PEXPRESSION_HPP_
|
#ifndef _PEXPRESSION_HPP_
|
||||||
#define _PEXPRESSION_HPP_
|
#define _PEXPRESSION_HPP_
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Spirit v2.5 allows you to suppress automatic generation
|
|
||||||
// of predefined terminals to speed up complation. With
|
|
||||||
// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are
|
|
||||||
// responsible in creating instances of the terminals that
|
|
||||||
// you need (e.g. see qi::uint_type uint_ below).
|
|
||||||
#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Uncomment this if you want to enable debugging
|
// Uncomment this if you want to enable debugging
|
||||||
// #define BOOST_SPIRIT_QI_DEBUG
|
// #define BOOST_SPIRIT_X3_DEBUG
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <boost/spirit/include/qi.hpp>
|
#include <boost/spirit/home/x3.hpp>
|
||||||
#include "PAst.hpp"
|
#include "PAst.hpp"
|
||||||
#include "PErrorHandler.hpp"
|
#include "PErrorHandler.hpp"
|
||||||
#include "PSkipper.hpp"
|
#include "PSkipper.hpp"
|
||||||
@@ -55,14 +46,14 @@
|
|||||||
|
|
||||||
namespace mupp { namespace parser
|
namespace mupp { namespace parser
|
||||||
{
|
{
|
||||||
namespace qi = boost::spirit::qi;
|
namespace x3 = boost::spirit::x3;
|
||||||
namespace ascii = boost::spirit::ascii;
|
namespace ascii = boost::spirit::x3::ascii;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
* @brief The PExpression grammar for parsing mathematical expressions.
|
* @brief The PExpression grammar for parsing mathematical expressions.
|
||||||
*
|
*
|
||||||
* This Boost.Spirit grammar defines the syntax for parsing arithmetic
|
* This Boost.Spirit X3 grammar defines the syntax for parsing arithmetic
|
||||||
* expressions with proper operator precedence and associativity:
|
* expressions with proper operator precedence and associativity:
|
||||||
* - Primary expressions: numbers, variables, functions, parenthesized expressions
|
* - Primary expressions: numbers, variables, functions, parenthesized expressions
|
||||||
* - Unary operators: +, - (highest precedence)
|
* - Unary operators: +, - (highest precedence)
|
||||||
@@ -80,31 +71,27 @@ namespace mupp { namespace parser
|
|||||||
* - 3.14 * $radius
|
* - 3.14 * $radius
|
||||||
* - sin($theta) + cos($phi)
|
* - sin($theta) + cos($phi)
|
||||||
* - pow($x, 2.0) + pow($y, 2.0)
|
* - pow($x, 2.0) + pow($y, 2.0)
|
||||||
*
|
|
||||||
* @tparam Iterator the iterator type for the input (typically std::string::const_iterator)
|
|
||||||
*/
|
*/
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <typename Iterator>
|
|
||||||
struct PExpression : qi::grammar<Iterator, ast::expression(), PSkipper<Iterator> >
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Constructor that initializes the grammar rules.
|
|
||||||
* @param error_handler reference to the error handler for reporting parse errors
|
|
||||||
*/
|
|
||||||
PExpression(PErrorHandler<Iterator>& error_handler);
|
|
||||||
|
|
||||||
qi::symbols<char, ast::optoken> additive_op; ///< Symbol table for additive operators (+, -)
|
// Rule IDs
|
||||||
qi::symbols<char, ast::optoken> multiplicative_op; ///< Symbol table for multiplicative operators (*, /)
|
struct expr_class;
|
||||||
qi::symbols<char, ast::optoken> unary_op; ///< Symbol table for unary operators (+, -)
|
struct additive_expr_class;
|
||||||
qi::symbols<char, ast::funid> fun_tok; ///< Symbol table for function names
|
struct multiplicative_expr_class;
|
||||||
|
struct unary_expr_class;
|
||||||
|
struct primary_expr_class;
|
||||||
|
struct identifier_class;
|
||||||
|
|
||||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > expr; ///< Top-level expression rule
|
// Rule declarations
|
||||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > additive_expr; ///< Additive expression rule (lowest precedence)
|
typedef x3::rule<expr_class, ast::expression> expr_type;
|
||||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > multiplicative_expr; ///< Multiplicative expression rule (medium precedence)
|
typedef x3::rule<additive_expr_class, ast::expression> additive_expr_type;
|
||||||
qi::rule<Iterator, ast::operand(), PSkipper<Iterator> > unary_expr; ///< Unary expression rule
|
typedef x3::rule<multiplicative_expr_class, ast::expression> multiplicative_expr_type;
|
||||||
qi::rule<Iterator, ast::operand(), PSkipper<Iterator> > primary_expr; ///< Primary expression rule (highest precedence)
|
typedef x3::rule<unary_expr_class, ast::operand> unary_expr_type;
|
||||||
qi::rule<Iterator, std::string(), PSkipper<Iterator> > identifier; ///< Identifier rule (variables prefixed with '$')
|
typedef x3::rule<primary_expr_class, ast::operand> primary_expr_type;
|
||||||
};
|
typedef x3::rule<identifier_class, std::string> identifier_type;
|
||||||
|
|
||||||
|
BOOST_SPIRIT_DECLARE(expr_type, additive_expr_type, multiplicative_expr_type,
|
||||||
|
unary_expr_type, primary_expr_type, identifier_type)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#endif // _PEXPRESSION_HPP_
|
#endif // _PEXPRESSION_HPP_
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
see https://github.com/boostorg/spirit
|
see https://github.com/boostorg/spirit
|
||||||
|
|
||||||
This file contains the implementation (definition) of the PExpression
|
This file contains the implementation (definition) of the PExpression
|
||||||
template grammar. It defines the actual grammar rules and their semantic
|
grammar. It defines the actual grammar rules and their semantic
|
||||||
actions using Boost.Spirit Qi.
|
actions using Boost.Spirit X3.
|
||||||
|
|
||||||
The grammar implements expression parsing with proper operator precedence:
|
The grammar implements expression parsing with proper operator precedence:
|
||||||
- Primary expressions (literals, variables, functions)
|
- Primary expressions (literals, variables, functions)
|
||||||
@@ -46,93 +46,116 @@
|
|||||||
#include "PExpression.hpp"
|
#include "PExpression.hpp"
|
||||||
#include "PErrorHandler.hpp"
|
#include "PErrorHandler.hpp"
|
||||||
#include "PAnnotation.hpp"
|
#include "PAnnotation.hpp"
|
||||||
#include <boost/phoenix/function.hpp>
|
|
||||||
|
|
||||||
namespace mupp { namespace parser
|
namespace mupp { namespace parser
|
||||||
{
|
{
|
||||||
template <typename Iterator>
|
namespace x3 = boost::spirit::x3;
|
||||||
PExpression<Iterator>::PExpression(PErrorHandler<Iterator>& error_handler)
|
namespace ascii = boost::spirit::x3::ascii;
|
||||||
: PExpression::base_type(expr)
|
|
||||||
{
|
|
||||||
qi::_1_type _1;
|
|
||||||
qi::_2_type _2;
|
|
||||||
qi::_3_type _3;
|
|
||||||
qi::_4_type _4;
|
|
||||||
|
|
||||||
qi::char_type char_;
|
using x3::char_;
|
||||||
qi::double_type double_;
|
using x3::double_;
|
||||||
qi::_val_type _val;
|
using x3::raw;
|
||||||
qi::raw_type raw;
|
using x3::lexeme;
|
||||||
qi::lexeme_type lexeme;
|
using ascii::alpha;
|
||||||
qi::alpha_type alpha;
|
using ascii::alnum;
|
||||||
qi::alnum_type alnum;
|
|
||||||
|
|
||||||
using qi::on_error;
|
|
||||||
using qi::on_success;
|
|
||||||
using qi::fail;
|
|
||||||
using boost::phoenix::function;
|
|
||||||
|
|
||||||
typedef function<mupp::PErrorHandler<Iterator> > error_handler_function;
|
|
||||||
typedef function<mupp::PAnnotation<Iterator> > annotation_function;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
// Tokens
|
// Symbol tables for operators and functions
|
||||||
additive_op.add
|
///////////////////////////////////////////////////////////////////////
|
||||||
("+", ast::op_plus)
|
|
||||||
("-", ast::op_minus)
|
|
||||||
;
|
|
||||||
|
|
||||||
multiplicative_op.add
|
inline struct additive_op_ : x3::symbols<ast::optoken>
|
||||||
("*", ast::op_times)
|
{
|
||||||
("/", ast::op_divide)
|
additive_op_()
|
||||||
;
|
{
|
||||||
|
add
|
||||||
|
("+", ast::op_plus)
|
||||||
|
("-", ast::op_minus)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
} additive_op;
|
||||||
|
|
||||||
unary_op.add
|
inline struct multiplicative_op_ : x3::symbols<ast::optoken>
|
||||||
("+", ast::op_positive)
|
{
|
||||||
("-", ast::op_negative)
|
multiplicative_op_()
|
||||||
;
|
{
|
||||||
|
add
|
||||||
|
("*", ast::op_times)
|
||||||
|
("/", ast::op_divide)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
} multiplicative_op;
|
||||||
|
|
||||||
fun_tok.add
|
inline struct unary_op_ : x3::symbols<ast::optoken>
|
||||||
("max", ast::fun_max)
|
{
|
||||||
("min", ast::fun_min)
|
unary_op_()
|
||||||
("abs", ast::fun_abs)
|
{
|
||||||
("sin", ast::fun_sin)
|
add
|
||||||
("cos", ast::fun_cos)
|
("+", ast::op_positive)
|
||||||
("tan", ast::fun_tan)
|
("-", ast::op_negative)
|
||||||
("sinh", ast::fun_sinh)
|
;
|
||||||
("cosh", ast::fun_cosh)
|
}
|
||||||
("tanh", ast::fun_tanh)
|
} unary_op;
|
||||||
("asin", ast::fun_asin)
|
|
||||||
("acos", ast::fun_acos)
|
inline struct fun_tok_ : x3::symbols<ast::funid>
|
||||||
("atan", ast::fun_atan)
|
{
|
||||||
("exp", ast::fun_exp)
|
fun_tok_()
|
||||||
("log", ast::fun_log)
|
{
|
||||||
("ln", ast::fun_ln)
|
add
|
||||||
("sqrt", ast::fun_sqrt)
|
("max", ast::fun_max)
|
||||||
;
|
("min", ast::fun_min)
|
||||||
|
("abs", ast::fun_abs)
|
||||||
|
("sin", ast::fun_sin)
|
||||||
|
("cos", ast::fun_cos)
|
||||||
|
("tan", ast::fun_tan)
|
||||||
|
("sinh", ast::fun_sinh)
|
||||||
|
("cosh", ast::fun_cosh)
|
||||||
|
("tanh", ast::fun_tanh)
|
||||||
|
("asin", ast::fun_asin)
|
||||||
|
("acos", ast::fun_acos)
|
||||||
|
("atan", ast::fun_atan)
|
||||||
|
("exp", ast::fun_exp)
|
||||||
|
("log", ast::fun_log)
|
||||||
|
("ln", ast::fun_ln)
|
||||||
|
("sqrt", ast::fun_sqrt)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
} fun_tok;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Rule definitions
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline expr_type const expr = "expr";
|
||||||
|
inline additive_expr_type const additive_expr = "additive_expr";
|
||||||
|
inline multiplicative_expr_type const multiplicative_expr = "multiplicative_expr";
|
||||||
|
inline unary_expr_type const unary_expr = "unary_expr";
|
||||||
|
inline primary_expr_type const primary_expr = "primary_expr";
|
||||||
|
inline identifier_type const identifier = "identifier";
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
// Grammar
|
// Grammar
|
||||||
expr =
|
///////////////////////////////////////////////////////////////////////
|
||||||
additive_expr.alias()
|
|
||||||
|
inline auto const expr_def =
|
||||||
|
additive_expr
|
||||||
;
|
;
|
||||||
|
|
||||||
additive_expr =
|
inline auto const additive_expr_def =
|
||||||
multiplicative_expr
|
multiplicative_expr
|
||||||
>> *(additive_op > multiplicative_expr)
|
>> *(additive_op > multiplicative_expr)
|
||||||
;
|
;
|
||||||
|
|
||||||
multiplicative_expr =
|
inline auto const multiplicative_expr_def =
|
||||||
unary_expr
|
unary_expr
|
||||||
>> *(multiplicative_op > unary_expr)
|
>> *(multiplicative_op > unary_expr)
|
||||||
;
|
;
|
||||||
|
|
||||||
unary_expr =
|
inline auto const unary_expr_def =
|
||||||
primary_expr
|
primary_expr
|
||||||
| (unary_op > primary_expr)
|
| (unary_op > primary_expr)
|
||||||
;
|
;
|
||||||
|
|
||||||
primary_expr =
|
inline auto const primary_expr_def =
|
||||||
double_
|
double_
|
||||||
| identifier
|
| identifier
|
||||||
| fun_tok > '(' > expr > ')'
|
| fun_tok > '(' > expr > ')'
|
||||||
@@ -140,36 +163,13 @@ namespace mupp { namespace parser
|
|||||||
| '(' > expr > ')'
|
| '(' > expr > ')'
|
||||||
;
|
;
|
||||||
|
|
||||||
identifier =
|
inline auto const identifier_def =
|
||||||
raw[lexeme['$' >> *(alnum | '_')]]
|
raw[lexeme['$' >> *(alnum | '_')]]
|
||||||
;
|
;
|
||||||
|
|
||||||
// name all the rules
|
BOOST_SPIRIT_DEFINE(expr, additive_expr, multiplicative_expr,
|
||||||
additive_expr.name("additive_expr");
|
unary_expr, primary_expr, identifier)
|
||||||
multiplicative_expr.name("multiplicative_expr");
|
|
||||||
unary_expr.name("unary_expr");
|
|
||||||
primary_expr.name("primary_expr");
|
|
||||||
identifier.name("identifier");
|
|
||||||
|
|
||||||
// Debugging and error handling and reporting support.
|
|
||||||
BOOST_SPIRIT_DEBUG_NODES(
|
|
||||||
(expr)
|
|
||||||
(additive_expr)
|
|
||||||
(multiplicative_expr)
|
|
||||||
(unary_expr)
|
|
||||||
(primary_expr)
|
|
||||||
(identifier)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Error handling: on error in expr, call error_handler.
|
|
||||||
on_error<fail>(expr,
|
|
||||||
error_handler_function(error_handler)(
|
|
||||||
"**ERROR** Expecting ", _4, _3));
|
|
||||||
|
|
||||||
// Annotation: on success in primary_expr, call annotation.
|
|
||||||
on_success(primary_expr,
|
|
||||||
annotation_function(error_handler.iters)(_val, _1));
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,12 @@
|
|||||||
#ifndef _PSKIPPER_HPP_
|
#ifndef _PSKIPPER_HPP_
|
||||||
#define _PSKIPPER_HPP_
|
#define _PSKIPPER_HPP_
|
||||||
|
|
||||||
#include <boost/spirit/include/qi.hpp>
|
#include <boost/spirit/home/x3.hpp>
|
||||||
|
|
||||||
namespace mupp { namespace parser
|
namespace mupp { namespace parser
|
||||||
{
|
{
|
||||||
namespace qi = boost::spirit::qi;
|
namespace x3 = boost::spirit::x3;
|
||||||
namespace ascii = boost::spirit::ascii;
|
namespace ascii = boost::spirit::x3::ascii;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
@@ -61,38 +61,22 @@ namespace mupp { namespace parser
|
|||||||
* / * This is a
|
* / * This is a
|
||||||
* multi-line comment * /
|
* multi-line comment * /
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
|
||||||
* @tparam Iterator the iterator type for the input (typically std::string::const_iterator)
|
|
||||||
*/
|
*/
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <typename Iterator>
|
|
||||||
struct PSkipper : qi::grammar<Iterator>
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Constructor that initializes the skipper grammar rules.
|
|
||||||
*
|
|
||||||
* Sets up the grammar to recognize whitespace and various comment styles.
|
|
||||||
*/
|
|
||||||
PSkipper() : PSkipper::base_type(start)
|
|
||||||
{
|
|
||||||
qi::char_type char_;
|
|
||||||
qi::lit_type lit;
|
|
||||||
qi::eol_type eol;
|
|
||||||
ascii::space_type space;
|
|
||||||
ascii::print_type print;
|
|
||||||
|
|
||||||
single_line_comment = (lit('%') | lit('#') | lit("//")) >> *print >> eol;
|
using x3::char_;
|
||||||
|
using x3::lit;
|
||||||
|
using x3::eol;
|
||||||
|
using ascii::space;
|
||||||
|
using ascii::print;
|
||||||
|
|
||||||
start =
|
inline auto const single_line_comment = (lit('%') | lit('#') | lit("//")) >> *print >> eol;
|
||||||
space // tab/space/cr/lf
|
|
||||||
| "/*" >> *(char_ - "*/") >> "*/" // C-style comments
|
|
||||||
| single_line_comment
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
qi::rule<Iterator> single_line_comment; ///< Rule for single-line comments (%, #, //)
|
inline auto const skipper =
|
||||||
qi::rule<Iterator> start; ///< Top-level skipper rule
|
space // tab/space/cr/lf
|
||||||
};
|
| "/*" >> *(char_ - "*/") >> "*/" // C-style comments
|
||||||
|
| single_line_comment
|
||||||
|
;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#endif // _PSKIPPER_HPP_
|
#endif // _PSKIPPER_HPP_
|
||||||
|
|||||||
@@ -59,25 +59,23 @@ namespace mupp { namespace parser
|
|||||||
*
|
*
|
||||||
* The grammar parses a statement list (one or more statements) and builds
|
* The grammar parses a statement list (one or more statements) and builds
|
||||||
* an AST that can be analyzed and evaluated by the semantic analyzer.
|
* an AST that can be analyzed and evaluated by the semantic analyzer.
|
||||||
*
|
|
||||||
* @tparam Iterator the iterator type for the input (typically std::string::const_iterator)
|
|
||||||
*/
|
*/
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <typename Iterator>
|
|
||||||
struct PStatement : qi::grammar<Iterator, ast::statement_list(), PSkipper<Iterator> >
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Constructor that initializes the statement grammar rules.
|
|
||||||
* @param error_handler reference to the error handler for reporting parse errors
|
|
||||||
*/
|
|
||||||
PStatement(PErrorHandler<Iterator>& error_handler);
|
|
||||||
|
|
||||||
PExpression<Iterator> expr; ///< Expression grammar for parsing right-hand sides
|
// Rule IDs
|
||||||
qi::rule<Iterator, ast::statement_list(), PSkipper<Iterator> > statement_list; ///< Rule for parsing a list of statements
|
struct statement_list_class;
|
||||||
qi::rule<Iterator, ast::variable_declaration(), PSkipper<Iterator> > variable_declaration; ///< Rule for variable declarations
|
struct variable_declaration_class;
|
||||||
qi::rule<Iterator, ast::assignment(), PSkipper<Iterator> > assignment; ///< Rule for assignment statements
|
struct assignment_class;
|
||||||
qi::rule<Iterator, std::string(), PSkipper<Iterator> > identifier; ///< Rule for identifiers (without '$' prefix)
|
struct stmt_identifier_class;
|
||||||
};
|
|
||||||
|
// Rule declarations
|
||||||
|
typedef x3::rule<statement_list_class, ast::statement_list> statement_list_type;
|
||||||
|
typedef x3::rule<variable_declaration_class, ast::variable_declaration> variable_declaration_type;
|
||||||
|
typedef x3::rule<assignment_class, ast::assignment> assignment_type;
|
||||||
|
typedef x3::rule<stmt_identifier_class, std::string> stmt_identifier_type;
|
||||||
|
|
||||||
|
BOOST_SPIRIT_DECLARE(statement_list_type, variable_declaration_type,
|
||||||
|
assignment_type, stmt_identifier_type)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#endif // _PSTATEMENT_HPP_
|
#endif // _PSTATEMENT_HPP_
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
see https://github.com/boostorg/spirit
|
see https://github.com/boostorg/spirit
|
||||||
|
|
||||||
This file contains the implementation (definition) of the PStatement
|
This file contains the implementation (definition) of the PStatement
|
||||||
template grammar. It defines the grammar rules for parsing variable
|
grammar. It defines the grammar rules for parsing variable
|
||||||
declarations and assignments using Boost.Spirit Qi.
|
declarations and assignments using Boost.Spirit X3.
|
||||||
|
|
||||||
The grammar supports:
|
The grammar supports:
|
||||||
- Variable declarations: var <identifier> = <expression>
|
- Variable declarations: var <identifier> = <expression>
|
||||||
@@ -43,77 +43,55 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#include "PStatement.hpp"
|
#include "PStatement.hpp"
|
||||||
|
#include "PExpressionDef.hpp"
|
||||||
#include "PErrorHandler.hpp"
|
#include "PErrorHandler.hpp"
|
||||||
#include "PAnnotation.hpp"
|
#include "PAnnotation.hpp"
|
||||||
|
|
||||||
namespace mupp { namespace parser
|
namespace mupp { namespace parser
|
||||||
{
|
{
|
||||||
template <typename Iterator>
|
namespace x3 = boost::spirit::x3;
|
||||||
PStatement<Iterator>::PStatement(PErrorHandler<Iterator>& error_handler)
|
namespace ascii = boost::spirit::x3::ascii;
|
||||||
: PStatement::base_type(statement_list), expr(error_handler)
|
|
||||||
{
|
|
||||||
qi::_1_type _1;
|
|
||||||
qi::_2_type _2;
|
|
||||||
qi::_3_type _3;
|
|
||||||
qi::_4_type _4;
|
|
||||||
|
|
||||||
qi::_val_type _val;
|
using x3::raw;
|
||||||
qi::raw_type raw;
|
using x3::lexeme;
|
||||||
qi::lexeme_type lexeme;
|
using ascii::alpha;
|
||||||
qi::alpha_type alpha;
|
using ascii::alnum;
|
||||||
qi::alnum_type alnum;
|
|
||||||
|
|
||||||
using qi::on_error;
|
///////////////////////////////////////////////////////////////////////
|
||||||
using qi::on_success;
|
// Rule definitions
|
||||||
using qi::fail;
|
///////////////////////////////////////////////////////////////////////
|
||||||
using boost::phoenix::function;
|
|
||||||
|
|
||||||
typedef function<mupp::PErrorHandler<Iterator> > error_handler_function;
|
inline statement_list_type const statement_list = "statement_list";
|
||||||
typedef function<mupp::PAnnotation<Iterator> > annotation_function;
|
inline variable_declaration_type const variable_declaration = "variable_declaration";
|
||||||
|
inline assignment_type const assignment = "assignment";
|
||||||
|
inline stmt_identifier_type const stmt_identifier = "identifier";
|
||||||
|
|
||||||
statement_list =
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Grammar
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline auto const statement_list_def =
|
||||||
+(variable_declaration | assignment)
|
+(variable_declaration | assignment)
|
||||||
;
|
;
|
||||||
|
|
||||||
identifier =
|
inline auto const stmt_identifier_def =
|
||||||
raw[lexeme[(alpha | '_') >> *(alnum | '_')]]
|
raw[lexeme[(alpha | '_') >> *(alnum | '_')]]
|
||||||
;
|
;
|
||||||
|
|
||||||
variable_declaration =
|
inline auto const variable_declaration_def =
|
||||||
lexeme["var" >> !(alnum | '_')] // make sure we have whole words
|
lexeme["var" >> !(alnum | '_')] // make sure we have whole words
|
||||||
> identifier
|
> stmt_identifier
|
||||||
> -('=' > expr)
|
> -('=' > expr)
|
||||||
;
|
;
|
||||||
|
|
||||||
assignment =
|
inline auto const assignment_def =
|
||||||
identifier
|
stmt_identifier
|
||||||
> '='
|
> '='
|
||||||
> expr
|
> expr
|
||||||
;
|
;
|
||||||
|
|
||||||
// name all the rules
|
BOOST_SPIRIT_DEFINE(statement_list, variable_declaration, assignment, stmt_identifier)
|
||||||
statement_list.name("statement_list");
|
|
||||||
identifier.name("identifier");
|
|
||||||
variable_declaration.name("variable_declaration");
|
|
||||||
assignment.name("assignment");
|
|
||||||
|
|
||||||
// Debugging and error handling and reporting support.
|
|
||||||
BOOST_SPIRIT_DEBUG_NODES(
|
|
||||||
(statement_list)
|
|
||||||
(identifier)
|
|
||||||
(variable_declaration)
|
|
||||||
(assignment)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Error handling: on error in statement_list, call error_handler.
|
|
||||||
on_error<fail>(statement_list,
|
|
||||||
error_handler_function(error_handler)(
|
|
||||||
"**ERROR** Expecting ", _4, _3));
|
|
||||||
|
|
||||||
// Annotation: on success in assignment, call annotation.
|
|
||||||
on_success(assignment,
|
|
||||||
annotation_function(error_handler.iters)(_val, _1));
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
Based on Joel de Guzman example on calc7,
|
Based on Joel de Guzman example on calc7,
|
||||||
see https://github.com/boostorg/spirit
|
see https://github.com/boostorg/spirit
|
||||||
|
|
||||||
This file explicitly instantiates the PExpression template grammar for
|
This file instantiates the PExpression grammar rules for
|
||||||
std::string::const_iterator. Template instantiation in a separate
|
std::string::const_iterator. Instantiation in a separate
|
||||||
compilation unit reduces compile times and allows the grammar
|
compilation unit reduces compile times and allows the grammar
|
||||||
implementation to be hidden from clients.
|
implementation to be hidden from clients.
|
||||||
|
|
||||||
@@ -35,11 +35,4 @@
|
|||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# pragma warning(disable: 4345)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "PExpressionDef.hpp"
|
#include "PExpressionDef.hpp"
|
||||||
|
|
||||||
typedef std::string::const_iterator iterator_type;
|
|
||||||
template struct mupp::parser::PExpression<iterator_type>;
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
Based on Joel de Guzman example on calc7,
|
Based on Joel de Guzman example on calc7,
|
||||||
see https://github.com/boostorg/spirit
|
see https://github.com/boostorg/spirit
|
||||||
|
|
||||||
This file explicitly instantiates the PStatement template grammar for
|
This file instantiates the PStatement grammar rules for
|
||||||
std::string::const_iterator. Template instantiation in a separate
|
std::string::const_iterator. Instantiation in a separate
|
||||||
compilation unit reduces compile times and allows the grammar
|
compilation unit reduces compile times and allows the grammar
|
||||||
implementation to be hidden from clients.
|
implementation to be hidden from clients.
|
||||||
|
|
||||||
@@ -35,11 +35,4 @@
|
|||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# pragma warning(disable: 4345)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "PStatementDef.hpp"
|
#include "PStatementDef.hpp"
|
||||||
|
|
||||||
typedef std::string::const_iterator iterator_type;
|
|
||||||
template struct mupp::parser::PStatement<iterator_type>;
|
|
||||||
|
|||||||
@@ -34,8 +34,11 @@
|
|||||||
#include "PSkipper.hpp"
|
#include "PSkipper.hpp"
|
||||||
#include "PErrorHandler.hpp"
|
#include "PErrorHandler.hpp"
|
||||||
#include "PStatement.hpp"
|
#include "PStatement.hpp"
|
||||||
|
#include "PStatementDef.hpp"
|
||||||
#include "PProgram.hpp"
|
#include "PProgram.hpp"
|
||||||
|
|
||||||
|
#include <boost/spirit/home/x3.hpp>
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* @brief Default constructor creating an invalid handler.
|
* @brief Default constructor creating an invalid handler.
|
||||||
@@ -78,12 +81,11 @@ PVarHandler::PVarHandler(PmuppCollection *coll, std::string parse_str, std::stri
|
|||||||
iterator_type end = fParseStr.end();
|
iterator_type end = fParseStr.end();
|
||||||
|
|
||||||
mupp::PErrorHandler<iterator_type> error_handler(iter, end); // the error handler
|
mupp::PErrorHandler<iterator_type> error_handler(iter, end); // the error handler
|
||||||
mupp::parser::PStatement<iterator_type> parser(error_handler); // the parser
|
|
||||||
mupp::prog::PProgram prog(error_handler); // our compiler, and exec
|
mupp::prog::PProgram prog(error_handler); // our compiler, and exec
|
||||||
mupp::parser::PSkipper<iterator_type> skipper; // the skipper parser
|
|
||||||
|
|
||||||
// perform the parsing
|
// perform the parsing
|
||||||
bool success = phrase_parse(iter, end, parser, skipper, fAst);
|
namespace x3 = boost::spirit::x3;
|
||||||
|
bool success = x3::phrase_parse(iter, end, mupp::parser::statement_list, mupp::parser::skipper, fAst);
|
||||||
if (success && iter == end) {
|
if (success && iter == end) {
|
||||||
if (prog(fAst)) { // semantic analysis
|
if (prog(fAst)) { // semantic analysis
|
||||||
std::vector<double> data, dataErr;
|
std::vector<double> data, dataErr;
|
||||||
|
|||||||
@@ -158,11 +158,11 @@ double PFunction::Eval()
|
|||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Evaluates a nil (empty) AST node.
|
* @brief Evaluates a leer (empty) AST node.
|
||||||
*
|
*
|
||||||
* @return Always returns 0.0
|
* @return Always returns 0.0
|
||||||
*/
|
*/
|
||||||
double PFunction::EvalVisitor::operator()(const musrfit::ast::nil&) const
|
double PFunction::EvalVisitor::operator()(const musrfit::ast::leer &) const
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,11 +129,11 @@ class PFunction {
|
|||||||
: fMap(map), fParam(param) {}
|
: fMap(map), fParam(param) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Evaluates a nil/empty AST node.
|
* @brief Evaluates a leer/empty AST node.
|
||||||
* @param AST nil node (unused)
|
* @param AST leer node (unused)
|
||||||
* @return 0.0
|
* @return 0.0
|
||||||
*/
|
*/
|
||||||
double operator()(const musrfit::ast::nil&) const;
|
double operator()(const musrfit::ast::leer&) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Evaluates a numeric literal.
|
* @brief Evaluates a numeric literal.
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ namespace musrfit { namespace ast
|
|||||||
*
|
*
|
||||||
* Used as a placeholder in variant types where no value is present.
|
* Used as a placeholder in variant types where no value is present.
|
||||||
*/
|
*/
|
||||||
struct nil {};
|
struct leer {};
|
||||||
|
|
||||||
// Forward declarations for recursive AST structures
|
// Forward declarations for recursive AST structures
|
||||||
struct expression;
|
struct expression;
|
||||||
@@ -173,7 +173,7 @@ namespace musrfit { namespace ast
|
|||||||
* recursive grammar structures.
|
* recursive grammar structures.
|
||||||
*/
|
*/
|
||||||
typedef boost::variant<
|
typedef boost::variant<
|
||||||
nil ///< Empty placeholder
|
leer ///< Empty placeholder
|
||||||
, double ///< Numeric literal
|
, double ///< Numeric literal
|
||||||
, constant ///< Constant value
|
, constant ///< Constant value
|
||||||
, parameter ///< Parameter reference
|
, parameter ///< Parameter reference
|
||||||
@@ -246,11 +246,11 @@ namespace musrfit { namespace ast
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stream output operator for nil nodes (debugging support).
|
* @brief Stream output operator for leer nodes (debugging support).
|
||||||
* @param out the output stream
|
* @param out the output stream
|
||||||
* @return the output stream for chaining
|
* @return the output stream for chaining
|
||||||
*/
|
*/
|
||||||
inline std::ostream& operator<<(std::ostream& out, nil) { out << std::string("nil"); return out; }
|
inline std::ostream& operator<<(std::ostream& out, leer) { out << std::string("leer"); return out; }
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// Boost.Fusion adaptations to make structures compatible with X3 attribute propagation
|
// Boost.Fusion adaptations to make structures compatible with X3 attribute propagation
|
||||||
|
|||||||
Reference in New Issue
Block a user