aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-03-02 09:10:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-03-02 09:10:28 +0200
commitfbd3c230d3861084b7316a6d5a8597cb00c9510b (patch)
treea5e1d1f5aeb77d74c66ac9874925d6e951cc0d3a
parentbbd05eb0c32a9614f012a1d9b75cef736a1d4150 (diff)
Implement value lexing mode
So that we can do foo=g++ without having to resort to quoting
-rw-r--r--build/lexer11
-rw-r--r--build/lexer.cxx76
2 files changed, 67 insertions, 20 deletions
diff --git a/build/lexer b/build/lexer
index 1944727..1723ae0 100644
--- a/build/lexer
+++ b/build/lexer
@@ -100,10 +100,17 @@ namespace build
std::uint64_t l_ {1};
std::uint64_t c_ {1};
- bool eos_ {false};
-
bool unget_ {false};
xchar buf_ {0, 0, 0};
+
+ bool eos_ {false};
+
+ // Context-dependent lexing mode. In the value mode we don't treat
+ // certain characters (e.g., +, =) as special so that we can use
+ // them in the variable values, e.g., 'foo = g++'.
+ //
+ enum class mode {normal, value};
+ mode mode_ {mode::normal};
};
}
diff --git a/build/lexer.cxx b/build/lexer.cxx
index 2870620..6836322 100644
--- a/build/lexer.cxx
+++ b/build/lexer.cxx
@@ -25,12 +25,13 @@ namespace build
//
case '\n':
{
+ // Restore the normal mode at the end of the line.
+ //
+ if (mode_ == mode::value)
+ mode_ = mode::normal;
+
return token (token_type::newline, ln, cn);
}
- case ':':
- {
- return token (token_type::colon, ln, cn);
- }
case '{':
{
return token (token_type::lcbrace, ln, cn);
@@ -39,16 +40,34 @@ namespace build
{
return token (token_type::rcbrace, ln, cn);
}
- case '=':
- {
- return token (token_type::equal, ln, cn);
- }
- case '+':
+ }
+
+ // The following characters are not treated as special in the
+ // value mode.
+ //
+ if (mode_ != mode::value)
+ {
+ // NOTE: remember to update name() if adding new punctuations.
+ //
+ switch (c)
{
- if (get () != '=')
- fail (c) << "expected = after +";
+ case ':':
+ {
+ return token (token_type::colon, ln, cn);
+ }
+ case '=':
+ {
+ mode_ = mode::value;
+ return token (token_type::equal, ln, cn);
+ }
+ case '+':
+ {
+ if (get () != '=')
+ fail (c) << "expected = after +";
- return token (token_type::plus_equal, ln, cn);
+ mode_ = mode::value;
+ return token (token_type::plus_equal, ln, cn);
+ }
}
}
@@ -127,35 +146,56 @@ namespace build
for (c = peek (); !is_eos (c); c = peek ())
{
+ bool done (false);
+
+ // The following characters are not treated as special in the
+ // value mode.
+ //
+ if (mode_ != mode::value)
+ {
+ switch (c)
+ {
+ case ':':
+ case '=':
+ case '+':
+ {
+ done = true;
+ break;
+ }
+ }
+
+ if (done)
+ break;
+ }
+
switch (c)
{
case ' ':
case '\t':
case '\n':
case '#':
- case ':':
case '{':
case '}':
- case '=':
- case '+':
{
+ done = true;
break;
}
case '\\':
{
get ();
lexeme += escape ();
- continue;
+ break;
}
default:
{
get ();
lexeme += c;
- continue;
+ break;
}
}
- break;
+ if (done)
+ break;
}
return token (lexeme, ln, cn);