329 lines
11 KiB
C++
329 lines
11 KiB
C++
/***************************************************************************
|
|
|
|
PFunctionGrammar.h
|
|
|
|
Author: Andreas Suter
|
|
e-mail: andreas.suter@psi.ch
|
|
|
|
Header-only grammar for parsing function entries in msr-file FUNCTION blocks.
|
|
This version uses Boost.Spirit X3 in header-only mode for maximum compatibility.
|
|
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* Copyright (C) 2007-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 _PFUNCTIONGRAMMAR_H_
|
|
#define _PFUNCTIONGRAMMAR_H_
|
|
|
|
// Check Boost version - require 1.61+ for Spirit X3
|
|
#include <boost/version.hpp>
|
|
#if BOOST_VERSION < 106100
|
|
# error "Boost version 1.61.0 or higher is required for Spirit X3. Please upgrade Boost."
|
|
#endif
|
|
|
|
#include "PFunctionAst.h"
|
|
#include <boost/spirit/home/x3.hpp>
|
|
|
|
namespace x3 = boost::spirit::x3;
|
|
|
|
/**
|
|
* @namespace musrfit::grammar
|
|
* @brief Boost.Spirit X3 grammar definitions for parsing function expressions.
|
|
*
|
|
* This namespace contains the complete grammar for parsing msr-file FUNCTION
|
|
* block entries. The grammar supports arithmetic expressions with operator
|
|
* precedence, mathematical functions, constants, and parameter/map references.
|
|
*
|
|
* The grammar is header-only for maximum portability and uses X3's modern
|
|
* attribute propagation system to automatically build the AST during parsing.
|
|
*/
|
|
namespace musrfit { namespace grammar
|
|
{
|
|
using x3::int_;
|
|
using x3::double_;
|
|
using x3::lit;
|
|
using x3::lexeme;
|
|
using x3::attr;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Symbol tables - using inline to avoid multiple definition errors
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief Symbol table for additive operators (+ and -).
|
|
*
|
|
* Maps operator characters to their corresponding AST token types
|
|
* for addition and subtraction operations.
|
|
*/
|
|
struct additive_op_ : x3::symbols<ast::optoken>
|
|
{
|
|
additive_op_()
|
|
{
|
|
add("+", ast::op_plus)("-", ast::op_minus);
|
|
}
|
|
};
|
|
|
|
inline additive_op_ additive_op; ///< Global instance of additive operator symbol table
|
|
|
|
/**
|
|
* @brief Symbol table for multiplicative operators (* and /).
|
|
*
|
|
* Maps operator characters to their corresponding AST token types
|
|
* for multiplication and division operations.
|
|
*/
|
|
struct multiplicative_op_ : x3::symbols<ast::optoken>
|
|
{
|
|
multiplicative_op_()
|
|
{
|
|
add("*", ast::op_times)("/", ast::op_divide);
|
|
}
|
|
};
|
|
|
|
inline multiplicative_op_ multiplicative_op; ///< Global instance of multiplicative operator symbol table
|
|
|
|
/**
|
|
* @brief Symbol table for mathematical function names.
|
|
*
|
|
* Maps uppercase function names (COS, SIN, EXP, etc.) to their
|
|
* corresponding AST function identifiers. Supports trigonometric,
|
|
* hyperbolic, inverse, exponential, and logarithmic functions.
|
|
*/
|
|
struct fun_tok_ : x3::symbols<ast::funid>
|
|
{
|
|
fun_tok_()
|
|
{
|
|
add
|
|
("COS", ast::fun_cos)
|
|
("SIN", ast::fun_sin)
|
|
("TAN", ast::fun_tan)
|
|
("COSH", ast::fun_cosh)
|
|
("SINH", ast::fun_sinh)
|
|
("TANH", ast::fun_tanh)
|
|
("ACOS", ast::fun_acos)
|
|
("ASIN", ast::fun_asin)
|
|
("ATAN", ast::fun_atan)
|
|
("ACOSH", ast::fun_acosh)
|
|
("ASINH", ast::fun_asinh)
|
|
("ATANH", ast::fun_atanh)
|
|
("LOG", ast::fun_log)
|
|
("LN", ast::fun_ln)
|
|
("EXP", ast::fun_exp)
|
|
("SQRT", ast::fun_sqrt);
|
|
}
|
|
};
|
|
|
|
inline fun_tok_ fun_tok; ///< Global instance of function name symbol table
|
|
|
|
/**
|
|
* @brief Symbol table for named constants.
|
|
*
|
|
* Maps constant names (PI, GAMMA_MU) to their corresponding
|
|
* AST constant type identifiers.
|
|
*/
|
|
struct const_tok_ : x3::symbols<ast::constant::type>
|
|
{
|
|
const_tok_()
|
|
{
|
|
add("PI", ast::constant::pi)("GAMMA_MU", ast::constant::gamma_mu);
|
|
}
|
|
};
|
|
|
|
inline const_tok_ const_tok; ///< Global instance of constant name symbol table
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Grammar Rules - Forward Declarations
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/// Top-level rule: FUN# = expression
|
|
x3::rule<class assignment, ast::assignment> const assignment = "assignment";
|
|
|
|
/// Expression with addition/subtraction (lowest precedence)
|
|
x3::rule<class expression, ast::expression> const expression = "expression";
|
|
|
|
/// Term with multiplication/division (higher precedence)
|
|
x3::rule<class term, ast::expression> const term = "term";
|
|
|
|
/// Factor: literal, constant, parameter, function, or parenthesized expression (highest precedence)
|
|
x3::rule<class factor, ast::operand> const factor = "factor";
|
|
|
|
/// Constant: PI, GAMMA_MU, B, EN, or T#
|
|
x3::rule<class constant, ast::constant> const constant = "constant";
|
|
|
|
/// Parameter reference: PAR# or -PAR#
|
|
x3::rule<class parameter, ast::parameter> const parameter = "parameter";
|
|
|
|
/// Map reference: MAP# or -MAP#
|
|
x3::rule<class map_ref, ast::map_ref> const map = "map";
|
|
|
|
/// Function call: FUNC(expression)
|
|
x3::rule<class function_call, ast::function_call> const function = "function";
|
|
|
|
/// Power operation: POW(base, exponent)
|
|
x3::rule<class power_call, ast::power_call> const power = "power";
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Grammar Rule Definitions
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief Assignment rule: FUN# = expression
|
|
*
|
|
* Parses a function assignment statement, extracting the function number
|
|
* and the expression to evaluate.
|
|
*/
|
|
auto const assignment_def =
|
|
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_
|