diff --git a/configure.py b/configure.py index 20b389d..6aece3f 100755 --- a/configure.py +++ b/configure.py @@ -504,6 +504,7 @@ for name in ['build', 'line_printer', 'manifest_parser', 'metrics', + 'parser', 'state', 'string_piece_util', 'util', diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc index 27c423b..226acb0 100644 --- a/src/manifest_parser.cc +++ b/src/manifest_parser.cc @@ -18,41 +18,18 @@ #include #include -#include "disk_interface.h" #include "graph.h" -#include "metrics.h" #include "state.h" #include "util.h" #include "version.h" ManifestParser::ManifestParser(State* state, FileReader* file_reader, ManifestParserOptions options) - : state_(state), file_reader_(file_reader), + : Parser(state, file_reader), options_(options), quiet_(false) { env_ = &state->bindings_; } -bool ManifestParser::Load(const string& filename, string* err, Lexer* parent) { - METRIC_RECORD(".ninja parse"); - string contents; - string read_err; - if (file_reader_->ReadFile(filename, &contents, &read_err) != FileReader::Okay) { - *err = "loading '" + filename + "': " + read_err; - if (parent) - parent->Error(string(*err), err); - return false; - } - - // The lexer needs a nul byte at the end of its input, to know when it's done. - // It takes a StringPiece, and StringPiece's string constructor uses - // string::data(). data()'s return value isn't guaranteed to be - // null-terminated (although in practice - libc++, libstdc++, msvc's stl -- - // it is, and C++11 demands that too), so add an explicit nul byte. - contents.resize(contents.size() + 1); - - return Parse(filename, contents, err); -} - bool ManifestParser::Parse(const string& filename, const string& input, string* err) { lexer_.Start(filename, input); @@ -434,14 +411,3 @@ bool ManifestParser::ParseFileInclude(bool new_scope, string* err) { return true; } - -bool ManifestParser::ExpectToken(Lexer::Token expected, string* err) { - Lexer::Token token = lexer_.ReadToken(); - if (token != expected) { - string message = string("expected ") + Lexer::TokenName(expected); - message += string(", got ") + Lexer::TokenName(token); - message += Lexer::TokenErrorHint(expected); - return lexer_.Error(message, err); - } - return true; -} diff --git a/src/manifest_parser.h b/src/manifest_parser.h index 76c17b0..e14d069 100644 --- a/src/manifest_parser.h +++ b/src/manifest_parser.h @@ -15,16 +15,10 @@ #ifndef NINJA_MANIFEST_PARSER_H_ #define NINJA_MANIFEST_PARSER_H_ -#include - -using namespace std; - -#include "lexer.h" +#include "parser.h" struct BindingEnv; struct EvalString; -struct FileReader; -struct State; enum DupeEdgeAction { kDupeEdgeActionWarn, @@ -45,13 +39,10 @@ struct ManifestParserOptions { }; /// Parses .ninja files. -struct ManifestParser { +struct ManifestParser : public Parser { ManifestParser(State* state, FileReader* file_reader, ManifestParserOptions options = ManifestParserOptions()); - /// Load and parse a file. - bool Load(const string& filename, string* err, Lexer* parent = NULL); - /// Parse a text string of input. Used by tests. bool ParseTest(const string& input, string* err) { quiet_ = true; @@ -72,14 +63,7 @@ private: /// Parse either a 'subninja' or 'include' line. bool ParseFileInclude(bool new_scope, string* err); - /// If the next token is not \a expected, produce an error string - /// saying "expected foo, got bar". - bool ExpectToken(Lexer::Token expected, string* err); - - State* state_; BindingEnv* env_; - FileReader* file_reader_; - Lexer lexer_; ManifestParserOptions options_; bool quiet_; }; diff --git a/src/parser.cc b/src/parser.cc new file mode 100644 index 0000000..745c532 --- /dev/null +++ b/src/parser.cc @@ -0,0 +1,51 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "parser.h" + +#include "disk_interface.h" +#include "metrics.h" + +bool Parser::Load(const string& filename, string* err, Lexer* parent) { + METRIC_RECORD(".ninja parse"); + string contents; + string read_err; + if (file_reader_->ReadFile(filename, &contents, &read_err) != + FileReader::Okay) { + *err = "loading '" + filename + "': " + read_err; + if (parent) + parent->Error(string(*err), err); + return false; + } + + // The lexer needs a nul byte at the end of its input, to know when it's done. + // It takes a StringPiece, and StringPiece's string constructor uses + // string::data(). data()'s return value isn't guaranteed to be + // null-terminated (although in practice - libc++, libstdc++, msvc's stl -- + // it is, and C++11 demands that too), so add an explicit nul byte. + contents.resize(contents.size() + 1); + + return Parse(filename, contents, err); +} + +bool Parser::ExpectToken(Lexer::Token expected, string* err) { + Lexer::Token token = lexer_.ReadToken(); + if (token != expected) { + string message = string("expected ") + Lexer::TokenName(expected); + message += string(", got ") + Lexer::TokenName(token); + message += Lexer::TokenErrorHint(expected); + return lexer_.Error(message, err); + } + return true; +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..e2d2b97 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,50 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef NINJA_PARSER_H_ +#define NINJA_PARSER_H_ + +#include + +using namespace std; + +#include "lexer.h" + +struct FileReader; +struct State; + +/// Base class for parsers. +struct Parser { + Parser(State* state, FileReader* file_reader) + : state_(state), file_reader_(file_reader) {} + + /// Load and parse a file. + bool Load(const string& filename, string* err, Lexer* parent = NULL); + +protected: + /// If the next token is not \a expected, produce an error string + /// saying "expected foo, got bar". + bool ExpectToken(Lexer::Token expected, string* err); + + State* state_; + FileReader* file_reader_; + Lexer lexer_; + +private: + /// Parse a file, given its contents as a string. + virtual bool Parse(const string& filename, const string& input, + string* err) = 0; +}; + +#endif // NINJA_PARSER_H_