diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-09-08 13:28:26 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-09-08 13:43:26 +0200 |
commit | b5940dd5562bfa12d6d76dceb61540b4480a4982 (patch) | |
tree | 1e8095300b5413ca510baa10bcb840101b06417c | |
parent | efd76ff778c0b7b1f8cb9e0485bb9b4b62b149a7 (diff) |
Use mode stack in lexer
-rw-r--r-- | build/lexer | 34 | ||||
-rw-r--r-- | build/lexer.cxx | 32 | ||||
-rw-r--r-- | build/parser.cxx | 2 |
3 files changed, 44 insertions, 24 deletions
diff --git a/build/lexer b/build/lexer index 9a0582d..1e253fd 100644 --- a/build/lexer +++ b/build/lexer @@ -7,7 +7,9 @@ #include <string> #include <iosfwd> +#include <cstddef> // size_t #include <cstdint> // uint64_t +#include <cassert> #include <exception> #include <butl/char-scanner> @@ -27,13 +29,13 @@ namespace build // pairs modes are automatically reset after the end of the line. // The variable mode is automatically reset after the name token. // - enum class lexer_mode {normal, value, variable, pairs}; + enum class lexer_mode {normal, variable, value, pairs}; class lexer: protected butl::char_scanner { public: lexer (std::istream& is, const std::string& name) - : char_scanner (is), fail (name) {} + : char_scanner (is), fail (name) {mode_.push (lexer_mode::normal);} const std::string& name () const {return fail.name_;} @@ -44,12 +46,17 @@ namespace build void mode (lexer_mode m, char pair_separator = '=') { - next_mode_ = m; + mode_.push (m); pair_separator_ = pair_separator; } + // Expire the current mode early. + // + void + expire_mode () {mode_.pop ();} + lexer_mode - mode () const {return mode_;} + mode () const {return mode_.top ();} char pair_separator () const {return pair_separator_;} @@ -93,10 +100,23 @@ namespace build private: fail_mark fail; - lexer_mode mode_ {lexer_mode::normal}; + // Currently, the maximum mode nesting is 3: {normal, value, variable}. + // + struct mode_stack + { + static const size_t max_size = 3; + + void push (lexer_mode m) {assert (n_ != max_size); d_[n_++] = m;} + void pop () {assert (n_ != 0); n_--;} + lexer_mode top () const {return d_[n_ - 1];} + + private: + size_t n_ = 0; + lexer_mode d_[max_size]; + }; + + mode_stack mode_; char pair_separator_; - lexer_mode next_mode_ {lexer_mode::normal}; // Switch to for next token. - lexer_mode prev_mode_; // Return to after current mode expires. }; } diff --git a/build/lexer.cxx b/build/lexer.cxx index 4151087..f4733be 100644 --- a/build/lexer.cxx +++ b/build/lexer.cxx @@ -11,12 +11,6 @@ namespace build token lexer:: next () { - if (mode_ != next_mode_) - { - prev_mode_ = mode_; - mode_ = next_mode_; - } - bool sep (skip_spaces ()); xchar c (get ()); @@ -25,16 +19,18 @@ namespace build if (eos (c)) return token (token_type::eos, sep, ln, cn); + lexer_mode m (mode_.top ()); + switch (c) { // NOTE: remember to update name() if adding new punctuations. // case '\n': { - // Restore the normal mode at the end of the line. + // Expire value/pairs mode at the end of the line. // - if (mode_ == lexer_mode::value || mode_ == lexer_mode::pairs) - mode_ = next_mode_ = lexer_mode::normal; + if (m == lexer_mode::value || m == lexer_mode::pairs) + mode_.pop (); return token (token_type::newline, sep, ln, cn); } @@ -62,13 +58,13 @@ namespace build // Handle pair separator. // - if (mode_ == lexer_mode::pairs && c == pair_separator_) + if (m == lexer_mode::pairs && c == pair_separator_) return token (token_type::pair_separator, sep, ln, cn); // The following characters are not treated as special in the // value or pairs mode. // - if (mode_ != lexer_mode::value && mode_ != lexer_mode::pairs) + if (m != lexer_mode::value && m != lexer_mode::pairs) { // NOTE: remember to update name() if adding new punctuations. // @@ -107,19 +103,21 @@ namespace build uint64_t ln (c.line), cn (c.column); string lexeme; + lexer_mode m (mode_.top ()); + for (; !eos (c); c = peek ()) { bool done (false); // Handle pair separator. // - if (mode_ == lexer_mode::pairs && c == pair_separator_) + if (m == lexer_mode::pairs && c == pair_separator_) break; // The following characters are not treated as special in the // value or pairs mode. // - if (mode_ != lexer_mode::value && mode_ != lexer_mode::pairs) + if (m != lexer_mode::value && m != lexer_mode::pairs) { switch (c) { @@ -139,7 +137,7 @@ namespace build // While these extra characters are treated as the name end in // the variable mode. // - if (mode_ == lexer_mode::variable) + if (m == lexer_mode::variable) { switch (c) { @@ -198,8 +196,10 @@ namespace build // assert (c.line != ln || c.column != cn); - if (mode_ == lexer_mode::variable) - next_mode_ = prev_mode_; + // Expire variable mode at the end of the name. + // + if (m == lexer_mode::variable) + mode_.pop (); return token (lexeme, sep, ln, cn); } diff --git a/build/parser.cxx b/build/parser.cxx index f140bc7..2daf1ce 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -1024,7 +1024,7 @@ namespace build bool paren (tt == type::lparen); if (paren) { - lexer_->mode (lexer_mode::normal); + lexer_->expire_mode (); next (t, tt); } |