summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--README13
-rw-r--r--elaborate.cxx7
-rw-r--r--elaborate.h1
-rw-r--r--main.cxx1
-rw-r--r--parse.cxx258
-rw-r--r--parse.h7
-rw-r--r--staptree.cxx27
-rw-r--r--staptree.h9
-rwxr-xr-xtestsuite/parseok/eleven.stp54
-rwxr-xr-xtestsuite/parseok/ten.stp14
-rwxr-xr-xtestsuite/transok/five.stp2
-rwxr-xr-xtestsuite/transok/one.stp56
-rwxr-xr-xtestsuite/transok/three.stp7
-rwxr-xr-xtestsuite/transok/two.stp2
-rw-r--r--translate.cxx479
16 files changed, 642 insertions, 310 deletions
diff --git a/ChangeLog b/ChangeLog
index b66a8902..4f99327f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2005-06-08 Frank Ch. Eigler <fche@redhat.com>
+
+ systemtap/916
+ Implement all basic scalar operators, including modify-assignment.
+ * parse.cxx (lexer): Allow multi-character lookahead in order to
+ scan 1/2/3-character operators.
+ (parse_boolean_or/and/xor/shift): New routines.
+ * translate.cxx (visit_assignment, visit_binary_expression,
+ visit_*_crement): Generally rewrote.
+ (visit_*): Added more parentheses in output.
+ (emit_module_init): Initialize globals.
+ * staptree.h, elaborate.cxx, elaborate.h: Remove exponentiation.
+ * main.cxx (main): Add an end-of-line to output file.
+ * testsuite/*: Several new tests.
+
2005-06-05 Frank Ch. Eigler <fche@elastic.org>
Implement for/next/continue/break/while statements.
diff --git a/README b/README
index dc174ca5..bf4b67fa 100644
--- a/README
+++ b/README
@@ -1,14 +1,15 @@
-systemtap prototype #3.2
+systemtap prototype #3.3
-- demonstrates partial parsing of hypothetical systemtap script
+- demonstrates parsing of hypothetical systemtap script
language using hand-written simpe LL(1) recursive-descent parser
and similar little lexer: parse.cxx, parse.h
-- semantic analysis in elaborate.cxx, driven from main.cxx
-- examples under testsuite
+- semantic analysis in elaborate.cxx; translation in translate.cxx;
+ driven from main.cxx
+- examples under testsuite/*
- "probe", "global", "function" top-level constructs parsed
- no provider-oriented syntax provided yet
- some tapset library auto-inclusion supported
- use autotools-style configure; make; make check
- to see parse tree: stap -p1 -e 'SCRIPT FRAGMENT'
- to see semantic/type analysis results: stap -p2 -e 'SCRIPT FRAGMENT'
-- to see translation of subset of constructs: stap -e 'SCRIPT FRAGMENT'
+- to see translation of constructs: stap -e 'SCRIPT FRAGMENT';
+ try compiling result with "gcc -c"!
diff --git a/elaborate.cxx b/elaborate.cxx
index 309b4115..2104c005 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -583,13 +583,6 @@ typeresolution_info::visit_concatenation (concatenation *e)
void
-typeresolution_info::visit_exponentiation (exponentiation *e)
-{
- visit_binary_expression (e);
-}
-
-
-void
typeresolution_info::visit_assignment (assignment *e)
{
if (t == pe_stats)
diff --git a/elaborate.h b/elaborate.h
index bd13fa08..06cec813 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -83,7 +83,6 @@ struct typeresolution_info: public visitor
void visit_array_in (array_in* e);
void visit_comparison (comparison* e);
void visit_concatenation (concatenation* e);
- void visit_exponentiation (exponentiation* e);
void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_symbol (symbol* e);
diff --git a/main.cxx b/main.cxx
index 6a9b70dc..da6200fe 100644
--- a/main.cxx
+++ b/main.cxx
@@ -224,6 +224,7 @@ main (int argc, char * const argv [])
if (rc == 0 && last_pass > 2)
rc = translate_pass (s);
+ s.op->line() << endl;
delete s.op;
return rc;
diff --git a/parse.cxx b/parse.cxx
index d1c0b954..d6908ed0 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -20,6 +20,8 @@ using namespace std;
// ------------------------------------------------------------------------
+
+
parser::parser (istream& i):
input_name ("<input>"), free_input (0), input (i, input_name),
last_t (0), next_t (0), num_errors (0)
@@ -138,14 +140,27 @@ lexer::lexer (istream& i, const string& in):
input (i), input_name (in), cursor_line (1), cursor_column (1)
{ }
+
+int
+lexer::input_peek (unsigned n)
+{
+ while (lookahead.size() <= n)
+ {
+ int c = input.get ();
+ lookahead.push_back (input ? c : -1);
+ }
+ return lookahead[n];
+}
+
+
int
lexer::input_get ()
{
- int c = input.get();
-
- if (! input)
- return -1;
-
+ int c = input_peek (0);
+ lookahead.erase (lookahead.begin ());
+
+ if (c < 0) return c; // EOF
+
// update source cursor
if (c == '\n')
{
@@ -185,7 +200,7 @@ lexer::scan ()
n->content = (char) c;
while (1)
{
- int c2 = input.peek ();
+ int c2 = input_peek ();
if (! input)
break;
if ((isalnum(c2) || c2 == '_' || c2 == '$'))
@@ -206,7 +221,7 @@ lexer::scan ()
while (1)
{
- int c2 = input.peek ();
+ int c2 = input_peek ();
if (! input)
break;
@@ -251,68 +266,79 @@ lexer::scan ()
else if (ispunct (c))
{
- int c2 = input.peek ();
+ int c2 = input_peek ();
+ int c3 = input_peek (1);
+ string s1 = string("") + (char) c;
+ string s2 = (c2 > 0 ? s1 + (char) c2 : s1);
+ string s3 = (c3 > 0 ? s2 + (char) c3 : s2);
- if (c == '#') // shell comment
+ if (s1 == "#") // shell comment
{
unsigned this_line = cursor_line;
- while (input && cursor_line == this_line)
- input_get ();
+ do { c = input_get (); }
+ while (c >= 0 && cursor_line == this_line);
goto skip;
}
- else if (c == '/' && c2 == '/') // C++ comment
+ else if (s2 == "//") // C++ comment
{
unsigned this_line = cursor_line;
- while (input && cursor_line == this_line)
- input_get ();
+ do { c = input_get (); }
+ while (c >= 0 && cursor_line == this_line);
goto skip;
}
else if (c == '/' && c2 == '*') // C comment
{
c2 = input_get ();
unsigned chars = 0;
- while (input)
+ while (c2 >= 0)
{
chars ++; // track this to prevent "/*/" from being accepted
c = c2;
c2 = input_get ();
if (chars > 1 && c == '*' && c2 == '/')
- goto skip;
+ break;
}
+ goto skip;
}
+ // We're committed to recognizing at least the first character
+ // as an operator.
n->type = tok_operator;
- n->content = (char) c;
- // handle two-character operators
- if ((c == '=' && c2 == '=') ||
- (c == '!' && c2 == '=') ||
- (c == '<' && c2 == '=') ||
- (c == '>' && c2 == '=') ||
- (c == '+' && c2 == '+') ||
- (c == '-' && c2 == '-') ||
- (c == '|' && c2 == '|') ||
- (c == '&' && c2 == '&') ||
- // (c == '<' && c2 == '<') ||
- // (c == '>' && c2 == '>') ||
- (c == '+' && c2 == '=') ||
- (c == '-' && c2 == '=') ||
- (c == '-' && c2 == '>') ||
- false) // XXX: etc.
- n->content.push_back ((char) input_get ());
-
- // handle three-character operator
- if (c == '<' && c2 == '<')
+ // match all valid operators, in decreasing size order
+ if (s3 == "<<<" ||
+ s3 == "<<=" ||
+ s3 == ">>=")
{
- input_get (); // swallow c2
- int c3 = input.peek ();
- if (c3 == '<')
- {
- input_get (); // swallow c3
- n->content = "<<<";
- }
- else
- n->content = "<<";
+ n->content = s3;
+ input_get (); input_get (); // swallow other two characters
+ }
+ else if (s2 == "==" ||
+ s2 == "!=" ||
+ s2 == "<=" ||
+ s2 == ">=" ||
+ s2 == "+=" ||
+ s2 == "-=" ||
+ s2 == "*=" ||
+ s2 == "/=" ||
+ s2 == "%=" ||
+ s2 == "&=" ||
+ s2 == "^=" ||
+ s2 == "|=" ||
+ s2 == "&&" ||
+ s2 == "||" ||
+ s2 == "++" ||
+ s2 == "--" ||
+ s2 == "->" ||
+ s2 == "<<" ||
+ s2 == ">>")
+ {
+ n->content = s2;
+ input_get (); // swallow other character
+ }
+ else
+ {
+ n->content = s1;
}
return n;
@@ -990,9 +1016,18 @@ parser::parse_assignment ()
&& (t->content == "=" ||
t->content == "<<<" ||
t->content == "+=" ||
- false)) // XXX: add /= etc.
+ t->content == "-=" ||
+ t->content == "*=" ||
+ t->content == "/=" ||
+ t->content == "%=" ||
+ t->content == "<<=" ||
+ t->content == ">>=" ||
+ t->content == "&=" ||
+ t->content == "^=" ||
+ t->content == "|=" ||
+ false))
{
- // NB: lvalueness is checked during translation / elaboration
+ // NB: lvalueness is checked during elaboration / translation
assignment* e = new assignment;
e->left = op1;
e->op = t->content;
@@ -1000,8 +1035,6 @@ parser::parse_assignment ()
next ();
e->right = parse_expression ();
op1 = e;
- // XXX: map assign/accumulate operators like +=, /=
- // to ordinary assignment + nested binary_expression
}
return op1;
@@ -1059,7 +1092,7 @@ parser::parse_logical_or ()
expression*
parser::parse_logical_and ()
{
- expression* op1 = parse_array_in ();
+ expression* op1 = parse_boolean_or ();
const token* t = peek ();
while (t && t->type == tok_operator && t->content == "&&")
@@ -1069,6 +1102,72 @@ parser::parse_logical_and ()
e->op = t->content;
e->tok = t;
next ();
+ e->right = parse_boolean_or ();
+ op1 = e;
+ t = peek ();
+ }
+
+ return op1;
+}
+
+
+expression*
+parser::parse_boolean_or ()
+{
+ expression* op1 = parse_boolean_xor ();
+
+ const token* t = peek ();
+ while (t && t->type == tok_operator && t->content == "|")
+ {
+ binary_expression* e = new binary_expression;
+ e->left = op1;
+ e->op = t->content;
+ e->tok = t;
+ next ();
+ e->right = parse_boolean_xor ();
+ op1 = e;
+ t = peek ();
+ }
+
+ return op1;
+}
+
+
+expression*
+parser::parse_boolean_xor ()
+{
+ expression* op1 = parse_boolean_and ();
+
+ const token* t = peek ();
+ while (t && t->type == tok_operator && t->content == "^")
+ {
+ binary_expression* e = new binary_expression;
+ e->left = op1;
+ e->op = t->content;
+ e->tok = t;
+ next ();
+ e->right = parse_boolean_and ();
+ op1 = e;
+ t = peek ();
+ }
+
+ return op1;
+}
+
+
+expression*
+parser::parse_boolean_and ()
+{
+ expression* op1 = parse_array_in ();
+
+ const token* t = peek ();
+ while (t && t->type == tok_operator && t->content == "&")
+ {
+ binary_expression* e = new binary_expression;
+ e->left = op1;
+ e->op = t->content;
+ e->tok = t;
+ next ();
e->right = parse_array_in ();
op1 = e;
t = peek ();
@@ -1147,7 +1246,7 @@ parser::parse_array_in ()
expression*
parser::parse_comparison ()
{
- expression* op1 = parse_concatenation ();
+ expression* op1 = parse_shift ();
const token* t = peek ();
while (t && t->type == tok_operator
@@ -1156,14 +1255,36 @@ parser::parse_comparison ()
t->content == "==" ||
t->content == "!=" ||
t->content == "<=" ||
- t->content == ">=" ||
- false )) // xxx: more
+ t->content == ">="))
{
comparison* e = new comparison;
e->left = op1;
e->op = t->content;
e->tok = t;
next ();
+ e->right = parse_shift ();
+ op1 = e;
+ t = peek ();
+ }
+
+ return op1;
+}
+
+
+expression*
+parser::parse_shift ()
+{
+ expression* op1 = parse_concatenation ();
+
+ const token* t = peek ();
+ while (t && t->type == tok_operator &&
+ (t->content == "<<" || t->content == ">>"))
+ {
+ binary_expression* e = new binary_expression;
+ e->left = op1;
+ e->op = t->content;
+ e->tok = t;
+ next ();
e->right = parse_concatenation ();
op1 = e;
t = peek ();
@@ -1248,7 +1369,11 @@ parser::parse_unary ()
{
const token* t = peek ();
if (t && t->type == tok_operator
- && (t->content == "+" || t->content == "-" || t->content == "!"))
+ && (t->content == "+" ||
+ t->content == "-" ||
+ t->content == "!" ||
+ t->content == "~" ||
+ false))
{
unary_expression* e = new unary_expression;
e->op = t->content;
@@ -1258,30 +1383,7 @@ parser::parse_unary ()
return e;
}
else
- return parse_exponentiation ();
-}
-
-
-expression*
-parser::parse_exponentiation ()
-{
- expression* op1 = parse_crement ();
-
- const token* t = peek ();
- // right associative: no loop
- if (t && t->type == tok_operator
- && (t->content == "^" || t->content == "**"))
- {
- exponentiation* e = new exponentiation;
- e->op = t->content;
- e->left = op1;
- e->tok = t;
- next ();
- e->right = parse_expression ();
- op1 = e;
- }
-
- return op1;
+ return parse_crement ();
}
diff --git a/parse.h b/parse.h
index 29ae41c8..b7054b0d 100644
--- a/parse.h
+++ b/parse.h
@@ -57,8 +57,10 @@ public:
private:
int input_get ();
+ int input_peek (unsigned n=0);
std::istream& input;
std::string input_name;
+ std::vector<int> lookahead;
unsigned cursor_line;
unsigned cursor_column;
};
@@ -115,13 +117,16 @@ private: // nonterminals
expression* parse_ternary ();
expression* parse_logical_or ();
expression* parse_logical_and ();
+ expression* parse_boolean_or ();
+ expression* parse_boolean_xor ();
+ expression* parse_boolean_and ();
expression* parse_array_in ();
expression* parse_comparison ();
+ expression* parse_shift ();
expression* parse_concatenation ();
expression* parse_additive ();
expression* parse_multiplicative ();
expression* parse_unary ();
- expression* parse_exponentiation ();
expression* parse_crement ();
expression* parse_value ();
expression* parse_symbol ();
diff --git a/staptree.cxx b/staptree.cxx
index 3ee34950..f74f9a91 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -285,7 +285,7 @@ void block::print (ostream& o)
o << "{" << endl;
for (unsigned i=0; i<statements.size(); i++)
o << *statements [i] << endl;
- o << "}" << endl;
+ o << "}";
}
@@ -297,7 +297,7 @@ void for_loop::print (ostream& o)
cond->print (o);
o << "; ";
incr->print (o);
- o << ")" << endl;
+ o << ") ";
block->print (o);
}
@@ -310,7 +310,7 @@ void foreach_loop::print (ostream& o)
if (i > 0) o << ", ";
indexes[i]->print (o);
}
- o << "] in " << base << ")" << endl;
+ o << "] in " << base << ") ";
block->print (o);
}
@@ -355,7 +355,7 @@ void continue_statement::print (ostream& o)
void if_statement::print (ostream& o)
{
- o << "if (" << *condition << ") " << endl
+ o << "if (" << *condition << ") "
<< *thenblock << endl;
if (elseblock)
o << "else " << *elseblock << endl;
@@ -570,12 +570,6 @@ concatenation::visit (visitor* u)
}
void
-exponentiation::visit (visitor* u)
-{
- u->visit_exponentiation (this);
-}
-
-void
ternary_expression::visit (visitor* u)
{
u->visit_ternary_expression (this);
@@ -750,13 +744,6 @@ traversing_visitor::visit_concatenation (concatenation* e)
}
void
-traversing_visitor::visit_exponentiation (exponentiation* e)
-{
- e->left->visit (this);
- e->right->visit (this);
-}
-
-void
traversing_visitor::visit_ternary_expression (ternary_expression* e)
{
e->cond->visit (this);
@@ -938,12 +925,6 @@ throwing_visitor::visit_concatenation (concatenation* e)
}
void
-throwing_visitor::visit_exponentiation (exponentiation* e)
-{
- throwone (e->tok);
-}
-
-void
throwing_visitor::visit_ternary_expression (ternary_expression* e)
{
throwone (e->tok);
diff --git a/staptree.h b/staptree.h
index 98bd057c..d357fc7d 100644
--- a/staptree.h
+++ b/staptree.h
@@ -149,12 +149,6 @@ struct concatenation: public binary_expression
};
-struct exponentiation: public binary_expression
-{
- void visit (visitor* u);
-};
-
-
struct ternary_expression: public expression
{
expression* cond;
@@ -429,7 +423,6 @@ struct visitor
virtual void visit_array_in (array_in* e) = 0;
virtual void visit_comparison (comparison* e) = 0;
virtual void visit_concatenation (concatenation* e) = 0;
- virtual void visit_exponentiation (exponentiation* e) = 0;
virtual void visit_ternary_expression (ternary_expression* e) = 0;
virtual void visit_assignment (assignment* e) = 0;
virtual void visit_symbol (symbol* e) = 0;
@@ -465,7 +458,6 @@ struct traversing_visitor: public visitor
void visit_array_in (array_in* e);
void visit_comparison (comparison* e);
void visit_concatenation (concatenation* e);
- void visit_exponentiation (exponentiation* e);
void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_symbol (symbol* e);
@@ -506,7 +498,6 @@ struct throwing_visitor: public visitor
void visit_array_in (array_in* e);
void visit_comparison (comparison* e);
void visit_concatenation (concatenation* e);
- void visit_exponentiation (exponentiation* e);
void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_symbol (symbol* e);
diff --git a/testsuite/parseok/eleven.stp b/testsuite/parseok/eleven.stp
new file mode 100755
index 00000000..c05ca66f
--- /dev/null
+++ b/testsuite/parseok/eleven.stp
@@ -0,0 +1,54 @@
+#! stap -p1
+
+probe two
+{
+ # all assignment operators
+ a = b
+ a <<< b
+ a += b
+ a -= b
+ a *= b
+ a /= b
+ a %= b
+ a <<= b
+ a >>= b
+ a &= b
+ a ^= b
+ a |= b
+
+ # all ternary operators
+ a ? b : c
+
+ # all binary operators
+ a || b
+ a && b
+ a | b
+ a & b
+ a ^ b
+ a < b
+ a > b
+ a == b
+ a != b
+ a <= b
+ a >= b
+ a << b
+ a >> b
+ a . b
+ a + b
+ a - b
+ a * b
+ a / b
+ a % b
+
+ # all unary operators
+ a ++
+ a --
+ -- a
+ ++ a
+ ~ a
+ ! a
+ ; # grammar glitch
+ + a
+ ; # grammar glitch
+ - a
+}
diff --git a/testsuite/parseok/ten.stp b/testsuite/parseok/ten.stp
index 25d16e62..2da82f04 100755
--- a/testsuite/parseok/ten.stp
+++ b/testsuite/parseok/ten.stp
@@ -4,13 +4,13 @@ probe two
{
for (;;) ;
for (a=0;;) { a + 4; break }
- for (;a>0;) { a + 5; continue }
- for (;;a++) { a + 5 }
- for (a=0;a>0;) { a + 4 }
- for (;a>0;a++) { a + 5 }
- for (a=0;;a++) { a + 5 }
- for (a=0; a<=4; a++) ;
- for (a=0; a<=4; a++) { b = a }
+ for (;a>0;) { a ^ 5; continue }
+ for (;;a++) { a | 5 }
+ for (a=0;a>0;) { a << 4 }
+ for (;a>0;++a) { a >> 5 }
+ for (a=0;;a--) { a & 5 * b }
+ for (a=0; a<=4 && b>=5; --a) ;
+ for (a=0; a==4 || b!=5; a++) { b = a }
next
while (99) ;
while (99) { break continue }
diff --git a/testsuite/transok/five.stp b/testsuite/transok/five.stp
index 266b3408..5cd50cb6 100755
--- a/testsuite/transok/five.stp
+++ b/testsuite/transok/five.stp
@@ -1,6 +1,6 @@
#! stap
-probe two
+probe begin
{
for (;;) ;
for (a=0;;) { if (a > 4) break }
diff --git a/testsuite/transok/one.stp b/testsuite/transok/one.stp
new file mode 100755
index 00000000..6c624f14
--- /dev/null
+++ b/testsuite/transok/one.stp
@@ -0,0 +1,56 @@
+#! stap -p3
+
+probe begin
+{
+ # all assignment operators
+ a = b
+ # a <<< b
+ a += b
+ a -= b
+ a *= b
+ a /= b
+ a %= b
+ a <<= b
+ a >>= b
+ a &= b
+ a ^= b
+ a |= b
+
+ # all ternary operators
+ a ? b : c
+
+ # all binary operators
+ a || b
+ a && b
+ a | b
+ a & b
+ a ^ b
+ a < b
+ a > b
+ a == b
+ a != b
+ a <= b
+ a >= b
+ a << b
+ a >> b
+ as . bs
+ as == bs # overload operators for strings
+ as != bs
+ a + b
+ a - b
+ a * b
+ a / b
+ a % b
+
+ # all unary operators
+ a ++
+ a --
+ -- a
+ -- b
+ ~ a
+ ! a
+ ; # grammar glitch
+ + a
+ ; # grammar glitch
+ - a
+}
diff --git a/testsuite/transok/three.stp b/testsuite/transok/three.stp
index c372b271..07703f90 100755
--- a/testsuite/transok/three.stp
+++ b/testsuite/transok/three.stp
@@ -5,7 +5,7 @@ function f1 (a, b) {
d = "hello";
# poo[c] = bab[d] = "hi"
bab = "hi";
- bab = poo[c];
+ # bab = poo[c];
return 0
}
@@ -14,14 +14,13 @@ function f2 () {
}
global koo
-global poo, bab
-probe z {
+probe begin {
f2 ();
koo = 1
}
-probe x,y {
+probe begin, end {
f2 ();
f1 (f1 (3 * 2 + 1, "foo"), "canoe")
}
diff --git a/testsuite/transok/two.stp b/testsuite/transok/two.stp
index d62e88a8..848934a7 100755
--- a/testsuite/transok/two.stp
+++ b/testsuite/transok/two.stp
@@ -1,5 +1,5 @@
#! stap
-probe k,l { 2; }
+probe begin, end { 2; }
function poo (zoo) { n = poo2 (8); return "foo" . zoo }
function poo2 (zoo) { return poo3 (2 + 4 * zoo) }
function poo3 (zoo) { return zoo }
diff --git a/translate.cxx b/translate.cxx
index 1c9724d9..dcccf1bd 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -112,7 +112,6 @@ struct c_unparser: public unparser, public visitor
void visit_array_in (array_in* e);
void visit_comparison (comparison* e);
void visit_concatenation (concatenation* e);
- void visit_exponentiation (exponentiation* e);
void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_symbol (symbol* e);
@@ -142,8 +141,6 @@ resolution_pass (systemtap_session& s)
s.probes.push_back (dp);
}
- // XXX: merge functiondecls
- // XXX: handle library files
// XXX: add builtin variables/functions
return rc;
}
@@ -267,16 +264,15 @@ struct c_tmpcounter: public traversing_visitor
// void visit_foreach_loop (foreach_loop* s);
// void visit_return_statement (return_statement* s);
// void visit_delete_statement (delete_statement* s);
- // void visit_binary_expression (binary_expression* e);
+ void visit_binary_expression (binary_expression* e);
// void visit_unary_expression (unary_expression* e);
- // void visit_pre_crement (pre_crement* e);
- // void visit_post_crement (post_crement* e);
+ void visit_pre_crement (pre_crement* e);
+ void visit_post_crement (post_crement* e);
// void visit_logical_or_expr (logical_or_expr* e);
// void visit_logical_and_expr (logical_and_expr* e);
// void visit_array_in (array_in* e);
// void visit_comparison (comparison* e);
void visit_concatenation (concatenation* e);
- // void visit_exponentiation (exponentiation* e);
// void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_arrayindex (arrayindex* e);
@@ -387,7 +383,23 @@ c_unparser::emit_module_init ()
o->newline() << "int STARTUP () {";
o->newline(1) << "int anyrc = 0;";
o->newline() << "int rc;";
- // XXX: initialize globals
+
+ for (unsigned i=0; i<session->globals.size(); i++)
+ {
+ vardecl* v = session->globals[i];
+ if (v->index_types.size() > 0) // array?
+ throw semantic_error ("array init not yet implemented", v->tok);
+ else if (v->type == pe_long)
+ o->newline() << "global_" << c_varname (v->name)
+ << " = 0;";
+ else if (v->type == pe_string)
+ o->newline() << "global_" << c_varname (v->name)
+ << "[0] = '\\0';";
+ else
+ throw semantic_error ("unsupported global variable type",
+ v->tok);
+ }
+
for (unsigned i=0; i<session->probes.size(); i++)
{
session->probes[i]->emit_registrations (o, i);
@@ -401,8 +413,7 @@ c_unparser::emit_module_init ()
o->newline() << "goto out;";
o->newline(-1) << "}";
}
- o->newline(-1) << "out:";
- o->indent(1);
+ o->newline() << "out:";
o->newline() << "return anyrc; /* if (anyrc) log badness */";
o->newline(-1) << "}" << endl;
}
@@ -448,7 +459,7 @@ c_unparser::emit_function (functiondecl* v)
for (unsigned i=0; i<v->locals.size(); i++)
{
if (v->locals[i]->index_types.size() > 0) // array?
- throw semantic_error ("not yet implemented", v->tok);
+ throw semantic_error ("array locals not supported", v->tok);
else if (v->locals[i]->type == pe_long)
o->newline() << "l->" << c_varname (v->locals[i]->name)
<< " = 0;";
@@ -491,7 +502,7 @@ c_unparser::emit_probe (derived_probe* v, unsigned i)
for (unsigned j=0; j<v->locals.size(); j++)
{
if (v->locals[j]->index_types.size() > 0) // array?
- throw semantic_error ("not yet implemented", v->tok);
+ throw semantic_error ("array locals not supported", v->tok);
else if (v->locals[j]->type == pe_long)
o->newline() << "l->" << c_varname (v->locals[j]->name)
<< " = 0;";
@@ -690,7 +701,7 @@ c_unparser::visit_for_loop (for_loop *s)
void
c_unparser::visit_foreach_loop (foreach_loop *s)
{
- throw semantic_error ("not yet implemented", s->tok);
+ throw semantic_error ("foreach loop not yet implemented", s->tok);
}
@@ -722,7 +733,7 @@ c_unparser::visit_next_statement (next_statement* s)
void
c_unparser::visit_delete_statement (delete_statement* s)
{
- throw semantic_error ("not yet implemented", s->tok);
+ throw semantic_error ("delete statement not yet implemented", s->tok);
}
@@ -763,28 +774,77 @@ c_unparser::visit_literal_number (literal_number* e)
}
+
+void
+c_tmpcounter::visit_binary_expression (binary_expression* e)
+{
+ if (e->op == "/" || e->op == "%")
+ {
+ parent->o->newline()
+ << parent->c_typename (pe_long)
+ << " __tmp" << tmpvar_counter ++ << ";";
+ parent->o->newline()
+ << parent->c_typename (pe_long)
+ << " __tmp" << tmpvar_counter ++ << ";";
+ }
+
+ e->left->visit (this);
+ e->right->visit (this);
+}
+
+
void
c_unparser::visit_binary_expression (binary_expression* e)
{
+ if (e->type != pe_long ||
+ e->left->type != pe_long ||
+ e->right->type != pe_long)
+ throw semantic_error ("expected numeric types", e->tok);
+
if (e->op == "+" ||
e->op == "-" ||
e->op == "*" ||
- false) // XXX: other simple arithmetic operators
+ e->op == "&" ||
+ e->op == "|" ||
+ e->op == "^" ||
+ e->op == "<<" ||
+ e->op == ">>")
{
- if (e->type != pe_long ||
- e->left->type != pe_long ||
- e->right->type != pe_long)
- throw semantic_error ("expected numeric types", e->tok);
-
- o->line() << "(";
+ o->line() << "((";
+ e->left->visit (this);
+ o->line() << ") " << e->op << " (";
+ e->right->visit (this);
+ o->line() << "))";
+ }
+ else if (e->op == "/" ||
+ e->op == "%")
+ {
+ // % and / need a division-by-zero check; and thus two temporaries
+ // for proper evaluation order
+ unsigned tmpidx1 = tmpvar_counter++;
+ unsigned tmpidx2 = tmpvar_counter++;
+ string tmp1 = "l->__tmp" + stringify (tmpidx1);
+ string tmp2 = "l->__tmp" + stringify (tmpidx2);
+ o->line() << "({";
+
+ o->newline(1) << tmp1 << " = ";
e->left->visit (this);
- o->line() << " " << e->op << " ";
+ o->line() << ";";
+
+ o->newline() << tmp2 << " = ";
e->right->visit (this);
- o->line() << ")";
+ o->line() << ";";
+
+ o->newline() << "if (" << tmp2 << " == 0) {";
+ o->newline(1) << "errorcount ++;";
+ o->newline() << tmp2 << " = 1;";
+ o->newline(-1) << "}";
+
+ o->newline() << tmp1 << " " << e->op << " " << tmp2 << ";";
+ o->newline(-1) << "})";
}
- // XXX: % and / need a division-by-zero check
else
- throw semantic_error ("not yet implemented", e->tok);
+ throw semantic_error ("operator not yet implemented", e->tok);
}
@@ -795,26 +855,11 @@ c_unparser::visit_unary_expression (unary_expression* e)
e->operand->type != pe_long)
throw semantic_error ("expected numeric types", e->tok);
- o->line() << e->op << " (";
+ o->line() << "(" << e->op << " (";
e->operand->visit (this);
- o->line() << ")";
-}
-
-
-void
-c_unparser::visit_pre_crement (pre_crement* e)
-{
- throw semantic_error ("not yet implemented", e->tok);
-}
-
-
-void
-c_unparser::visit_post_crement (post_crement* e)
-{
- throw semantic_error ("not yet implemented", e->tok);
+ o->line() << "))";
}
-
void
c_unparser::visit_logical_or_expr (logical_or_expr* e)
{
@@ -823,11 +868,11 @@ c_unparser::visit_logical_or_expr (logical_or_expr* e)
e->right->type != pe_long)
throw semantic_error ("expected numeric types", e->tok);
- o->line() << "(";
+ o->line() << "((";
e->left->visit (this);
o->line() << ") " << e->op << " (";
e->right->visit (this);
- o->line() << ")";
+ o->line() << "))";
}
@@ -839,18 +884,18 @@ c_unparser::visit_logical_and_expr (logical_and_expr* e)
e->right->type != pe_long)
throw semantic_error ("expected numeric types", e->tok);
- o->line() << "(";
+ o->line() << "((";
e->left->visit (this);
o->line() << ") " << e->op << " (";
e->right->visit (this);
- o->line() << ")";
+ o->line() << "))";
}
void
c_unparser::visit_array_in (array_in* e)
{
- throw semantic_error ("not yet implemented", e->tok);
+ throw semantic_error ("array-in expression not yet implemented", e->tok);
}
@@ -878,11 +923,11 @@ c_unparser::visit_comparison (comparison* e)
e->right->type != pe_long)
throw semantic_error ("expected numeric types", e->tok);
- o->line() << "(";
+ o->line() << "((";
e->left->visit (this);
o->line() << ") " << e->op << " (";
e->right->visit (this);
- o->line() << ")";
+ o->line() << "))";
}
else
throw semantic_error ("unexpected type", e->left->tok);
@@ -895,8 +940,7 @@ void
c_tmpcounter::visit_concatenation (concatenation* e)
{
parent->o->newline() << parent->c_typename (e->type)
- << " __tmp" << tmpvar_counter ++ << ";"
- << " /* " << e->op << " result */";
+ << " __tmp" << tmpvar_counter ++ << ";";
e->left->visit (this);
e->right->visit (this);
}
@@ -927,13 +971,6 @@ c_unparser::visit_concatenation (concatenation* e)
void
-c_unparser::visit_exponentiation (exponentiation* e)
-{
- throw semantic_error ("not yet implemented", e->tok);
-}
-
-
-void
c_unparser::visit_ternary_expression (ternary_expression* e)
{
if (e->cond->type != pe_long)
@@ -959,9 +996,13 @@ struct c_unparser_assignment: public throwing_visitor
c_unparser* parent;
string op;
expression* rvalue;
+ bool pre;
c_unparser_assignment (c_unparser* p, const string& o, expression* e):
throwing_visitor ("invalid lvalue type"),
- parent (p), op (o), rvalue (e) {}
+ parent (p), op (o), rvalue (e), pre (false) {}
+ c_unparser_assignment (c_unparser* p, const string& o, bool pp):
+ throwing_visitor ("invalid lvalue type"),
+ parent (p), op (o), rvalue (0), pre (pp) {}
// only symbols and arrayindex nodes are possible lvalues
void visit_symbol (symbol *e);
@@ -1003,13 +1044,46 @@ c_unparser::visit_assignment (assignment* e)
throw semantic_error ("type mismatch", e->right->tok,
"vs", e->left->tok);
- if (e->op == "=" || e->op == "<<<")
- {
- c_unparser_assignment tav (this, e->op, e->right);
- e->left->visit (& tav);
- }
- else
- throw semantic_error ("not yet implemented ", e->tok);
+ c_unparser_assignment tav (this, e->op, e->right);
+ e->left->visit (& tav);
+}
+
+
+void
+c_tmpcounter::visit_pre_crement (pre_crement* e)
+{
+ c_tmpcounter_assignment tav (this, e->op, 0);
+ e->operand->visit (& tav);
+}
+
+void
+c_unparser::visit_pre_crement (pre_crement* e)
+{
+ if (e->type != pe_long ||
+ e->type != e->operand->type)
+ throw semantic_error ("expected numeric type", e->tok);
+
+ c_unparser_assignment tav (this, e->op, true);
+ e->operand->visit (& tav);
+}
+
+
+void
+c_tmpcounter::visit_post_crement (post_crement* e)
+{
+ c_tmpcounter_assignment tav (this, e->op, 0);
+ e->operand->visit (& tav);
+}
+
+void
+c_unparser::visit_post_crement (post_crement* e)
+{
+ if (e->type != pe_long ||
+ e->type != e->operand->type)
+ throw semantic_error ("expected numeric type", e->tok);
+
+ c_unparser_assignment tav (this, e->op, false);
+ e->operand->visit (& tav);
}
@@ -1077,16 +1151,46 @@ c_unparser::visit_symbol (symbol* e)
}
+
+
+// Assignment expansion is tricky.
+//
+// Because assignments are nestable expressions, we have
+// to emit C constructs that are nestable expressions too.
+// We have to evaluate the given expressions the proper number of times,
+// including array indices.
+// We have to lock the lvalue (if global) against concurrent modification,
+// especially with modify-assignment operations (+=, ++).
+// We have to check the rvalue (for division-by-zero checks).
+
+// In the normal "pre=false" case, for (A op B) emit:
+// ({ tmp = B; check(B); lock(A); res = A op tmp; A = res; unlock(A); res; })
+// In the "pre=true" case, emit instead:
+// ({ tmp = B; check(B); lock(A); res = A; A = res op tmp; unlock(A); res; })
+//
+// (op is the plain operator portion of a combined calculate/assignment:
+// "+" for "+=", and so on. It is in the "macop" variable below.)
+//
+// For array assignments, additional temporaries are used for each
+// index, which are expanded before the "tmp=B" expression, in order
+// to consistently order evaluation of lhs before rhs.
+//
+
void
c_tmpcounter_assignment::visit_symbol (symbol *e)
{
+ // tmp
parent->parent->o->newline()
<< parent->parent->c_typename (e->type)
- << " __tmp" << parent->tmpvar_counter ++ << ";"
- << " /* " << e->name << " rvalue */";
- rvalue->visit (parent);
-}
+ << " __tmp" << parent->tmpvar_counter ++ << ";";
+ // res
+ parent->parent->o->newline()
+ << parent->parent->c_typename (e->type)
+ << " __tmp" << parent->tmpvar_counter ++ << ";";
+ if (rvalue)
+ rvalue->visit (parent);
+}
void
c_unparser_assignment::visit_symbol (symbol *e)
@@ -1097,104 +1201,152 @@ c_unparser_assignment::visit_symbol (symbol *e)
derived_probe* current_probe = parent->current_probe;
systemtap_session* session = parent->session;
- if (op != "=")
- throw semantic_error ("not yet implemented", e->tok);
-
if (r->index_types.size() != 0)
- throw semantic_error ("invalid reference to array", e->tok);
-
- // XXX: handle special macro symbols
+ throw semantic_error ("unexpected reference to array", e->tok);
unsigned tmpidx = parent->tmpvar_counter ++;
+ unsigned residx = parent->tmpvar_counter ++;
string tmp_base = "l->__tmp";
-
- // NB: because assignments are nestable expressions, we have
- // to emit C constructs that are nestable expressions too.
- // ... (A = B) ... ==>
- // ... ({ tmp = B; store(A,tmp); tmp; }) ...
-
+ string tmpvar = tmp_base + stringify (tmpidx);
+ string resvar = tmp_base + stringify (residx);
o->line() << "({ ";
o->indent(1);
- parent->c_assign (tmp_base + stringify (tmpidx), rvalue, "assignment");
+ // part 1: "tmp = B"
+ if (rvalue)
+ parent->c_assign (tmpvar, rvalue, "assignment");
+ else
+ {
+ if (op == "++" || op == "--")
+ o->newline() << tmpvar << " = 1;";
+ else
+ // internal error
+ throw semantic_error ("need rvalue for assignment", e->tok);
+ }
+ // OPT: literal rvalues could be used without a tmp* copy
- // XXX: strings may be passed safely via a char*, without
- // a full copy in tmpNNN
+ // part 2: "check (B)"
+ if (op == "/=" || op == "%=")
+ {
+ // need division-by-zero check
+ o->newline() << "if (" << tmpvar << " == 0) {";
+ o->newline(1) << "errorcount ++;";
+ o->newline() << tmpvar << " = 1;";
+ o->newline(-1) << "}";
+ }
// maybe the variable is a local
- if (current_probe)
- {
- for (unsigned i=0; i<current_probe->locals.size(); i++)
- {
- vardecl* rr = current_probe->locals[i];
- if (rr == r) // comparison of pointers is sufficient
- {
- parent->c_assign ("l->" + parent->c_varname (r->name),
- tmp_base + stringify (tmpidx),
- rvalue->type,
- "local variable assignment", rvalue->tok);
+ string lvaluename;
+ bool lock_global = false;
- o->newline() << tmp_base << tmpidx << ";";
- o->newline(-1) << "})";
- return;
- }
- }
- }
- else if (current_function)
+ if (current_probe)
+ for (unsigned i=0; i<current_probe->locals.size(); i++)
+ if (current_probe->locals[i] == r)
+ lvaluename = "l->" + parent->c_varname (r->name);
+ if (current_function)
{
for (unsigned i=0; i<current_function->locals.size(); i++)
- {
- vardecl* rr = current_function->locals[i];
- if (rr == r) // comparison of pointers is sufficient
- {
- parent->c_assign ("l->" + parent->c_varname (r->name),
- tmp_base + stringify (tmpidx),
- rvalue->type,
- "local variable assignment", rvalue->tok);
+ if (current_function->locals[i] == r)
+ lvaluename = "l->" + parent->c_varname (r->name);
+
+ for (unsigned i=0; i<current_function->formal_args.size(); i++)
+ if (current_function->formal_args[i] == r)
+ lvaluename = "l->" + parent->c_varname (r->name);
+ }
+ if (lvaluename == "")
+ for (unsigned i=0; i<session->globals.size(); i++)
+ if (session->globals[i] == r)
+ {
+ lvaluename = "global_" + parent->c_varname (r->name);
+ lock_global = true;
+ }
- o->newline() << tmp_base << tmpidx << ";";
- o->newline(-1) << "})";
- return;
- }
- }
+ if (lvaluename == "")
+ throw semantic_error ("unresolved assignment to ", e->tok);
- for (unsigned i=0; i<current_function->formal_args.size(); i++)
- {
- vardecl* rr = current_function->formal_args[i];
- if (rr == r) // comparison of pointers is sufficient
- {
- parent->c_assign ("l->" + parent->c_varname (r->name),
- tmp_base + stringify (tmpidx),
- rvalue->type,
- "formal argument assignment", rvalue->tok);
+ // part 3: "lock(A)"
+ if (lock_global)
+ o->newline() << "/* XXX lock " << lvaluename << " */";
- o->newline() << tmp_base << tmpidx << ";";
- o->newline(-1) << "})";
- return;
- }
- }
+ // part 4/5
+ if (e->type == pe_string)
+ {
+ if (pre)
+ throw semantic_error ("pre assignment on strings not supported",
+ e->tok);
+ if (op == "=")
+ {
+ o->newline() << "strncpy (" << lvaluename
+ << ", " << tmpvar
+ << ", MAXSTRINGLEN);";
+ // no need for second copy
+ resvar = tmpvar;
+ }
+ else if (op == ".=")
+ {
+ // shortcut two-step construction of concatenated string in
+ // empty resvar, then copy to tmpvar: instead concatenate
+ // to lvalue directly, then copy back to resvar
+ o->newline() << "strncat (" << lvaluename
+ << ", " << tmpvar
+ << ", MAXSTRINGLEN);";
+ o->newline() << "strncpy (" << resvar
+ << ", " << lvaluename
+ << ", MAXSTRINGLEN);";
+ }
+ else
+ throw semantic_error ("string assignment operator " +
+ op + " unsupported", e->tok);
}
-
- // it better be a global
- for (unsigned i=0; i<session->globals.size(); i++)
+ else if (e->type == pe_long)
{
- if (session->globals[i] == r)
- {
- // XXX: acquire write lock on global
- o->newline() << "/* wlock global_" << parent->c_varname (r->name) << " */";
- parent->c_assign ("global_" + parent->c_varname (r->name),
- tmp_base + stringify (tmpidx),
- rvalue->type,
- "global variable assignment", rvalue->tok);
- o->newline() << "/* unlock global_" << parent->c_varname (r->name) << " */";
-
- o->newline() << tmp_base << tmpidx << ";";
- o->newline(-1) << "})";
- return;
- }
+ // a lot of operators come through this "gate":
+ // - vanilla assignment "="
+ // - stats aggregation "<<<"
+ // - modify-accumulate "+=" and many friends
+ // - pre/post-crement "++"/"--"
+
+ // compute the modify portion of a modify-accumulate
+ string macop;
+ unsigned oplen = op.size();
+ if (op == "=")
+ macop = "* 0 +"; // clever (?) trick to select rvalue (tmp) only
+ else if (oplen > 1 && op[oplen-1] == '=') // for +=, %=, <<=, etc...
+ macop = op.substr(0, oplen-1);
+ else if (op == "<<<")
+ throw semantic_error ("stats aggregation not yet implemented", e->tok);
+ else if (op == "++")
+ macop = "+";
+ else if (op == "--")
+ macop = "-";
+ else
+ // internal error
+ throw semantic_error ("unknown macop for assignment", e->tok);
+
+ // part 4
+ if (pre)
+ o->newline() << resvar << " = " << lvaluename << ";";
+ else
+ o->newline() << resvar << " = "
+ << lvaluename << " " << macop << " " << tmpvar << ";";
+
+ // part 5
+ if (pre)
+ o->newline() << lvaluename << " = "
+ << resvar << " " << macop << " " << tmpvar << ";";
+ else
+ o->newline() << lvaluename << " = " << resvar << ";";
}
+ else
+ throw semantic_error ("assignment type not yet implemented", e->tok);
- throw semantic_error ("unresolved symbol", e->tok);
+ // part 6: "unlock(A)"
+ if (lock_global)
+ o->newline() << "/* XXX unlock " << lvaluename << " */";
+
+ // part 7: "res"
+ o->newline() << resvar << ";";
+ o->newline(-1) << "})";
}
@@ -1206,13 +1358,11 @@ c_tmpcounter::visit_arrayindex (arrayindex *e)
for (unsigned i=0; i<r->index_types.size(); i++)
parent->o->newline()
<< parent->c_typename (r->index_types[i])
- << " __tmp" << tmpvar_counter ++ << ";"
- << " /* " << e->base << " idx #" << i << " */";
+ << " __tmp" << tmpvar_counter ++ << ";";
// now the result
parent->o->newline()
<< parent->c_typename (r->type)
- << " __tmp" << tmpvar_counter ++ << ";"
- << " /* " << e->base << "value */";
+ << " __tmp" << tmpvar_counter ++ << ";";
for (unsigned i=0; i<e->indexes.size(); i++)
e->indexes[i]->visit (this);
@@ -1228,6 +1378,8 @@ c_unparser::visit_arrayindex (arrayindex* e)
r->index_types.size() != e->indexes.size())
throw semantic_error ("invalid array reference", e->tok);
+ throw semantic_error ("array read not supported", e->tok);
+
o->line() << "({";
o->indent(1);
@@ -1241,6 +1393,7 @@ c_unparser::visit_arrayindex (arrayindex* e)
// reentrancy issues that pop up with nested expressions:
// e.g. a[a[c]=5] could deadlock
+
unsigned tmpidx_base = tmpvar_counter;
tmpvar_counter += r->index_types.size() + 1 /* result */;
string tmp_base = "l->__tmp";
@@ -1258,23 +1411,6 @@ c_unparser::visit_arrayindex (arrayindex* e)
}
o->newline() << "if (errorcount) goto out;";
- o->newline() << "/* XXX: write to array */";
-#if 0
- // it better be a global
- for (unsigned i=0; i<session->globals.size(); i++)
- {
- if (session->globals[i] == r)
- {
- // XXX: acquire read lock on global; copy value
- // into local temporary
- o->line() << "global_" << c_varname (r->name);
- return;
- }
- }
-
- throw semantic_error ("unresolved symbol", e->tok);
-#endif
-
o->newline() << tmp_base << residx << ";";
o->newline(-1) << "})";
@@ -1289,7 +1425,7 @@ c_tmpcounter_assignment::visit_arrayindex (arrayindex *e)
void
c_unparser_assignment::visit_arrayindex (arrayindex *e)
{
- throw semantic_error ("not yet implemented", e->tok);
+ throw semantic_error ("array write not supported", e->tok);
}
@@ -1301,8 +1437,7 @@ c_tmpcounter::visit_functioncall (functioncall *e)
for (unsigned i=0; i<r->formal_args.size(); i++)
parent->o->newline()
<< parent->c_typename (r->formal_args[i]->type)
- << " __tmp" << tmpvar_counter ++ << ";"
- << " /* " << e->function << " arg #" << i << " */";
+ << " __tmp" << tmpvar_counter ++ << ";";
for (unsigned i=0; i<e->args.size(); i++)
e->args[i]->visit (this);