diff options
author | graydon <graydon> | 2005-08-10 03:15:21 +0000 |
---|---|---|
committer | graydon <graydon> | 2005-08-10 03:15:21 +0000 |
commit | d7f3e0c5d0b0af0dcb5f8168e1184f15a0554a4e (patch) | |
tree | 905bbe1cff9ae08a6cf9f314fd4d5bc8976215fa | |
parent | 0110f903329ab531bcbe9d555d5b6f6dc77d8a54 (diff) | |
download | systemtap-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-- | ChangeLog | 28 | ||||
-rw-r--r-- | elaborate.cxx | 60 | ||||
-rw-r--r-- | elaborate.h | 1 | ||||
-rw-r--r-- | parse.cxx | 189 | ||||
-rw-r--r-- | parse.h | 11 | ||||
-rw-r--r-- | staptree.cxx | 82 | ||||
-rw-r--r-- | staptree.h | 25 | ||||
-rw-r--r-- | tapsets.cxx | 102 | ||||
-rw-r--r-- | translate.cxx | 8 |
9 files changed, 330 insertions, 176 deletions
@@ -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); }; @@ -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 ')'"); } @@ -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; @@ -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) { |