diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2014-12-15 10:43:16 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2014-12-15 10:43:16 +0200 |
commit | 835ed5f7080a98e9ee80ac08d5585ccdbb63fe0e (patch) | |
tree | 23eda92dd9df59e698f6d4a1eb24658fb3fcf323 /build/parser.cxx | |
parent | 257ad3c2c5e633d2fd3f2228021ac3ae8d6d07cb (diff) |
Parse directory scopes
Diffstat (limited to 'build/parser.cxx')
-rw-r--r-- | build/parser.cxx | 155 |
1 files changed, 119 insertions, 36 deletions
diff --git a/build/parser.cxx b/build/parser.cxx index 669ac8b..348d285 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -19,7 +19,6 @@ namespace build operator<< (ostream&, const token&); typedef token_type type; - typedef token_punctuation punc; void parser:: parse (istream& is, const path& p) @@ -28,31 +27,122 @@ namespace build lexer_ = &l; path_ = &p; - token t (0, 0); // eos + token t (type::eos, 0, 0); type tt; + next (t, tt); - for (next (t, tt); tt != type::eos; ) + parse_clause (t, tt); + + if (tt != type::eos) + { + error (t) << "unexpected " << t << endl; + throw parser_error (); + } + } + + void parser:: + parse_clause (token& t, token_type& tt) + { + while (tt != type::eos) { // We always start with one or more names. // - names (t, tt); + if (tt != type::name && tt != type::lcbrace) + break; // Something else. Let our caller handle that. + + names ns (parse_names (t, tt)); - if (t.is (punc::colon)) + if (tt == type::colon) { next (t, tt); - if (tt == type::name || t.is (punc::lcbrace)) - names (t, tt); + // Dependency declaration. + // + if (tt == type::name || tt == type::lcbrace) + { + names ns (parse_names (t, tt)); - if (t.is (punc::newline)) - next (t, tt); - else if (tt != type::eos) + if (tt == type::newline) + next (t, tt); + else if (tt != type::eos) + { + error (t) << "expected newline instead of " << t << endl; + throw parser_error (); + } + + continue; + } + + if (tt == type::newline) { - error (t) << "expected newline insetad of " << t << endl; - throw parser_error (); + // See if we have a directory/target scope. + // + if (next (t, tt) == type::lcbrace) + { + // Should be on its own line. + // + if (next (t, tt) != type::newline) + { + error (t) << "expected newline after '{'" << endl; + throw parser_error (); + } + + // See if this is a directory or target scope. Different + // things can appear inside depending on which it is. + // + bool dir (false); + for (const auto& n: ns) + { + if (n.back () == '/') + { + if (ns.size () != 1) + { + // @@ TODO: point to name. + // + error (t) << "multiple names in directory scope" << endl; + throw parser_error (); + } + + dir = true; + } + } + + next (t, tt); + + if (dir) + // A directory scope can contain anything that a top level can. + // + parse_clause (t, tt); + else + { + // @@ TODO: target scope. + } + + if (tt != type::rcbrace) + { + error (t) << "expected '}' instead of " << t << endl; + throw parser_error (); + } + + // Should be on its own line. + // + if (next (t, tt) == type::newline) + next (t, tt); + else if (tt != type::eos) + { + error (t) << "expected newline after '}'" << endl; + throw parser_error (); + } + } + + continue; } - continue; + if (tt == type::eos) + continue; + + error (t) << "expected newline insetad of " << t << endl; + throw parser_error (); } error (t) << "unexpected " << t << endl; @@ -61,18 +151,18 @@ namespace build } void parser:: - names (token& t, type& tt) + parse_names (token& t, type& tt, names& ns) { for (bool first (true);; first = false) { // Untyped name group, e.g., '{foo bar}'. // - if (t.is (punc::lcbrace)) + if (tt == type::lcbrace) { next (t, tt); - names (t, tt); + parse_names (t, tt, ns); - if (!t.is (punc::rcbrace)) + if (tt != type::rcbrace) { error (t) << "expected '}' instead of " << t << endl; throw parser_error (); @@ -90,9 +180,7 @@ namespace build // See if this is a type name, that is, it is followed by '{'. // - next (t, tt); - - if (t.is (punc::lcbrace)) + if (next (t, tt) == type::lcbrace) { //cout << "type: " << name << endl; @@ -101,9 +189,9 @@ namespace build // - detect nested typed name groups, e.g., 'cxx{hxx{foo}}'. // next (t, tt); - names (t, tt); + parse_names (t, tt, ns); - if (!t.is (punc::rcbrace)) + if (tt != type::rcbrace) { error (t) << "expected '}' instead of " << t << endl; throw parser_error (); @@ -115,6 +203,7 @@ namespace build // This is a target, directory, or variable name. //cout << "name: " << name << endl; + ns.push_back (name); continue; } @@ -126,11 +215,12 @@ namespace build } } - void parser:: + token_type parser:: next (token& t, token_type& tt) { t = lexer_->next (); tt = t.type (); + return tt; } ostream& parser:: @@ -147,19 +237,12 @@ namespace build { switch (t.type ()) { - case token_type::eos: os << "<end-of-stream>"; break; - case token_type::punctuation: - { - switch (t.punctuation ()) - { - case token_punctuation::newline: os << "<newline>"; break; - case token_punctuation::colon: os << "':'"; break; - case token_punctuation::lcbrace: os << "'{'"; break; - case token_punctuation::rcbrace: os << "'}'"; break; - } - break; - } - case token_type::name: os << '\'' << t.name () << '\''; break; + case token_type::eos: os << "<end-of-stream>"; break; + case token_type::newline: os << "<newline>"; break; + case token_type::colon: os << "':'"; break; + case token_type::lcbrace: os << "'{'"; break; + case token_type::rcbrace: os << "'}'"; break; + case token_type::name: os << '\'' << t.name () << '\''; break; } return os; |