From ea9d28c0e5fe16d5a0ade210f40cb98ea191d318 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 20 Oct 2016 15:33:39 +0200 Subject: Use special mode for attribute lexing --- build2/lexer | 14 +++++++++----- build2/lexer.cxx | 34 +++++++++++++++++++++++++--------- build2/parser.cxx | 12 +++--------- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/build2/lexer b/build2/lexer index df8c852..f0a0fa6 100644 --- a/build2/lexer +++ b/build2/lexer @@ -21,15 +21,18 @@ namespace build2 // characters (e.g., '+', '=') as special so that we can use them in the // variable values, e.g., 'foo = g++'. In contrast, in the variable mode, we // restrict certain character (e.g., '/') from appearing in the name. The - // eval mode is used in the evaluation context. Quoted are internal modes - // and should not be set explicitly. + // attribute mode is like value except it doesn't treat '{' and '}' as + // special (so we cannot have name groups in attributes). The eval mode is + // used in the evaluation context. Quoted are internal modes and should not + // be set explicitly. // // Note that the normal, value, and eval modes split words separated by the // pair character (to disable pairs one can pass '\0' as a pair character). // - // The alternnative modes must be set manually. The value mode is - // automatically reset after the end of the line. The variable mode is reset - // after the word token. And the eval mode is reset after the closing ')'. + // The alternnative modes must be set manually. The value mode automatically + // expires after the end of the line. The attribute mode expires after the + // closing ']'. The variable mode expires after the word token. And the eval + // mode expires after the closing ')'. // // Note that normally it is only safe to switch mode when the current token // is not quoted (or, more generally, when you are not in the double-quoted @@ -49,6 +52,7 @@ namespace build2 normal = base_type::value_next, variable, value, + attribute, eval, single_quoted, double_quoted, diff --git a/build2/lexer.cxx b/build2/lexer.cxx index 8760c13..f2426e7 100644 --- a/build2/lexer.cxx +++ b/build2/lexer.cxx @@ -54,6 +54,13 @@ namespace build2 p = ps; break; } + case lexer_mode::attribute: + { + s1 = " $(]#\t\n"; + s2 = " "; + p = ps; + break; + } case lexer_mode::eval: { s1 = ":<>=! $(){}[]#\t\n"; @@ -87,11 +94,12 @@ namespace build2 switch (m) { case lexer_mode::normal: - case lexer_mode::variable: - case lexer_mode::value: break; - case lexer_mode::eval: return next_eval (); + case lexer_mode::value: + case lexer_mode::attribute: + case lexer_mode::variable: break; + case lexer_mode::eval: return next_eval (); case lexer_mode::double_quoted: return next_quoted (); - default: assert (false); // Unhandled custom mode. + default: assert (false); // Unhandled custom mode. } bool sep (skip_spaces ()); @@ -109,8 +117,7 @@ namespace build2 // Handle pair separator. // - if ((m == lexer_mode::normal || m == lexer_mode::value) && - c == st.sep_pair) + if (c == st.sep_pair) return make_token (type::pair_separator); switch (c) @@ -130,15 +137,24 @@ namespace build2 case '{': return make_token (type::lcbrace); case '}': return make_token (type::rcbrace); case '[': return make_token (type::lsbrace); - case ']': return make_token (type::rsbrace); + case ']': + { + // Expire attribute mode after closing ']'. + // + if (m == lexer_mode::attribute) + state_.pop (); + + return make_token (type::rsbrace); + } case '$': return make_token (type::dollar); case '(': return make_token (type::lparen); case ')': return make_token (type::rparen); } - // The following characters are not treated as special in the value mode. + // The following characters are not treated as special in the value and + // attribute modes. // - if (m != lexer_mode::value) + if (m != lexer_mode::value && m != lexer_mode::attribute) { switch (c) { diff --git a/build2/parser.cxx b/build2/parser.cxx index 64907b4..341ba34 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -1836,12 +1836,12 @@ namespace build2 // Using '@' for attribute key-value pairs would be just too ugly. Seeing // that we control what goes into keys/values, let's use a much nicer '='. // - mode (lexer_mode::value, '='); + mode (lexer_mode::attribute, '='); next (t, tt); - if (tt != type::rsbrace && tt != type::newline && tt != type::eos) + if (tt != type::rsbrace) { - names ns (parse_names (t, tt, false, "key-value", nullptr)); + names ns (parse_names (t, tt, false, "attribute", nullptr)); if (!pre_parse_) { @@ -1880,12 +1880,6 @@ namespace build2 } } - // Manually expire the value mode if we haven't reached newline/eos (where - // it expires automatically). - // - if (mode () == lexer_mode::value) - expire_mode (); - if (tt != type::rsbrace) fail (t) << "expected ']' instead of " << t; -- cgit v1.1