aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-09-08 13:28:26 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-09-08 13:43:26 +0200
commitb5940dd5562bfa12d6d76dceb61540b4480a4982 (patch)
tree1e8095300b5413ca510baa10bcb840101b06417c
parentefd76ff778c0b7b1f8cb9e0485bb9b4b62b149a7 (diff)
Use mode stack in lexer
-rw-r--r--build/lexer34
-rw-r--r--build/lexer.cxx32
-rw-r--r--build/parser.cxx2
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);
}