aboutsummaryrefslogtreecommitdiff
path: root/build/parser.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'build/parser.cxx')
-rw-r--r--build/parser.cxx155
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;