/*************************************************************************** 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 #if BOOST_VERSION < 106100 # error "Boost version 1.61.0 or higher is required for Spirit X3. Please upgrade Boost." #endif #include "PFunctionAst.h" #include namespace x3 = boost::spirit::x3; /** * @namespace musrfit::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 { 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 { 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 { 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 { 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 const assignment = "assignment"; /// Expression with addition/subtraction (lowest precedence) x3::rule const expression = "expression"; /// Term with multiplication/division (higher precedence) x3::rule const term = "term"; /// Factor: literal, constant, parameter, function, or parenthesized expression (highest precedence) x3::rule const factor = "factor"; /// Constant: PI, GAMMA_MU, B, EN, or T# x3::rule const constant = "constant"; /// Parameter reference: PAR# or -PAR# x3::rule const parameter = "parameter"; /// Map reference: MAP# or -MAP# x3::rule const map = "map"; /// Function call: FUNC(expression) x3::rule const function = "function"; /// Power operation: POW(base, exponent) x3::rule 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_