aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-09-09 15:56:54 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-09-09 15:56:54 +0200
commitea66709a853255c7957a8a7907fd21fa7f6cfd3f (patch)
tree061f828174b4a1d9d5c5fbc0b3b7427b5eea1ee8
parent8a9870ed59225972de389b7b4a494a57390bff1b (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.cxx10
-rw-r--r--build/file.cxx6
-rw-r--r--build/lexer.cxx7
-rw-r--r--build/parser.cxx27
-rw-r--r--build/token39
-rw-r--r--build/token.cxx4
-rw-r--r--tests/directive/buildfile8
-rw-r--r--tests/directive/test.out1
-rwxr-xr-xtests/directive/test.sh3
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 -