mpw-shell/phase2.rl

183 lines
3.0 KiB
Plaintext
Raw Normal View History

2016-01-30 03:23:14 +00:00
/*
* phase2 -- parse a line into major control structures (begin/end/if/etc)
* input is a full line -- comments have been removed, escape-nl handled, trailing newline stripped.
*
*/
#include "mpw-shell-grammar.h"
#include "phase2.h"
#include "command.h"
%%{
machine main;
alphtype unsigned char;
action not_special { !special() }
ws = [ \t];
main := |*
'||' when not_special => {
flush();
parse(PIPE_PIPE, std::string(ts, te));
};
'&&' when not_special => {
flush();
parse(AMP_AMP, std::string(ts, te));
};
'(' when not_special => {
flush();
parse(LPAREN, std::string(ts, te));
};
# ) may include redirection so start a new token but don't parse it yet.
')' when not_special => {
flush();
scratch.push_back(fc);
type = RPAREN;
};
# todo -- also add in strings and escapes.
';' => { flush(); parse(SEMI, ";"); };
ws => { if (!scratch.empty()) scratch.push_back(fc); };
any => { scratch.push_back(fc); };
*|;
}%%
%%{
machine classify;
alphtype unsigned char;
ws = [ \t];
IF = /if/i;
ELSE = /else/i;
END = /end/i;
BEGIN = /begin/i;
EVALUATE = /evaluate/i;
main := |*
IF %eof{ type = IF; return; };
IF ws => { type = IF; return; };
ELSE %eof{ type = ELSE; return; };
ELSE ws => { type = ELSE; return; };
ELSE ws+ IF %eof{ type = ELSE_IF; return; };
ELSE ws+ IF ws => { type = ELSE_IF; return; };
EVALUATE %eof{ type = EVALUATE; return; };
EVALUATE ws => { type = EVALUATE; return; };
END %eof{ type = END; return; };
END ws => { type = END; return; };
BEGIN %eof{ type = BEGIN; return; };
BEGIN ws => { type = BEGIN; return; };
')' => { type = LPAREN; return; };
*|;
}%%
namespace {
%% machine classify;
%% write data;
%% machine main;
%% write data;
}
void phase2::flush() {
// remove white space...
while (!scratch.empty() && isspace(scratch.back())) scratch.pop_back();
if (!scratch.empty()) {
if (!type) classify();
parse(type, std::move(scratch));
}
type = 0;
scratch.clear();
}
bool phase2::special() {
if (!type) classify();
switch (type) {
case IF:
case ELSE:
case ELSE_IF:
case EVALUATE:
return true;
default:
return false;
}
}
void phase2::classify() {
if (type) return;
if (scratch.empty()) return;
int cs;
int act;
const unsigned char *p = (const unsigned char *)scratch.data();
const unsigned char *pe = p + scratch.size();
const unsigned char *eof = pe;
const unsigned char *te, *ts;
type = COMMAND;
%% machine classify;
%% write init;
%% write exec;
}
void phase2::process(const std::string &line) {
int cs;
int act;
const unsigned char *p = (const unsigned char *)line.data();
const unsigned char *pe = p + line.size();
const unsigned char *eof = pe;
const unsigned char *te, *ts;
scratch.clear();
type = 0;
%% machine main;
%% write init;
%% write exec;
flush();
parse(NL, "");
exec();
}
void phase2::finish() {
parse(0, "");
exec();
}
void phase2::exec() {
if (pipe_to) {
for (auto &p : command_queue) {
if (p) {
pipe_to(std::move(p));
}
}
command_queue.clear();
}
}