mirror of
https://github.com/ksherlock/mpw-shell.git
synced 2024-12-27 18:30:39 +00:00
f125b533f7
commit f0944a89f27e44b1764988806e655f09764e80df Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:24:08 2016 -0400 exit throws execution of input error w/ possible 0 value. catch it. commit 9e7f9c1ae049aa26513413f4767268b47ee22e98 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:23:21 2016 -0400 builtins - more consistent argument handling. commit be4c1c902f5a3a3f01e92ae52c7d6cc5d8731b65 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:23:01 2016 -0400 . commit 68d0c29fec112c6e7bc3a672b41eb7eb758a8941 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:22:51 2016 -0400 exit command. commit 25b0a7f7da9220b03026123bb5072c2da1d73fde Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:21:16 2016 -0400 builtin quit command.
239 lines
5.4 KiB
Plaintext
239 lines
5.4 KiB
Plaintext
|
|
/*
|
|
>, < 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> phase3::make() {
|
|
return std::make_unique<yypParser>();
|
|
}
|
|
|
|
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<or_command>(std::move(L), std::move(R));
|
|
}
|
|
|
|
command(RV) ::= command(L) AMP_AMP opt_nl command(R). {
|
|
RV = std::make_unique<and_command>(std::move(L), std::move(R));
|
|
}
|
|
|
|
command(RV) ::= command(L) PIPE opt_nl command(R). {
|
|
RV = std::make_unique<pipe_command>(std::move(L), std::move(R));
|
|
}
|
|
|
|
command(C) ::= term(C).
|
|
|
|
term(RV) ::= COMMAND(C). { RV = std::make_unique<simple_command>(std::move(C)); }
|
|
term(RV) ::= EVALUATE(C). { RV = std::make_unique<evaluate_command>(std::move(C)); }
|
|
term(RV) ::= BREAK(C). { RV = std::make_unique<break_command>(std::move(C)); }
|
|
term(RV) ::= CONTINUE(C). { RV = std::make_unique<continue_command>(std::move(C)); }
|
|
term(RV) ::= EXIT(C). { RV = std::make_unique<exit_command>(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<error_command>(@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<begin_command>(@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<begin_command>(@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<loop_command>(@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<for_command>(@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_else_clause>(IF, std::move(L), std::move(I)));
|
|
|
|
RV = std::make_unique<if_command>(
|
|
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_else_clause>(IF, std::move(L), std::move(I)));
|
|
for(auto &c : EC) { v.emplace_back(std::move(c)); }
|
|
|
|
RV = std::make_unique<if_command>(
|
|
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<if_else_clause>(@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<if_else_clause>(@E, std::move(L), std::move(E)));
|
|
}
|
|
|
|
|
|
opt_nl ::= .
|
|
opt_nl ::= opt_nl NL .
|