summaryrefslogtreecommitdiffstats
path: root/staptree.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'staptree.cxx')
-rw-r--r--staptree.cxx601
1 files changed, 596 insertions, 5 deletions
diff --git a/staptree.cxx b/staptree.cxx
index 94fd540d..6ea1fc70 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -11,6 +11,7 @@
#include "parse.h"
#include <iostream>
#include <typeinfo>
+#include <sstream>
#include <cassert>
using namespace std;
@@ -45,7 +46,7 @@ symbol::symbol ():
arrayindex::arrayindex ():
- referent (0)
+ base (0)
{
}
@@ -316,6 +317,377 @@ void functioncall::print (ostream& o) const
}
+string
+print_format::components_to_string(vector<format_component> const & components)
+{
+ ostringstream oss;
+
+ for (vector<format_component>::const_iterator i = components.begin();
+ i != components.end(); ++i)
+ {
+
+ assert (i->type != conv_unspecified);
+
+ if (i->type == conv_literal)
+ {
+ assert(!i->literal_string.empty());
+ for (string::const_iterator j = i->literal_string.begin();
+ j != i->literal_string.end(); ++j)
+ {
+ if (*j == '%')
+ oss << '%';
+ oss << *j;
+ }
+ }
+ else
+ {
+ oss << '%';
+
+ if (i->flags & static_cast<unsigned long>(fmt_flag_zeropad))
+ oss << '0';
+
+ if (i->flags & static_cast<unsigned long>(fmt_flag_plus))
+ oss << '+';
+
+ if (i->flags & static_cast<unsigned long>(fmt_flag_space))
+ oss << ' ';
+
+ if (i->flags & static_cast<unsigned long>(fmt_flag_left))
+ oss << '-';
+
+ if (i->flags & static_cast<unsigned long>(fmt_flag_special))
+ oss << '#';
+
+ if (i->width > 0)
+ oss << i->width;
+
+ if (i->precision > 0)
+ oss << '.' << i->precision;
+
+ switch (i->type)
+ {
+ case conv_signed_decimal:
+ oss << "lld";
+ break;
+
+ case conv_unsigned_decimal:
+ oss << "llu";
+ break;
+
+ case conv_unsigned_octal:
+ oss << "llo";
+ break;
+
+ case conv_unsigned_uppercase_hex:
+ oss << "llX";
+ break;
+
+ case conv_unsigned_lowercase_hex:
+ oss << "llx";
+ break;
+
+ case conv_string:
+ oss << 's';
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ return oss.str ();
+}
+
+vector<print_format::format_component>
+print_format::string_to_components(string const & str)
+{
+ format_component curr;
+ vector<format_component> res;
+
+ enum
+ {
+ parsing_plain_data,
+ parsing_flags,
+ parsing_width,
+ parsing_precision,
+ parsing_conversion_specifier
+ }
+ state = parsing_plain_data;
+
+ curr.clear();
+
+ string::const_iterator i = str.begin();
+
+ while (i != str.end())
+ {
+ switch (state)
+ {
+ case parsing_plain_data:
+
+ if (*i != '%')
+ {
+ assert (curr.type == conv_unspecified || curr.type == conv_literal);
+ curr.type = conv_literal;
+ curr.literal_string += *i;
+ }
+ else if (i+1 == str.end() || *(i+1) == '%')
+ {
+ assert(*i == '%');
+ // *i == '%' and *(i+1) == '%'; append only one '%' to the literal string
+ assert (curr.type == conv_unspecified || curr.type == conv_literal);
+ curr.type = conv_literal;
+ curr.literal_string += '%';
+ }
+ else
+ {
+ assert(*i == '%');
+ state = parsing_flags;
+ if (curr.type != conv_unspecified)
+ {
+ assert (curr.type == conv_literal);
+ res.push_back(curr);
+ curr.clear();
+ }
+ }
+ ++i;
+ break;
+
+ case parsing_flags:
+ switch (*i)
+ {
+ case '0':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_zeropad);
+ ++i;
+ break;
+
+ case '+':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_plus);
+ ++i;
+ break;
+
+ case '-':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_left);
+ ++i;
+ break;
+
+ case ' ':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_space);
+ ++i;
+ break;
+
+ case '#':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_special);
+ ++i;
+ break;
+
+ default:
+ state = parsing_width;
+ break;
+ }
+ break;
+
+ case parsing_width:
+ while (isdigit(*i))
+ {
+ curr.width *= 10;
+ curr.width += (*i - '0');
+ ++i;
+ }
+ state = parsing_precision;
+ break;
+
+ case parsing_precision:
+ if (*i == '.')
+ {
+ ++i;
+ while (isdigit(*i))
+ {
+ curr.precision *= 10;
+ curr.precision += (*i - '0');
+ ++i;
+ }
+ }
+ state = parsing_conversion_specifier;
+ break;
+
+ case parsing_conversion_specifier:
+ switch (*i)
+ {
+
+ default:
+ if (curr.type == conv_unspecified)
+ throw semantic_error("no conversion specifier provided");
+
+ res.push_back(curr);
+ curr.clear();
+ state = parsing_plain_data;
+ break;
+
+ // Valid conversion types
+ case 's':
+ if (curr.type != conv_unspecified)
+ throw semantic_error("multiple conversion types supplied");
+ curr.type = conv_string;
+ ++i;
+ break;
+
+ case 'd':
+ case 'i':
+ if (curr.type != conv_unspecified)
+ throw semantic_error("multiple conversion types supplied");
+ curr.type = conv_signed_decimal;
+ ++i;
+ break;
+
+ case 'o':
+ if (curr.type != conv_unspecified)
+ throw semantic_error("multiple conversion types supplied");
+ curr.type = conv_unsigned_octal;
+ ++i;
+ break;
+
+ case 'u':
+ if (curr.type != conv_unspecified)
+ throw semantic_error("multiple conversion types supplied");
+ curr.type = conv_unsigned_decimal;
+ ++i;
+ break;
+
+ case 'X':
+ if (curr.type != conv_unspecified)
+ throw semantic_error("multiple conversion types supplied");
+ curr.type = conv_unsigned_uppercase_hex;
+ ++i;
+
+ case 'x':
+ if (curr.type != conv_unspecified)
+ throw semantic_error("multiple conversion types supplied");
+ curr.type = conv_unsigned_lowercase_hex;
+ ++i;
+ break;
+
+ // We prohibit users passing any funny stuff through which might
+ // make linux's printf function do naughty things.
+ case 'p':
+ case 'n':
+ case 'c':
+ case 'q':
+ case 'j':
+ case 't':
+
+ case ',':
+ case '.':
+ case '*':
+
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ case 'h':
+ case 'H':
+ case 'I':
+ case 'l':
+ case 'L':
+ case 'z':
+ case 'Z':
+ string err("prohibited conversion character '");
+ err += *i;
+ err += '"';
+ throw parse_error(err);
+ }
+ break;
+ }
+ }
+
+ // Flush final component
+ if (curr.type != conv_unspecified)
+ res.push_back(curr);
+
+ return res;
+}
+
+
+void print_format::print (ostream& o) const
+{
+ string name = (string(print_to_stream ? "" : "s")
+ + string("print")
+ + string(print_with_format ? "f" : ""));
+ o << name << "(";
+ if (print_with_format)
+ {
+ o << '"' << components_to_string(components) << "\", ";
+ }
+ for (vector<expression*>::const_iterator i = args.begin();
+ i != args.end(); ++i)
+ {
+ if (i != args.begin())
+ o << ", ";
+ (*i)->print(o);
+ }
+ o << ")";
+}
+
+void stat_op::print (ostream& o) const
+{
+ o << '@';
+ switch (ctype)
+ {
+ case sc_average:
+ o << "avg(";
+ break;
+
+ case sc_count:
+ o << "count(";
+ break;
+
+ case sc_sum:
+ o << "sum(";
+ break;
+
+ case sc_min:
+ o << "min(";
+ break;
+
+ case sc_max:
+ o << "max(";
+ break;
+ }
+ stat->print(o);
+ o << ")";
+}
+
+void
+hist_op::print (ostream& o) const
+{
+ o << '@';
+ switch (htype)
+ {
+ case hist_linear:
+ assert(params.size() == 3);
+ o << "hist_linear(";
+ stat->print(o);
+ for (size_t i = 0; i < params.size(); ++i)
+ {
+ o << ", " << params[i];
+ }
+ o << ")";
+ break;
+
+ case hist_log:
+ assert(params.size() == 1);
+ o << "hist_log(";
+ stat->print(o);
+ for (size_t i = 0; i < params.size(); ++i)
+ {
+ o << ", " << params[i];
+ }
+ o << ")";
+ break;
+ }
+}
+
ostream& operator << (ostream& o, const statement& k)
{
k.print (o);
@@ -706,6 +1078,147 @@ functioncall::visit (visitor* u)
u->visit_functioncall (this);
}
+void
+print_format::visit (visitor *u)
+{
+ u->visit_print_format (this);
+}
+
+void
+stat_op::visit (visitor *u)
+{
+ u->visit_stat_op (this);
+}
+
+void
+hist_op::visit (visitor *u)
+{
+ u->visit_hist_op (this);
+}
+
+void
+indexable::print_indexable (std::ostream& o) const
+{
+ const symbol *sym;
+ const hist_op *hist;
+ classify_const_indexable(this, sym, hist);
+ if (sym)
+ sym->print (o);
+ else
+ {
+ assert (hist);
+ hist->print (o);
+ }
+}
+
+void
+indexable::visit_indexable (visitor* u)
+{
+ symbol *sym;
+ hist_op *hist;
+ classify_indexable(this, sym, hist);
+ if (sym)
+ sym->visit (u);
+ else
+ {
+ assert (hist);
+ hist->visit (u);
+ }
+}
+
+
+bool
+indexable::is_symbol(symbol *& sym_out)
+{
+ sym_out = NULL;
+ return false;
+}
+
+bool
+indexable::is_hist_op(hist_op *& hist_out)
+{
+ hist_out = NULL;
+ return false;
+}
+
+bool
+indexable::is_const_symbol(const symbol *& sym_out) const
+{
+ sym_out = NULL;
+ return false;
+}
+
+bool
+indexable::is_const_hist_op(const hist_op *& hist_out) const
+{
+ hist_out = NULL;
+ return false;
+}
+
+bool
+symbol::is_symbol(symbol *& sym_out)
+{
+ sym_out = this;
+ return true;
+}
+
+bool
+symbol::is_const_symbol(const symbol *& sym_out) const
+{
+ sym_out = this;
+ return true;
+}
+
+const token *
+symbol::get_tok() const
+{
+ return tok;
+}
+
+bool
+hist_op::is_hist_op(hist_op *& hist_out)
+{
+ hist_out = this;
+ return true;
+}
+
+bool
+hist_op::is_const_hist_op(const hist_op *& hist_out) const
+{
+ hist_out = this;
+ return true;
+}
+
+const token *
+hist_op::get_tok() const
+{
+ return tok;
+}
+
+void
+classify_indexable(indexable* ix,
+ symbol *& array_out,
+ hist_op *& hist_out)
+{
+ array_out = NULL;
+ hist_out = NULL;
+ if (!(ix->is_symbol (array_out) || ix->is_hist_op (hist_out)))
+ throw semantic_error("Expecting symbol or histogram operator", ix->get_tok());
+ if (ix && !(hist_out || array_out))
+ throw semantic_error("Failed to classify indexable", ix->get_tok());
+}
+
+void
+classify_const_indexable(const indexable* ix,
+ const symbol *& array_out,
+ const hist_op *& hist_out)
+{
+ array_out = NULL;
+ hist_out = NULL;
+ if (!(ix->is_const_symbol(array_out) || ix->is_const_hist_op(hist_out)))
+ throw semantic_error("Expecting symbol or histogram operator", ix->get_tok());
+}
+
// ------------------------------------------------------------------------
bool
@@ -921,6 +1434,25 @@ traversing_visitor::visit_functioncall (functioncall* e)
e->args[i]->visit (this);
}
+void
+traversing_visitor::visit_print_format (print_format* e)
+{
+ for (unsigned i=0; i<e->args.size(); i++)
+ e->args[i]->visit (this);
+}
+
+void
+traversing_visitor::visit_stat_op (stat_op* e)
+{
+ e->stat->visit (this);
+}
+
+void
+traversing_visitor::visit_hist_op (hist_op* e)
+{
+ e->stat->visit (this);
+}
+
// ------------------------------------------------------------------------
@@ -1110,6 +1642,24 @@ throwing_visitor::visit_functioncall (functioncall* e)
throwone (e->tok);
}
+void
+throwing_visitor::visit_print_format (print_format* e)
+{
+ throwone (e->tok);
+}
+
+void
+throwing_visitor::visit_stat_op (stat_op* e)
+{
+ throwone (e->tok);
+}
+
+void
+throwing_visitor::visit_hist_op (hist_op* e)
+{
+ throwone (e->tok);
+}
+
// ------------------------------------------------------------------------
@@ -1188,10 +1738,12 @@ deep_copy_visitor::visit_foreach_loop (foreach_loop* s)
require <symbol*> (this, &sym, s->indexes[i]);
n->indexes.push_back(sym);
}
- n->base = s->base;
- n->base_referent = NULL;
+
+ require <indexable*> (this, &(n->base), s->base);
+
n->sort_direction = s->sort_direction;
n->sort_column = s->sort_column;
+
require <statement*> (this, &(n->block), s->block);
provide <foreach_loop*> (this, n);
}
@@ -1396,8 +1948,9 @@ deep_copy_visitor::visit_arrayindex (arrayindex* e)
{
arrayindex* n = new arrayindex;
n->tok = e->tok;
- n->base = e->base;
- n->referent = NULL;
+
+ require <indexable*> (this, &(n->base), e->base);
+
for (unsigned i = 0; i < e->indexes.size(); ++i)
{
expression* ne;
@@ -1423,6 +1976,44 @@ deep_copy_visitor::visit_functioncall (functioncall* e)
provide <functioncall*> (this, n);
}
+void
+deep_copy_visitor::visit_print_format (print_format* e)
+{
+ print_format* n = new print_format;
+ n->tok = e->tok;
+ n->print_with_format = e->print_with_format;
+ n->print_to_stream = e->print_to_stream;
+ n->components = e->components;
+ for (unsigned i = 0; i < e->args.size(); ++i)
+ {
+ expression* na;
+ require <expression*> (this, &na, e->args[i]);
+ n->args.push_back(na);
+ }
+ provide <print_format*> (this, n);
+}
+
+void
+deep_copy_visitor::visit_stat_op (stat_op* e)
+{
+ stat_op* n = new stat_op;
+ n->tok = e->tok;
+ n->ctype = e->ctype;
+ require <expression*> (this, &(n->stat), e->stat);
+ provide <stat_op*> (this, n);
+}
+
+void
+deep_copy_visitor::visit_hist_op (hist_op* e)
+{
+ hist_op* n = new hist_op;
+ n->tok = e->tok;
+ n->htype = e->htype;
+ n->params = e->params;
+ require <expression*> (this, &(n->stat), e->stat);
+ provide <hist_op*> (this, n);
+}
+
block*
deep_copy_visitor::deep_copy (block* b)
{