From dfd19b9637c6b917a40413a57b391d7ff27f50da Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 26 Mar 2020 07:03:50 +0200 Subject: Make buildfile parser reset'able Note that the testscript parser (which derives from the buildfile parser) is (still) not reset'able (this functionality is currently not needed so why complicate things). --- libbuild2/parser.cxx | 44 ++++++++++++++++++++++++++++++++------------ libbuild2/parser.hxx | 32 +++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index fbf3bda..2cb51c6 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -212,6 +212,17 @@ namespace build2 }; void parser:: + reset () + { + pre_parse_ = false; + attributes_.clear (); + default_target_ = nullptr; + peeked_ = false; + replay_ = replay::stop; + replay_data_.clear (); + } + + void parser:: parse_buildfile (istream& is, const path_name& in, scope& root, scope& base) { lexer l (is, in); @@ -223,12 +234,13 @@ namespace build2 { path_ = &l.name (); lexer_ = &l; + root_ = &root; scope_ = &base; - pbase_ = scope_->src_path_; target_ = nullptr; prerequisite_ = nullptr; - default_target_ = nullptr; + + pbase_ = scope_->src_path_; enter_buildfile (*path_); // Needs scope_. @@ -249,11 +261,14 @@ namespace build2 { path_ = &l.name (); lexer_ = &l; + + root_ = nullptr; scope_ = &s; - pbase_ = scope_->src_path_; // Normally NULL. target_ = nullptr; prerequisite_ = nullptr; + pbase_ = scope_->src_path_; // Normally NULL. + token t; type tt; parse_variable (t, tt, var, kind); @@ -268,11 +283,14 @@ namespace build2 { path_ = &l.name (); lexer_ = &l; + + root_ = nullptr; scope_ = &s; - pbase_ = b; target_ = nullptr; prerequisite_ = nullptr; + pbase_ = b; + token t; type tt; value rhs (parse_variable_value (t, tt)); @@ -1968,9 +1986,9 @@ namespace build2 if (val.type != nullptr) untypify (val); - export_value_ = move (val).as (); + export_value = move (val).as (); - if (export_value_.empty ()) + if (export_value.empty ()) fail (l) << "empty value in export"; next_after_newline (t, tt); @@ -3675,7 +3693,7 @@ namespace build2 bool has (tt == type::lsbrace); if (!pre_parse_) - attributes_.push (attributes {has, l, {}}); + attributes_.push_back (attributes {has, l, {}}); if (!has) return make_pair (false, l); @@ -3727,7 +3745,7 @@ namespace build2 } if (!pre_parse_) - attributes_.top ().ats.emplace_back (move (n), move (v)); + attributes_.back ().ats.emplace_back (move (n), move (v)); if (tt == type::comma) next (t, tt); @@ -5592,18 +5610,20 @@ namespace build2 buildspec parser:: parse_buildspec (istream& is, const path_name& in) { - path_ = ∈ - // We do "effective escaping" and only for ['"\$(] (basically what's // necessary inside a double-quoted literal plus the single quote). // + path_ = ∈ lexer l (is, *path_, 1 /* line */, "\'\"\\$("); lexer_ = &l; - scope_ = root_ = &ctx.global_scope.rw (); - pbase_ = &work; // Use current working directory. + + root_ = &ctx.global_scope.rw (); + scope_ = root_; target_ = nullptr; prerequisite_ = nullptr; + pbase_ = &work; // Use current working directory. + // Turn on the buildspec mode/pairs recognition with '@' as the pair // separator (e.g., src_root/@out_root/exe{foo bar}). // diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx index ba707da..6d78ce1 100644 --- a/libbuild2/parser.hxx +++ b/libbuild2/parser.hxx @@ -4,8 +4,6 @@ #ifndef LIBBUILD2_PARSER_HXX #define LIBBUILD2_PARSER_HXX -#include - #include #include #include @@ -60,9 +58,22 @@ namespace build2 parse_export_stub (istream& is, const path_name& name, scope& r, scope& b) { parse_buildfile (is, name, r, b); - return move (export_value_); + return move (export_value); } + // The above functions may be called again on the same parser instance + // after a reset. + // + void + reset (); + + // Ad hoc parsing results for some cases. + // + // Note that these are not touched by reset(). + // + public: + names export_value; + // Recursive descent parser. // protected: @@ -246,13 +257,13 @@ namespace build2 attributes_pop () { assert (!pre_parse_); - attributes r (move (attributes_.top ())); - attributes_.pop (); + attributes r (move (attributes_.back ())); + attributes_.pop_back (); return r; } attributes& - attributes_top () {return attributes_.top ();} + attributes_top () {return attributes_.back ();} // Source a stream optionnaly entering it as a buildfile and performing // the default target processing. @@ -703,6 +714,10 @@ namespace build2 protected: const fail_mark fail; + // Parser state. + // + // NOTE: remember to update reset() if adding anything here. + // protected: context& ctx; stage stage_; @@ -719,10 +734,9 @@ namespace build2 const dir_path* pbase_ = nullptr; // Current pattern base directory. - std::stack attributes_; + small_vector attributes_; - target* default_target_; - names export_value_; + target* default_target_ = nullptr; replay_token peek_; bool peeked_ = false; -- cgit v1.1