diff options
author | fche <fche> | 2005-06-05 16:35:28 +0000 |
---|---|---|
committer | fche <fche> | 2005-06-05 16:35:28 +0000 |
commit | f3c26ea55e2f2c1d222312bf75035359c439ed21 (patch) | |
tree | 1a58dfcdebe04941002e7e0203f765b619ca9c67 | |
parent | 8846477c222cdae649b02117cc96999b0be6ad40 (diff) | |
download | systemtap-steved-f3c26ea55e2f2c1d222312bf75035359c439ed21.tar.gz systemtap-steved-f3c26ea55e2f2c1d222312bf75035359c439ed21.tar.xz systemtap-steved-f3c26ea55e2f2c1d222312bf75035359c439ed21.zip |
2005-06-05 Frank Ch. Eigler <fche@elastic.org>
Implement for/next/continue/break/while statements.
* staptree.h: Declare new 0-arity statement types. Tweak for_loop.
* parse.cxx: Parse them all.
* translate.cxx (c_unparser): Maintain break/continue label stack.
(visit_for_loop, *_statement): New implementations.
* elaborate.*, staptree.cxx: Mechanical changes.
* testsuite/parseok/ten.stp, semko/twelve.stp, transko/two.stp,
transok/five.stp: New tests.
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | elaborate.cxx | 18 | ||||
-rw-r--r-- | elaborate.h | 3 | ||||
-rw-r--r-- | parse.cxx | 158 | ||||
-rw-r--r-- | parse.h | 4 | ||||
-rw-r--r-- | staptree.cxx | 75 | ||||
-rw-r--r-- | staptree.h | 35 | ||||
-rwxr-xr-x | testsuite/parseok/ten.stp | 17 | ||||
-rwxr-xr-x | testsuite/semko/twelve.stp | 6 | ||||
-rwxr-xr-x | testsuite/transko/two.stp | 11 | ||||
-rwxr-xr-x | testsuite/transok/five.stp | 17 | ||||
-rw-r--r-- | translate.cxx | 79 |
13 files changed, 419 insertions, 16 deletions
@@ -1,3 +1,14 @@ +2005-06-05 Frank Ch. Eigler <fche@elastic.org> + + Implement for/next/continue/break/while statements. + * staptree.h: Declare new 0-arity statement types. Tweak for_loop. + * parse.cxx: Parse them all. + * translate.cxx (c_unparser): Maintain break/continue label stack. + (visit_for_loop, *_statement): New implementations. + * elaborate.*, staptree.cxx: Mechanical changes. + * testsuite/parseok/ten.stp, semko/twelve.stp, transko/two.stp, + transok/five.stp: New tests. + 2005-06-03 Frank Ch. Eigler <fche@elastic.org> * elaborate.cxx (find_*): Remove arity checks from here ... @@ -1,5 +1,4 @@ LANGUAGE - for/while/break/continue statements lock (var) { block } (http://tinyurl.com/5rpzg) builtin functions varargs/overloaded functions (?) diff --git a/elaborate.cxx b/elaborate.cxx index c6596da6..f3edd81b 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1004,6 +1004,24 @@ typeresolution_info::visit_delete_statement (delete_statement* e) void +typeresolution_info::visit_next_statement (next_statement* s) +{ +} + + +void +typeresolution_info::visit_break_statement (break_statement* s) +{ +} + + +void +typeresolution_info::visit_continue_statement (continue_statement* s) +{ +} + + +void typeresolution_info::visit_array_in (array_in* e) { // all unary operators only work on numerics diff --git a/elaborate.h b/elaborate.h index f4bc1b68..bd13fa08 100644 --- a/elaborate.h +++ b/elaborate.h @@ -69,6 +69,9 @@ struct typeresolution_info: public visitor void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); + void visit_next_statement (next_statement* s); + void visit_break_statement (break_statement* s); + void visit_continue_statement (continue_statement* s); void visit_literal_string (literal_string* e); void visit_literal_number (literal_number* e); void visit_binary_expression (binary_expression* e); @@ -486,18 +486,23 @@ parser::parse_statement () return parse_stmt_block (); else if (t && t->type == tok_identifier && t->content == "if") return parse_if_statement (); - /* else if (t && t->type == tok_identifier && t->content == "for") return parse_for_loop (); - */ else if (t && t->type == tok_identifier && t->content == "foreach") return parse_foreach_loop (); else if (t && t->type == tok_identifier && t->content == "return") return parse_return_statement (); else if (t && t->type == tok_identifier && t->content == "delete") return parse_delete_statement (); - // XXX: other control constructs ("delete", "while", "do", - // "break", "continue", "exit") + else if (t && t->type == tok_identifier && t->content == "while") + return parse_while_loop (); + else if (t && t->type == tok_identifier && t->content == "break") + return parse_break_statement (); + else if (t && t->type == tok_identifier && t->content == "continue") + return parse_continue_statement (); + else if (t && t->type == tok_identifier && t->content == "next") + return parse_next_statement (); + // XXX: "do/while" statement? else if (t && (t->type == tok_operator || // expressions are flexible t->type == tok_identifier || t->type == tok_number || @@ -746,10 +751,153 @@ parser::parse_delete_statement () } +next_statement* +parser::parse_next_statement () +{ + const token* t = next (); + if (! (t->type == tok_identifier && t->content == "next")) + throw parse_error ("expected 'next'"); + next_statement* s = new next_statement; + s->tok = t; + return s; +} + + +break_statement* +parser::parse_break_statement () +{ + const token* t = next (); + if (! (t->type == tok_identifier && t->content == "break")) + throw parse_error ("expected 'break'"); + break_statement* s = new break_statement; + s->tok = t; + return s; +} + + +continue_statement* +parser::parse_continue_statement () +{ + const token* t = next (); + if (! (t->type == tok_identifier && t->content == "continue")) + throw parse_error ("expected 'continue'"); + continue_statement* s = new continue_statement; + s->tok = t; + return s; +} + + for_loop* parser::parse_for_loop () { - throw parse_error ("not yet implemented"); + const token* t = next (); + if (! (t->type == tok_identifier && t->content == "for")) + throw parse_error ("expected 'for'"); + for_loop* s = new for_loop; + s->tok = t; + + t = next (); + if (! (t->type == tok_operator && t->content == "(")) + throw parse_error ("expected '('"); + + // initializer + ";" + t = peek (); + if (t && t->type == tok_operator && t->content == ";") + { + literal_number* l = new literal_number(0); + expr_statement* es = new expr_statement; + es->value = l; + s->init = es; + es->value->tok = es->tok = next (); + } + else + { + s->init = parse_expr_statement (); + t = next (); + if (! (t->type == tok_operator && t->content == ";")) + throw parse_error ("expected ';'"); + } + + // condition + ";" + t = peek (); + if (t && t->type == tok_operator && t->content == ";") + { + literal_number* l = new literal_number(1); + s->cond = l; + s->cond->tok = next (); + } + else + { + s->cond = parse_expression (); + t = next (); + if (! (t->type == tok_operator && t->content == ";")) + throw parse_error ("expected ';'"); + } + + // increment + ")" + t = peek (); + if (t && t->type == tok_operator && t->content == ")") + { + literal_number* l = new literal_number(2); + expr_statement* es = new expr_statement; + es->value = l; + s->incr = es; + es->value->tok = es->tok = next (); + } + else + { + s->incr = parse_expr_statement (); + t = next (); + if (! (t->type == tok_operator && t->content == ")")) + throw parse_error ("expected ';'"); + } + + // block + s->block = parse_statement (); + + return s; +} + + +for_loop* +parser::parse_while_loop () +{ + const token* t = next (); + if (! (t->type == tok_identifier && t->content == "while")) + throw parse_error ("expected 'while'"); + for_loop* s = new for_loop; + s->tok = t; + + t = next (); + if (! (t->type == tok_operator && t->content == "(")) + throw parse_error ("expected '('"); + + // dummy init and incr fields + literal_number* l = new literal_number(0); + expr_statement* es = new expr_statement; + es->value = l; + s->init = es; + es->value->tok = es->tok = t; + + l = new literal_number(2); + es = new expr_statement; + es->value = l; + s->incr = es; + es->value->tok = es->tok = t; + + + // condition + s->cond = parse_expression (); + + + t = next (); + if (! (t->type == tok_operator && t->content == ")")) + throw parse_error ("expected ')'"); + + // block + s->block = parse_statement (); + + return s; } @@ -102,10 +102,14 @@ private: // nonterminals statement* parse_statement (); if_statement* parse_if_statement (); for_loop* parse_for_loop (); + for_loop* parse_while_loop (); foreach_loop* parse_foreach_loop (); expr_statement* parse_expr_statement (); return_statement* parse_return_statement (); delete_statement* parse_delete_statement (); + next_statement* parse_next_statement (); + break_statement* parse_break_statement (); + continue_statement* parse_continue_statement (); expression* parse_expression (); expression* parse_assignment (); expression* parse_ternary (); diff --git a/staptree.cxx b/staptree.cxx index 756fbc1e..3ee34950 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -161,6 +161,7 @@ void literal_string::print (ostream& o) o << '"' << value << '"'; } + void literal_number::print (ostream& o) { o << value; @@ -290,7 +291,14 @@ void block::print (ostream& o) void for_loop::print (ostream& o) { - o << "<for_loop>" << endl; + o << "for ("; + init->print (o); + o << "; "; + cond->print (o); + o << "; "; + incr->print (o); + o << ")" << endl; + block->print (o); } @@ -330,6 +338,20 @@ void delete_statement::print (ostream& o) o << "delete " << *value; } +void next_statement::print (ostream& o) +{ + o << "next"; +} + +void break_statement::print (ostream& o) +{ + o << "break"; +} + +void continue_statement::print (ostream& o) +{ + o << "continue"; +} void if_statement::print (ostream& o) { @@ -464,6 +486,24 @@ if_statement::visit (visitor* u) } void +next_statement::visit (visitor* u) +{ + u->visit_next_statement (this); +} + +void +break_statement::visit (visitor* u) +{ + u->visit_break_statement (this); +} + +void +continue_statement::visit (visitor* u) +{ + u->visit_continue_statement (this); +} + +void literal_string::visit(visitor* u) { u->visit_literal_string (this); @@ -625,6 +665,21 @@ traversing_visitor::visit_delete_statement (delete_statement* s) } void +traversing_visitor::visit_next_statement (next_statement* s) +{ +} + +void +traversing_visitor::visit_break_statement (break_statement* s) +{ +} + +void +traversing_visitor::visit_continue_statement (continue_statement* s) +{ +} + +void traversing_visitor::visit_literal_string (literal_string* e) { } @@ -798,6 +853,24 @@ throwing_visitor::visit_delete_statement (delete_statement* s) } void +throwing_visitor::visit_next_statement (next_statement* s) +{ + throwone (s->tok); +} + +void +throwing_visitor::visit_break_statement (break_statement* s) +{ + throwone (s->tok); +} + +void +throwing_visitor::visit_continue_statement (continue_statement* s) +{ + throwone (s->tok); +} + +void throwing_visitor::visit_literal_string (literal_string* e) { throwone (e->tok); @@ -275,11 +275,12 @@ struct block: public statement }; +struct expr_statement; struct for_loop: public statement { - expression* init; + expr_statement* init; expression* cond; - expression* incr; + expr_statement* incr; statement* block; void print (std::ostream& o); void visit (visitor* u); @@ -338,6 +339,27 @@ struct delete_statement: public expr_statement }; +struct break_statement: public statement +{ + void print (std::ostream& o); + void visit (visitor* u); +}; + + +struct continue_statement: public statement +{ + void print (std::ostream& o); + void visit (visitor* u); +}; + + +struct next_statement: public statement +{ + void print (std::ostream& o); + void visit (visitor* u); +}; + + struct probe; struct stapfile { @@ -393,6 +415,9 @@ struct visitor virtual void visit_foreach_loop (foreach_loop* s) = 0; virtual void visit_return_statement (return_statement* s) = 0; virtual void visit_delete_statement (delete_statement* s) = 0; + virtual void visit_next_statement (next_statement* s) = 0; + virtual void visit_break_statement (break_statement* s) = 0; + virtual void visit_continue_statement (continue_statement* s) = 0; virtual void visit_literal_string (literal_string* e) = 0; virtual void visit_literal_number (literal_number* e) = 0; virtual void visit_binary_expression (binary_expression* e) = 0; @@ -426,6 +451,9 @@ struct traversing_visitor: public visitor void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); + void visit_next_statement (next_statement* s); + void visit_break_statement (break_statement* s); + void visit_continue_statement (continue_statement* s); void visit_literal_string (literal_string* e); void visit_literal_number (literal_number* e); void visit_binary_expression (binary_expression* e); @@ -464,6 +492,9 @@ struct throwing_visitor: public visitor void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); + void visit_next_statement (next_statement* s); + void visit_break_statement (break_statement* s); + void visit_continue_statement (continue_statement* s); void visit_literal_string (literal_string* e); void visit_literal_number (literal_number* e); void visit_binary_expression (binary_expression* e); diff --git a/testsuite/parseok/ten.stp b/testsuite/parseok/ten.stp new file mode 100755 index 00000000..25d16e62 --- /dev/null +++ b/testsuite/parseok/ten.stp @@ -0,0 +1,17 @@ +#! stap -p1 + +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 } + next + while (99) ; + while (99) { break continue } +} diff --git a/testsuite/semko/twelve.stp b/testsuite/semko/twelve.stp new file mode 100755 index 00000000..ab71d579 --- /dev/null +++ b/testsuite/semko/twelve.stp @@ -0,0 +1,6 @@ +#! stap -p2 + +probe end { + for (a=0; "hello";) {} + while ("goodbye") {} +} diff --git a/testsuite/transko/two.stp b/testsuite/transko/two.stp new file mode 100755 index 00000000..69f78b5c --- /dev/null +++ b/testsuite/transko/two.stp @@ -0,0 +1,11 @@ +#! stap -p3 + +function bar () { + next +} + +probe foo { + break + for (a=0; a<10; a=a+1) for (b=0; b<10; b=b+1) ; + continue +} diff --git a/testsuite/transok/five.stp b/testsuite/transok/five.stp new file mode 100755 index 00000000..266b3408 --- /dev/null +++ b/testsuite/transok/five.stp @@ -0,0 +1,17 @@ +#! stap + +probe two +{ + for (;;) ; + for (a=0;;) { if (a > 4) break } + for (;a>0;) { a + 5 } + for (;;a=a+1) { a + 5 } + for (a=0;a>0;) { if (a < 4) continue } + for (;a>0;a=a+1) { a + 5 } + for (a=0;;a=a+1) { a + 5 } + for (a=0; a<=4; a=a+1) ; + for (a=0; a<=4; a=a+1) { b = a } + + while (99) next + while (99) {} +} diff --git a/translate.cxx b/translate.cxx index 972e188c..df20389f 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1,4 +1,4 @@ -// semantic analysis pass, beginnings of elaboration +// translation pass // Copyright (C) 2005 Red Hat Inc. // // This file is part of systemtap, and is free software. You can @@ -65,10 +65,11 @@ struct c_unparser: public unparser, public visitor unsigned current_probenum; functiondecl* current_function; unsigned tmpvar_counter; + unsigned label_counter; c_unparser (systemtap_session *ss): session (ss), o (ss->op), current_probe(0), current_function (0), - tmpvar_counter (0) {} + tmpvar_counter (0), label_counter (0) {} ~c_unparser () {} void emit_common_header (); @@ -79,9 +80,9 @@ struct c_unparser: public unparser, public visitor void emit_function (functiondecl* v); void emit_probe (derived_probe* v, unsigned i); - // XXX: for use by loop/nesting constructs - // vector<string> loop_break_labels; - // vector<string> loop_continue_labels; + // for use by looping constructs + vector<string> loop_break_labels; + vector<string> loop_continue_labels; string c_typename (exp_type e); string c_varname (const string& e); @@ -97,6 +98,9 @@ struct c_unparser: public unparser, public visitor void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); + void visit_next_statement (next_statement* s); + void visit_break_statement (break_statement* s); + void visit_continue_statement (continue_statement* s); void visit_literal_string (literal_string* e); void visit_literal_number (literal_number* e); void visit_binary_expression (binary_expression* e); @@ -593,7 +597,7 @@ c_unparser::visit_block (block *s) o->newline() << "{"; o->indent (1); o->newline() << "c->actioncount += " << s->statements.size() << ";"; - o->newline() << "if (c->actioncount > MAXACTION) errorcount ++;" << endl; + o->newline() << "if (c->actioncount > MAXACTION) errorcount ++;"; for (unsigned i=0; i<s->statements.size(); i++) { @@ -653,7 +657,33 @@ c_unparser::visit_if_statement (if_statement *s) void c_unparser::visit_for_loop (for_loop *s) { - throw semantic_error ("not yet implemented", s->tok); + s->init->visit (this); + string ctr = stringify (label_counter++); + string contlabel = "continue_" + ctr; + string breaklabel = "break_" + ctr; + + o->newline() << contlabel << ":"; + + o->newline() << "c->actioncount ++;"; + o->newline() << "if (c->actioncount > MAXACTION) errorcount ++;"; + o->newline() << "if (errorcount) goto out;"; + + o->newline() << "if (! ("; + if (s->cond->type != pe_long) + throw semantic_error ("expected numeric type", s->cond->tok); + s->cond->visit (this); + o->line() << ")) goto " << breaklabel << ";"; + + loop_break_labels.push_back (breaklabel); + loop_continue_labels.push_back (contlabel); + s->block->visit (this); + loop_break_labels.pop_back (); + loop_continue_labels.pop_back (); + + s->incr->visit (this); + o->newline() << "goto " << contlabel << ";"; + + o->newline() << breaklabel << ": ; /* dummy statement */"; } @@ -680,17 +710,52 @@ c_unparser::visit_return_statement (return_statement* s) void +c_unparser::visit_next_statement (next_statement* s) +{ + if (current_probe == 0) + throw semantic_error ("cannot 'next' from non-probe", s->tok); + + o->newline() << "goto out;"; +} + + +void c_unparser::visit_delete_statement (delete_statement* s) { throw semantic_error ("not yet implemented", s->tok); } + +void +c_unparser::visit_break_statement (break_statement* s) +{ + if (loop_break_labels.size() == 0) + throw semantic_error ("cannot 'break' outside loop", s->tok); + + string label = loop_break_labels[loop_break_labels.size()-1]; + o->newline() << "goto " << label << ";"; +} + + +void +c_unparser::visit_continue_statement (continue_statement* s) +{ + if (loop_continue_labels.size() == 0) + throw semantic_error ("cannot 'continue' outside loop", s->tok); + + string label = loop_continue_labels[loop_continue_labels.size()-1]; + o->newline() << "goto " << label << ";"; +} + + + void c_unparser::visit_literal_string (literal_string* e) { o->line() << '"' << e->value << '"'; // XXX: escape special chars } + void c_unparser::visit_literal_number (literal_number* e) { |