diff options
author | fche <fche> | 2005-06-08 22:02:09 +0000 |
---|---|---|
committer | fche <fche> | 2005-06-08 22:02:09 +0000 |
commit | bb2e3076ea20631d4606050550bc9664204f2c62 (patch) | |
tree | ef9cfb841ddb001c1f3aa266523f1ff6f56b21b5 | |
parent | 22f4623195facb4cbc1b50c45c0bd689f6958a9d (diff) | |
download | systemtap-steved-bb2e3076ea20631d4606050550bc9664204f2c62.tar.gz systemtap-steved-bb2e3076ea20631d4606050550bc9664204f2c62.tar.xz systemtap-steved-bb2e3076ea20631d4606050550bc9664204f2c62.zip |
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.
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | README | 13 | ||||
-rw-r--r-- | elaborate.cxx | 7 | ||||
-rw-r--r-- | elaborate.h | 1 | ||||
-rw-r--r-- | main.cxx | 1 | ||||
-rw-r--r-- | parse.cxx | 258 | ||||
-rw-r--r-- | parse.h | 7 | ||||
-rw-r--r-- | staptree.cxx | 27 | ||||
-rw-r--r-- | staptree.h | 9 | ||||
-rwxr-xr-x | testsuite/parseok/eleven.stp | 54 | ||||
-rwxr-xr-x | testsuite/parseok/ten.stp | 14 | ||||
-rwxr-xr-x | testsuite/transok/five.stp | 2 | ||||
-rwxr-xr-x | testsuite/transok/one.stp | 56 | ||||
-rwxr-xr-x | testsuite/transok/three.stp | 7 | ||||
-rwxr-xr-x | testsuite/transok/two.stp | 2 | ||||
-rw-r--r-- | translate.cxx | 479 |
16 files changed, 642 insertions, 310 deletions
@@ -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. @@ -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); @@ -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; @@ -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 (); } @@ -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); @@ -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); |