summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--TODO1
-rw-r--r--elaborate.cxx18
-rw-r--r--elaborate.h3
-rw-r--r--parse.cxx158
-rw-r--r--parse.h4
-rw-r--r--staptree.cxx75
-rw-r--r--staptree.h35
-rwxr-xr-xtestsuite/parseok/ten.stp17
-rwxr-xr-xtestsuite/semko/twelve.stp6
-rwxr-xr-xtestsuite/transko/two.stp11
-rwxr-xr-xtestsuite/transok/five.stp17
-rw-r--r--translate.cxx79
13 files changed, 419 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 5b495119..b66a8902 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 ...
diff --git a/TODO b/TODO
index 0179b67f..92ed9691 100644
--- a/TODO
+++ b/TODO
@@ -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);
diff --git a/parse.cxx b/parse.cxx
index 5595f359..d1c0b954 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -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;
}
diff --git a/parse.h b/parse.h
index 28690e95..29ae41c8 100644
--- a/parse.h
+++ b/parse.h
@@ -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);
diff --git a/staptree.h b/staptree.h
index 48862d05..98bd057c 100644
--- a/staptree.h
+++ b/staptree.h
@@ -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)
{