summaryrefslogtreecommitdiffstats
path: root/src/parsers.cc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2011-05-22 17:15:11 (GMT)
committerEvan Martin <martine@danga.com>2011-05-27 02:35:39 (GMT)
commit55fd4232d35de1f163310333d216d81a35cc0ef1 (patch)
tree1b0f3dedb6bc5b216ba8ae0809f78d20e45323f6 /src/parsers.cc
parent976166706db05dcd4496586ae995b7fdb1afab35 (diff)
downloadNinja-55fd4232d35de1f163310333d216d81a35cc0ef1.zip
Ninja-55fd4232d35de1f163310333d216d81a35cc0ef1.tar.gz
Ninja-55fd4232d35de1f163310333d216d81a35cc0ef1.tar.bz2
switch to $ as the line continuation char
This means that backslashes are passed through without interpretation, allowing us to support Windows paths without worrying about escaping.
Diffstat (limited to 'src/parsers.cc')
-rw-r--r--src/parsers.cc34
1 files changed, 24 insertions, 10 deletions
diff --git a/src/parsers.cc b/src/parsers.cc
index 4f04e42..2599b07 100644
--- a/src/parsers.cc
+++ b/src/parsers.cc
@@ -66,12 +66,14 @@ void Tokenizer::SkipWhitespace(bool newline) {
if (token_.type_ == Token::NEWLINE && newline)
Newline(NULL);
+ const char kContinuation = makefile_flavor_ ? '\\' : '$';
+
while (cur_ < end_) {
if (*cur_ == ' ') {
++cur_;
} else if (newline && *cur_ == '\n') {
Newline(NULL);
- } else if (*cur_ == '\\' && cur_ + 1 < end_ && cur_[1] == '\n') {
+ } else if (*cur_ == kContinuation && cur_ + 1 < end_ && cur_[1] == '\n') {
++cur_; ++cur_;
cur_line_ = cur_;
++line_number_;
@@ -101,7 +103,7 @@ static bool IsIdentChar(char c) {
('a' <= c && c <= 'z') ||
('+' <= c && c <= '9') || // +,-./ and numbers
('A' <= c && c <= 'Z') ||
- (c == '_') || (c == '$');
+ (c == '_') || (c == '$') || (c == '\\');
}
bool Tokenizer::ExpectToken(Token::Type expected, string* err) {
@@ -131,10 +133,23 @@ bool Tokenizer::ReadIdent(string* out) {
return true;
}
+// A note on backslashes in Makefiles, from reading the docs:
+// Backslash-newline is the line continuation character.
+// Backslash-# escapes a # (otherwise meaningful as a comment start).
+// Backslash-% escapes a % (otherwise meaningful as a special).
+// Finally, quoting the GNU manual, "Backslashes that are not in danger
+// of quoting ‘%’ characters go unmolested."
+// How do you end a line with a backslash? The netbsd Make docs suggest
+// reading the result of a shell command echoing a backslash!
+//
+// Rather than implement the above, we do the simpler thing here.
+// If anyone actually has depfiles that rely on the more complicated
+// behavior we can adjust this.
bool Tokenizer::ReadToNewline(string *text, string* err, size_t max_length) {
// XXX token_.clear();
+ const char kContinuation = makefile_flavor_ ? '\\' : '$';
while (cur_ < end_ && *cur_ != '\n') {
- if (*cur_ == '\\') {
+ if (*cur_ == kContinuation) {
// Might be a line continuation; peek ahead to check.
if (cur_ + 1 >= end_)
return Error("unexpected eof", err);
@@ -144,10 +159,7 @@ bool Tokenizer::ReadToNewline(string *text, string* err, size_t max_length) {
continue;
}
- // XXX we just let other backslashes through verbatim now.
- // This may not be wise.
- text->push_back(*cur_);
- ++cur_;
+ // Otherwise, just treat it like a normal character.
text->push_back(*cur_);
++cur_;
} else {
@@ -167,7 +179,7 @@ Token::Type Tokenizer::PeekToken() {
return token_.type_;
token_.pos_ = cur_;
- if (whitespace_significant_ && cur_indent_ == -1) {
+ if (!makefile_flavor_ && cur_indent_ == -1) {
cur_indent_ = cur_ - cur_line_;
if (cur_indent_ != last_indent_) {
if (cur_indent_ > last_indent_) {
@@ -227,7 +239,9 @@ void Tokenizer::ConsumeToken() {
token_.Clear();
}
-MakefileParser::MakefileParser() : tokenizer_(false) {}
+MakefileParser::MakefileParser() {
+ tokenizer_.SetMakefileFlavor();
+}
bool MakefileParser::Parse(const string& input, string* err) {
tokenizer_.Start(input.data(), input.data() + input.size());
@@ -252,7 +266,7 @@ bool MakefileParser::Parse(const string& input, string* err) {
}
ManifestParser::ManifestParser(State* state, FileReader* file_reader)
- : state_(state), file_reader_(file_reader), tokenizer_(true) {
+ : state_(state), file_reader_(file_reader) {
env_ = &state->bindings_;
}
bool ManifestParser::Load(const string& filename, string* err) {