diff options
author | graydon <graydon> | 2005-11-14 04:39:47 +0000 |
---|---|---|
committer | graydon <graydon> | 2005-11-14 04:39:47 +0000 |
commit | d02548c0925a02dd0af64a9dc13cce9e84d87b4f (patch) | |
tree | 0bdccf0887cdc1ff1b697d6b790df11cac7fb839 /parse.cxx | |
parent | a14d81b2a2cce703422e596fd2f3d6ea699e93ce (diff) | |
download | systemtap-steved-d02548c0925a02dd0af64a9dc13cce9e84d87b4f.tar.gz systemtap-steved-d02548c0925a02dd0af64a9dc13cce9e84d87b4f.tar.xz systemtap-steved-d02548c0925a02dd0af64a9dc13cce9e84d87b4f.zip |
2005-11-13 Graydon Hoare <graydon@redhat.com>
* staptree.h (struct indexable): New struct.
(classify_indexable): New function.
(classify_const_indexable): New function.
(struct symbol): Implement indexable.
(struct arrayindex): Take indexable as base.
(struct foreach_loop): Take indexable as base.
(struct print_format): New struct.
(enum stat_component_type): New enum.
(struct stat_op): New struct.
(enum historgram_type): New enum.
(struct hist_op): New struct.
(struct visitor)
(struct traversing_visitor)
(struct throwing_visitor)
(struct deep_copy_visitor): Add new visitor methods.
(require): Specialize for indexable*.
* staptree.cxx (print_format::*)
(stat_op::*)
(hist_op::*)
(indexable::*)
(traversing_visitor::*)
(throwing_visitor::*)
(deep_copy_visitor::*)
(classify_indexable)
(classify_const_indexable): Implement
(deep_copy_visitor::*): Update to use indexables.
* parse.h (parser::parse_indexable): New method.
(parser::parse_hist_op_or_bare_name): New method.
* parse.cxx (lexer::scan): Accept @ in identifiers.
(parser::parse_array_in)
(parser::parse_foreach_loop): Call parse_indexable.
(parser::parse_hist_op_or_bare_name): Implement.
(parser::parse_indexable): Implement.
(parser::parse_symbol): Accept printf, stat_ops, hist_ops.
* elaborate.h (struct typeresolution_info): Add methods for
visiting print_format, stat_op, hist_op.
* elaborate.cxx (symbol_fetcher): New class.
(get_symbol_within_expression): New function.
(get_symbol_within_indexable): New function.
(mutated_var_collector): Replace mutated_map_collector.
(no_var_mutation_during_iteration_check): Replace
no_map_mutation_during_iteration_check.
(semantic_pass_vars): Replace semantic_pass_maps.
(semantic_pass): Update call accordingly.
(symresolution_info::*) Add new visitors, teach about indexables
(typeresolution_info::*) Likewise.
* translate.cxx
(c_unparser::getiter): Take symbol, not foreach_loop.
(c_unparser::*) Add new visitors, teach about indexables.
(c_tmpcounter::*)
(delete_statement_operand_visitor::visit_arrayindex)
(c_tmpcounter_assignment::*)
(c_unparser_assignment::*): Likewise.
(hist_op_downcaster): New struct.
(expression_is_hist_op): New function.
* testsuite/buildok/printf.stp: New test for print_format.
Diffstat (limited to 'parse.cxx')
-rw-r--r-- | parse.cxx | 303 |
1 files changed, 224 insertions, 79 deletions
@@ -431,7 +431,7 @@ lexer::scan () if (isspace (c)) goto skip; - else if (isalpha (c) || c == '$' || c == '_') + else if (isalpha (c) || c == '$' || c == '@' || c == '_') { n->type = tok_identifier; n->content = (char) c; @@ -1407,11 +1407,8 @@ parser::parse_foreach_loop () t = next (); if (! (t->type == tok_identifier && t->content == "in")) throw parse_error ("expected 'in'"); - - t = next (); - if (t->type != tok_identifier) - throw parse_error ("expected identifier"); - s->base = t->content; + + s->base = parse_indexable(); t = peek (); if (t && t->type == tok_operator && @@ -1662,13 +1659,8 @@ parser::parse_array_in () arrayindex* a = new arrayindex; a->indexes = indexes; - - t = next (); - if (t->type != tok_identifier) - throw parse_error ("expected identifier"); - a->tok = t; - a->base = t->content; - + a->base = parse_indexable(); + a->tok = a->base->get_tok(); e->operand = a; return e; } @@ -1880,50 +1872,231 @@ parser::parse_value () } -// var, var[index], func(parms), thread->var, process->var +const token * +parser::parse_hist_op_or_bare_name (hist_op *&hop, string &name) +{ + hop = NULL; + const token* t = expect_ident (name); + if (name == "@hist_linear" || name == "@hist_log") + { + hop = new hist_op; + if (name == "@hist_linear") + hop->htype = hist_linear; + else if (name == "@hist_log") + hop->htype = hist_log; + hop->tok = t; + expect_op("("); + hop->stat = parse_expression (); + int64_t tnum; + if (hop->htype == hist_linear) + { + for (size_t i = 0; i < 3; ++i) + { + expect_op (","); + expect_number (tnum); + hop->params.push_back (tnum); + } + } + else + { + assert(hop->htype == hist_log); + if (peek_op (",")) + { + expect_op (","); + expect_number (tnum); + hop->params.push_back (tnum); + } + else + { + // FIXME (magic value): Logarithmic histograms get 64 + // buckets by default. + hop->params.push_back (64); + } + } + expect_op(")"); + } + return t; +} + + +indexable* +parser::parse_indexable () +{ + hist_op *hop = NULL; + string name; + const token *tok = parse_hist_op_or_bare_name(hop, name); + if (hop) + return hop; + else + { + symbol* sym = new symbol; + sym->name = name; + sym->tok = tok; + return sym; + } +} + + +// var, indexable[index], func(parms), printf("...", ...), $var, $var->member, @stat_op(stat) expression* parser::parse_symbol () { + hist_op *hop = NULL; + symbol *sym = NULL; string name; - const token* t = expect_ident (name); - const token* t2 = t; - - if (name.size() > 0 && name[0] == '$') + const token *t = parse_hist_op_or_bare_name(hop, name); + + if (!hop) { - // target_symbol time - target_symbol *tsym = new target_symbol; - tsym->tok = t; - tsym->base_name = name; - while (true) + // If we didn't get a hist_op, then we did get an identifier. We can + // now scrutinize this identifier for the various magic forms of identifier + // (printf, @stat_op, and $var...) + + if (name.size() > 0 && name[0] == '@') { - string c; - if (peek_op ("->")) - { - next(); - expect_ident (c); - tsym->components.push_back - (make_pair (target_symbol::comp_struct_member, c)); + stat_op *sop = new stat_op; + if (name == "@avg") + sop->ctype = sc_average; + else if (name == "@count") + sop->ctype = sc_count; + else if (name == "@sum") + sop->ctype = sc_sum; + else if (name == "@min") + sop->ctype = sc_min; + else if (name == "@max") + sop->ctype = sc_max; + else + throw parse_error("unknown statistic operator " + name); + expect_op("("); + sop->tok = t; + sop->stat = parse_expression (); + expect_op(")"); + return sop; + } + + else if (name.size() > 0 && (name == "print" + || name == "sprint" + || name == "printf" + || name == "sprintf")) + { + print_format *fmt = new print_format; + fmt->tok = t; + fmt->print_with_format = (name[name.size() - 1] == 'f'); + fmt->print_to_stream = (name[0] == 'p'); + expect_op("("); + if (fmt->print_with_format) + { + // Consume and convert a format string, and any subsequent + // arguments. Agreement between the format string and the + // arguments is postponed to the typechecking phase. + string tmp; + expect_unknown (tok_string, tmp); + fmt->components = print_format::string_to_components (tmp); + while (!peek_op (")")) + { + expect_op(","); + expression *e = parse_expression (); + fmt->args.push_back(e); + } } - 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; + { + // If we are not printing with a format string, we permit + // exactly one argument (of any type). + expression *e = parse_expression (); + fmt->args.push_back(e); + } + expect_op(")"); + return fmt; + } + + else if (name.size() > 0 && name[0] == '$') + { + // target_symbol time + target_symbol *tsym = new target_symbol; + tsym->tok = t; + 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_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 (peek_op ("(")) // function call + { + next (); + struct functioncall* f = new functioncall; + f->tok = t; + f->function = name; + // Allow empty actual parameter list + if (peek_op (")")) + { + next (); + return f; + } + while (1) + { + f->args.push_back (parse_expression ()); + if (peek_op (")")) + { + next(); + break; + } + else if (peek_op (",")) + { + next(); + continue; + } + else + throw parse_error ("expected ',' or ')'"); + } + return f; + } + + else + { + sym = new symbol; + sym->name = name; + sym->tok = t; } - return tsym; } + // By now, either we had a hist_op in the first place, or else + // we had a plain word and it was converted to a symbol. + + assert (hop || sym); + + // All that remains is to check for array indexing + if (peek_op ("[")) // array { next (); struct arrayindex* ai = new arrayindex; - ai->tok = t2; - ai->base = name; + ai->tok = t; + + if (hop) + ai->base = hop; + else + ai->base = sym; + while (1) { ai->indexes.push_back (parse_expression ()); @@ -1942,42 +2115,14 @@ parser::parse_symbol () } return ai; } - else if (peek_op ("(")) // function call - { - next (); - struct functioncall* f = new functioncall; - f->tok = t2; - f->function = name; - // Allow empty actual parameter list - if (peek_op (")")) - { - next (); - return f; - } - while (1) - { - f->args.push_back (parse_expression ()); - if (peek_op (")")) - { - next(); - break; - } - else if (peek_op (",")) - { - next(); - continue; - } - else - throw parse_error ("expected ',' or ')'"); - } - return f; - } - else - { - symbol* sym = new symbol; - sym->name = name; - sym->tok = t2; - return sym; - } + + // If we got to here, we *should* have a symbol; if we have + // a hist_op on its own, it doesn't count as an expression, + // so we throw a parse error. + + if (hop) + throw parse_error("base histogram operator where expression expected", t); + + return sym; } |