diff --git a/include/xo/reader2/DProgressSsm.hpp b/include/xo/reader2/DProgressSsm.hpp index 7258731c..31b3a55d 100644 --- a/include/xo/reader2/DProgressSsm.hpp +++ b/include/xo/reader2/DProgressSsm.hpp @@ -100,14 +100,12 @@ namespace xo { optype op); static void start(DArena & parser_mm, - obj valex, + obj lhs, ParserStateMachine * p_psm); - -#ifdef NOT_YET - static void start(rp valex, + static void start(DArena & parsermm, + obj lhs, optype optype, - parserstatemachine * p_psm); -#endif + ParserStateMachine * p_psm); syntaxstatetype ssm_type() const noexcept; @@ -147,6 +145,8 @@ namespace xo { ParserStateMachine * p_psm); void on_singleassign_token(const Token & tk, ParserStateMachine * p_psm); + void on_operator_token(const Token & tk, + ParserStateMachine * p_psm); void on_string_token(const Token & tk, ParserStateMachine * p_psm); void on_f64_token(const Token & tk, @@ -207,17 +207,6 @@ namespace xo { void print(std::ostream & os) const override; - - private: - /** assemble expression representing - * value of - * @code - * f(lhs_, rhs_) - * @endcode - * - * where f determined by @ref op_type_ - **/ - obj assemble_expr(ParserStateMachine * p_psm); #endif private: @@ -227,7 +216,14 @@ namespace xo { /** infix operator, if supplied **/ optype op_type_ = optype::invalid; - /** populate an expression here, following infix operator */ + /** populate an expression here, that follows an infix operator. + * + * Note this may not resolve immediately. + * Consider input + * 5 + 6 + * Need to know if following token is * + * before deciding if 6 belongs to addition 5 + 6 + **/ obj rhs_; }; } /*namespace scm*/ diff --git a/src/reader2/DExpectExprSsm.cpp b/src/reader2/DExpectExprSsm.cpp index fc5dbe08..49e95296 100644 --- a/src/reader2/DExpectExprSsm.cpp +++ b/src/reader2/DExpectExprSsm.cpp @@ -180,12 +180,11 @@ namespace xo { case tokentype::tk_in: case tokentype::tk_end: case tokentype::N: + p_psm->illegal_input_on_token("DExpectExprSsm::on_token", + tk, + this->get_expect_str()); break; } - - p_psm->illegal_input_on_token("DExpectExprSsm::on_token", - tk, - this->get_expect_str()); } void diff --git a/src/reader2/DProgressSsm.cpp b/src/reader2/DProgressSsm.cpp index 85f7b1d3..830dd30e 100644 --- a/src/reader2/DProgressSsm.cpp +++ b/src/reader2/DProgressSsm.cpp @@ -5,6 +5,15 @@ #include "DProgressSsm.hpp" #include "ssm/ISyntaxStateMachine_DProgressSsm.hpp" + +#include "DExpectExprSsm.hpp" +#include "ssm/ISyntaxStateMachine_DExpectExprSsm.hpp" + +#ifdef NOT_YET +#include "DApplySsm.hpp" +#include "ssm/ISyntaxStateMachine_DApplySsm.hpp" +#endif + #include #include #include @@ -67,6 +76,7 @@ namespace xo { return "???"; } + /** higher-precedence operators bind before lower-preference operators **/ int precedence(optype x) { switch (x) { @@ -97,6 +107,40 @@ namespace xo { return 0; } + namespace { + optype + tk2op(const tokentype & tktype) { + switch (tktype) { + case tokentype::tk_assign: + return optype::op_assign; + case tokentype::tk_plus: + return optype::op_add; + case tokentype::tk_minus: + return optype::op_subtract; + case tokentype::tk_star: + return optype::op_multiply; + case tokentype::tk_slash: + return optype::op_divide; + case tokentype::tk_cmpeq: + return optype::op_equal; + case tokentype::tk_cmpne: + return optype::op_not_equal; + case tokentype::tk_leftangle: + return optype::op_less; + case tokentype::tk_lessequal: + return optype::op_less_equal; + case tokentype::tk_rightangle: + return optype::op_great; + case tokentype::tk_greatequal: + return optype::op_great_equal; + default: + assert(false); + return optype::invalid; + } + return optype::invalid; + } + } + DProgressSsm * DProgressSsm::make(DArena & mm, obj lhs, @@ -112,26 +156,26 @@ namespace xo { void DProgressSsm::start(DArena & parser_mm, - obj valex, + obj lhs, + optype op, ParserStateMachine * p_psm) { DProgressSsm * progress_ssm - = DProgressSsm::make(parser_mm, valex, optype::invalid); + = DProgressSsm::make(parser_mm, lhs, op); - obj ssm - = with_facet::mkobj(progress_ssm); + obj ssm(progress_ssm); p_psm->push_ssm(ssm); } -#ifdef NOT_YET void - progress_xs::start(rp valex, optype op, parserstatemachine * p_psm) { - p_psm->push_exprstate(progress_xs::make(valex, op)); + DProgressSsm::start(DArena & parser_mm, + obj lhs, + ParserStateMachine * p_psm) + { + start(parser_mm, lhs, optype::invalid, p_psm); } -#endif - DProgressSsm::DProgressSsm(obj valex, optype op) : lhs_{valex}, @@ -225,12 +269,11 @@ namespace xo { case tokentype::tk_plus: case tokentype::tk_minus: break; + case tokentype::tk_star: -#ifdef NOT_YET this->on_operator_token(tk, p_psm); return; -#endif - break; + case tokentype::tk_slash: case tokentype::tk_cmpeq: case tokentype::tk_cmpne: @@ -295,6 +338,75 @@ namespace xo { this->get_expect_str()); } + void + DProgressSsm::on_operator_token(const Token & tk, + ParserStateMachine * p_psm) + { + if (op_type_ == optype::invalid) { + // tk is the operator this instance was waiting for + this->op_type_ = tk2op(tk.tk_type()); + + DExpectExprSsm::start(p_psm->parser_alloc(), p_psm); + return; + } else if (rhs_) { + optype op_type2 = tk2op(tk.tk_type()); + + /* already have {lhs_, op_type_, rhs_}, + * with incoming op_type2 operator decides whether to parse like + * (lhs_, op_type_, rhs_) op_type2 ... + * or + * (lhs_, op_type_, (rhs_ op_type2 ...)) + */ + + if (precedence(op_type_) >= precedence(op_type2)) { + /* associate to the left + * + * parse like + * a + b - ... (a + b) - ... + * a * b - ... (a * b) - ... + */ + + auto lhs2 = this->assemble_expr(p_psm); + + p_psm->pop_ssm(); + + DProgressSsm::start(p_psm->parser_alloc(), + lhs2, + op_type2, + p_psm); + return; + } else { + /* associate to the right + * + * parse like + * a + b * ... (a + (b * ...)) + */ + + p_psm->pop_ssm(); + + /* (a + ..) */ + DProgressSsm::start(p_psm->parser_alloc(), + lhs_, + op_type_, + p_psm); + DExpectExprSsm::start(p_psm->parser_alloc(), + p_psm); + /* (b * ..) */ + DProgressSsm::start(p_psm->parser_alloc(), + rhs_, + op_type2, + p_psm); + DExpectExprSsm::start(p_psm->parser_alloc(), + p_psm); + return; + } + } + + p_psm->illegal_input_on_token("DProgressSsm::on_operator_token", + tk, + this->get_expect_str()); + } + void DProgressSsm::on_string_token(const Token & tk, ParserStateMachine * p_psm) @@ -905,112 +1017,10 @@ namespace xo { * { n * n } */ } +#endif - namespace { - optype - tk2op(const tokentype & tktype) { - switch (tktype) { - case tokentype::tk_assign: - return optype::op_assign; - case tokentype::tk_plus: - return optype::op_add; - case tokentype::tk_minus: - return optype::op_subtract; - case tokentype::tk_star: - return optype::op_multiply; - case tokentype::tk_slash: - return optype::op_divide; - case tokentype::tk_cmpeq: - return optype::op_equal; - case tokentype::tk_cmpne: - return optype::op_not_equal; - case tokentype::tk_leftangle: - return optype::op_less; - case tokentype::tk_lessequal: - return optype::op_less_equal; - case tokentype::tk_rightangle: - return optype::op_great; - case tokentype::tk_greatequal: - return optype::op_great_equal; - default: - assert(false); - return optype::invalid; - } - return optype::invalid; - } - } - - void - progress_xs::on_operator_token(const token_type & tk, - parserstatemachine * p_psm) - { - scope log(XO_DEBUG(p_psm->debug_flag())); - - constexpr const char * c_self_name = "progress_xs::on_operator_token"; - - if (op_type_ == optype::invalid) { - this->op_type_ = tk2op(tk.tk_type()); - - /* infix operator must be followed by non-empty expression */ - expect_expr_xs::start(p_psm); - } else if (rhs_) { - /* already have complete expression stashed. - * behavior depends on operator precedence for tk with stored operator - * this->op_type_ - */ - optype op2 = tk2op(tk.tk_type()); - - if (precedence(op2) <= precedence(this->op_type_)) { - /* e.g. - * 6.2 * 4.9 + ... - * - * in stack: - * 1. progress_xs lhs=6.2, op=*, rhs=4.9 - * - * out stack - * 1. progress_xs lhs=apply(*,6.2,4.9), op=+ - */ - - /* 1. instantiate expression for *this */ - auto expr = this->assemble_expr(p_psm); - - /* 2. remove from stack */ - std::unique_ptr self = p_psm->pop_exprstate(); - - /* 3. replace with new progress_xs: */ - progress_xs::start(expr, op2, p_psm); - - /* infix operator must be followed by non-empty expression */ - expect_expr_xs::start(p_psm); - } else { - /* e.g. - * 6.2 + 4.9 * ... - * - * in stack: - * 1. progress_xs lhs=6.2, op=+, rhs=4.9 - * - * out stack: - * 1. progress_xs lhs=6.2, op=+ - * 2. expect_rhs_expression - * 3. progress_xs lhs=4.9, op=* - * 4. expect_rhs_expression - */ - - std::unique_ptr self = p_psm->pop_exprstate(); - - /* 1. replace with nested incomplete infix exprs */ - progress_xs::start(lhs_, op_type_, p_psm); - expect_expr_xs::start(p_psm); - progress_xs::start(rhs_, op2, p_psm); - expect_expr_xs::start(p_psm); - } - - } else { - throw std::runtime_error(tostr(c_self_name, - ": expected expression following operator", - xtag("tk", tk))); - } - } +#ifdef OBSOLETE + //void progress_xs::on_operator_token(const token_type & tk, parserstatemachine * p_psm) void progress_xs::on_bool_token(const token_type & tk, @@ -1163,7 +1173,25 @@ namespace xo { case optype::op_great_equal: case optype::op_add: case optype::op_subtract: + break; + case optype::op_multiply: +#ifdef NOT_YET + { + /* note: + * 1. don't assume we know lhs_ / rhs_ value types yet. + * perhaps have expression like + * f(..) * g(..) + * where f is the function that contains current ssm. + * 2. consequence: we need representation for + * polymorphic multiply on unknown numeric arguments. + */ + + DApplyExpr::make2(); + } +#endif + + break; case optype::op_divide: // TODO: implement binary operator expression assembly break;