diff --git a/src/musredit_qt6/mupp/var/include/PAnnotation.hpp b/src/musredit_qt6/mupp/var/include/PAnnotation.hpp index 261487ae3..f2fca0521 100644 --- a/src/musredit_qt6/mupp/var/include/PAnnotation.hpp +++ b/src/musredit_qt6/mupp/var/include/PAnnotation.hpp @@ -51,7 +51,7 @@ namespace mupp * 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. + * analysis, integrated with the Spirit X3 parser. * * @tparam Iterator the iterator type for traversing the source code (typically std::string::const_iterator) */ @@ -59,9 +59,6 @@ namespace mupp template struct PAnnotation { - /// Result type specification required by Boost.Phoenix function protocol - template - struct result { typedef void type; }; std::vector& iters; ///< Reference to vector storing iterator positions indexed by AST node IDs @@ -79,8 +76,6 @@ namespace mupp */ struct set_id { - typedef void result_type; ///< Return type for Boost.Phoenix compatibility - int id; ///< The ID to assign to tagged AST nodes /** diff --git a/src/musredit_qt6/mupp/var/include/PErrorHandler.hpp b/src/musredit_qt6/mupp/var/include/PErrorHandler.hpp index 5f770011e..6db39f558 100644 --- a/src/musredit_qt6/mupp/var/include/PErrorHandler.hpp +++ b/src/musredit_qt6/mupp/var/include/PErrorHandler.hpp @@ -46,7 +46,7 @@ namespace mupp * * 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 + * error position. It integrates with the Boost.Spirit X3 parser error handling * mechanism and works in conjunction with the PAnnotation handler to map * AST node IDs back to source positions. * @@ -58,9 +58,6 @@ namespace mupp template struct PErrorHandler { - /// Result type specification required by Boost.Phoenix function protocol - template - struct result { typedef void type; }; /** * @brief Constructor that stores the source code range. diff --git a/src/musredit_qt6/mupp/var/include/PExpression.hpp b/src/musredit_qt6/mupp/var/include/PExpression.hpp index bf2e332eb..1cd09129e 100644 --- a/src/musredit_qt6/mupp/var/include/PExpression.hpp +++ b/src/musredit_qt6/mupp/var/include/PExpression.hpp @@ -33,21 +33,12 @@ #ifndef _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 -// #define BOOST_SPIRIT_QI_DEBUG +// #define BOOST_SPIRIT_X3_DEBUG /////////////////////////////////////////////////////////////////////////////// -#include +#include #include "PAst.hpp" #include "PErrorHandler.hpp" #include "PSkipper.hpp" @@ -55,14 +46,14 @@ namespace mupp { namespace parser { - namespace qi = boost::spirit::qi; - namespace ascii = boost::spirit::ascii; + namespace x3 = boost::spirit::x3; + namespace ascii = boost::spirit::x3::ascii; /////////////////////////////////////////////////////////////////////////////// /** * @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: * - Primary expressions: numbers, variables, functions, parenthesized expressions * - Unary operators: +, - (highest precedence) @@ -80,31 +71,27 @@ namespace mupp { namespace parser * - 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 - struct PExpression : qi::grammar > - { - /** - * @brief Constructor that initializes the grammar rules. - * @param error_handler reference to the error handler for reporting parse errors - */ - PExpression(PErrorHandler& error_handler); - qi::symbols additive_op; ///< Symbol table for additive operators (+, -) - qi::symbols multiplicative_op; ///< Symbol table for multiplicative operators (*, /) - qi::symbols unary_op; ///< Symbol table for unary operators (+, -) - qi::symbols fun_tok; ///< Symbol table for function names + // Rule IDs + struct expr_class; + struct additive_expr_class; + struct multiplicative_expr_class; + struct unary_expr_class; + struct primary_expr_class; + struct identifier_class; - qi::rule > expr; ///< Top-level expression rule - qi::rule > additive_expr; ///< Additive expression rule (lowest precedence) - qi::rule > multiplicative_expr; ///< Multiplicative expression rule (medium precedence) - qi::rule > unary_expr; ///< Unary expression rule - qi::rule > primary_expr; ///< Primary expression rule (highest precedence) - qi::rule > identifier; ///< Identifier rule (variables prefixed with '$') - }; + // Rule declarations + typedef x3::rule expr_type; + typedef x3::rule additive_expr_type; + typedef x3::rule multiplicative_expr_type; + typedef x3::rule unary_expr_type; + typedef x3::rule primary_expr_type; + typedef x3::rule identifier_type; + + BOOST_SPIRIT_DECLARE(expr_type, additive_expr_type, multiplicative_expr_type, + unary_expr_type, primary_expr_type, identifier_type) }} #endif // _PEXPRESSION_HPP_ diff --git a/src/musredit_qt6/mupp/var/include/PExpressionDef.hpp b/src/musredit_qt6/mupp/var/include/PExpressionDef.hpp index 1a7a29119..a7d508cef 100644 --- a/src/musredit_qt6/mupp/var/include/PExpressionDef.hpp +++ b/src/musredit_qt6/mupp/var/include/PExpressionDef.hpp @@ -9,8 +9,8 @@ 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. + grammar. It defines the actual grammar rules and their semantic + actions using Boost.Spirit X3. The grammar implements expression parsing with proper operator precedence: - Primary expressions (literals, variables, functions) @@ -46,93 +46,116 @@ #include "PExpression.hpp" #include "PErrorHandler.hpp" #include "PAnnotation.hpp" -#include namespace mupp { namespace parser { - template - PExpression::PExpression(PErrorHandler& error_handler) - : PExpression::base_type(expr) - { - qi::_1_type _1; - qi::_2_type _2; - qi::_3_type _3; - qi::_4_type _4; + namespace x3 = boost::spirit::x3; + namespace ascii = boost::spirit::x3::ascii; - qi::char_type char_; - qi::double_type double_; - qi::_val_type _val; - qi::raw_type raw; - qi::lexeme_type lexeme; - qi::alpha_type alpha; - qi::alnum_type alnum; - - using qi::on_error; - using qi::on_success; - using qi::fail; - using boost::phoenix::function; - - typedef function > error_handler_function; - typedef function > annotation_function; + using x3::char_; + using x3::double_; + using x3::raw; + using x3::lexeme; + using ascii::alpha; + using ascii::alnum; /////////////////////////////////////////////////////////////////////// - // Tokens - additive_op.add - ("+", ast::op_plus) - ("-", ast::op_minus) - ; + // Symbol tables for operators and functions + /////////////////////////////////////////////////////////////////////// - multiplicative_op.add - ("*", ast::op_times) - ("/", ast::op_divide) - ; + inline struct additive_op_ : x3::symbols + { + additive_op_() + { + add + ("+", ast::op_plus) + ("-", ast::op_minus) + ; + } + } additive_op; - unary_op.add - ("+", ast::op_positive) - ("-", ast::op_negative) - ; + inline struct multiplicative_op_ : x3::symbols + { + multiplicative_op_() + { + add + ("*", ast::op_times) + ("/", ast::op_divide) + ; + } + } multiplicative_op; - fun_tok.add - ("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) - ; + inline struct unary_op_ : x3::symbols + { + unary_op_() + { + add + ("+", ast::op_positive) + ("-", ast::op_negative) + ; + } + } unary_op; + + inline struct fun_tok_ : x3::symbols + { + fun_tok_() + { + add + ("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 - expr = - additive_expr.alias() + /////////////////////////////////////////////////////////////////////// + + inline auto const expr_def = + additive_expr ; - additive_expr = + inline auto const additive_expr_def = multiplicative_expr >> *(additive_op > multiplicative_expr) - ; + ; - multiplicative_expr = + inline auto const multiplicative_expr_def = unary_expr >> *(multiplicative_op > unary_expr) - ; + ; - unary_expr = + inline auto const unary_expr_def = primary_expr | (unary_op > primary_expr) ; - primary_expr = + inline auto const primary_expr_def = double_ | identifier | fun_tok > '(' > expr > ')' @@ -140,36 +163,13 @@ namespace mupp { namespace parser | '(' > expr > ')' ; - identifier = + inline auto const identifier_def = raw[lexeme['$' >> *(alnum | '_')]] ; - // name all the rules - additive_expr.name("additive_expr"); - multiplicative_expr.name("multiplicative_expr"); - unary_expr.name("unary_expr"); - primary_expr.name("primary_expr"); - identifier.name("identifier"); + BOOST_SPIRIT_DEFINE(expr, additive_expr, multiplicative_expr, + unary_expr, primary_expr, 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(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)); - } }} diff --git a/src/musredit_qt6/mupp/var/include/PSkipper.hpp b/src/musredit_qt6/mupp/var/include/PSkipper.hpp index cb357c40e..55da8583d 100644 --- a/src/musredit_qt6/mupp/var/include/PSkipper.hpp +++ b/src/musredit_qt6/mupp/var/include/PSkipper.hpp @@ -33,12 +33,12 @@ #ifndef _PSKIPPER_HPP_ #define _PSKIPPER_HPP_ -#include +#include namespace mupp { namespace parser { - namespace qi = boost::spirit::qi; - namespace ascii = boost::spirit::ascii; + namespace x3 = boost::spirit::x3; + namespace ascii = boost::spirit::x3::ascii; /////////////////////////////////////////////////////////////////////////////// /** @@ -61,38 +61,22 @@ namespace mupp { namespace parser * /* This is a * multi-line comment * / * @endcode - * - * @tparam Iterator the iterator type for the input (typically std::string::const_iterator) */ /////////////////////////////////////////////////////////////////////////////// - template - struct PSkipper : qi::grammar - { - /** - * @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 = - space // tab/space/cr/lf - | "/*" >> *(char_ - "*/") >> "*/" // C-style comments - | single_line_comment - ; - } + inline auto const single_line_comment = (lit('%') | lit('#') | lit("//")) >> *print >> eol; - qi::rule single_line_comment; ///< Rule for single-line comments (%, #, //) - qi::rule start; ///< Top-level skipper rule - }; + inline auto const skipper = + space // tab/space/cr/lf + | "/*" >> *(char_ - "*/") >> "*/" // C-style comments + | single_line_comment + ; }} #endif // _PSKIPPER_HPP_ diff --git a/src/musredit_qt6/mupp/var/include/PStatement.hpp b/src/musredit_qt6/mupp/var/include/PStatement.hpp index 0208a4f55..7d4857a6e 100644 --- a/src/musredit_qt6/mupp/var/include/PStatement.hpp +++ b/src/musredit_qt6/mupp/var/include/PStatement.hpp @@ -59,25 +59,23 @@ namespace mupp { namespace parser * * 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 - struct PStatement : qi::grammar > - { - /** - * @brief Constructor that initializes the statement grammar rules. - * @param error_handler reference to the error handler for reporting parse errors - */ - PStatement(PErrorHandler& error_handler); - PExpression expr; ///< Expression grammar for parsing right-hand sides - qi::rule > statement_list; ///< Rule for parsing a list of statements - qi::rule > variable_declaration; ///< Rule for variable declarations - qi::rule > assignment; ///< Rule for assignment statements - qi::rule > identifier; ///< Rule for identifiers (without '$' prefix) - }; + // Rule IDs + struct statement_list_class; + struct variable_declaration_class; + struct assignment_class; + struct stmt_identifier_class; + + // Rule declarations + typedef x3::rule statement_list_type; + typedef x3::rule variable_declaration_type; + typedef x3::rule assignment_type; + typedef x3::rule stmt_identifier_type; + + BOOST_SPIRIT_DECLARE(statement_list_type, variable_declaration_type, + assignment_type, stmt_identifier_type) }} #endif // _PSTATEMENT_HPP_ diff --git a/src/musredit_qt6/mupp/var/include/PStatementDef.hpp b/src/musredit_qt6/mupp/var/include/PStatementDef.hpp index caa770fea..a496cdffe 100644 --- a/src/musredit_qt6/mupp/var/include/PStatementDef.hpp +++ b/src/musredit_qt6/mupp/var/include/PStatementDef.hpp @@ -9,8 +9,8 @@ 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. + grammar. It defines the grammar rules for parsing variable + declarations and assignments using Boost.Spirit X3. The grammar supports: - Variable declarations: var = @@ -43,77 +43,55 @@ ***************************************************************************/ #include "PStatement.hpp" +#include "PExpressionDef.hpp" #include "PErrorHandler.hpp" #include "PAnnotation.hpp" namespace mupp { namespace parser { - template - PStatement::PStatement(PErrorHandler& error_handler) - : PStatement::base_type(statement_list), expr(error_handler) - { - qi::_1_type _1; - qi::_2_type _2; - qi::_3_type _3; - qi::_4_type _4; + namespace x3 = boost::spirit::x3; + namespace ascii = boost::spirit::x3::ascii; - qi::_val_type _val; - qi::raw_type raw; - qi::lexeme_type lexeme; - qi::alpha_type alpha; - qi::alnum_type alnum; + using x3::raw; + using x3::lexeme; + using ascii::alpha; + using ascii::alnum; - using qi::on_error; - using qi::on_success; - using qi::fail; - using boost::phoenix::function; + /////////////////////////////////////////////////////////////////////// + // Rule definitions + /////////////////////////////////////////////////////////////////////// - typedef function > error_handler_function; - typedef function > annotation_function; + inline statement_list_type const statement_list = "statement_list"; + 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) ; - identifier = + inline auto const stmt_identifier_def = raw[lexeme[(alpha | '_') >> *(alnum | '_')]] ; - variable_declaration = + inline auto const variable_declaration_def = lexeme["var" >> !(alnum | '_')] // make sure we have whole words - > identifier + > stmt_identifier > -('=' > expr) ; - assignment = - identifier + inline auto const assignment_def = + stmt_identifier > '=' > expr ; - // name all the rules - statement_list.name("statement_list"); - identifier.name("identifier"); - variable_declaration.name("variable_declaration"); - assignment.name("assignment"); + BOOST_SPIRIT_DEFINE(statement_list, variable_declaration, assignment, stmt_identifier) - // 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(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)); - } }} diff --git a/src/musredit_qt6/mupp/var/src/PExpression.cpp b/src/musredit_qt6/mupp/var/src/PExpression.cpp index ca95e8535..0d632030a 100644 --- a/src/musredit_qt6/mupp/var/src/PExpression.cpp +++ b/src/musredit_qt6/mupp/var/src/PExpression.cpp @@ -8,8 +8,8 @@ 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 + This file instantiates the PExpression grammar rules for + std::string::const_iterator. Instantiation in a separate compilation unit reduces compile times and allows the grammar implementation to be hidden from clients. @@ -35,11 +35,4 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#if defined(_MSC_VER) -# pragma warning(disable: 4345) -#endif - #include "PExpressionDef.hpp" - -typedef std::string::const_iterator iterator_type; -template struct mupp::parser::PExpression; diff --git a/src/musredit_qt6/mupp/var/src/PStatement.cpp b/src/musredit_qt6/mupp/var/src/PStatement.cpp index 1f815640e..00f934225 100644 --- a/src/musredit_qt6/mupp/var/src/PStatement.cpp +++ b/src/musredit_qt6/mupp/var/src/PStatement.cpp @@ -8,8 +8,8 @@ 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 + This file instantiates the PStatement grammar rules for + std::string::const_iterator. Instantiation in a separate compilation unit reduces compile times and allows the grammar implementation to be hidden from clients. @@ -35,11 +35,4 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#if defined(_MSC_VER) -# pragma warning(disable: 4345) -#endif - #include "PStatementDef.hpp" - -typedef std::string::const_iterator iterator_type; -template struct mupp::parser::PStatement; diff --git a/src/musredit_qt6/mupp/var/src/PVarHandler.cpp b/src/musredit_qt6/mupp/var/src/PVarHandler.cpp index 889eb23ff..c45f14999 100644 --- a/src/musredit_qt6/mupp/var/src/PVarHandler.cpp +++ b/src/musredit_qt6/mupp/var/src/PVarHandler.cpp @@ -34,8 +34,11 @@ #include "PSkipper.hpp" #include "PErrorHandler.hpp" #include "PStatement.hpp" +#include "PStatementDef.hpp" #include "PProgram.hpp" +#include + //-------------------------------------------------------------------------- /** * @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(); mupp::PErrorHandler error_handler(iter, end); // the error handler - mupp::parser::PStatement parser(error_handler); // the parser mupp::prog::PProgram prog(error_handler); // our compiler, and exec - mupp::parser::PSkipper skipper; // the skipper parser // 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 (prog(fAst)) { // semantic analysis std::vector data, dataErr;