summaryrefslogtreecommitdiffstats
path: root/staptree.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'staptree.cxx')
-rw-r--r--staptree.cxx692
1 files changed, 13 insertions, 679 deletions
diff --git a/staptree.cxx b/staptree.cxx
index ab2ebb97..3c4fe435 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -2,12 +2,15 @@
// Copyright 2005 Red Hat Inc.
// GPL
+#include "config.h"
#include "staptree.h"
#include "parse.h"
#include <iostream>
#include <typeinfo>
#include <cassert>
+using namespace std;
+
expression::expression ():
type (pe_unknown), tok (0)
@@ -79,15 +82,19 @@ probe_point::component::component ():
}
-vardecl::vardecl ()
+vardecl::vardecl ():
+ arity (-1)
{
}
-vardecl::vardecl (unsigned arity)
+void
+vardecl::set_arity (int a)
{
+ assert (a >= 0);
+ arity = a;
index_types.resize (arity);
- for (unsigned i=0; i<arity; i++)
+ for (int i=0; i<arity; i++)
index_types[i] = pe_unknown;
}
@@ -139,6 +146,7 @@ ostream& operator << (ostream& o, expression& k)
void literal_string::print (ostream& o)
{
+ // XXX: quote special chars
o << '"' << value << '"';
}
@@ -362,681 +370,6 @@ ostream& operator << (ostream& o, symboldecl& k)
}
-// ------------------------------------------------------------------------
-// semantic processing: symbol resolution
-
-
-symresolution_info::symresolution_info (vector<vardecl*>& l,
- vector<vardecl*>& g,
- vector<functiondecl*>& f):
- locals (l), globals (g), functions (f), current_function (0)
-{
- num_unresolved = 0;
-}
-
-
-symresolution_info::symresolution_info (vector<vardecl*>& l,
- vector<vardecl*>& g,
- vector<functiondecl*>& f,
- functiondecl* cf):
- locals (l), globals (g), functions (f), current_function (cf)
-{
- num_unresolved = 0;
-}
-
-
-void
-literal::resolve_symbols (symresolution_info& r)
-{
-}
-
-
-void
-binary_expression::resolve_symbols (symresolution_info& r)
-{
- left->resolve_symbols (r);
- right->resolve_symbols (r);
-}
-
-
-void
-unary_expression::resolve_symbols (symresolution_info& r)
-{
- operand->resolve_symbols (r);
-}
-
-
-void
-ternary_expression::resolve_symbols (symresolution_info& r)
-{
- cond->resolve_symbols (r);
- truevalue->resolve_symbols (r);
- falsevalue->resolve_symbols (r);
-}
-
-
-void
-symbol::resolve_symbols (symresolution_info& r)
-{
- if (referent)
- return;
-
- vardecl* d = r.find_scalar (name);
- if (d)
- referent = d;
- else
- {
- // new local
- vardecl* v = new vardecl;
- v->name = name;
- v->tok = tok;
- r.locals.push_back (v);
- referent = v;
- }
-}
-
-
-void
-arrayindex::resolve_symbols (symresolution_info& r)
-{
- for (unsigned i=0; i<indexes.size(); i++)
- indexes[i]->resolve_symbols (r);
-
- if (referent)
- return;
-
- vardecl* d = r.find_array (base, indexes);
- if (d)
- referent = d;
- else
- {
- // new local
- vardecl* v = new vardecl (indexes.size());
- v->name = base;
- v->tok = tok;
- r.locals.push_back (v);
- referent = v;
- }
-}
-
-
-void
-functioncall::resolve_symbols (symresolution_info& r)
-{
- for (unsigned i=0; i<args.size(); i++)
- args[i]->resolve_symbols (r);
-
- if (referent)
- return;
-
- functiondecl* d = r.find_function (function, args);
- if (d)
- referent = d;
- else
- r.unresolved (tok);
-}
-
-
-void
-block::resolve_symbols (symresolution_info& r)
-{
- for (unsigned i=0; i<statements.size(); i++)
- statements[i]->resolve_symbols (r);
-}
-
-
-void
-if_statement::resolve_symbols (symresolution_info& r)
-{
- condition->resolve_symbols (r);
- thenblock->resolve_symbols (r);
- elseblock->resolve_symbols (r);
-}
-
-
-void
-for_loop::resolve_symbols (symresolution_info& r)
-{
- init->resolve_symbols (r);
- cond->resolve_symbols (r);
- incr->resolve_symbols (r);
- block->resolve_symbols (r);
-}
-
-
-void
-expr_statement::resolve_symbols (symresolution_info& r)
-{
- value->resolve_symbols (r);
-}
-
-
-vardecl*
-symresolution_info::find_scalar (const string& name)
-{
- // search locals
- for (unsigned i=0; i<locals.size(); i++)
- if (locals[i]->name == name)
- return locals[i];
-
- // search builtins that become locals
- // XXX: need to invent a proper formalism for this
- if (name == "$pid" || name == "$tid")
- {
- vardecl_builtin* vb = new vardecl_builtin;
- vb->name = name;
- vb->type = pe_long;
-
- // XXX: need a better way to synthesize tokens
- token* t = new token;
- t->type = tok_identifier;
- t->content = name;
- t->location.file = "<builtin>";
- vb->tok = t;
-
- locals.push_back (vb);
- return vb;
- }
-
- // search function formal parameters (if any)
- if (current_function)
- {
- for (unsigned i=0; i<current_function->formal_args.size(); i++)
- if (current_function->formal_args [i]->name == name)
- return current_function->formal_args [i];
- }
-
- // search globals
- for (unsigned i=0; i<globals.size(); i++)
- if (globals[i]->name == name)
- return globals[i];
-
- return 0;
- // XXX: add checking for conflicting array or function
-}
-
-
-vardecl*
-symresolution_info::find_array (const string& name,
- const vector<expression*>& indexes)
-{
- // search locals
- for (unsigned i=0; i<locals.size(); i++)
- if (locals[i]->name == name)
- return locals[i];
-
- // search function formal parameters (if any)
- if (current_function)
- {
- for (unsigned i=0; i<current_function->formal_args.size(); i++)
- if (current_function->formal_args [i]->name == name)
- return current_function->formal_args [i];
- }
-
- // search globals
- for (unsigned i=0; i<globals.size(); i++)
- if (globals[i]->name == name)
- return globals[i];
-
- return 0;
- // XXX: add checking for conflicting scalar or function
-}
-
-
-functiondecl*
-symresolution_info::find_function (const string& name,
- const vector<expression*>& args)
-{
- for (unsigned j = 0; j < functions.size(); j++)
- {
- functiondecl* fd = functions[j];
- if (fd->name == name)
- return fd;
- }
-
- return 0;
- // XXX: add checking for conflicting variables
-}
-
-
-
-void
-symresolution_info::unresolved (const token* tok)
-{
- num_unresolved ++;
-
- cerr << "error: unresolved symbol for ";
- if (tok)
- cerr << *tok;
- else
- cerr << "a token";
- cerr << endl;
-}
-
-
-// ------------------------------------------------------------------------
-// semantic processing: type resolution
-
-
-void
-literal::resolve_types (typeresolution_info& r, exp_type t)
-{
- assert (type == pe_long || type == pe_string);
- if ((t == type) || (t == pe_unknown))
- return;
-
- r.mismatch (tok, type, t);
-}
-
-
-void
-binary_expression::resolve_types (typeresolution_info& r, exp_type t)
-{
- if (op == "<<<") // stats aggregation
- {
- left->resolve_types (r, pe_stats);
- right->resolve_types (r, pe_long);
- if (t == pe_stats || t == pe_string)
- r.mismatch (tok, t, pe_long);
- else if (type == pe_unknown)
- {
- type = pe_long;
- r.resolved (tok, type);
- }
- }
- else if (op == ".") // string concatenation
- {
- left->resolve_types (r, pe_string);
- right->resolve_types (r, pe_string);
- if (t == pe_long || t == pe_stats)
- r.mismatch (tok, t, pe_string);
- else if (type == pe_unknown)
- {
- type = pe_string;
- r.resolved (tok, type);
- }
- }
- else if (op == "=="
- || op == "in" // XXX: really a unary operator
- || false) // XXX: other comparison operators
- {
- left->resolve_types (r, pe_unknown);
- right->resolve_types (r, pe_unknown);
- if (t == pe_string || t == pe_stats)
- r.mismatch (tok, t, pe_long);
- else if (type == pe_unknown)
- {
- type = pe_long;
- r.resolved (tok, type);
- }
- }
- else // general arithmetic operators?
- {
- // propagate type downward
- exp_type subtype = t;
- if ((t == pe_unknown) && (type != pe_unknown))
- subtype = type;
- left->resolve_types (r, subtype);
- right->resolve_types (r, subtype);
-
- if ((t == pe_unknown) && (type != pe_unknown))
- ; // already resolved
- else if ((t != pe_unknown) && (type == pe_unknown))
- {
- type = t;
- r.resolved (tok, type);
- }
- else if ((t == pe_unknown) && (left->type != pe_unknown))
- {
- type = left->type;
- r.resolved (tok, type);
- }
- else if ((t == pe_unknown) && (right->type != pe_unknown))
- {
- type = right->type;
- r.resolved (tok, type);
- }
- else if (type != t)
- r.mismatch (tok, t, type);
- }
-}
-
-
-void
-unary_expression::resolve_types (typeresolution_info& r, exp_type t)
-{
- // all unary operators only work on numerics
-
- operand->resolve_types (r, pe_long);
-
- if (t == pe_unknown && type != pe_unknown)
- ; // already resolved
- else if (t == pe_string || t == pe_stats)
- r.mismatch (tok, t, pe_long);
- else if (type == pe_unknown)
- {
- type = pe_long;
- r.resolved (tok, type);
- }
-}
-
-
-void
-ternary_expression::resolve_types (typeresolution_info& r, exp_type t)
-{
- cond->resolve_types (r, pe_long);
- truevalue->resolve_types (r, t);
- falsevalue->resolve_types (r, t);
-}
-
-
-template <class Referrer, class Referent>
-void resolve_2types (Referrer* referrer, Referent* referent,
- typeresolution_info& r, exp_type t)
-{
- exp_type& rtype = referrer->type;
- const token* rtok = referrer->tok;
- exp_type& ttype = referent->type;
- const token* ttok = referent->tok;
-
- if (t != pe_unknown && rtype == t && rtype == ttype)
- ; // do nothing: all three types in agreement
- else if (t == pe_unknown && rtype != pe_unknown && rtype == ttype)
- ; // do nothing: two known types in agreement
- else if (rtype != pe_unknown && ttype != pe_unknown && rtype != ttype)
- r.mismatch (rtok, rtype, ttype);
- else if (rtype != pe_unknown && t != pe_unknown && rtype != t)
- r.mismatch (rtok, rtype, t);
- else if (ttype != pe_unknown && t != pe_unknown && ttype != t)
- r.mismatch (ttok, ttype, t);
- else if (rtype == pe_unknown && t != pe_unknown)
- {
- // propagate from upstream
- rtype = t;
- r.resolved (rtok, rtype);
- // catch rtype/ttype mismatch later
- }
- else if (rtype == pe_unknown && ttype != pe_unknown)
- {
- // propagate from referent
- rtype = ttype;
- r.resolved (rtok, rtype);
- // catch rtype/t mismatch later
- }
- else if (rtype != pe_unknown && ttype == pe_unknown)
- {
- // propagate to referent
- ttype = rtype;
- r.resolved (ttok, ttype);
- // catch rtype/t mismatch later
- }
- else
- r.unresolved (rtok);
-}
-
-
-void
-symbol::resolve_types (typeresolution_info& r, exp_type t)
-{
- assert (referent != 0);
-
- if (referent->index_types.size() > 0)
- r.unresolved (tok); // array
- else
- resolve_2types (this, referent, r, t);
-}
-
-
-void
-arrayindex::resolve_types (typeresolution_info& r, exp_type t)
-{
- assert (referent != 0);
-
- resolve_2types (this, referent, r, t);
-
- // now resolve the array indexes
- if (referent->index_types.size() == 0)
- {
- // designate referent as array
- referent->index_types.resize (indexes.size());
- for (unsigned i=0; i<indexes.size(); i++)
- referent->index_types[i] = pe_unknown;
- // NB: we "fall through" to for loop
- }
-
- if (indexes.size() != referent->index_types.size())
- r.unresolved (tok);
- else for (unsigned i=0; i<indexes.size(); i++)
- {
- expression* e = indexes[i];
- e->resolve_types (r, referent->index_types[i]);
- exp_type it = e->type;
- referent->index_types[i] = it;
-
- if (it == pe_string || it == pe_long)
- ; // do nothing
- else if (it == pe_stats)
- r.invalid (e->tok, it);
- else // pe_unknown
- r.unresolved (e->tok);
- }
-}
-
-
-void
-functioncall::resolve_types (typeresolution_info& r, exp_type t)
-{
- assert (referent != 0);
-
- resolve_2types (this, referent, r, t);
-
- if (type == pe_stats)
- r.mismatch (tok, pe_unknown, type);
-
- // XXX: but what about functions that return no value,
- // and are used only as an expression-statement for side effects?
-
- // now resolve the function parameters
- if (args.size() != referent->formal_args.size())
- r.unresolved (tok);
- else for (unsigned i=0; i<args.size(); i++)
- {
- expression* e = args[i];
- exp_type& ft = referent->formal_args[i]->type;
- const token* ftok = referent->formal_args[i]->tok;
- e->resolve_types (r, ft);
- exp_type at = e->type;
-
- if (((at == pe_string) || (at == pe_long)) && ft == pe_unknown)
- {
- // propagate to formal arg
- ft = at;
- r.resolved (referent->formal_args[i]->tok, ft);
- }
- if (at == pe_stats)
- r.invalid (e->tok, at);
- if (ft == pe_stats)
- r.invalid (ftok, ft);
- if (at != pe_unknown && ft != pe_unknown && ft != at)
- r.mismatch (e->tok, at, ft);
- if (at == pe_unknown)
- r.unresolved (e->tok);
- }
-}
-
-
-void
-block::resolve_types (typeresolution_info& r)
-{
- for (unsigned i=0; i<statements.size(); i++)
- statements[i]->resolve_types (r);
-}
-
-
-void
-if_statement::resolve_types (typeresolution_info& r)
-{
- condition->resolve_types (r, pe_long);
- thenblock->resolve_types (r);
- elseblock->resolve_types (r);
-}
-
-
-void
-for_loop::resolve_types (typeresolution_info& r)
-{
- init->resolve_types (r, pe_unknown);
- cond->resolve_types (r, pe_long);
- incr->resolve_types (r, pe_unknown);
- block->resolve_types (r);
-}
-
-
-void
-expr_statement::resolve_types (typeresolution_info& r)
-{
- value->resolve_types (r, pe_unknown);
-}
-
-
-void
-return_statement::resolve_types (typeresolution_info& r)
-{
- // This is like symbol::resolve_types, where the referent is
- // the return value of the function.
-
- // XXX: need control flow semantic checking; until then:
- if (r.current_function == 0)
- {
- r.unresolved (tok);
- return;
- }
-
- exp_type& type = r.current_function->type;
- value->resolve_types (r, type);
-
- if (type != pe_unknown && value->type != pe_unknown
- && type != value->type)
- r.mismatch (r.current_function->tok, type, value->type);
- if (type == pe_unknown &&
- (value->type == pe_long || value->type == pe_string))
- {
- // propagate non-statistics from value
- type = value->type;
- r.resolved (r.current_function->tok, value->type);
- }
- if (value->type == pe_stats)
- r.invalid (value->tok, value->type);
-}
-
-
-void
-typeresolution_info::unresolved (const token* tok)
-{
- num_still_unresolved ++;
-
- if (assert_resolvability)
- {
- cerr << "error: unresolved type for ";
- if (tok)
- cerr << *tok;
- else
- cerr << "a token";
- cerr << endl;
- }
-}
-
-
-void
-typeresolution_info::invalid (const token* tok, exp_type pe)
-{
- num_still_unresolved ++;
-
- if (assert_resolvability)
- {
- cerr << "error: invalid type " << pe << " for ";
- if (tok)
- cerr << *tok;
- else
- cerr << "a token";
- cerr << endl;
- }
-}
-
-
-void
-typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2)
-{
- num_still_unresolved ++;
-
- if (assert_resolvability)
- {
- cerr << "error: type mismatch for ";
- if (tok)
- cerr << *tok;
- else
- cerr << "a token";
- cerr << ": " << t1 << " vs. " << t2 << endl;
- }
-}
-
-
-void
-typeresolution_info::resolved (const token* tok, exp_type t)
-{
- num_newly_resolved ++;
- // cerr << "resolved " << *tok << " type " << t << endl;
-}
-
-
-// ------------------------------------------------------------------------
-// semantic processing: lvalue checking: XXX: unneeded?
-
-
-bool
-assignment::is_lvalue ()
-{
- return left->is_lvalue ();
-}
-
-
-// ------------------------------------------------------------------------
-// unparser
-
-
-translator_output::translator_output (ostream& f):
- o (f), tablevel (0)
-{
-}
-
-
-ostream&
-translator_output::newline (int indent)
-{
- assert (indent > 0 || tablevel >= (unsigned)-indent);
- tablevel += indent;
- o << endl;
- for (unsigned i=0; i<tablevel; i++)
- o << " ";
- return o;
-}
-
-
-void
-translator_output::indent (int indent)
-{
- assert (indent > 0 || tablevel >= (unsigned)-indent);
- tablevel += indent;
-}
-
-
-ostream&
-translator_output::line ()
-{
- return o;
-}
-
-
// ------------------------------------------------------------------------
// visitors
@@ -1212,7 +545,8 @@ traversing_visitor::visit_if_statement (if_statement* s)
{
s->condition->visit (this);
s->thenblock->visit (this);
- s->elseblock->visit (this);
+ if (s->elseblock)
+ s->elseblock->visit (this);
}
void