improve the doxygen documentation of the var-part of mupp.
This commit is contained in:
@@ -42,40 +42,89 @@
|
||||
namespace mupp
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The annotation handler links the AST to a map of iterator positions
|
||||
// for the purpose of subsequent semantic error handling when the
|
||||
// program is being compiled.
|
||||
/**
|
||||
* @brief The PAnnotation struct links AST nodes to source code positions.
|
||||
*
|
||||
* The annotation handler associates each AST node with its corresponding
|
||||
* iterator position in the source code. This mapping enables accurate error
|
||||
* reporting during semantic analysis and compilation by allowing the error
|
||||
* handler to pinpoint the exact location of errors in the source text.
|
||||
*
|
||||
* The annotation is performed after successful parsing but before semantic
|
||||
* analysis, using Boost.Phoenix function objects integrated with the parser.
|
||||
*
|
||||
* @tparam Iterator the iterator type for traversing the source code (typically std::string::const_iterator)
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Iterator>
|
||||
struct PAnnotation
|
||||
{
|
||||
/// Result type specification required by Boost.Phoenix function protocol
|
||||
template <typename, typename>
|
||||
struct result { typedef void type; };
|
||||
|
||||
std::vector<Iterator>& iters;
|
||||
std::vector<Iterator>& iters; ///< Reference to vector storing iterator positions indexed by AST node IDs
|
||||
|
||||
/**
|
||||
* @brief Constructor that initializes the annotation handler.
|
||||
* @param iters reference to vector that will store iterator positions for each annotated AST node
|
||||
*/
|
||||
PAnnotation(std::vector<Iterator>& iters) : iters(iters) {}
|
||||
|
||||
/**
|
||||
* @brief Helper struct to set ID tags on AST nodes.
|
||||
*
|
||||
* Uses template metaprogramming to selectively assign IDs only to nodes
|
||||
* that inherit from ast::tagged, avoiding overhead for non-tagged nodes.
|
||||
*/
|
||||
struct set_id
|
||||
{
|
||||
typedef void result_type;
|
||||
typedef void result_type; ///< Return type for Boost.Phoenix compatibility
|
||||
|
||||
int id;
|
||||
int id; ///< The ID to assign to tagged AST nodes
|
||||
|
||||
/**
|
||||
* @brief Constructor that stores the ID to be assigned.
|
||||
* @param id the unique identifier corresponding to a source position
|
||||
*/
|
||||
set_id(int id) : id(id) {}
|
||||
|
||||
/**
|
||||
* @brief Dispatches to the appropriate handler based on node type.
|
||||
*
|
||||
* Uses boost::is_base_of to determine at compile time whether the node
|
||||
* inherits from ast::tagged.
|
||||
* @tparam T the AST node type
|
||||
* @param x reference to the AST node to potentially tag
|
||||
*/
|
||||
template <typename T>
|
||||
void operator()(T& x) const
|
||||
{
|
||||
this->dispatch(x, boost::is_base_of<ast::tagged, T>());
|
||||
}
|
||||
|
||||
// This will catch all nodes except those inheriting from ast::tagged
|
||||
/**
|
||||
* @brief No-op handler for non-tagged AST nodes.
|
||||
*
|
||||
* This overload is selected at compile time for nodes that don't
|
||||
* inherit from ast::tagged.
|
||||
* @tparam T the non-tagged AST node type
|
||||
* @param x reference to the AST node (unused)
|
||||
*/
|
||||
template <typename T>
|
||||
void dispatch(T& x, boost::mpl::false_) const
|
||||
{
|
||||
// (no-op) no need for tags
|
||||
}
|
||||
|
||||
// This will catch all nodes inheriting from ast::tagged
|
||||
/**
|
||||
* @brief Assigns ID to tagged AST nodes.
|
||||
*
|
||||
* This overload is selected at compile time for nodes that inherit
|
||||
* from ast::tagged, setting their id field.
|
||||
* @tparam T the tagged AST node type
|
||||
* @param x reference to the AST node whose id field will be set
|
||||
*/
|
||||
template <typename T>
|
||||
void dispatch(T& x, boost::mpl::true_) const
|
||||
{
|
||||
@@ -83,6 +132,14 @@ namespace mupp
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Annotates an operand AST node with its source position.
|
||||
*
|
||||
* Stores the iterator position and assigns a unique ID to the operand node
|
||||
* by applying the set_id visitor to handle different operand variant types.
|
||||
* @param ast reference to the operand AST node to annotate
|
||||
* @param pos iterator pointing to the operand's position in the source code
|
||||
*/
|
||||
void operator()(ast::operand& ast, Iterator pos) const
|
||||
{
|
||||
int id = iters.size();
|
||||
@@ -90,6 +147,14 @@ namespace mupp
|
||||
boost::apply_visitor(set_id(id), ast);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Annotates an assignment AST node with its source position.
|
||||
*
|
||||
* Stores the iterator position and assigns a unique ID to the left-hand
|
||||
* side variable of the assignment.
|
||||
* @param ast reference to the assignment AST node to annotate
|
||||
* @param pos iterator pointing to the assignment's position in the source code
|
||||
*/
|
||||
void operator()(ast::assignment& ast, Iterator pos) const
|
||||
{
|
||||
int id = iters.size();
|
||||
|
||||
@@ -43,119 +43,243 @@
|
||||
namespace mupp { namespace ast
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The AST
|
||||
/**
|
||||
* @brief Abstract Syntax Tree (AST) definitions for the variable parser.
|
||||
*
|
||||
* This namespace defines the complete AST structure used to represent
|
||||
* parsed variable expressions. The AST is built using Boost.Variant for
|
||||
* type-safe unions and Boost.Spirit's automatic AST generation from
|
||||
* grammar rules.
|
||||
*
|
||||
* The AST supports:
|
||||
* - Arithmetic operations: +, -, *, /
|
||||
* - Unary operations: +, -
|
||||
* - Mathematical functions: sin, cos, tan, exp, log, sqrt, etc.
|
||||
* - Power operations: pow(base, exponent)
|
||||
* - Variable declarations and assignments
|
||||
* - Expression evaluation with proper precedence
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Base struct for AST nodes that require position annotation.
|
||||
*
|
||||
* Tagged nodes store an ID that maps to their position in the source code.
|
||||
* This enables accurate error reporting by the error handler. Not all AST
|
||||
* nodes need to be tagged; only those that may generate semantic errors.
|
||||
*/
|
||||
struct tagged
|
||||
{
|
||||
int id; // Used to annotate the AST with the iterator position.
|
||||
// This id is used as a key to a map<int, Iterator>
|
||||
// (not really part of the AST.)
|
||||
int id; ///< ID used as key to map to iterator position in source code (not part of the logical AST structure)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enumeration of arithmetic and unary operators.
|
||||
*
|
||||
* These tokens represent the fundamental operations supported by the
|
||||
* expression evaluator.
|
||||
*/
|
||||
enum optoken
|
||||
{
|
||||
op_plus,
|
||||
op_minus,
|
||||
op_times,
|
||||
op_divide,
|
||||
op_positive,
|
||||
op_negative,
|
||||
op_plus, ///< Addition operator (+)
|
||||
op_minus, ///< Subtraction operator (-)
|
||||
op_times, ///< Multiplication operator (*)
|
||||
op_divide, ///< Division operator (/)
|
||||
op_positive, ///< Unary plus operator (+x)
|
||||
op_negative, ///< Unary minus operator (-x)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enumeration of supported mathematical functions.
|
||||
*
|
||||
* These function identifiers map to standard mathematical operations
|
||||
* evaluated during the semantic analysis phase.
|
||||
*/
|
||||
enum funid
|
||||
{
|
||||
fun_max,
|
||||
fun_min,
|
||||
fun_abs,
|
||||
fun_sin,
|
||||
fun_cos,
|
||||
fun_tan,
|
||||
fun_sinh,
|
||||
fun_cosh,
|
||||
fun_tanh,
|
||||
fun_asin,
|
||||
fun_acos,
|
||||
fun_atan,
|
||||
fun_exp,
|
||||
fun_log,
|
||||
fun_ln,
|
||||
fun_sqrt
|
||||
fun_max, ///< Maximum value function
|
||||
fun_min, ///< Minimum value function
|
||||
fun_abs, ///< Absolute value function
|
||||
fun_sin, ///< Sine function
|
||||
fun_cos, ///< Cosine function
|
||||
fun_tan, ///< Tangent function
|
||||
fun_sinh, ///< Hyperbolic sine function
|
||||
fun_cosh, ///< Hyperbolic cosine function
|
||||
fun_tanh, ///< Hyperbolic tangent function
|
||||
fun_asin, ///< Arcsine function
|
||||
fun_acos, ///< Arccosine function
|
||||
fun_atan, ///< Arctangent function
|
||||
fun_exp, ///< Exponential function
|
||||
fun_log, ///< Base-10 logarithm function
|
||||
fun_ln, ///< Natural logarithm function
|
||||
fun_sqrt ///< Square root function
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents an empty/null AST node.
|
||||
*
|
||||
* Used as a placeholder in variant types where no value is present.
|
||||
*/
|
||||
struct nil {};
|
||||
|
||||
// Forward declarations for recursive AST structures
|
||||
struct unary;
|
||||
struct expression;
|
||||
struct function;
|
||||
struct power;
|
||||
|
||||
/**
|
||||
* @brief Represents a variable in an expression.
|
||||
*
|
||||
* Variables are identifiers prefixed with '$' in the source code.
|
||||
* They reference parameters from the collection or previously declared
|
||||
* variables. Inherits from tagged to support error reporting.
|
||||
*/
|
||||
struct variable : tagged
|
||||
{
|
||||
/**
|
||||
* @brief Constructor for variable node.
|
||||
* @param name the variable name (without the leading '$')
|
||||
*/
|
||||
variable(std::string const& name = "") : name(name) {}
|
||||
std::string name;
|
||||
std::string name; ///< Variable name without the '$' prefix
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Variant type representing any operand in an expression.
|
||||
*
|
||||
* An operand can be a literal number, variable, function call, power
|
||||
* operation, unary expression, or parenthesized expression. The variant
|
||||
* uses recursive_wrapper for types that contain expressions to handle
|
||||
* recursive grammar structures.
|
||||
*/
|
||||
typedef boost::variant<
|
||||
nil
|
||||
, double
|
||||
, variable
|
||||
, boost::recursive_wrapper<function>
|
||||
, boost::recursive_wrapper<power>
|
||||
, boost::recursive_wrapper<unary>
|
||||
, boost::recursive_wrapper<expression>
|
||||
nil ///< Empty placeholder
|
||||
, double ///< Numeric literal
|
||||
, variable ///< Variable reference
|
||||
, boost::recursive_wrapper<function> ///< Function call (recursive)
|
||||
, boost::recursive_wrapper<power> ///< Power operation (recursive)
|
||||
, boost::recursive_wrapper<unary> ///< Unary operation (recursive)
|
||||
, boost::recursive_wrapper<expression> ///< Parenthesized expression (recursive)
|
||||
>
|
||||
operand;
|
||||
|
||||
/**
|
||||
* @brief Represents a unary operation applied to an operand.
|
||||
*
|
||||
* Examples: -x, +y
|
||||
*/
|
||||
struct unary
|
||||
{
|
||||
optoken operator_;
|
||||
operand operand_;
|
||||
optoken operator_; ///< The unary operator (positive or negative)
|
||||
operand operand_; ///< The operand the operator is applied to
|
||||
};
|
||||
|
||||
/**
|
||||
* @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_;
|
||||
operand operand_;
|
||||
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;
|
||||
std::list<operation> rest;
|
||||
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: sin($x), sqrt($y), abs($z)
|
||||
*/
|
||||
struct function
|
||||
{
|
||||
funid func_id;
|
||||
expression arg;
|
||||
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
|
||||
{
|
||||
expression base;
|
||||
expression pow;
|
||||
expression base; ///< The base expression
|
||||
expression pow; ///< The exponent expression
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents an assignment statement.
|
||||
*
|
||||
* Syntax: var_name = expression
|
||||
* Assigns the result of evaluating the right-hand expression to an
|
||||
* existing variable.
|
||||
*/
|
||||
struct assignment
|
||||
{
|
||||
variable lhs;
|
||||
expression rhs;
|
||||
variable lhs; ///< The left-hand side variable being assigned to
|
||||
expression rhs; ///< The right-hand side expression to evaluate
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents a variable declaration with optional initialization.
|
||||
*
|
||||
* Syntax: var var_name = expression (with initialization)
|
||||
* var var_name (without initialization)
|
||||
* Declares a new variable and optionally initializes it with an expression.
|
||||
*/
|
||||
struct variable_declaration
|
||||
{
|
||||
variable lhs;
|
||||
boost::optional<expression> rhs;
|
||||
variable lhs; ///< The variable being declared
|
||||
boost::optional<expression> rhs; ///< Optional initialization expression
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Variant type representing a single statement.
|
||||
*
|
||||
* A statement can be either a variable declaration or an assignment.
|
||||
*/
|
||||
typedef boost::variant<
|
||||
variable_declaration
|
||||
, assignment>
|
||||
variable_declaration ///< Variable declaration statement
|
||||
, assignment> ///< Assignment statement
|
||||
statement;
|
||||
|
||||
/**
|
||||
* @brief Type alias for a list of statements forming a program.
|
||||
*
|
||||
* The parser builds this list from the input, and the semantic analyzer
|
||||
* processes it sequentially.
|
||||
*/
|
||||
typedef std::list<statement> statement_list;
|
||||
|
||||
// print functions for debugging
|
||||
/**
|
||||
* @brief Stream output operator for nil nodes (debugging support).
|
||||
* @param out the output stream
|
||||
* @return the output stream for chaining
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, nil) { out << std::string("nil"); return out; }
|
||||
|
||||
/**
|
||||
* @brief Stream output operator for variable nodes (debugging support).
|
||||
* @param out the output stream
|
||||
* @param var the variable node to output
|
||||
* @return the output stream for chaining
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, variable const& var) { out << var.name; return out; }
|
||||
}}
|
||||
|
||||
|
||||
@@ -41,17 +41,49 @@
|
||||
namespace mupp
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The error handler
|
||||
/**
|
||||
* @brief The PErrorHandler struct handles parsing and semantic errors.
|
||||
*
|
||||
* This error handler logs detailed error information to a file, including
|
||||
* the error message, line number, source line, and a visual pointer to the
|
||||
* error position. It integrates with the Boost.Spirit parser error handling
|
||||
* mechanism and works in conjunction with the PAnnotation handler to map
|
||||
* AST node IDs back to source positions.
|
||||
*
|
||||
* Errors are appended to: ~/.musrfit/mupp/mupp_err.log
|
||||
*
|
||||
* @tparam Iterator the iterator type for the source code (typically std::string::const_iterator)
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Iterator>
|
||||
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.
|
||||
* @param first iterator pointing to the beginning of the source code
|
||||
* @param last iterator pointing to the end of the source code
|
||||
*/
|
||||
PErrorHandler(Iterator first, Iterator last)
|
||||
: first(first), last(last) {}
|
||||
|
||||
/**
|
||||
* @brief Function call operator that logs an error to file.
|
||||
*
|
||||
* Determines the line number and position of the error, formats a
|
||||
* user-friendly error message with a visual indicator (^~~), and appends
|
||||
* it to the error log file. Handles both mid-file errors and unexpected
|
||||
* end-of-file errors.
|
||||
*
|
||||
* @tparam Message the message type (typically std::string)
|
||||
* @tparam What the expected element type (typically std::string)
|
||||
* @param message the error message prefix (e.g., "**ERROR** Expecting ")
|
||||
* @param what description of what was expected at the error position
|
||||
* @param err_pos iterator pointing to the position where the error occurred
|
||||
*/
|
||||
template <typename Message, typename What>
|
||||
void operator()(
|
||||
Message const& message,
|
||||
@@ -76,6 +108,16 @@ namespace mupp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds the start of the line containing an error and computes line number.
|
||||
*
|
||||
* Scans from the beginning of the source to the error position, counting
|
||||
* line breaks (CR, LF, or CRLF) to determine the line number.
|
||||
*
|
||||
* @param err_pos iterator pointing to the error position
|
||||
* @param line output parameter that will contain the 1-based line number
|
||||
* @return iterator pointing to the start of the line containing the error
|
||||
*/
|
||||
Iterator get_pos(Iterator err_pos, int& line) const
|
||||
{
|
||||
line = 1;
|
||||
@@ -99,6 +141,14 @@ namespace mupp
|
||||
return line_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts the complete line containing an error.
|
||||
*
|
||||
* Returns the substring from the start of the line to the next line break.
|
||||
*
|
||||
* @param err_pos iterator pointing to the start of the line
|
||||
* @return string containing the complete line (without line break characters)
|
||||
*/
|
||||
std::string get_line(Iterator err_pos) const
|
||||
{
|
||||
Iterator i = err_pos;
|
||||
@@ -108,9 +158,9 @@ namespace mupp
|
||||
return std::string(err_pos, i);
|
||||
}
|
||||
|
||||
Iterator first;
|
||||
Iterator last;
|
||||
std::vector<Iterator> iters;
|
||||
Iterator first; ///< Iterator to the beginning of the source code
|
||||
Iterator last; ///< Iterator to the end of the source code
|
||||
std::vector<Iterator> iters; ///< Vector mapping AST node IDs to source positions (used by PAnnotation)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -59,22 +59,51 @@ namespace mupp { namespace parser
|
||||
namespace ascii = boost::spirit::ascii;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The expression grammar
|
||||
/**
|
||||
* @brief The PExpression grammar for parsing mathematical expressions.
|
||||
*
|
||||
* This Boost.Spirit grammar defines the syntax for parsing arithmetic
|
||||
* expressions with proper operator precedence and associativity:
|
||||
* - Primary expressions: numbers, variables, functions, parenthesized expressions
|
||||
* - Unary operators: +, - (highest precedence)
|
||||
* - Multiplicative operators: *, / (medium precedence)
|
||||
* - Additive operators: +, - (lowest precedence)
|
||||
*
|
||||
* The grammar supports:
|
||||
* - Numeric literals (double)
|
||||
* - Variable identifiers (prefixed with '$')
|
||||
* - Mathematical functions: sin, cos, tan, exp, log, sqrt, etc.
|
||||
* - Power function: pow(base, exponent)
|
||||
* - Arithmetic operations with standard precedence
|
||||
*
|
||||
* Example expressions:
|
||||
* - 3.14 * $radius
|
||||
* - sin($theta) + cos($phi)
|
||||
* - 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, multiplicative_op, unary_op;
|
||||
qi::symbols<char, ast::funid> fun_tok;
|
||||
qi::symbols<char, ast::optoken> additive_op; ///< Symbol table for additive operators (+, -)
|
||||
qi::symbols<char, ast::optoken> multiplicative_op; ///< Symbol table for multiplicative operators (*, /)
|
||||
qi::symbols<char, ast::optoken> unary_op; ///< Symbol table for unary operators (+, -)
|
||||
qi::symbols<char, ast::funid> fun_tok; ///< Symbol table for function names
|
||||
|
||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > expr;
|
||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > additive_expr;
|
||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > multiplicative_expr;
|
||||
qi::rule<Iterator, ast::operand(), PSkipper<Iterator> > unary_expr;
|
||||
qi::rule<Iterator, ast::operand(), PSkipper<Iterator> > primary_expr;
|
||||
qi::rule<Iterator, std::string(), PSkipper<Iterator> > identifier;
|
||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > expr; ///< Top-level expression rule
|
||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > additive_expr; ///< Additive expression rule (lowest precedence)
|
||||
qi::rule<Iterator, ast::expression(), PSkipper<Iterator> > multiplicative_expr; ///< Multiplicative expression rule (medium precedence)
|
||||
qi::rule<Iterator, ast::operand(), PSkipper<Iterator> > unary_expr; ///< Unary expression rule
|
||||
qi::rule<Iterator, ast::operand(), PSkipper<Iterator> > primary_expr; ///< Primary expression rule (highest precedence)
|
||||
qi::rule<Iterator, std::string(), PSkipper<Iterator> > identifier; ///< Identifier rule (variables prefixed with '$')
|
||||
};
|
||||
}}
|
||||
|
||||
|
||||
@@ -8,6 +8,19 @@
|
||||
Based on Joel de Guzman example on calc7,
|
||||
see https://github.com/boostorg/spirit
|
||||
|
||||
This file contains the implementation (definition) of the PExpression
|
||||
template grammar. It defines the actual grammar rules and their semantic
|
||||
actions using Boost.Spirit Qi.
|
||||
|
||||
The grammar implements expression parsing with proper operator precedence:
|
||||
- Primary expressions (literals, variables, functions)
|
||||
- Unary operations (+, -)
|
||||
- Multiplicative operations (*, /)
|
||||
- Additive operations (+, -)
|
||||
|
||||
Symbol tables are populated with operators and function names, and error
|
||||
handling is integrated for reporting parse failures.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
@@ -48,39 +48,128 @@
|
||||
|
||||
namespace mupp { namespace prog {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Variable Handler
|
||||
/**
|
||||
* @brief The PVarHandler class manages variable data during evaluation.
|
||||
*
|
||||
* This class stores a variable's name, values, and associated errors.
|
||||
* Variables are vector-valued, where each element corresponds to data
|
||||
* from a different run in the collection. The values and errors vectors
|
||||
* must have the same size for the variable to be valid.
|
||||
*
|
||||
* This class is used by both the semantic analyzer (PProgram) to track
|
||||
* declared variables and by the evaluator (PProgEval) to store and
|
||||
* retrieve computed results.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
class PVarHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor initializing an unnamed variable.
|
||||
*/
|
||||
PVarHandler() : fName("") {}
|
||||
|
||||
/**
|
||||
* @brief Sets the variable name.
|
||||
* @param name the name to assign to this variable
|
||||
*/
|
||||
void SetName(std::string name) { fName = name; }
|
||||
|
||||
/**
|
||||
* @brief Sets all values for this variable.
|
||||
* @param dval vector of values to assign
|
||||
*/
|
||||
void SetValue(std::vector<double> &dval) { fValue = dval; }
|
||||
|
||||
/**
|
||||
* @brief Sets a single value at a specific index.
|
||||
* @param dval the value to set
|
||||
* @param idx the index at which to set the value
|
||||
*/
|
||||
void SetValue(double dval, unsigned idx);
|
||||
|
||||
/**
|
||||
* @brief Sets all error values for this variable.
|
||||
* @param dval vector of error values to assign
|
||||
*/
|
||||
void SetError(std::vector<double> &dval) { fError = dval; }
|
||||
|
||||
/**
|
||||
* @brief Sets a single error value at a specific index.
|
||||
* @param dval the error value to set
|
||||
* @param idx the index at which to set the error value
|
||||
*/
|
||||
void SetError(double dval, unsigned idx);
|
||||
|
||||
/**
|
||||
* @brief Gets the variable name.
|
||||
* @return the name of this variable
|
||||
*/
|
||||
std::string GetName() { return fName; }
|
||||
|
||||
/**
|
||||
* @brief Gets the size of the variable data.
|
||||
* @return the size if value and error vectors match, 0 otherwise
|
||||
*/
|
||||
unsigned int GetSize() { return (fValue.size() == fError.size()) ? fValue.size() : 0; }
|
||||
|
||||
/**
|
||||
* @brief Gets all values.
|
||||
* @return vector of all values
|
||||
*/
|
||||
std::vector<double> GetValue() { return fValue; }
|
||||
|
||||
/**
|
||||
* @brief Gets a single value at a specific index.
|
||||
* @param idx the index of the value to retrieve
|
||||
* @return the value at the specified index, or 0 if index is out of range
|
||||
*/
|
||||
double GetValue(unsigned int idx) { return (idx < fValue.size()) ? fValue[idx] : 0; }
|
||||
|
||||
/**
|
||||
* @brief Gets all error values.
|
||||
* @return vector of all error values
|
||||
*/
|
||||
std::vector<double> GetError() { return fError; }
|
||||
|
||||
/**
|
||||
* @brief Gets a single error value at a specific index.
|
||||
* @param idx the index of the error value to retrieve
|
||||
* @return the error value at the specified index, or 0 if index is out of range
|
||||
*/
|
||||
double GetError(unsigned int idx) { return (idx < fError.size()) ? fError[idx] : 0; }
|
||||
|
||||
private:
|
||||
std::string fName;
|
||||
std::vector<double> fValue;
|
||||
std::vector<double> fError;
|
||||
std::string fName; ///< Variable name
|
||||
std::vector<double> fValue; ///< Vector of values (one per run)
|
||||
std::vector<double> fError; ///< Vector of error values (one per run)
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Program Semantic Analysis
|
||||
/**
|
||||
* @brief The PProgram struct performs semantic analysis on the AST.
|
||||
*
|
||||
* This visitor pattern struct traverses the AST generated by the parser
|
||||
* and performs semantic checks:
|
||||
* - Verifies that variables are declared before use
|
||||
* - Prevents duplicate variable declarations
|
||||
* - Validates function and operator usage
|
||||
* - Resolves variable references and position-based lookups
|
||||
*
|
||||
* After successful semantic analysis, the variable table can be used by
|
||||
* PProgEval for expression evaluation. Semantic errors are reported via
|
||||
* the error handler with source position information.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
struct PProgram
|
||||
{
|
||||
typedef bool result_type;
|
||||
typedef bool result_type; ///< Return type for all visitor methods
|
||||
|
||||
/**
|
||||
* @brief Constructor that sets up the error handler.
|
||||
* @tparam PErrorHandler the error handler type
|
||||
* @param error_handler_ reference to the error handler for reporting semantic errors
|
||||
*/
|
||||
template <typename PErrorHandler>
|
||||
PProgram(PErrorHandler& error_handler_)
|
||||
{
|
||||
@@ -91,67 +180,278 @@ namespace mupp { namespace prog {
|
||||
"**ERROR** ", _2, phx::cref(error_handler_.iters)[_1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Visitor for nil AST nodes (should never be called).
|
||||
* @return always false (assertion failure)
|
||||
*/
|
||||
bool operator()(ast::nil) { BOOST_ASSERT(0); return false; }
|
||||
|
||||
/**
|
||||
* @brief Visitor for numeric literal nodes.
|
||||
* @param x the numeric value
|
||||
* @return true (literals are always valid)
|
||||
*/
|
||||
bool operator()(double x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for assignment statements.
|
||||
* @param x the assignment AST node
|
||||
* @return true if variable exists and RHS is valid, false otherwise
|
||||
*/
|
||||
bool operator()(ast::assignment const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for expression nodes.
|
||||
* @param x the expression AST node
|
||||
* @return true if all operands and operations are valid, false otherwise
|
||||
*/
|
||||
bool operator()(ast::expression const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for function call nodes.
|
||||
* @param x the function AST node
|
||||
* @return true if function is valid and argument is valid, false otherwise
|
||||
*/
|
||||
bool operator()(ast::function const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for binary operation nodes.
|
||||
* @param x the operation AST node
|
||||
* @return true if operation and operand are valid, false otherwise
|
||||
*/
|
||||
bool operator()(ast::operation const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for power operation nodes.
|
||||
* @param x the power AST node
|
||||
* @return true if base and exponent are valid, false otherwise
|
||||
*/
|
||||
bool operator()(ast::power const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for statement nodes (variant wrapper).
|
||||
* @param x the statement AST node
|
||||
* @return result of visiting the underlying statement type
|
||||
*/
|
||||
bool operator()(ast::statement const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for statement lists (program entry point).
|
||||
* @param x the statement list AST node
|
||||
* @return true if all statements are valid, false if any statement fails
|
||||
*/
|
||||
bool operator()(ast::statement_list const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for unary operation nodes.
|
||||
* @param x the unary AST node
|
||||
* @return true if operator and operand are valid, false otherwise
|
||||
*/
|
||||
bool operator()(ast::unary const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for variable reference nodes.
|
||||
* @param x the variable AST node
|
||||
* @return true if variable is declared, false otherwise
|
||||
*/
|
||||
bool operator()(ast::variable const &x);
|
||||
|
||||
/**
|
||||
* @brief Visitor for variable declaration nodes.
|
||||
* @param x the variable declaration AST node
|
||||
* @return true if declaration is valid and RHS (if present) is valid, false otherwise
|
||||
*/
|
||||
bool operator()(ast::variable_declaration const &x);
|
||||
|
||||
/**
|
||||
* @brief Injects predefined variable values from collection data.
|
||||
* @param name the variable name
|
||||
* @param val vector of values for this variable
|
||||
* @param err vector of error values for this variable
|
||||
*/
|
||||
void add_predef_var_values(const std::string &name,
|
||||
std::vector<double> &val,
|
||||
std::vector<double> &err);
|
||||
|
||||
/**
|
||||
* @brief Adds a variable to the symbol table.
|
||||
* @param name the variable name to add
|
||||
*/
|
||||
void add_var(std::string const& name);
|
||||
|
||||
/**
|
||||
* @brief Checks if a variable exists in the symbol table.
|
||||
* @param name the variable name to find (with or without leading '$')
|
||||
* @return true if variable exists, false otherwise
|
||||
*/
|
||||
bool find_var(std::string const &name);
|
||||
|
||||
/**
|
||||
* @brief Finds a variable and returns its index.
|
||||
* @param name the variable name to find (with or without leading '$')
|
||||
* @param idx output parameter for the variable index
|
||||
* @return true if variable exists, false otherwise
|
||||
*/
|
||||
bool find_var(std::string const &name, unsigned int &idx);
|
||||
|
||||
/**
|
||||
* @brief Converts position-based variable reference to variable name.
|
||||
*
|
||||
* Supports syntax like $0, $1, etc. to reference variables by position.
|
||||
* @param name the variable reference (name or position number)
|
||||
* @param ok output parameter indicating whether conversion succeeded
|
||||
* @return the resolved variable name, or "??" if position is out of range
|
||||
*/
|
||||
std::string pos_to_var(std::string const &name, bool &ok);
|
||||
|
||||
/**
|
||||
* @brief Gets all variables from the symbol table.
|
||||
* @return vector of all variable handlers
|
||||
*/
|
||||
std::vector<PVarHandler> getVars() { return fVariable; }
|
||||
|
||||
private:
|
||||
std::vector<PVarHandler> fVariable;
|
||||
std::map<int, std::string> fVarPos;
|
||||
std::vector<PVarHandler> fVariable; ///< Symbol table of declared variables
|
||||
std::map<int, std::string> fVarPos; ///< Map from position index to variable name
|
||||
|
||||
boost::function<
|
||||
void(int tag, std::string const& what)>
|
||||
error_handler;
|
||||
error_handler; ///< Error handler function for reporting semantic errors
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Program Evaluation
|
||||
/**
|
||||
* @brief The PProgEval struct evaluates expressions using the AST.
|
||||
*
|
||||
* This visitor pattern struct traverses the AST and computes numerical
|
||||
* results for all variables. It operates on vector-valued variables where
|
||||
* each vector element corresponds to a different run in the collection.
|
||||
*
|
||||
* The evaluator:
|
||||
* - Evaluates arithmetic operations element-wise on vectors
|
||||
* - Computes mathematical functions on each vector element
|
||||
* - Handles both regular variables and error variables (suffixed with 'Err')
|
||||
* - Stores results back into the variable table
|
||||
*
|
||||
* After evaluation, variable values and errors can be extracted using
|
||||
* getVar() for use in the GUI.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
struct PProgEval
|
||||
{
|
||||
typedef std::vector<double> result_type;
|
||||
typedef std::vector<double> result_type; ///< Return type for all visitor methods (vector of values)
|
||||
|
||||
/**
|
||||
* @brief Constructor that initializes the evaluator with variables.
|
||||
* @param var vector of variable handlers from semantic analysis
|
||||
*/
|
||||
PProgEval(std::vector<PVarHandler> var) : fVariable(var) {}
|
||||
|
||||
/**
|
||||
* @brief Evaluates a nil node (should never be called).
|
||||
* @return zero-filled vector
|
||||
*/
|
||||
std::vector<double> operator()(ast::nil);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a numeric literal.
|
||||
* @param x the numeric value
|
||||
* @return vector filled with the literal value
|
||||
*/
|
||||
std::vector<double> operator()(double x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates an assignment statement.
|
||||
* @param x the assignment AST node
|
||||
* @return the computed RHS values, also stored in the variable
|
||||
*/
|
||||
std::vector<double> operator()(ast::assignment const &x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates an expression.
|
||||
* @param x the expression AST node
|
||||
* @return vector of computed values
|
||||
*/
|
||||
std::vector<double> operator()(ast::expression const &x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a function call.
|
||||
* @param x the function AST node
|
||||
* @return vector of function results applied element-wise
|
||||
*/
|
||||
std::vector<double> operator()(ast::function const &x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a binary operation.
|
||||
* @param x the operation AST node
|
||||
* @param lhs vector of left-hand side values
|
||||
* @return vector of operation results applied element-wise
|
||||
*/
|
||||
std::vector<double> operator()(ast::operation const &x, std::vector<double> lhs);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a power operation.
|
||||
* @param x the power AST node
|
||||
* @return vector of pow(base, exponent) computed element-wise
|
||||
*/
|
||||
std::vector<double> operator()(ast::power const &x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a statement.
|
||||
* @param x the statement AST node
|
||||
* @return zero-filled vector (statements have side effects only)
|
||||
*/
|
||||
std::vector<double> operator()(ast::statement const &x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a statement list (program entry point).
|
||||
* @param x the statement list AST node
|
||||
* @return zero-filled vector (evaluation has side effects on variables)
|
||||
*/
|
||||
std::vector<double> operator()(ast::statement_list const &x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a unary operation.
|
||||
* @param x the unary AST node
|
||||
* @return vector of unary operation results applied element-wise
|
||||
*/
|
||||
std::vector<double> operator()(ast::unary const &x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a variable reference.
|
||||
* @param x the variable AST node
|
||||
* @return vector of variable values (or errors for variables ending with 'Err')
|
||||
*/
|
||||
std::vector<double> operator()(ast::variable const &x);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a variable declaration.
|
||||
* @param x the variable declaration AST node
|
||||
* @return vector of initialization values (or predefined values for injected variables)
|
||||
*/
|
||||
std::vector<double> operator()(ast::variable_declaration const &x);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a variable by name after evaluation.
|
||||
* @param name the variable name to find
|
||||
* @param ok output parameter indicating whether variable was found
|
||||
* @return the variable handler, or the first variable if not found
|
||||
*/
|
||||
PVarHandler getVar(const std::string name, bool &ok);
|
||||
|
||||
/**
|
||||
* @brief Prints all variable results to standard output (debugging).
|
||||
*/
|
||||
void print_result();
|
||||
|
||||
private:
|
||||
std::vector<PVarHandler> fVariable;
|
||||
std::vector<PVarHandler> fVariable; ///< Variable table with values and errors
|
||||
|
||||
/**
|
||||
* @brief Finds a variable index by name.
|
||||
* @param name the variable name (with or without leading '$')
|
||||
* @return the index of the variable, or 0 if not found
|
||||
*/
|
||||
unsigned int find_var(std::string const &name);
|
||||
};
|
||||
}}
|
||||
|
||||
@@ -41,11 +41,38 @@ namespace mupp { namespace parser
|
||||
namespace ascii = boost::spirit::ascii;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The skipper grammar
|
||||
/**
|
||||
* @brief The PSkipper grammar for skipping whitespace and comments.
|
||||
*
|
||||
* This grammar defines what the parser should skip (ignore) between tokens.
|
||||
* It handles:
|
||||
* - Whitespace: spaces, tabs, carriage returns, line feeds
|
||||
* - C-style block comments: /* comment * /
|
||||
* - Single-line comments: % comment, # comment, // comment
|
||||
*
|
||||
* The skipper is used automatically by the parser between all grammar rules,
|
||||
* allowing flexible formatting and documentation of input expressions.
|
||||
*
|
||||
* Example valid comments:
|
||||
* @code
|
||||
* var x = $y + 1.0 // this is a comment
|
||||
* var z = $x * 2.0 # another comment
|
||||
* var a = $z / 3.0 % yet another comment
|
||||
* /* This is a
|
||||
* multi-line comment * /
|
||||
* @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_;
|
||||
@@ -63,8 +90,8 @@ namespace mupp { namespace parser
|
||||
;
|
||||
}
|
||||
|
||||
qi::rule<Iterator> single_line_comment;
|
||||
qi::rule<Iterator> start;
|
||||
qi::rule<Iterator> single_line_comment; ///< Rule for single-line comments (%, #, //)
|
||||
qi::rule<Iterator> start; ///< Top-level skipper rule
|
||||
};
|
||||
}}
|
||||
|
||||
|
||||
@@ -38,18 +38,45 @@
|
||||
namespace mupp { namespace parser
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The statement grammar
|
||||
/**
|
||||
* @brief The PStatement grammar for parsing variable statements.
|
||||
*
|
||||
* This grammar defines the syntax for variable declarations and assignments.
|
||||
* It builds on top of the PExpression grammar to parse complete statements
|
||||
* that form a variable definition program.
|
||||
*
|
||||
* Supported statement types:
|
||||
* - Variable declaration: var <identifier> = <expression>
|
||||
* - Variable declaration without initialization: var <identifier>
|
||||
* - Assignment: <identifier> = <expression>
|
||||
*
|
||||
* Example statements:
|
||||
* @code
|
||||
* var sigma = pow(abs(pow($T1,2.0)-pow(0.11,2.0)),0.5)
|
||||
* var sigmaErr = 0.01
|
||||
* result = $sigma * 2.0
|
||||
* @endcode
|
||||
*
|
||||
* The grammar parses a statement list (one or more statements) and builds
|
||||
* 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;
|
||||
qi::rule<Iterator, ast::statement_list(), PSkipper<Iterator> > statement_list;
|
||||
qi::rule<Iterator, ast::variable_declaration(), PSkipper<Iterator> > variable_declaration;
|
||||
qi::rule<Iterator, ast::assignment(), PSkipper<Iterator> > assignment;
|
||||
qi::rule<Iterator, std::string(), PSkipper<Iterator> > identifier;
|
||||
PExpression<Iterator> expr; ///< Expression grammar for parsing right-hand sides
|
||||
qi::rule<Iterator, ast::statement_list(), PSkipper<Iterator> > statement_list; ///< Rule for parsing a list of statements
|
||||
qi::rule<Iterator, ast::variable_declaration(), PSkipper<Iterator> > variable_declaration; ///< Rule for variable declarations
|
||||
qi::rule<Iterator, ast::assignment(), PSkipper<Iterator> > assignment; ///< Rule for assignment statements
|
||||
qi::rule<Iterator, std::string(), PSkipper<Iterator> > identifier; ///< Rule for identifiers (without '$' prefix)
|
||||
};
|
||||
}}
|
||||
|
||||
|
||||
@@ -8,6 +8,18 @@
|
||||
Based on Joel de Guzman example on calc7,
|
||||
see https://github.com/boostorg/spirit
|
||||
|
||||
This file contains the implementation (definition) of the PStatement
|
||||
template grammar. It defines the grammar rules for parsing variable
|
||||
declarations and assignments using Boost.Spirit Qi.
|
||||
|
||||
The grammar supports:
|
||||
- Variable declarations: var <identifier> = <expression>
|
||||
- Variable declarations without initialization: var <identifier>
|
||||
- Assignments: <identifier> = <expression>
|
||||
|
||||
The grammar integrates with PExpression for parsing right-hand side
|
||||
expressions and includes error handling and AST annotation.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
@@ -39,30 +39,125 @@
|
||||
#include "PAst.hpp"
|
||||
#include "PProgram.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief The PVarHandler class handles variable parsing, evaluation, and data management.
|
||||
*
|
||||
* This class provides the main interface for parsing variable definition strings,
|
||||
* evaluating expressions using the Boost.Spirit parser framework, and managing
|
||||
* the resulting computed values and errors. It integrates with PmuppCollection
|
||||
* to access run data and inject predefined variables for use in expressions.
|
||||
*
|
||||
* The variable syntax supports:
|
||||
* - Variable declarations: var <name> = <expression>
|
||||
* - Identifiers (prefixed with '$'): $varName
|
||||
* - Mathematical functions: sin, cos, tan, exp, log, sqrt, pow, etc.
|
||||
* - Arithmetic operations: +, -, *, /
|
||||
* - Error variables (suffixed with 'Err'): must be defined for each variable
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* PmuppCollection *coll = ...;
|
||||
* std::string expr = "var sigma = pow(abs(pow($T1,2.0)-pow(0.11,2.0)),0.5)";
|
||||
* PVarHandler handler(coll, expr, "sigma");
|
||||
* if (handler.isValid()) {
|
||||
* std::vector<double> values = handler.getValues();
|
||||
* std::vector<double> errors = handler.getErrors();
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class PVarHandler {
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*
|
||||
* Creates an invalid PVarHandler instance with null pointers and empty strings.
|
||||
*/
|
||||
PVarHandler();
|
||||
|
||||
/**
|
||||
* @brief Constructor that parses and evaluates a variable expression.
|
||||
*
|
||||
* Parses the provided expression string, performs semantic analysis, injects
|
||||
* predefined variables from the collection, evaluates the expression, and
|
||||
* stores the results.
|
||||
*
|
||||
* @param coll pointer to the PmuppCollection containing run data and parameters
|
||||
* @param parse_str the variable definition string to parse (e.g., "var x = $T1 + 1.0")
|
||||
* @param var_name optional variable name to extract from the evaluation results; if empty, only parsing/checking is performed
|
||||
*/
|
||||
PVarHandler(PmuppCollection *coll, std::string parse_str, std::string var_name="");
|
||||
|
||||
/**
|
||||
* @brief Checks if the parsing and evaluation were successful.
|
||||
* @return true if the expression was parsed and evaluated successfully, false otherwise
|
||||
*/
|
||||
bool isValid() { return fIsValid; }
|
||||
|
||||
/**
|
||||
* @brief Gets the collection name.
|
||||
* @return QString containing the name of the associated collection
|
||||
*/
|
||||
QString getCollName() { return fColl->GetName(); }
|
||||
|
||||
/**
|
||||
* @brief Gets the variable name.
|
||||
* @return QString containing the variable name
|
||||
*/
|
||||
QString getVarName() { return QString(fVarName.c_str()); }
|
||||
|
||||
/**
|
||||
* @brief Gets the computed values for the variable.
|
||||
* @return vector of double values computed from the expression evaluation
|
||||
*/
|
||||
std::vector<double> getValues();
|
||||
|
||||
/**
|
||||
* @brief Gets the computed errors for the variable.
|
||||
* @return vector of double error values computed from the expression evaluation
|
||||
*/
|
||||
std::vector<double> getErrors();
|
||||
|
||||
private:
|
||||
PmuppCollection *fColl; ///< collection needed for parsing and evaluation
|
||||
std::string fParseStr; ///< the variable input to be parsed
|
||||
std::string fVarName; ///< variable name
|
||||
mupp::prog::PVarHandler fVar; ///< values of the evaluation
|
||||
PmuppCollection *fColl; ///< pointer to collection containing run data needed for parsing and evaluation
|
||||
std::string fParseStr; ///< the variable input string to be parsed
|
||||
std::string fVarName; ///< name of the variable to extract from evaluation results
|
||||
mupp::prog::PVarHandler fVar; ///< variable handler storing the computed values and errors
|
||||
|
||||
bool fIsValid;
|
||||
mupp::ast::statement_list fAst; ///< the AST
|
||||
bool fIsValid; ///< flag indicating whether parsing and evaluation succeeded
|
||||
mupp::ast::statement_list fAst; ///< Abstract Syntax Tree generated from parsing
|
||||
|
||||
/**
|
||||
* @brief Injects predefined variables from the collection into the AST.
|
||||
*
|
||||
* Extracts all parameter names from the collection's first run and creates
|
||||
* variable declarations for both the parameter names and their corresponding
|
||||
* error variables (suffixed with 'Err'). These declarations are prepended
|
||||
* to the AST before evaluation.
|
||||
*/
|
||||
void injectPredefVariables();
|
||||
|
||||
/**
|
||||
* @brief Gets the variable name at a specific parameter index.
|
||||
* @param idx the parameter index in the collection
|
||||
* @return variable name as a string, or "??" if index is out of range
|
||||
*/
|
||||
std::string getVarName(int idx);
|
||||
|
||||
/**
|
||||
* @brief Gets the data values for a specific parameter across all runs.
|
||||
* @param idx the parameter index in the collection
|
||||
* @return vector of data values from all runs for the specified parameter
|
||||
*/
|
||||
std::vector<double> getData(int idx);
|
||||
|
||||
/**
|
||||
* @brief Gets the error values for a specific parameter across all runs.
|
||||
*
|
||||
* Computes the geometric mean of positive and negative errors for each run.
|
||||
* @param idx the parameter index in the collection
|
||||
* @return vector of error values (geometric mean of pos/neg errors) from all runs
|
||||
*/
|
||||
std::vector<double> getDataErr(int idx);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/***************************************************************************
|
||||
|
||||
PExpression.hpp
|
||||
PExpression.cpp
|
||||
|
||||
Author: Andreas Suter
|
||||
e-mail: andreas.suter@psi.ch
|
||||
@@ -8,6 +8,11 @@
|
||||
Based on Joel de Guzman example on calc7,
|
||||
see https://github.com/boostorg/spirit
|
||||
|
||||
This file explicitly instantiates the PExpression template grammar for
|
||||
std::string::const_iterator. Template instantiation in a separate
|
||||
compilation unit reduces compile times and allows the grammar
|
||||
implementation to be hidden from clients.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
@@ -8,6 +8,24 @@
|
||||
Based on Joel de Guzman example on calc7,
|
||||
see https://github.com/boostorg/spirit
|
||||
|
||||
This file implements the semantic analysis (PProgram) and evaluation
|
||||
(PProgEval) visitor classes for the variable expression AST.
|
||||
|
||||
PProgram performs semantic checks:
|
||||
- Variable declaration validation
|
||||
- Variable reference resolution
|
||||
- Type and operator validation
|
||||
- Building the symbol table
|
||||
|
||||
PProgEval performs expression evaluation:
|
||||
- Element-wise vector operations
|
||||
- Mathematical function evaluation
|
||||
- Variable value and error computation
|
||||
- Result storage in variable handlers
|
||||
|
||||
Both classes use the visitor pattern to traverse the AST generated by
|
||||
the parser and process each node type appropriately.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
Based on Joel de Guzman example on calc7,
|
||||
see https://github.com/boostorg/spirit
|
||||
|
||||
This file explicitly instantiates the PStatement template grammar for
|
||||
std::string::const_iterator. Template instantiation in a separate
|
||||
compilation unit reduces compile times and allows the grammar
|
||||
implementation to be hidden from clients.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
@@ -38,7 +38,10 @@
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief PVarHandler::PVarHandler
|
||||
* @brief Default constructor creating an invalid handler.
|
||||
*
|
||||
* Initializes all members to default/null values, resulting in an invalid
|
||||
* handler that will return false from isValid().
|
||||
*/
|
||||
PVarHandler::PVarHandler() :
|
||||
fColl(nullptr), fParseStr(""), fVarName(""), fIsValid(false)
|
||||
@@ -48,7 +51,22 @@ PVarHandler::PVarHandler() :
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief PVarHandler::PVarHandler
|
||||
* @brief Constructor that parses and evaluates a variable expression.
|
||||
*
|
||||
* Performs the complete variable processing pipeline:
|
||||
* 1. Injects predefined variables from the collection into the AST
|
||||
* 2. Parses the input string using the PStatement grammar
|
||||
* 3. Performs semantic analysis using PProgram
|
||||
* 4. Injects actual data values from the collection
|
||||
* 5. Evaluates the expression using PProgEval
|
||||
* 6. Extracts and stores the requested variable results
|
||||
*
|
||||
* If parsing, semantic analysis, or evaluation fails, fIsValid is set to false
|
||||
* and error messages are logged to ~/.musrfit/mupp/mupp_err.log.
|
||||
*
|
||||
* @param coll pointer to the collection containing run data
|
||||
* @param parse_str the variable definition string to parse
|
||||
* @param var_name optional variable name to extract; if empty, only validation is performed
|
||||
*/
|
||||
PVarHandler::PVarHandler(PmuppCollection *coll, std::string parse_str, std::string var_name) :
|
||||
fColl(coll), fParseStr(parse_str), fVarName(var_name), fIsValid(false)
|
||||
@@ -95,8 +113,12 @@ PVarHandler::PVarHandler(PmuppCollection *coll, std::string parse_str, std::stri
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief PVarHandler::getValues
|
||||
* @return
|
||||
* @brief Gets the computed values for the variable.
|
||||
*
|
||||
* Returns the vector of values computed during expression evaluation.
|
||||
* Each element corresponds to a different run in the collection.
|
||||
*
|
||||
* @return vector of computed values, or empty vector if not valid
|
||||
*/
|
||||
std::vector<double> PVarHandler::getValues()
|
||||
{
|
||||
@@ -109,8 +131,12 @@ std::vector<double> PVarHandler::getValues()
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief PVarHandler::getErrors
|
||||
* @return
|
||||
* @brief Gets the computed error values for the variable.
|
||||
*
|
||||
* Returns the vector of error values computed during expression evaluation.
|
||||
* Each element corresponds to a different run in the collection.
|
||||
*
|
||||
* @return vector of computed error values, or empty vector if not valid
|
||||
*/
|
||||
std::vector<double> PVarHandler::getErrors()
|
||||
{
|
||||
@@ -123,7 +149,13 @@ std::vector<double> PVarHandler::getErrors()
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief PVarHandler::injectPredefVariables
|
||||
* @brief Injects predefined variables from the collection into the AST.
|
||||
*
|
||||
* For each parameter in the collection's first run, creates variable
|
||||
* declarations for both the parameter name and its corresponding error
|
||||
* variable (with 'Err' suffix). These declarations are prepended to the
|
||||
* AST so they are processed before user-defined variables, making all
|
||||
* collection parameters available for use in expressions.
|
||||
*/
|
||||
void PVarHandler::injectPredefVariables()
|
||||
{
|
||||
@@ -148,9 +180,13 @@ void PVarHandler::injectPredefVariables()
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief PVarHandler::getVarName
|
||||
* @param idx
|
||||
* @return
|
||||
* @brief Gets the variable name at a specific parameter index.
|
||||
*
|
||||
* Retrieves the parameter name from the collection's first run at the
|
||||
* specified index.
|
||||
*
|
||||
* @param idx the parameter index (0-based)
|
||||
* @return the parameter name, or "??" if index is out of range
|
||||
*/
|
||||
std::string PVarHandler::getVarName(int idx)
|
||||
{
|
||||
@@ -165,9 +201,13 @@ std::string PVarHandler::getVarName(int idx)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief PVarHandler::getData
|
||||
* @param idx
|
||||
* @return
|
||||
* @brief Gets the data values for a specific parameter across all runs.
|
||||
*
|
||||
* Collects the value of the specified parameter from every run in the
|
||||
* collection, returning them as a vector.
|
||||
*
|
||||
* @param idx the parameter index (0-based)
|
||||
* @return vector of parameter values from all runs, or empty vector if index is out of range
|
||||
*/
|
||||
std::vector<double> PVarHandler::getData(int idx)
|
||||
{
|
||||
@@ -188,9 +228,14 @@ std::vector<double> PVarHandler::getData(int idx)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief PVarHandler::getDataErr
|
||||
* @param idx
|
||||
* @return
|
||||
* @brief Gets the error values for a specific parameter across all runs.
|
||||
*
|
||||
* Collects the error of the specified parameter from every run in the
|
||||
* collection. The error is computed as the geometric mean of the positive
|
||||
* and negative errors: sqrt(abs(posErr * negErr)).
|
||||
*
|
||||
* @param idx the parameter index (0-based)
|
||||
* @return vector of parameter errors from all runs, or empty vector if index is out of range
|
||||
*/
|
||||
std::vector<double> PVarHandler::getDataErr(int idx)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user