summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgraydon <graydon>2005-08-10 03:15:21 +0000
committergraydon <graydon>2005-08-10 03:15:21 +0000
commitd7f3e0c5d0b0af0dcb5f8168e1184f15a0554a4e (patch)
tree905bbe1cff9ae08a6cf9f314fd4d5bc8976215fa
parent0110f903329ab531bcbe9d555d5b6f6dc77d8a54 (diff)
downloadsystemtap-steved-d7f3e0c5d0b0af0dcb5f8168e1184f15a0554a4e.tar.gz
systemtap-steved-d7f3e0c5d0b0af0dcb5f8168e1184f15a0554a4e.tar.xz
systemtap-steved-d7f3e0c5d0b0af0dcb5f8168e1184f15a0554a4e.zip
2005-08-09 Graydon Hoare <graydon@redhat.com>
* staptree.{cxx,h} (target_symbol): New struct. (*_visitor::visit_target_symbol): Support it. (visitor::active_lvalues) (visitor::is_active_lvalue) (visitor::push_active_lvalue) (visitor::pop_active_lvalue): Support lvalue-detection. (delete_statement::visit) (pre_crement::visit) (post_crement::visit) (assignment::visit): Push and pop lvalue expressions. * elaborate.{cxx,h} (lvalule_aware_traversing_visitor): Remove class. (no_map_mutation_during_iteration_check) (mutated_map_collector): Update lvalue logic. (typeresolution_info::visit_target_symbol): Add, throw error. * parse.{cxx,h} (tt2str) (tok_is) (parser::expect_*) (parser::peek_*): New helpers. (parser::parse_symbol): Rewrite, support target_symbols. * translate.cxx (c_unparser::visit_target_symbol): Implement. * tapsets.cxx (var_expanding_copy_visitor): Update lvalue logic, change visit_symbol to visit_target_symbol.
-rw-r--r--ChangeLog28
-rw-r--r--elaborate.cxx60
-rw-r--r--elaborate.h1
-rw-r--r--parse.cxx189
-rw-r--r--parse.h11
-rw-r--r--staptree.cxx82
-rw-r--r--staptree.h25
-rw-r--r--tapsets.cxx102
-rw-r--r--translate.cxx8
9 files changed, 330 insertions, 176 deletions
diff --git a/ChangeLog b/ChangeLog
index 196ce645..c8cd2546 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2005-08-09 Graydon Hoare <graydon@redhat.com>
+
+ * staptree.{cxx,h}
+ (target_symbol): New struct.
+ (*_visitor::visit_target_symbol): Support it.
+ (visitor::active_lvalues)
+ (visitor::is_active_lvalue)
+ (visitor::push_active_lvalue)
+ (visitor::pop_active_lvalue): Support lvalue-detection.
+ (delete_statement::visit)
+ (pre_crement::visit)
+ (post_crement::visit)
+ (assignment::visit): Push and pop lvalue expressions.
+ * elaborate.{cxx,h}
+ (lvalule_aware_traversing_visitor): Remove class.
+ (no_map_mutation_during_iteration_check)
+ (mutated_map_collector): Update lvalue logic.
+ (typeresolution_info::visit_target_symbol): Add, throw error.
+ * parse.{cxx,h}
+ (tt2str)
+ (tok_is)
+ (parser::expect_*)
+ (parser::peek_*): New helpers.
+ (parser::parse_symbol): Rewrite, support target_symbols.
+ * translate.cxx (c_unparser::visit_target_symbol): Implement.
+ * tapsets.cxx (var_expanding_copy_visitor): Update lvalue logic,
+ change visit_symbol to visit_target_symbol.
+
2005-08-09 Martin Hunt <hunt@redhat.com>
PR 1174
diff --git a/elaborate.cxx b/elaborate.cxx
index c9f1fcd1..0cecab7e 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -396,53 +396,9 @@ symresolution_info::derive_probes (match_node * root,
// Map usage checks
//
-class lvalue_aware_traversing_visitor
- : public traversing_visitor
-{
- unsigned lval_depth;
-public:
-
- lvalue_aware_traversing_visitor() : lval_depth(0) {}
-
- bool is_in_lvalue()
- {
- return lval_depth > 0;
- }
-
- virtual void visit_pre_crement (pre_crement* e)
- {
- ++lval_depth;
- e->operand->visit (this);
- --lval_depth;
- }
-
- virtual void visit_post_crement (post_crement* e)
- {
- ++lval_depth;
- e->operand->visit (this);
- --lval_depth;
- }
-
- virtual void visit_assignment (assignment* e)
- {
- ++lval_depth;
- e->left->visit (this);
- --lval_depth;
- e->right->visit (this);
- }
-
- virtual void visit_delete_statement (delete_statement* s)
- {
- ++lval_depth;
- s->value->visit (this);
- --lval_depth;
- }
-
-};
-
struct mutated_map_collector
- : public lvalue_aware_traversing_visitor
+ : public traversing_visitor
{
set<vardecl *> * mutated_maps;
@@ -452,14 +408,14 @@ struct mutated_map_collector
void visit_arrayindex (arrayindex *e)
{
- if (is_in_lvalue())
+ if (is_active_lvalue(e))
mutated_maps->insert(e->referent);
}
};
struct no_map_mutation_during_iteration_check
- : public lvalue_aware_traversing_visitor
+ : public traversing_visitor
{
systemtap_session & session;
map<functiondecl *,set<vardecl *> *> & function_mutates_maps;
@@ -473,7 +429,7 @@ struct no_map_mutation_during_iteration_check
void visit_arrayindex (arrayindex *e)
{
- if (is_in_lvalue())
+ if (is_active_lvalue(e))
{
for (unsigned i = 0; i < maps_being_iterated.size(); ++i)
{
@@ -1346,13 +1302,19 @@ typeresolution_info::visit_symbol (symbol* e)
if (e->referent->arity > 0)
unresolved (e->tok); // symbol resolution should not permit this
- // XXX: but consider "delete <array>;" and similar constructs
else
resolve_2types (e, e->referent, this, t);
}
void
+typeresolution_info::visit_target_symbol (target_symbol* e)
+{
+ throw semantic_error("unresolved target-symbol expression", e->tok);
+}
+
+
+void
typeresolution_info::visit_arrayindex (arrayindex* e)
{
assert (e->referent != 0);
diff --git a/elaborate.h b/elaborate.h
index 86da8b51..b4180c31 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -90,6 +90,7 @@ struct typeresolution_info: public visitor
void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_symbol (symbol* e);
+ void visit_target_symbol (target_symbol* e);
void visit_arrayindex (arrayindex* e);
void visit_functioncall (functioncall* e);
};
diff --git a/parse.cxx b/parse.cxx
index 9e91f5b7..c4098562 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -55,17 +55,25 @@ parser::parse (const std::string& n, bool pr)
return p.parse ();
}
+static string
+tt2str(token_type tt)
+{
+ switch (tt)
+ {
+ case tok_junk: return "junk";
+ case tok_identifier: return "identifier";
+ case tok_operator: return "operator";
+ case tok_string: return "string";
+ case tok_number: return "number";
+ case tok_embedded: return "embedded-code";
+ }
+ return "unknown token";
+}
ostream&
operator << (ostream& o, const token& t)
{
- o << (t.type == tok_junk ? "junk" :
- t.type == tok_identifier ? "identifier" :
- t.type == tok_operator ? "operator" :
- t.type == tok_string ? "string" :
- t.type == tok_number ? "number" :
- t.type == tok_embedded ? "embedded-code" :
- "unknown token");
+ o << tt2str(t.type);
if (t.type != tok_embedded) // XXX: other types?
{
@@ -141,6 +149,70 @@ parser::peek ()
}
+static inline bool
+tok_is(token const * t, token_type tt, string const & expected)
+{
+ return t && t->type == tt && t->content == expected;
+}
+
+
+const token*
+parser::expect_known (token_type tt, string const & expected)
+{
+ const token *t = next();
+ if (! t && t->type == tt && t->content == expected)
+ throw parse_error ("expected '" + expected + "'");
+ return t;
+}
+
+
+const token*
+parser::expect_unknown (token_type tt, string & target)
+{
+ const token *t = next();
+ if (!(t && t->type == tt))
+ throw parse_error ("expected " + tt2str(tt));
+ target = t->content;
+ return t;
+}
+
+
+const token*
+parser::expect_op (std::string const & expected)
+{
+ return expect_known (tok_operator, expected);
+}
+
+
+const token*
+parser::expect_kw (std::string const & expected)
+{
+ return expect_known (tok_identifier, expected);
+}
+
+
+const token*
+parser::expect_ident (std::string & target)
+{
+ return expect_unknown (tok_identifier, target);
+}
+
+
+bool
+parser::peek_op (std::string const & op)
+{
+ return tok_is (peek(), tok_operator, op);
+}
+
+
+bool
+parser::peek_kw (std::string const & kw)
+{
+ return tok_is (peek(), tok_identifier, kw);
+}
+
+
+
lexer::lexer (istream& i, const string& in):
input (i), input_name (in), cursor_line (1), cursor_column (1)
{ }
@@ -1534,41 +1606,47 @@ parser::parse_value ()
expression*
parser::parse_symbol ()
{
- const token* t = next ();
- if (t->type != tok_identifier)
- throw parse_error ("expected identifier");
+ string name;
+ const token* t = expect_ident (name);
const token* t2 = t;
- string name = t->content;
- t = peek ();
- if (t && t->type == tok_operator && t->content == "->")
+ if (name.size() > 0 && name[0] == '$')
{
- // shorthand for process- or thread-specific array element
- // map "thread->VAR" to "VAR[$tid]",
- // and "process->VAR" to "VAR[$pid]"
- symbol* sym = new symbol;
- if (name == "thread")
- sym->name = "$tid";
- else if (name == "process")
- sym->name = "$pid";
- else
- throw parse_error ("expected 'thread->' or 'process->'");
- struct token* t2prime = new token (*t2);
- t2prime->content = sym->name;
- sym->tok = t2prime;
-
- next (); // swallow "->"
- t = next ();
- if (! (t->type == tok_identifier))
- throw parse_error ("expected identifier");
-
- struct arrayindex* ai = new arrayindex;
- ai->tok = t;
- ai->base = t->content;
- ai->indexes.push_back (sym);
- return ai;
+ // target_symbol time
+ target_symbol *tsym = new target_symbol;
+ tsym->base_name = name;
+ while (true)
+ {
+ string c;
+ if (peek_op ("."))
+ {
+ next();
+ expect_ident (c);
+ tsym->components.push_back
+ (make_pair (target_symbol::comp_struct_member, c));
+ }
+ else if (peek_op ("->"))
+ {
+ next();
+ expect_ident (c);
+ tsym->components.push_back
+ (make_pair (target_symbol::comp_struct_pointer_member, c));
+ }
+ else if (peek_op ("["))
+ {
+ next();
+ expect_unknown (tok_number, c);
+ expect_op ("]");
+ tsym->components.push_back
+ (make_pair (target_symbol::comp_literal_array_index, c));
+ }
+ else
+ break;
+ }
+ return tsym;
}
- else if (t && t->type == tok_operator && t->content == "[") // array
+
+ if (peek_op ("[")) // array
{
next ();
struct arrayindex* ai = new arrayindex;
@@ -1577,25 +1655,29 @@ parser::parse_symbol ()
while (1)
{
ai->indexes.push_back (parse_expression ());
- t = next ();
- if (t->type == tok_operator && t->content == "]")
- break;
- if (t->type == tok_operator && t->content == ",")
- continue;
+ if (peek_op ("]"))
+ {
+ next();
+ break;
+ }
+ else if (peek_op (","))
+ {
+ next();
+ continue;
+ }
else
throw parse_error ("expected ',' or ']'");
}
return ai;
}
- else if (t && t->type == tok_operator && t->content == "(") // function call
+ else if (peek_op ("(")) // function call
{
next ();
struct functioncall* f = new functioncall;
f->tok = t2;
f->function = name;
// Allow empty actual parameter list
- const token* t3 = peek ();
- if (t3 && t3->type == tok_operator && t3->content == ")")
+ if (peek_op (")"))
{
next ();
return f;
@@ -1603,11 +1685,16 @@ parser::parse_symbol ()
while (1)
{
f->args.push_back (parse_expression ());
- t = next ();
- if (t->type == tok_operator && t->content == ")")
- break;
- if (t->type == tok_operator && t->content == ",")
- continue;
+ if (peek_op (")"))
+ {
+ next();
+ break;
+ }
+ else if (peek_op (","))
+ {
+ next();
+ continue;
+ }
else
throw parse_error ("expected ',' or ')'");
}
diff --git a/parse.h b/parse.h
index 7e5b90a4..316f8258 100644
--- a/parse.h
+++ b/parse.h
@@ -92,6 +92,17 @@ private:
const token* last_t; // the last value returned by peek() or next()
const token* next_t; // lookahead token
+
+ // expectations
+ const token* expect_known (token_type tt, std::string const & expected);
+ const token* expect_unknown (token_type tt, std::string & target);
+
+ // convenience forms
+ const token* expect_op (std::string const & expected);
+ const token* expect_kw (std::string const & expected);
+ const token* expect_ident (std::string & target);
+ bool peek_op (std::string const & op);
+ bool peek_kw (std::string const & kw);
void print_error (const parse_error& pe);
unsigned num_errors;
diff --git a/staptree.cxx b/staptree.cxx
index 31330017..811605ca 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -232,6 +232,26 @@ void symbol::print (ostream& o)
}
+void target_symbol::print (std::ostream& o)
+{
+ o << base_name;
+ for (unsigned i = 0; i < components.size(); ++i)
+ {
+ switch (components[i].first)
+ {
+ case comp_literal_array_index:
+ o << '[' << components[i].second << ']';
+ break;
+ case comp_struct_pointer_member:
+ o << "->" << components[i].second;
+ break;
+ case comp_struct_member:
+ o << "." << components[i].second;
+ }
+ }
+}
+
+
void vardecl::print (ostream& o)
{
o << name;
@@ -540,7 +560,9 @@ return_statement::visit (visitor* u)
void
delete_statement::visit (visitor* u)
{
+ u->push_active_lvalue (this->value);
u->visit_delete_statement (this);
+ u->pop_active_lvalue ();
}
void
@@ -594,13 +616,17 @@ unary_expression::visit (visitor* u)
void
pre_crement::visit (visitor* u)
{
+ u->push_active_lvalue (this->operand);
u->visit_pre_crement (this);
+ u->pop_active_lvalue ();
}
void
post_crement::visit (visitor* u)
{
+ u->push_active_lvalue (this->operand);
u->visit_post_crement (this);
+ u->pop_active_lvalue ();
}
void
@@ -642,7 +668,9 @@ ternary_expression::visit (visitor* u)
void
assignment::visit (visitor* u)
{
+ u->push_active_lvalue (this->left);
u->visit_assignment (this);
+ u->pop_active_lvalue ();
}
void
@@ -651,6 +679,12 @@ symbol::visit (visitor* u)
u->visit_symbol (this);
}
+void
+target_symbol::visit (visitor* u)
+{
+ u->visit_target_symbol(this);
+}
+
void
arrayindex::visit (visitor* u)
{
@@ -663,6 +697,33 @@ functioncall::visit (visitor* u)
u->visit_functioncall (this);
}
+// ------------------------------------------------------------------------
+
+bool
+visitor::is_active_lvalue(expression *e)
+{
+ for (unsigned i = 0; i < active_lvalues.size(); ++i)
+ {
+ if (active_lvalues[i] == e)
+ return true;
+ }
+ return false;
+}
+
+void
+visitor::push_active_lvalue(expression *e)
+{
+ active_lvalues.push_back(e);
+}
+
+void
+visitor::pop_active_lvalue()
+{
+ assert(!active_lvalues.empty());
+ active_lvalues.pop_back();
+}
+
+
// ------------------------------------------------------------------------
@@ -833,6 +894,11 @@ traversing_visitor::visit_symbol (symbol* e)
}
void
+traversing_visitor::visit_target_symbol (target_symbol* e)
+{
+}
+
+void
traversing_visitor::visit_arrayindex (arrayindex* e)
{
for (unsigned i=0; i<e->indexes.size(); i++)
@@ -1018,6 +1084,12 @@ throwing_visitor::visit_symbol (symbol* e)
}
void
+throwing_visitor::visit_target_symbol (target_symbol* e)
+{
+ throwone (e->tok);
+}
+
+void
throwing_visitor::visit_arrayindex (arrayindex* e)
{
throwone (e->tok);
@@ -1299,6 +1371,16 @@ deep_copy_visitor::visit_symbol (symbol* e)
}
void
+deep_copy_visitor::visit_target_symbol (target_symbol* e)
+{
+ target_symbol* n = new target_symbol;
+ n->tok = e->tok;
+ n->base_name = e->base_name;
+ n->components = e->components;
+ provide <target_symbol*> (this, n);
+}
+
+void
deep_copy_visitor::visit_arrayindex (arrayindex* e)
{
arrayindex* n = new arrayindex;
diff --git a/staptree.h b/staptree.h
index 34e04ec7..93537921 100644
--- a/staptree.h
+++ b/staptree.h
@@ -177,6 +177,21 @@ struct symbol: public expression
};
+struct target_symbol : public expression
+{
+ enum component_type
+ {
+ comp_struct_member,
+ comp_struct_pointer_member,
+ comp_literal_array_index
+ };
+ std::string base_name;
+ std::vector<std::pair<component_type, std::string> > components;
+ void print (std::ostream& o);
+ void visit (visitor* u);
+};
+
+
struct arrayindex: public expression
{
std::string base;
@@ -426,6 +441,12 @@ struct probe_alias: public probe
// statement/expression tree.
struct visitor
{
+ // Machinery for differentiating lvalue visits from non-lvalue.
+ std::vector<expression *> active_lvalues;
+ bool is_active_lvalue(expression *e);
+ void push_active_lvalue(expression *e);
+ void pop_active_lvalue();
+
virtual ~visitor () {}
virtual void visit_block (block *s) = 0;
virtual void visit_embeddedcode (embeddedcode *s) = 0;
@@ -453,6 +474,7 @@ struct visitor
virtual void visit_ternary_expression (ternary_expression* e) = 0;
virtual void visit_assignment (assignment* e) = 0;
virtual void visit_symbol (symbol* e) = 0;
+ virtual void visit_target_symbol (target_symbol* e) = 0;
virtual void visit_arrayindex (arrayindex* e) = 0;
virtual void visit_functioncall (functioncall* e) = 0;
};
@@ -489,6 +511,7 @@ struct traversing_visitor: public visitor
void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_symbol (symbol* e);
+ void visit_target_symbol (target_symbol* e);
void visit_arrayindex (arrayindex* e);
void visit_functioncall (functioncall* e);
};
@@ -530,6 +553,7 @@ struct throwing_visitor: public visitor
void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_symbol (symbol* e);
+ void visit_target_symbol (target_symbol* e);
void visit_arrayindex (arrayindex* e);
void visit_functioncall (functioncall* e);
};
@@ -573,6 +597,7 @@ struct deep_copy_visitor: public visitor
virtual void visit_ternary_expression (ternary_expression* e);
virtual void visit_assignment (assignment* e);
virtual void visit_symbol (symbol* e);
+ virtual void visit_target_symbol (target_symbol* e);
virtual void visit_arrayindex (arrayindex* e);
virtual void visit_functioncall (functioncall* e);
};
diff --git a/tapsets.cxx b/tapsets.cxx
index 887ddd60..2df8fc65 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -1204,58 +1204,15 @@ struct
var_expanding_copy_visitor
: public deep_copy_visitor
{
- // Alas, we cannot easily mixin lvalue_aware_traversing_visitor.
- // But behold the *awesome power* of copy and paste.
-
static unsigned tick;
dwarf_query & q;
- unsigned lval_depth;
Dwarf_Addr addr;
var_expanding_copy_visitor(dwarf_query & q, Dwarf_Addr a)
- : q(q), lval_depth(0), addr(a)
+ : q(q), addr(a)
{}
-
- bool is_in_lvalue()
- {
- return lval_depth > 0;
- }
-
- void visit_pre_crement (pre_crement* e)
- {
- ++lval_depth;
- deep_copy_visitor::visit_pre_crement (e);
- --lval_depth;
- }
-
- void visit_post_crement (post_crement* e)
- {
- ++lval_depth;
- deep_copy_visitor::visit_post_crement (e);
- --lval_depth;
- }
-
- void visit_assignment (assignment* e)
- {
- assignment* n = new assignment;
- n->op = e->op;
- n->tok = e->tok;
- ++lval_depth;
- require <expression*> (this, &(n->left), e->left);
- --lval_depth;
- require <expression*> (this, &(n->right), e->right);
- provide <assignment*> (this, n);
- }
-
- void visit_delete_statement (delete_statement* s)
- {
- ++lval_depth;
- deep_copy_visitor::visit_delete_statement (s);
- --lval_depth;
- }
-
- void visit_symbol (symbol* e);
+ void visit_target_symbol (target_symbol* e);
};
@@ -1263,40 +1220,33 @@ unsigned var_expanding_copy_visitor::tick = 0;
void
-var_expanding_copy_visitor::visit_symbol (symbol *e)
+var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
{
- if (e->name.size() > 0 &&
- e->name[0] == '$')
- {
- if (is_in_lvalue())
- {
- throw semantic_error("read-only special variable "
- + e->name + " used in lvalue", e->tok);
- }
-
- string fname = "get_" + e->name.substr(1) + "_" + lex_cast<string>(tick++);
-
- // synthesize a function
- functiondecl *fdecl = new functiondecl;
- embeddedcode *ec = new embeddedcode;
- ec->code = q.dw.literal_stmt_for_local(addr, e->name.substr(1));
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = pe_long;
- q.sess.functions.push_back(fdecl);
-
- // synthesize a call
- functioncall* n = new functioncall;
- n->tok = e->tok;
- n->function = fname;
- n->referent = NULL;
- provide <functioncall*> (this, n);
-
- }
- else
+ assert(e->base_name.size() > 0 && e->base_name[0] == '$');
+
+ if (is_active_lvalue(e))
{
- deep_copy_visitor::visit_symbol (e);
+ throw semantic_error("read-only special variable "
+ + e->base_name + " used as lvalue", e->tok);
}
+
+ string fname = "get_" + e->base_name.substr(1) + "_" + lex_cast<string>(tick++);
+
+ // synthesize a function
+ functiondecl *fdecl = new functiondecl;
+ embeddedcode *ec = new embeddedcode;
+ ec->code = q.dw.literal_stmt_for_local(addr, e->base_name.substr(1));
+ fdecl->name = fname;
+ fdecl->body = ec;
+ fdecl->type = pe_long;
+ q.sess.functions.push_back(fdecl);
+
+ // synthesize a call
+ functioncall* n = new functioncall;
+ n->tok = e->tok;
+ n->function = fname;
+ n->referent = NULL;
+ provide <functioncall*> (this, n);
}
diff --git a/translate.cxx b/translate.cxx
index b013fc29..4add7b64 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -121,6 +121,7 @@ struct c_unparser: public unparser, public visitor
void visit_ternary_expression (ternary_expression* e);
void visit_assignment (assignment* e);
void visit_symbol (symbol* e);
+ void visit_target_symbol (target_symbol* e);
void visit_arrayindex (arrayindex* e);
void visit_functioncall (functioncall* e);
};
@@ -1836,6 +1837,13 @@ c_unparser_assignment::visit_symbol (symbol *e)
}
+void
+c_unparser::visit_target_symbol (target_symbol* e)
+{
+ throw semantic_error("cannot translate general target-symbol expression");
+}
+
+
void
c_tmpcounter::visit_arrayindex (arrayindex *e)
{