/* >, < redirection is handled later, after environment expansion. (also, redirection can be in the middle of a command.) */ %include { #include "phase3_parser.h" #include "command.h" #define LEMON_SUPER phase3 } %code { std::unique_ptr phase3::make() { return std::make_unique(); } bool phase3::continuation() const { yypParser *self = (yypParser *)this; for (const auto &e : *self) { if (e.major == BEGIN) return true; if (e.major == LPAREN) return true; if (e.major == IF) return true; if (e.major == AMP_AMP) return true; if (e.major == PIPE_PIPE) return true; if (e.major == LOOP) return true; if (e.major == FOR) return true; if (e.major == PIPE) return true; if (e.major == PIPE_PIPE) return true; if (e.major == AMP_AMP) return true; } return false; } void phase3::parse_accept() { error = false; } void phase3::parse_failure() { error = false; } void phase3::syntax_error(int yymajor, std::string &yyminor) { /* switch (yymajor) { case END: fprintf(stderr, "### MPW Shell - Extra END command.\n"); break; case RPAREN: fprintf(stderr, "### MPW Shell - Extra ) command.\n"); break; case ELSE: case ELSE_IF: fprintf(stderr, "### MPW Shell - ELSE must be within IF ... END.\n"); break; default: fprintf(stderr, "### Parse error near %s\n", yyminor.c_str()); break; } */ fprintf(stderr, "### MPW Shell - Parse error near %s\n", yymajor ? yyminor.c_str() : "EOF"); error = true; } } %left PIPE_PIPE AMP_AMP. %left PIPE. %token_type {std::string} %default_type {command_ptr} %type start {void} %type command_list {void} /* these are put into a queue for immmediate execution */ start ::= command_list. command_list ::= . command_list ::= command_list sep . command_list ::= command_list command(C) sep . { if (C) command_queue.emplace_back(std::move(C)); } /* compound_list is identical to command_list, but it is not executed immediately. */ %type compound_list { command_ptr_vector } compound_list ::= . compound_list(L) ::= compound_list(L) sep. compound_list(L) ::= compound_list(L) command(C) sep . { if (C) L.emplace_back(std::move(C)); } sep ::= SEMI. sep ::= NL. %type command { command_ptr } /* nb -- ||, &&, | -- both sides are optional. This does not. */ command(RV) ::= command(L) PIPE_PIPE opt_nl command(R). { RV = std::make_unique(std::move(L), std::move(R)); } command(RV) ::= command(L) AMP_AMP opt_nl command(R). { RV = std::make_unique(std::move(L), std::move(R)); } command(RV) ::= command(L) PIPE opt_nl command(R). { RV = std::make_unique(std::move(L), std::move(R)); } command(C) ::= term(C). term(RV) ::= COMMAND(C). { RV = std::make_unique(std::move(C)); } term(RV) ::= EVALUATE(C). { RV = std::make_unique(std::move(C)); } term(RV) ::= BREAK(C). { RV = std::make_unique(std::move(C)); } term(RV) ::= CONTINUE(C). { RV = std::make_unique(std::move(C)); } term(RV) ::= EXIT(C). { RV = std::make_unique(std::move(C)); } term(C) ::= if_command(C). term(C) ::= begin_command(C). term(C) ::= paren_command(C). term(C) ::= loop_command(C). term(C) ::= for_command(C). /* lexer error (mismatched quotes, etc) */ term(RV) ::= ERROR(C). { RV = std::make_unique(@C, std::move(C)); } /* * fall back to an end error. w/o fallback, it will cause a parse conflict. */ /* %fallback ERROR END RPAREN ELSE ELSE_IF. */ /* term(RV) ::= error RPAREN. term(RV) ::= error END. term(RV) ::= LPAREN error RPAREN. term(RV) ::= BEGIN error END. term(RV) ::= IF error END. term(RV) ::= LOOP error END. term(RV) ::= FOR error END. */ /* compound list ends with a separator. paren command does not need the final separator */ %type paren_list { command_ptr_vector } paren_list(L) ::= compound_list(L) . paren_list(L) ::= compound_list(L) command(C) . { L.emplace_back(std::move(C)); } paren_command(RV) ::= LPAREN(T) paren_list(L) RPAREN(E). { RV = std::make_unique(@T, std::move(L), std::move(T), std::move(E)); } begin_command(RV) ::= BEGIN(T) sep compound_list(L) END(E). { RV = std::make_unique(@T, std::move(L), std::move(T), std::move(E)); } loop_command(RV) ::= LOOP(T) sep compound_list(L) END(E). { RV = std::make_unique(@T, std::move(L), std::move(T), std::move(E)); } for_command(RV) ::= FOR(T) sep compound_list(L) END(E). { RV = std::make_unique(@T, std::move(L), std::move(T), std::move(E)); } if_command(RV) ::= IF(I) sep compound_list(L) END(E). { if_command::clause_vector_type v; v.emplace_back(std::make_unique(IF, std::move(L), std::move(I))); RV = std::make_unique( std::move(v), std::move(E) ); } if_command(RV) ::= IF(I) sep compound_list(L) else_command(EC) END(E). { if_command::clause_vector_type v; v.emplace_back(std::make_unique(IF, std::move(L), std::move(I))); for(auto &c : EC) { v.emplace_back(std::move(c)); } RV = std::make_unique( std::move(v), std::move(E)); } %token_class else ELSE_IF ELSE. %type else_command { if_command::clause_vector_type } else_command(RV) ::= else(E) sep compound_list(L). { RV.emplace_back(std::make_unique(@E, std::move(L), std::move(E))); } else_command(EC) ::= else_command(EC) else(E) sep compound_list(L). { EC.emplace_back(std::make_unique(@E, std::move(L), std::move(E))); } opt_nl ::= . opt_nl ::= opt_nl NL .