From ea66709a853255c7957a8a7907fd21fa7f6cfd3f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 9 Sep 2015 15:56:54 +0200 Subject: Add support for quoting directive names Now only unquoted, literal names are recognized as directives, for example: 'print' = abc print $print --- build/b.cxx | 10 +++++----- build/file.cxx | 6 +++--- build/lexer.cxx | 7 ++++++- build/parser.cxx | 27 ++++++++++++++------------- build/token | 39 +++++++++++++++------------------------ build/token.cxx | 4 ++-- tests/directive/buildfile | 8 ++++++++ tests/directive/test.out | 1 + tests/directive/test.sh | 3 +++ 9 files changed, 57 insertions(+), 48 deletions(-) create mode 100644 tests/directive/buildfile create mode 100644 tests/directive/test.out create mode 100755 tests/directive/test.sh 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, ""); 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 (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 #include // size_t #include // uint64_t -#include #include // 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 << ""; break; case token_type::newline: os << ""; 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 - -- cgit v1.1