/*************************************************************************** PExpressionDef.hpp Author: Andreas Suter e-mail: andreas.suter@psi.ch Based on Joel de Guzman example on calc7, see https://github.com/boostorg/spirit This file contains the implementation (definition) of the PExpression 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) - Unary operations (+, -) - Multiplicative operations (*, /) - Additive operations (+, -) Symbol tables are populated with operators and function names, and error handling is integrated for reporting parse failures. ***************************************************************************/ /*************************************************************************** * Copyright (C) 2023 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. * ***************************************************************************/ #include "PExpression.hpp" #include "PErrorHandler.hpp" #include "PAnnotation.hpp" namespace mupp { namespace parser { namespace x3 = boost::spirit::x3; namespace ascii = boost::spirit::x3::ascii; using x3::char_; using x3::double_; using x3::raw; using x3::lexeme; using ascii::alpha; using ascii::alnum; /////////////////////////////////////////////////////////////////////// // Symbol tables for operators and functions /////////////////////////////////////////////////////////////////////// inline struct additive_op_ : x3::symbols { additive_op_() { add ("+", ast::op_plus) ("-", ast::op_minus) ; } } additive_op; inline struct multiplicative_op_ : x3::symbols { multiplicative_op_() { add ("*", ast::op_times) ("/", ast::op_divide) ; } } multiplicative_op; 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 /////////////////////////////////////////////////////////////////////// inline auto const expr_def = additive_expr ; inline auto const additive_expr_def = multiplicative_expr >> *(additive_op > multiplicative_expr) ; inline auto const multiplicative_expr_def = unary_expr >> *(multiplicative_op > unary_expr) ; inline auto const unary_expr_def = primary_expr | (unary_op > primary_expr) ; inline auto const primary_expr_def = double_ | identifier | fun_tok > '(' > expr > ')' | "pow(" > expr > ',' > expr > ')' | '(' > expr > ')' ; inline auto const identifier_def = raw[lexeme['$' >> *(alnum | '_')]] ; BOOST_SPIRIT_DEFINE(expr, additive_expr, multiplicative_expr, unary_expr, primary_expr, identifier) }}