diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-09-09 15:56:54 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-09-09 15:56:54 +0200 |
commit | ea66709a853255c7957a8a7907fd21fa7f6cfd3f (patch) | |
tree | 061f828174b4a1d9d5c5fbc0b3b7427b5eea1ee8 | |
parent | 8a9870ed59225972de389b7b4a494a57390bff1b (diff) |
Add support for quoting directive names
Now only unquoted, literal names are recognized as directives, for
example:
'print' = abc
print $print
-rw-r--r-- | build/b.cxx | 10 | ||||
-rw-r--r-- | build/file.cxx | 6 | ||||
-rw-r--r-- | build/lexer.cxx | 7 | ||||
-rw-r--r-- | build/parser.cxx | 27 | ||||
-rw-r--r-- | build/token | 39 | ||||
-rw-r--r-- | build/token.cxx | 4 | ||||
-rw-r--r-- | tests/directive/buildfile | 8 | ||||
-rw-r--r-- | tests/directive/test.out | 1 | ||||
-rwxr-xr-x | tests/directive/test.sh | 3 |
9 files changed, 57 insertions, 48 deletions
diff --git a/build/b.cxx b/build/b.cxx index bbfc635..665fac8 100644 --- a/build/b.cxx +++ b/build/b.cxx @@ -146,24 +146,24 @@ main (int argc, char* argv[]) lexer l (is, "<cmdline>"); token t (l.next ()); - if (t.type () == token_type::eos) + if (t.type == token_type::eos) continue; // Whitespace-only argument. // Unless this is a name followed by = or +=, assume it is // a start of the buildspec. // - if (t.type () != token_type::name) + if (t.type != token_type::name) break; - token_type tt (l.next ().type ()); + token_type tt (l.next ().type); if (tt != token_type::equal && tt != token_type::plus_equal) break; parser p; - t = p.parse_variable (l, *global_scope, t.name (), tt); + t = p.parse_variable (l, *global_scope, t.value, tt); - if (t.type () != token_type::eos) + if (t.type != token_type::eos) fail << "unexpected " << t << " in variable " << s; } diff --git a/build/file.cxx b/build/file.cxx index f8f62f9..f6fdd10 100644 --- a/build/file.cxx +++ b/build/file.cxx @@ -274,8 +274,8 @@ namespace build token t (lex.next ()); token_type tt; - if (t.type () != token_type::name || t.name () != var || - ((tt = lex.next ().type ()) != token_type::equal && + if (t.type != token_type::name || t.value != var || + ((tt = lex.next ().type) != token_type::equal && tt != token_type::plus_equal)) { error << "variable '" << var << "' expected as first line in " << rbf; @@ -284,7 +284,7 @@ namespace build parser p; temp_scope tmp (*global_scope); - p.parse_variable (lex, tmp, t.name (), tt); + p.parse_variable (lex, tmp, t.value, tt); auto l (tmp.vars[var]); assert (l.defined ()); diff --git a/build/lexer.cxx b/build/lexer.cxx index 133375b..e083b4a 100644 --- a/build/lexer.cxx +++ b/build/lexer.cxx @@ -152,6 +152,7 @@ namespace build string lexeme; lexer_mode m (mode_.top ()); + bool quoted (m == lexer_mode::quoted); for (; !eos (c); c = peek ()) { @@ -247,6 +248,7 @@ namespace build if (eos (c)) fail (c) << "unterminated single-quoted sequence"; + quoted = true; continue; } } @@ -281,7 +283,10 @@ namespace build if (m == lexer_mode::quoted) mode_.pop (); else + { mode_.push (lexer_mode::quoted); + quoted = true; + } m = mode_.top (); continue; @@ -307,7 +312,7 @@ namespace build if (m == lexer_mode::variable) mode_.pop (); - return token (lexeme, sep, ln, cn); + return token (lexeme, sep, quoted, ln, cn); } bool lexer:: diff --git a/build/parser.cxx b/build/parser.cxx index 42b9a98..1ceb193 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -90,11 +90,12 @@ namespace build tt != type::colon) // Empty name: ': ...' break; // Something else. Let our caller handle that. - // See if this is one of the keywords. + // See if this is one of the directives. This should be an + // unquoted literal name. // - if (tt == type::name) + if (tt == type::name && !t.quoted) { - const string& n (t.name ()); + const string& n (t.value); if (n == "print") { @@ -642,7 +643,7 @@ namespace build if (at == token_type::equal || at == token_type::plus_equal) { - var = &variable_pool.find (t.name ()); + var = &variable_pool.find (t.value); val = at == token_type::equal ? &scope_->assign (*var) : &scope_->append (*var); @@ -857,10 +858,10 @@ namespace build if (!concat.empty () && ((tt != type::name && tt != type::dollar && - tt != type::lparen) || peeked ().separated ())) + tt != type::lparen) || peeked ().separated)) { tt = type::name; - t = token (move (concat), true, t.line (), t.column ()); + t = token (move (concat), true, false, t.line, t.column); concat.clear (); } else if (!first) @@ -870,7 +871,7 @@ namespace build // if (tt == type::name) { - string name (t.name ()); //@@ move? + string name (t.value); //@@ move? tt = peek (); // Should we accumulate? If the buffer is not empty, then @@ -881,7 +882,7 @@ namespace build // if (!concat.empty () || // Continue. ((tt == type::dollar || - tt == type::lparen) && !peeked ().separated ())) // Start. + tt == type::lparen) && !peeked ().separated)) // Start. { concat += name; continue; @@ -1062,7 +1063,7 @@ namespace build string n; if (tt == type::name) - n = t.name (); + n = t.value; else if (tt == type::lparen) { lexer_->expire_mode (); @@ -1159,7 +1160,7 @@ namespace build if (!concat.empty () || // Continue. ((tt == type::name || // Start. tt == type::dollar || - tt == type::lparen) && !peeked ().separated ())) + tt == type::lparen) && !peeked ().separated)) { // This should be a simple value or a simple directory. The // token still points to the name (or closing paren). @@ -1642,7 +1643,7 @@ namespace build peeked_ = false; } - tt = t.type (); + tt = t.type; return tt; } @@ -1655,7 +1656,7 @@ namespace build peeked_ = true; } - return peek_.type (); + return peek_.type; } static location @@ -1663,6 +1664,6 @@ namespace build { assert (data != nullptr); const string& p (**static_cast<const string* const*> (data)); - return location (p.c_str (), t.line (), t.column ()); + return location (p.c_str (), t.line, t.column); } } diff --git a/build/token b/build/token index 3b9edb1..fedaba0 100644 --- a/build/token +++ b/build/token @@ -9,7 +9,6 @@ #include <iosfwd> #include <cstddef> // size_t #include <cstdint> // uint64_t -#include <cassert> #include <utility> // move namespace build @@ -33,34 +32,26 @@ namespace build class token { public: - token_type - type () const {return t_;} + token_type type; + bool separated; // Whitespace-separated from the previous token. + bool quoted; // Name (or some part of it) was quoted. - // Token is whitespace-separated from the previous token. - // - bool - separated () const {return s_;} + std::string value; // Only valid for name. - std::string const& - name () const {assert (t_ == token_type::name); return n_;} - - std::uint64_t line () const {return l_;} - std::uint64_t column () const {return c_;} + std::uint64_t line; + std::uint64_t column; public: token (token_type t, bool s, std::uint64_t l, std::uint64_t c) - : t_ (t), s_ (s), l_ (l), c_ (c) {} - - token (std::string n, bool s, std::uint64_t l, std::uint64_t c) - : t_ (token_type::name), s_ (s), n_ (std::move (n)), l_ (l), c_ (c) {} - - private: - token_type t_; - bool s_; - std::string n_; - - std::uint64_t l_; - std::uint64_t c_; + : type (t), separated (s), line (l), column (c) {} + + token (std::string n, bool s, bool q, std::uint64_t l, std::uint64_t c) + : type (token_type::name), + separated (s), + quoted (q), + value (std::move (n)), + line (l), + column (c) {} }; // Output the token value in a format suitable for diagnostics. diff --git a/build/token.cxx b/build/token.cxx index 22f5b75..35a7f89 100644 --- a/build/token.cxx +++ b/build/token.cxx @@ -13,7 +13,7 @@ namespace build ostream& operator<< (ostream& os, const token& t) { - switch (t.type ()) + switch (t.type) { case token_type::eos: os << "<end-of-file>"; break; case token_type::newline: os << "<newline>"; break; @@ -26,7 +26,7 @@ namespace build case token_type::dollar: os << "$"; break; case token_type::lparen: os << "("; break; case token_type::rparen: os << ")"; break; - case token_type::name: os << t.name (); break; + case token_type::name: os << t.value; break; } return os; diff --git a/tests/directive/buildfile b/tests/directive/buildfile new file mode 100644 index 0000000..0f83717 --- /dev/null +++ b/tests/directive/buildfile @@ -0,0 +1,8 @@ +"print" = a +'print' += b +pr"int" += c +print'' += d + +print $print + +./: diff --git a/tests/directive/test.out b/tests/directive/test.out new file mode 100644 index 0000000..8e13e46 --- /dev/null +++ b/tests/directive/test.out @@ -0,0 +1 @@ +a b c d diff --git a/tests/directive/test.sh b/tests/directive/test.sh new file mode 100755 index 0000000..b898b3c --- /dev/null +++ b/tests/directive/test.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind -q b -q | diff -u test.out - |