From 1219a40d07034c4d5c5a8bf2d07cd6ead27ccb22 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sun, 31 Jan 2016 00:41:02 -0500 Subject: [PATCH] phase parsing improvements --- phase1.h | 12 +++++++-- phase2.h | 8 ++++++ phase2.rl | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 9 deletions(-) diff --git a/phase1.h b/phase1.h index 5511a9e..c0b9e2c 100644 --- a/phase1.h +++ b/phase1.h @@ -24,11 +24,19 @@ public: void reset(); - //template - //phase1 &operator >>= (F &&f) { pipe_to = pipe_function(f); return *this; } phase1 &operator >>= (pipe_function f) { pipe_to = f; return *this; } + + template + phase1 &operator >>= (F &f) { + using std::placeholders::_1; + pipe_to = std::bind(&F::operator(), &f, _1); + return *this; + } + + + private: std::string scratch; pipe_function pipe_to; diff --git a/phase2.h b/phase2.h index 5968ec7..24de6c3 100644 --- a/phase2.h +++ b/phase2.h @@ -52,11 +52,19 @@ public: phase2 & operator=(const phase2 &) = delete; phase2 & operator=(phase2 &&) = default; + void operator()(const std::string &line) { process(line); } void process(const std::string &line); void finish(); phase2 &operator >>=(pipe_function f) { pipe_to = f; return *this; } + template + phase2 &operator >>= (F &f) { + using std::placeholders::_1; + pipe_to = std::bind(&F::operator(), &f, _1); + return *this; + } + private: void parse(int, std::string &&); diff --git a/phase2.rl b/phase2.rl index 3901bbc..98d00e8 100644 --- a/phase2.rl +++ b/phase2.rl @@ -14,9 +14,51 @@ action not_special { !special() } + + escape = 0xb6; ws = [ \t]; - + + + escape_seq = + escape any + ; + + sstring = + ['] + ( (any-[']) )* + ['] + $err{ + throw std::runtime_error("### MPW Shell - 's must occur in pairs."); + } + ; + + vstring = + [{] + ( (any-[{]) )* + [}] + $err{ + throw std::runtime_error("### MPW Shell - 's must occur in pairs."); + } + ; + + # double-quoted string. + dstring = + ["] + ( + escape_seq + | + (any-escape-["]) + )* + ["] + $err{ + throw std::runtime_error("### MPW Shell - \"s must occur in pairs."); + } + ; + + + main := |* + '||' when not_special => { flush(); parse(PIPE_PIPE, std::string(ts, te)); @@ -27,23 +69,42 @@ parse(AMP_AMP, std::string(ts, te)); }; - '(' when not_special => { + + # ( evaluate (1+2) ) is lparen, eval, rparen. + # need to balance parens here and terminate a special token when it goes negative. + + + '(' => { + if (special()) { + pcount++; + scratch.push_back(fc); + } else { flush(); parse(LPAREN, std::string(ts, te)); + } }; - # ) may include redirection so start a new token but don't parse it yet. - ')' when not_special => { + ')' => { + if (special() && pcount-- > 0) scratch.push_back(fc); + else { 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); }; + + sstring => { scratch.append(ts, te); }; + dstring => { scratch.append(ts, te); }; + vstring => { scratch.append(ts, te); }; + escape_seq => { scratch.append(ts, te); }; + + + (any-escape-['"{]) => { scratch.push_back(fc); }; *|; }%% @@ -80,7 +141,7 @@ BEGIN %eof{ type = BEGIN; return; }; BEGIN ws => { type = BEGIN; return; }; - ')' => { type = LPAREN; return; }; + '(' => { type = LPAREN; return; }; *|; }%% @@ -106,6 +167,7 @@ void phase2::flush() { scratch.clear(); } +/* slightly wrong since whitespace is needed for it to be special. */ bool phase2::special() { if (!type) classify(); @@ -140,6 +202,7 @@ void phase2::classify() { void phase2::process(const std::string &line) { + int pcount = 0; // special form parens cannot cross lines. int cs; int act; @@ -156,6 +219,8 @@ void phase2::process(const std::string &line) { %% write exec; flush(); + // 2 NLs to make the stack reduce. harmless if in a multi-line constuct. + parse(NL, ""); parse(NL, ""); exec(); @@ -185,6 +250,8 @@ void phase2::exec() { phase2::phase2() { parser = std::move(phase2_parser::make()); + //parser->trace(stdout, " ] "); + } #pragma mark - phase2_parser