summaryrefslogtreecommitdiffstats
path: root/parse.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'parse.cxx')
-rw-r--r--parse.cxx188
1 files changed, 112 insertions, 76 deletions
diff --git a/parse.cxx b/parse.cxx
index 82116009..59f3cb8a 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -150,6 +150,27 @@ parser::last ()
}
+
+template <typename OPERAND>
+bool eval_comparison (const OPERAND& lhs, const token* op, const OPERAND& rhs)
+{
+ if (op->type == tok_operator && op->content == "<=")
+ { return lhs <= rhs; }
+ else if (op->type == tok_operator && op->content == ">=")
+ { return lhs >= rhs; }
+ else if (op->type == tok_operator && op->content == "<")
+ { return lhs < rhs; }
+ else if (op->type == tok_operator && op->content == ">")
+ { return lhs > rhs; }
+ else if (op->type == tok_operator && op->content == "==")
+ { return lhs == rhs; }
+ else if (op->type == tok_operator && op->content == "!=")
+ { return lhs != rhs; }
+ else
+ throw parse_error ("expected comparison operator", op);
+}
+
+
// Here, we perform on-the-fly preprocessing.
// The basic form is %( CONDITION %? THEN-TOKENS %: ELSE-TOKENS %)
// where CONDITION is: kernel_v[r] COMPARISON-OP "version-string"
@@ -159,7 +180,7 @@ parser::last ()
// The %: ELSE-TOKENS part is optional.
//
// e.g. %( kernel_v > "2.5" %? "foo" %: "baz" %)
-// e.g. %( arch != "i686" %? "foo" %: "baz" %)
+// e.g. %( arch != "i?86" %? "foo" %: "baz" %)
//
// Up to an entire %( ... %) expression is processed by a single call
// to this function. Tokens included by any nested conditions are
@@ -241,35 +262,19 @@ bool eval_pp_conditional (systemtap_session& s,
return result;
}
- else if ((l->type == tok_string && r->type == tok_string)
- || (l->type == tok_number && r->type == tok_number))
+ else if (l->type == tok_string && r->type == tok_string)
{
- // collect acceptable strverscmp results.
- int rvc_ok1, rvc_ok2;
- if (op->type == tok_operator && op->content == "<=")
- { rvc_ok1 = -1; rvc_ok2 = 0; }
- else if (op->type == tok_operator && op->content == ">=")
- { rvc_ok1 = 1; rvc_ok2 = 0; }
- else if (op->type == tok_operator && op->content == "<")
- { rvc_ok1 = -1; rvc_ok2 = -1; }
- else if (op->type == tok_operator && op->content == ">")
- { rvc_ok1 = 1; rvc_ok2 = 1; }
- else if (op->type == tok_operator && op->content == "==")
- { rvc_ok1 = 0; rvc_ok2 = 0; }
- else if (op->type == tok_operator && op->content == "!=")
- { rvc_ok1 = -1; rvc_ok2 = 1; }
- else
- throw parse_error ("expected comparison operator", op);
-
- int rvc_result = l->content.compare(r->content);
-
- // normalize rvc_result
- if (rvc_result < 0) rvc_result = -1;
- if (rvc_result > 0) rvc_result = 1;
-
+ string lhs = l->content;
+ string rhs = r->content;
+ return eval_comparison (lhs, op, rhs);
+ // NB: no wildcarding option here
+ }
+ else if (l->type == tok_number && r->type == tok_number)
+ {
+ int64_t lhs = lex_cast<int64_t>(l->content);
+ int64_t rhs = lex_cast<int64_t>(r->content);
+ return eval_comparison (lhs, op, rhs);
// NB: no wildcarding option here
-
- return (rvc_result == rvc_ok1 || rvc_result == rvc_ok2);
}
else if (l->type == tok_string && r->type == tok_number
&& op->type == tok_operator)
@@ -277,17 +282,18 @@ bool eval_pp_conditional (systemtap_session& s,
else if (l->type == tok_number && r->type == tok_string
&& op->type == tok_operator)
throw parse_error ("expected number literal as right value", r);
+
// XXX: support other forms? "CONFIG_SMP" ?
+
else
throw parse_error ("expected 'arch' or 'kernel_v' or 'kernel_vr'\n"
" or comparison between strings or integers", l);
}
-// expand_args is used to know if we must expand $x and @x identifiers.
// Only tokens corresponding to the TRUE statement must be expanded
const token*
-parser::scan_pp (bool wildcard, bool expand_args)
+parser::scan_pp (bool wildcard)
{
while (true)
{
@@ -298,7 +304,7 @@ parser::scan_pp (bool wildcard, bool expand_args)
return t;
}
- const token* t = input.scan (wildcard, expand_args); // NB: not recursive!
+ const token* t = input.scan (wildcard); // NB: not recursive!
if (t == 0) // EOF
return t;
@@ -308,77 +314,108 @@ parser::scan_pp (bool wildcard, bool expand_args)
// We have a %( - it's time to throw a preprocessing party!
const token *l, *op, *r;
- l = input.scan (false, expand_args); // NB: not recursive, though perhaps could be
- op = input.scan (false, expand_args);
- r = input.scan (false, expand_args);
+ l = input.scan (false); // NB: not recursive, though perhaps could be
+ op = input.scan (false);
+ r = input.scan (false);
if (l == 0 || op == 0 || r == 0)
throw parse_error ("incomplete condition after '%('", t);
// NB: consider generalizing to consume all tokens until %?, and
// passing that as a vector to an evaluator.
// Do not evaluate the condition if we haven't expanded everything.
- // This may occured when having several recursive conditionals.
- bool result = expand_args && eval_pp_conditional (session, l, op, r);
+ // This may occur when having several recursive conditionals.
+ bool result = eval_pp_conditional (session, l, op, r);
delete l;
delete op;
delete r;
-
+
+ /*
+ clog << "PP eval (" << *t << ") == " << result << endl;
+ */
+
const token *m = input.scan (); // NB: not recursive
if (! (m && m->type == tok_operator && m->content == "%?"))
throw parse_error ("expected '%?' marker for conditional", t);
delete m; // "%?"
vector<const token*> my_enqueued_pp;
- bool have_token = false;
-
+
+ int nesting = 0;
while (true) // consume THEN tokens
{
- m = scan_pp (wildcard, result); // NB: recursive
- if (m == 0)
- throw parse_error (have_token ?
- "incomplete conditional - missing %: or %)" :
- "missing THEN tokens for conditional",
- t);
-
- have_token = true;
- if (m->type == tok_operator && (m->content == "%:" || // ELSE
- m->content == "%)")) // END
+ try
+ {
+ m = result ? scan_pp (wildcard) : input.scan (wildcard);
+ }
+ catch (const parse_error &e)
+ {
+ if (result) throw e; // propagate errors if THEN branch taken
+ continue;
+ }
+
+ if (m && m->type == tok_operator && m->content == "%(") // nested %(
+ nesting ++;
+ if (nesting == 0 && m && (m->type == tok_operator && (m->content == "%:" || // ELSE
+ m->content == "%)"))) // END
break;
- // enqueue token
- if (result)
+ if (nesting && m && m->type == tok_operator && m->content == "%)") // nested %)
+ nesting --;
+
+ if (!m)
+ throw parse_error ("incomplete conditional - missing '%:' or '%)'", t);
+ if (result)
my_enqueued_pp.push_back (m);
- else
- delete m; // unused token
- // continue
+ if (!result)
+ delete m; // do nothing, just dispose of unkept THEN token
+
+ continue;
}
- have_token = false;
if (m && m->type == tok_operator && m->content == "%:") // ELSE
{
delete m; // "%:"
+ int nesting = 0;
while (true)
{
- m = scan_pp (wildcard, expand_args && !result); // NB: recursive
- if (m == 0)
- throw parse_error (have_token ?
- "incomplete conditional - missing %)" :
- "missing ELSE tokens for conditional",
- t);
-
- have_token = true;
- if (m->type == tok_operator && m->content == "%)") // END
+ try
+ {
+ m = result ? input.scan (wildcard) : scan_pp (wildcard);
+ }
+ catch (const parse_error& e)
+ {
+ if (!result) throw e; // propagate errors if ELSE branch taken
+ continue;
+ }
+
+ if (m && m->type == tok_operator && m->content == "%(") // nested %(
+ nesting ++;
+ if (nesting == 0 && m && m->type == tok_operator && m->content == "%)") // END
break;
- // enqueue token
- if (! result)
- my_enqueued_pp.push_back (m);
- else
- delete m; // unused token
- // continue
+ if (nesting && m && m->type == tok_operator && m->content == "%)") // nested %)
+ nesting --;
+
+ if (!m)
+ throw parse_error ("incomplete conditional - missing %)", t);
+ if (!result)
+ my_enqueued_pp.push_back (m);
+ if (result)
+ delete m; // do nothing, just dispose of unkept ELSE token
+
+ continue;
}
}
+
+ /*
+ clog << "PP eval (" << *t << ") == " << result << " tokens: " << endl;
+ for (unsigned k=0; k<my_enqueued_pp.size(); k++)
+ clog << * my_enqueued_pp[k] << endl;
+ clog << endl;
+ */
+
delete t; // "%("
delete m; // "%)"
+
// NB: we transcribe the retained tokens here, and not inside
// the THEN/ELSE while loops. If it were done there, each loop
// would become infinite (each iteration consuming an ordinary
@@ -598,7 +635,7 @@ lexer::input_put (const string& chars)
token*
-lexer::scan (bool wildcard, bool expand_args)
+lexer::scan (bool wildcard)
{
token* n = new token;
n->location.file = input_name;
@@ -633,8 +670,7 @@ lexer::scan (bool wildcard, bool expand_args)
// characters; @1..@999 are quoted/escaped as strings.
// $# and @# expand to the number of arguments, similarly
// raw or quoted.
- if (expand_args &&
- (c == '$' || c == '@') &&
+ if ((c == '$' || c == '@') &&
(c2 == '#'))
{
input_get(); // swallow '#'
@@ -645,8 +681,7 @@ lexer::scan (bool wildcard, bool expand_args)
semiskipped_p ++;
goto semiskip;
}
- else if (expand_args &&
- (c == '$' || c == '@') &&
+ else if ((c == '$' || c == '@') &&
(isdigit (c2)))
{
unsigned idx = 0;
@@ -660,7 +695,8 @@ lexer::scan (bool wildcard, bool expand_args)
idx <= session.args.size()); // prevent overflow
if (idx == 0 ||
idx-1 >= session.args.size())
- throw parse_error ("command line argument index invalid or out of range", n);
+ throw parse_error ("command line argument index " + lex_cast<string>(idx)
+ + " out of range [1-" + lex_cast<string>(session.args.size()) + "]", n);
string arg = session.args[idx-1];
if (c == '$') input_put (arg);