diff options
author | fche <fche> | 2005-06-02 19:43:55 +0000 |
---|---|---|
committer | fche <fche> | 2005-06-02 19:43:55 +0000 |
commit | 69c68955b910a9f284fa25b9ebb30eff5c040e0b (patch) | |
tree | 3fa502458891d0b54150d678368f7a2dee18fa0f | |
parent | f37b5c92191dd81aad57ade2899a4999099a3e35 (diff) | |
download | systemtap-steved-69c68955b910a9f284fa25b9ebb30eff5c040e0b.tar.gz systemtap-steved-69c68955b910a9f284fa25b9ebb30eff5c040e0b.tar.xz systemtap-steved-69c68955b910a9f284fa25b9ebb30eff5c040e0b.zip |
2005-06-02 Frank Ch. Eigler <fche@redhat.com>
Parse foreach construct. Added fuller copyright notices throughout.
* staptree.h (foreach_loop): New tree node type.
* staptree.cxx: Print it, visit it, love it, leave it.
* parse.cxx: Parse it.
(parse_stmt_block): Don't require ";" separators between statements.
(parse_array_in): Use [] as index group operator instead of ().
* elaborate.cxx (visit_foreach_loop): New code.
* translate.cxx: Slightly tighten errorcount/actioncount handling.
* main.cxx: Accept "-" as script file name standing for stdin.
(visit_arrayindex): Switch to simpler set_arity call.
* configure.ac: Generate DATE macro.
* Makefile.in, configure, config.in: Regenerated.
* testsuite/*: New/updated tests for syntax changes, foreach ().
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | Makefile.in | 1 | ||||
-rw-r--r-- | config.in | 3 | ||||
-rwxr-xr-x | configure | 11 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | elaborate.cxx | 83 | ||||
-rw-r--r-- | elaborate.h | 11 | ||||
-rw-r--r-- | main.cxx | 18 | ||||
-rw-r--r-- | parse.cxx | 149 | ||||
-rw-r--r-- | parse.h | 12 | ||||
-rw-r--r-- | staptree.cxx | 53 | ||||
-rw-r--r-- | staptree.h | 30 | ||||
-rwxr-xr-x | testsuite/parseko/eight.stp | 4 | ||||
-rwxr-xr-x | testsuite/parseko/seven.stp | 6 | ||||
-rwxr-xr-x | testsuite/parseko/three.stp | 5 | ||||
-rwxr-xr-x | testsuite/parseok/eight.stp | 4 | ||||
-rwxr-xr-x | testsuite/parseok/nine.stp | 15 | ||||
-rwxr-xr-x | testsuite/semko/eleven.stp | 15 | ||||
-rwxr-xr-x | testsuite/semok/eleven.stp | 38 | ||||
-rwxr-xr-x | testsuite/semok/ten.stp | 19 | ||||
-rw-r--r-- | translate.cxx | 56 | ||||
-rw-r--r-- | translate.h | 9 |
22 files changed, 455 insertions, 108 deletions
@@ -1,3 +1,19 @@ +2005-06-02 Frank Ch. Eigler <fche@redhat.com> + + Parse foreach construct. Added fuller copyright notices throughout. + * staptree.h (foreach_loop): New tree node type. + * staptree.cxx: Print it, visit it, love it, leave it. + * parse.cxx: Parse it. + (parse_stmt_block): Don't require ";" separators between statements. + (parse_array_in): Use [] as index group operator instead of (). + * elaborate.cxx (visit_foreach_loop): New code. + * translate.cxx: Slightly tighten errorcount/actioncount handling. + * main.cxx: Accept "-" as script file name standing for stdin. + (visit_arrayindex): Switch to simpler set_arity call. + * configure.ac: Generate DATE macro. + * Makefile.in, configure, config.in: Regenerated. + * testsuite/*: New/updated tests for syntax changes, foreach (). + 2005-05-30 Frank Ch. Eigler <fche@redhat.com> More fully parse & elaborate "expr in array" construct. diff --git a/Makefile.in b/Makefile.in index efaaa1b5..b738a971 100644 --- a/Makefile.in +++ b/Makefile.in @@ -103,6 +103,7 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ +DATE = @DATE@ DEFS = -DDEFPATH=$(DEFPATH) -DHAVE_CONFIG_H DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ @@ -1,5 +1,8 @@ /* config.in. Generated from configure.ac by autoheader. */ +/* Configuration/build date */ +#undef DATE + /* Define to 1 if you have the <elfutils/libdw.h> header file. */ #undef HAVE_ELFUTILS_LIBDW_H @@ -310,7 +310,7 @@ ac_includes_default="\ # include <unistd.h> #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CPP EGREP U ANSI2KNR RANLIB ac_ct_RANLIB CXXCPP LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CPP EGREP U ANSI2KNR RANLIB ac_ct_RANLIB CXXCPP DATE LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -5609,6 +5609,14 @@ _ACEOF fi +date=`date +%Y-%m-%d` + +cat >>confdefs.h <<_ACEOF +#define DATE "$date" +_ACEOF + + + ac_config_headers="$ac_config_headers config.h:config.in" ac_config_files="$ac_config_files Makefile" @@ -6326,6 +6334,7 @@ s,@ANSI2KNR@,$ANSI2KNR,;t t s,@RANLIB@,$RANLIB,;t t s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t s,@CXXCPP@,$CXXCPP,;t t +s,@DATE@,$DATE,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF diff --git a/configure.ac b/configure.ac index 2c609720..31b5f745 100644 --- a/configure.ac +++ b/configure.ac @@ -27,6 +27,11 @@ AC_CHECK_HEADERS([libelf.h elfutils/libdw.h]) AC_CHECK_LIB(dw, dwarf_begin) AC_CHECK_LIB(elf, elf_begin) +dnl Plop in the build (configure) date +date=`date +%Y-%m-%d` +AC_DEFINE_UNQUOTED(DATE, "$date", [Configuration/build date]) +AC_SUBST(DATE) + AC_CONFIG_HEADERS([config.h:config.in]) AC_CONFIG_FILES(Makefile) AC_OUTPUT diff --git a/elaborate.cxx b/elaborate.cxx index 02c81a2d..7a6c2359 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1,7 +1,10 @@ // elaboration functions -// Copyright 2005 Red Hat Inc. -// GPL - +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. #include "config.h" #include "elaborate.h" @@ -201,6 +204,25 @@ symresolution_info::visit_block (block* e) void +symresolution_info::visit_foreach_loop (foreach_loop* e) +{ + for (unsigned i=0; i<e->indexes.size(); i++) + e->indexes[i]->visit (this); + + if (e->base_referent) + return; + + vardecl* d = find_array (e->base, e->indexes.size ()); + if (d) + e->base_referent = d; + else + throw semantic_error ("unresolved global array " + e->base, e->tok); + + e->block->visit (this); +} + + +void symresolution_info::visit_symbol (symbol* e) { if (e->referent) @@ -773,14 +795,10 @@ typeresolution_info::visit_arrayindex (arrayindex* e) resolve_2types (e, e->referent, this, t); // now resolve the array indexes - if (e->referent->index_types.size() == 0) - { - // redesignate referent as array - e->referent->index_types.resize (e->indexes.size()); - for (unsigned i=0; i<e->indexes.size(); i++) - e->referent->index_types[i] = pe_unknown; - // NB: we "fall through" to for loop - } + + // if (e->referent->index_types.size() == 0) + // // redesignate referent as array + // e->referent->set_arity (e->indexes.size ()); if (e->indexes.size() != e->referent->index_types.size()) unresolved (e->tok); // symbol resolution should prevent this @@ -904,6 +922,49 @@ typeresolution_info::visit_for_loop (for_loop* e) void +typeresolution_info::visit_foreach_loop (foreach_loop* e) +{ + // See also visit_arrayindex. + // This is different in that, being a statement, we can't assign + // a type to the outer array, only propagate to/from the indexes + + // if (e->referent->index_types.size() == 0) + // // redesignate referent as array + // e->referent->set_arity (e->indexes.size ()); + + if (e->indexes.size() != e->base_referent->index_types.size()) + unresolved (e->tok); // symbol resolution should prevent this + else for (unsigned i=0; i<e->indexes.size(); i++) + { + expression* ee = e->indexes[i]; + exp_type& ft = e->base_referent->index_types [i]; + t = ft; + ee->visit (this); + exp_type at = ee->type; + + if ((at == pe_string || at == pe_long) && ft == pe_unknown) + { + // propagate to formal type + ft = at; + resolved (e->base_referent->tok, ft); + // uses array decl as there is no token for "formal type" + } + if (at == pe_stats) + invalid (ee->tok, at); + if (ft == pe_stats) + invalid (ee->tok, ft); + if (at != pe_unknown && ft != pe_unknown && ft != at) + mismatch (e->tok, at, ft); + if (at == pe_unknown) + unresolved (ee->tok); + } + + t = pe_unknown; + e->block->visit (this); +} + + +void typeresolution_info::visit_null_statement (null_statement* e) { } diff --git a/elaborate.h b/elaborate.h index 8375833a..f4bc1b68 100644 --- a/elaborate.h +++ b/elaborate.h @@ -1,7 +1,10 @@ // -*- C++ -*- -// Copyright 2005 Red Hat Inc. -// GPL - +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. #ifndef ELABORATE_H #define ELABORATE_H @@ -36,6 +39,7 @@ protected: void visit_block (block *s); void visit_symbol (symbol* e); + void visit_foreach_loop (foreach_loop* e); void visit_arrayindex (arrayindex* e); void visit_functioncall (functioncall* e); }; @@ -62,6 +66,7 @@ struct typeresolution_info: public visitor void visit_expr_statement (expr_statement *s); void visit_if_statement (if_statement* s); void visit_for_loop (for_loop* s); + void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); void visit_literal_string (literal_string* e); @@ -1,6 +1,10 @@ // systemtap translator driver -// Copyright 2005 Red Hat Inc. -// GPL +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. #include "config.h" #include "staptree.h" @@ -20,9 +24,13 @@ extern "C" { using namespace std; - void usage () { + cerr << "SystemTap translator " + << "(version " << VERSION << " built " << DATE << ")" << endl; + cerr << "Copyright (C) 2005 Red Hat, Inc." << endl; + cerr << "This is free software; see the source for copying conditions." << endl; + cerr << endl; cerr << "Usage: stap [options] FILE [ARGS ...] \tRun script files." << endl; cerr << " or: stap [options] -e PROGRAM [ARGS ...]\tRun script." << endl; cerr << endl; @@ -118,7 +126,9 @@ main (int argc, char * const argv []) // PASS 1a: PARSING USER SCRIPT // XXX: pass args vector, so parser (or lexer?) can substitute // $1..$NN with actual arguments - if (script_file != "") + if (script_file == "-") + s.user_file = parser::parse (cin); + else if (script_file != "") s.user_file = parser::parse (script_file); else { @@ -1,6 +1,10 @@ // recursive descent parser for systemtap scripts -// Copyright 2005 Red Hat Inc. -// GPL +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. #include "config.h" #include "staptree.h" @@ -109,8 +113,6 @@ parser::next () if (! next_t) throw parse_error ("unexpected end-of-file"); - // cerr << "[" << next_t->content << "]" << endl; - last_t = next_t; // advance by zeroing next_t next_t = 0; @@ -411,7 +413,6 @@ parser::parse_stmt_block () { try { - // handle empty blocks t = peek (); if (t && t->type == tok_operator && t->content == "}") { @@ -420,24 +421,6 @@ parser::parse_stmt_block () } pb->statements.push_back (parse_statement ()); - - // ';' is a statement separator in awk, not a terminator. - // Note that ';' is also a possible null statement. - t = peek (); - if (t && t->type == tok_operator && t->content == "}") - { - next (); - break; - } - else if (t && t->type == tok_operator && t->content == ";") - { - next (); - continue; - // this also accepts semicolon as a terminator: - // { a=1; } - } - else - throw parse_error ("expected ';' or '}'"); } catch (parse_error& pe) { @@ -466,29 +449,31 @@ parser::parse_statement () const token* t = peek (); if (t && t->type == tok_operator && t->content == ";") { - next (); - return new null_statement (); + null_statement* n = new null_statement (); + n->tok = next (); + return n; } else if (t && t->type == tok_operator && t->content == "{") return parse_stmt_block (); else if (t && t->type == tok_identifier && t->content == "if") return parse_if_statement (); + /* + else if (t && t->type == tok_identifier && t->content == "for") + return parse_for_loop (); + */ + else if (t && t->type == tok_identifier && t->content == "foreach") + return parse_foreach_loop (); else if (t && t->type == tok_identifier && t->content == "return") return parse_return_statement (); else if (t && t->type == tok_identifier && t->content == "delete") return parse_delete_statement (); - // XXX: other control constructs ("for", "delete", "while", "do", - // "break", "continue", "exit", "return") + // XXX: other control constructs ("delete", "while", "do", + // "break", "continue", "exit") else if (t && (t->type == tok_operator || // expressions are flexible t->type == tok_identifier || t->type == tok_number || t->type == tok_string)) - { - expr_statement *es = new expr_statement; - es->tok = t; - es->value = parse_expression (); - return es; - } + return parse_expr_statement (); else throw parse_error ("expected statement"); } @@ -695,6 +680,17 @@ parser::parse_if_statement () } +expr_statement* +parser::parse_expr_statement () +{ + expr_statement *es = new expr_statement; + const token* t = peek (); + es->tok = t; + es->value = parse_expression (); + return es; +} + + return_statement* parser::parse_return_statement () { @@ -721,6 +717,84 @@ parser::parse_delete_statement () } +for_loop* +parser::parse_for_loop () +{ + throw parse_error ("not yet implemented"); +} + + +foreach_loop* +parser::parse_foreach_loop () +{ + const token* t = next (); + if (! (t->type == tok_identifier && t->content == "foreach")) + throw parse_error ("expected 'foreach'"); + foreach_loop* s = new foreach_loop; + s->tok = t; + + t = next (); + if (! (t->type == tok_operator && t->content == "(")) + throw parse_error ("expected '('"); + + // see also parse_array_in + + bool parenthesized = false; + t = peek (); + if (t && t->type == tok_operator && t->content == "[") + { + next (); + parenthesized = true; + } + + while (1) + { + t = next (); + if (! (t->type == tok_identifier)) + throw parse_error ("expected identifier"); + symbol* sym = new symbol; + sym->tok = t; + sym->name = t->content; + s->indexes.push_back (sym); + + if (parenthesized) + { + const token* t = peek (); + if (t && t->type == tok_operator && t->content == ",") + { + next (); + continue; + } + else if (t && t->type == tok_operator && t->content == "]") + { + next (); + break; + } + else + throw parse_error ("expected ',' or ']'"); + } + else + break; // expecting only one expression + } + + 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; + + t = next (); + if (! (t->type == tok_operator && t->content == ")")) + throw parse_error ("expected ')'"); + + s->block = parse_statement (); + return s; +} + + expression* parser::parse_expression () { @@ -831,12 +905,12 @@ expression* parser::parse_array_in () { // This is a very tricky case. All these are legit expressions: - // "a in b" "a+0 in b" "(a,b) in c" "(c,(d+0)) in b" + // "a in b" "a+0 in b" "[a,b] in c" "[c,(d+0)] in b" vector<expression*> indexes; bool parenthesized = false; const token* t = peek (); - if (t && t->type == tok_operator && t->content == "(") + if (t && t->type == tok_operator && t->content == "[") { next (); parenthesized = true; @@ -855,13 +929,13 @@ parser::parse_array_in () next (); continue; } - else if (t && t->type == tok_operator && t->content == ")") + else if (t && t->type == tok_operator && t->content == "]") { next (); break; } else - throw parse_error ("expected ',' or ')'"); + throw parse_error ("expected ',' or ']'"); } else break; // expecting only one expression @@ -871,7 +945,6 @@ parser::parse_array_in () if (t && t->type == tok_identifier && t->content == "in") { array_in *e = new array_in; - e->op = t->content; e->tok = t; next (); // swallow "in" @@ -1,6 +1,11 @@ // -*- C++ -*- -// Copyright 2005 Red Hat Inc. -// GPL +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + #ifndef PARSE_H #define PARSE_H @@ -96,6 +101,9 @@ private: // nonterminals block* parse_stmt_block (); statement* parse_statement (); if_statement* parse_if_statement (); + for_loop* parse_for_loop (); + foreach_loop* parse_foreach_loop (); + expr_statement* parse_expr_statement (); return_statement* parse_return_statement (); delete_statement* parse_delete_statement (); expression* parse_expression (); diff --git a/staptree.cxx b/staptree.cxx index cf934fa2..d0fd79be 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -1,6 +1,10 @@ // parse tree functions -// Copyright 2005 Red Hat Inc. -// GPL +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. #include "config.h" #include "staptree.h" @@ -169,6 +173,16 @@ void unary_expression::print (ostream& o) o << op << '(' << *operand << ")"; } +void array_in::print (ostream& o) +{ + o << "["; + for (unsigned i=0; i<operand->indexes.size(); i++) + { + if (i > 0) o << ", "; + operand->indexes[i]->print (o); + } + o << "] in " << operand->base; +} void post_crement::print (ostream& o) { @@ -262,7 +276,7 @@ void block::print (ostream& o) { o << "{" << endl; for (unsigned i=0; i<statements.size(); i++) - o << *statements [i] << ";" << endl; + o << *statements [i] << endl; o << "}" << endl; } @@ -273,6 +287,19 @@ void for_loop::print (ostream& o) } +void foreach_loop::print (ostream& o) +{ + o << "foreach (["; + for (unsigned i=0; i<indexes.size(); i++) + { + if (i > 0) o << ", "; + indexes[i]->print (o); + } + o << "] in " << base << ")" << endl; + block->print (o); +} + + void null_statement::print (ostream& o) { o << ";"; @@ -395,6 +422,12 @@ for_loop::visit (visitor* u) } void +foreach_loop::visit (visitor* u) +{ + u->visit_foreach_loop (this); +} + +void null_statement::visit (visitor* u) { u->visit_null_statement (this); @@ -566,6 +599,14 @@ traversing_visitor::visit_for_loop (for_loop* s) } void +traversing_visitor::visit_foreach_loop (foreach_loop* s) +{ + for (unsigned i=0; i<s->indexes.size(); i++) + s->indexes[i]->visit (this); + s->block->visit (this); +} + +void traversing_visitor::visit_return_statement (return_statement* s) { s->value->visit (this); @@ -733,6 +774,12 @@ throwing_visitor::visit_for_loop (for_loop* s) } void +throwing_visitor::visit_foreach_loop (foreach_loop* s) +{ + throwone (s->tok); +} + +void throwing_visitor::visit_return_statement (return_statement* s) { throwone (s->tok); @@ -1,6 +1,10 @@ // -*- C++ -*- -// Copyright 2005 Red Hat Inc. -// GPL +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. #ifndef STAPTREE_H #define STAPTREE_H @@ -124,8 +128,11 @@ struct logical_and_expr: public binary_expression }; -struct array_in: public unary_expression +struct arrayindex; +struct array_in: public expression { + arrayindex* operand; + void print (std::ostream& o); void visit (visitor* u); }; @@ -267,6 +274,7 @@ struct block: public statement void visit (visitor* u); }; + struct for_loop: public statement { expression* init; @@ -278,6 +286,19 @@ struct for_loop: public statement }; +struct foreach_loop: public statement +{ + // this part is a specialization of arrayindex + std::vector<symbol*> indexes; + std::string base; + vardecl* base_referent; + + statement* block; + void print (std::ostream& o); + void visit (visitor* u); +}; + + struct null_statement: public statement { void print (std::ostream& o); @@ -369,6 +390,7 @@ struct visitor virtual void visit_expr_statement (expr_statement *s) = 0; virtual void visit_if_statement (if_statement* s) = 0; virtual void visit_for_loop (for_loop* s) = 0; + virtual void visit_foreach_loop (foreach_loop* s) = 0; virtual void visit_return_statement (return_statement* s) = 0; virtual void visit_delete_statement (delete_statement* s) = 0; virtual void visit_literal_string (literal_string* e) = 0; @@ -401,6 +423,7 @@ struct traversing_visitor: public visitor void visit_expr_statement (expr_statement *s); void visit_if_statement (if_statement* s); void visit_for_loop (for_loop* s); + void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); void visit_literal_string (literal_string* e); @@ -438,6 +461,7 @@ struct throwing_visitor: public visitor void visit_expr_statement (expr_statement *s); void visit_if_statement (if_statement* s); void visit_for_loop (for_loop* s); + void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); void visit_literal_string (literal_string* e); diff --git a/testsuite/parseko/eight.stp b/testsuite/parseko/eight.stp new file mode 100755 index 00000000..4d343159 --- /dev/null +++ b/testsuite/parseko/eight.stp @@ -0,0 +1,4 @@ +#! stap -p1 +probe foo { + foreach ([a, b, c] in) ; +} diff --git a/testsuite/parseko/seven.stp b/testsuite/parseko/seven.stp index 06f8a3ba..0b72f9f8 100755 --- a/testsuite/parseko/seven.stp +++ b/testsuite/parseko/seven.stp @@ -1,8 +1,8 @@ #! stap -p1 probe foo { - (a,) in b; - (,c) in d; - () in e; + [a,] in b; + [,c] in d; + [] in e; a in e[2]; } diff --git a/testsuite/parseko/three.stp b/testsuite/parseko/three.stp index be810e9d..b40c7708 100755 --- a/testsuite/parseko/three.stp +++ b/testsuite/parseko/three.stp @@ -1,7 +1,4 @@ #! stap -p1 - probe foo { - a(1) -# need ; - b(2) + foreach (a) ; } diff --git a/testsuite/parseok/eight.stp b/testsuite/parseok/eight.stp index 0da5c8d2..29602775 100755 --- a/testsuite/parseok/eight.stp +++ b/testsuite/parseok/eight.stp @@ -2,5 +2,7 @@ probe all { - "1" in a1; ("1", 2) in a2; (a) in a3; + "1" in a1; ["1", 2] in a2; [a] in a3; [("1").("2"), "1"."2"] in a4; + a = [akbar(("foo").("bar"))] in it_s_a_trap + foreach ([a, b] in a4) { foreach ([c, d] in a2) ; } } diff --git a/testsuite/parseok/nine.stp b/testsuite/parseok/nine.stp new file mode 100755 index 00000000..13e40cbf --- /dev/null +++ b/testsuite/parseok/nine.stp @@ -0,0 +1,15 @@ +#! stap -p1 + +probe one +{ + if (a) if (b) d else e +} + +probe two +{ + a = b + c = d + e = f(); + g = h; + ; +} diff --git a/testsuite/semko/eleven.stp b/testsuite/semko/eleven.stp new file mode 100755 index 00000000..34dfa225 --- /dev/null +++ b/testsuite/semko/eleven.stp @@ -0,0 +1,15 @@ +#! stap -p2 + +global arr,rra + +probe begin { + arr[0]="value" + rra["key"]=0 +} +probe end { + # confirm that typechecking works the same way for all array indexing + if (k in arr) { k.""; arr[k]+0 } + foreach (l in arr) { l.""; arr[l]+0 } + if (m in rra) { m+1; rra[m]."" } + foreach (n in rra) { n+0; rra[n]."" } +} diff --git a/testsuite/semok/eleven.stp b/testsuite/semok/eleven.stp new file mode 100755 index 00000000..bcfa4222 --- /dev/null +++ b/testsuite/semok/eleven.stp @@ -0,0 +1,38 @@ +#! stap -p2 + +global entry_time, my_count, my_fd, read_times + +# future built-ins +function string (v) { return "" } +function hexstring (v) { return "" } +function trace (s) { return 0 } + +probe kernel.syscall("read") { + $count=0 $timestamp=0 $fd=0 + + thread->entry_time = $timestamp # "macro" variable + thread->my_count = $count # function argument + thread->my_fd = $fd # function argument + trace ("my_count = " . string(thread->my_count) . + "my_fd = " . string(thread->my_fd)) +} + +probe kernel.syscall("read").return { + $syscall_name="" $retvalue=0 + + if (thread->entry_time) { + read_times[$syscall_name] # variable from provider alias + += $timestamp - thread->entry_time + } + trace ("syscall " . $syscall_name . + " return value = " . + hexstring ($retvalue)) # function pseudo-argument +} + +probe end { + foreach (syscall in read_times) { + trace ("syscall " . syscall . + " total-time=" . string (read_times[syscall])) + } +} + diff --git a/testsuite/semok/ten.stp b/testsuite/semok/ten.stp index d56c2a4a..bb353a9f 100755 --- a/testsuite/semok/ten.stp +++ b/testsuite/semok/ten.stp @@ -1,10 +1,15 @@ -#! stap -p1 +#! stap -p2 -global a1, a2, a3 +global arr,rra -probe all -{ - a = "1" in a1; - a = ("1", a) in a2; - a = (a, a+a, a1[a], a2[0+a]) in a3; +probe begin { + arr["key"]=0 + rra[0]="value" +} +probe end { + # confirm that typechecking works the same way for all array indexing + if (k in arr) { k.""; arr[k]+0 } + foreach (l in arr) { l.""; arr[l]+0 } + if (m in rra) { m+0; rra[m]."" } + foreach (n in rra) { n+0; rra[n]."" } } diff --git a/translate.cxx b/translate.cxx index ebfd619e..adf2135c 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1,6 +1,10 @@ // semantic analysis pass, beginnings of elaboration -// Copyright 2005 Red Hat Inc. -// GPL +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. #include "config.h" #include "staptree.h" @@ -90,6 +94,7 @@ struct c_unparser: public unparser, public visitor void visit_expr_statement (expr_statement *s); void visit_if_statement (if_statement* s); void visit_for_loop (for_loop* s); + void visit_foreach_loop (foreach_loop* s); void visit_return_statement (return_statement* s); void visit_delete_statement (delete_statement* s); void visit_literal_string (literal_string* e); @@ -594,19 +599,14 @@ c_unparser::visit_block (block *s) o->newline() << "{"; o->indent (1); o->newline() << "c->actioncount += " << s->statements.size() << ";"; - o->newline() << "if (c->actioncount > MAXACTION)"; - o->newline(1) << "errorcount ++;"; - o->indent(-1); + o->newline() << "if (c->actioncount > MAXACTION) errorcount ++;" << endl; for (unsigned i=0; i<s->statements.size(); i++) { try { // XXX: it's probably not necessary to check this so frequently - o->newline() << "if (errorcount)"; - o->newline(1) << "goto out;" << endl; - o->indent(-1); - + o->newline() << "if (errorcount) goto out;" << endl; s->statements[i]->visit (this); o->newline(); } @@ -676,6 +676,16 @@ c_unparser::visit_for_loop (for_loop *s) void +c_unparser::visit_foreach_loop (foreach_loop *s) +{ + const token* t = s->tok; + o->newline() << "# " << t->location.line + << " \"" << t->location.file << "\" " << endl; + throw semantic_error ("not yet implemented", s->tok); +} + + +void c_unparser::visit_return_statement (return_statement* s) { const token* t = s->tok; @@ -787,13 +797,13 @@ c_unparser::visit_ternary_expression (ternary_expression* e) } - struct c_unparser_assignment: public throwing_visitor { c_unparser* parent; string op; expression* rvalue; c_unparser_assignment (c_unparser* p, const string& o, expression* e): + throwing_visitor ("invalid lvalue type"), parent (p), op (o), rvalue (e) {} // only symbols and arrayindex nodes are possible lvalues @@ -1014,11 +1024,12 @@ c_unparser_assignment::visit_symbol (symbol *e) if (session->globals[i] == r) { // XXX: acquire write lock on global - + o->newline() << "/* wlock global_" << parent->c_varname (r->name) << " */"; parent->c_assign ("global_" + parent->c_varname (r->name), tmp_base + stringify (tmpidx), rvalue->type, "global variable assignment", rvalue->tok); + o->newline() << "/* unlock global_" << parent->c_varname (r->name) << " */"; o->newline() << tmp_base << tmpidx << ";"; o->newline(-1) << "})"; @@ -1089,10 +1100,8 @@ c_unparser::visit_arrayindex (arrayindex* e) e->indexes[i], "array index copy"); } - o->newline() << "if (errorcount)"; - o->newline(1) << "goto out;"; - o->indent(-1); - + o->newline() << "if (errorcount) goto out;"; + o->newline() << "/* XXX: write to array */"; #if 0 // it better be a global for (unsigned i=0; i<session->globals.size(); i++) @@ -1158,8 +1167,7 @@ c_unparser::visit_functioncall (functioncall* e) // to avoid colliding sharing of context variables with // nested function calls: f(f(f(1))) - o->newline() << "/* compute actual arguments */"; - + // compute actual arguments unsigned tmpidx_base = tmpvar_counter; tmpvar_counter += r->formal_args.size(); string tmp_base = "l->__tmp"; @@ -1176,14 +1184,12 @@ c_unparser::visit_functioncall (functioncall* e) e->args[i], "function actual argument evaluation"); } - o->newline() << "if (c->nesting+2 >= MAXNESTING)"; - o->newline(1) << "errorcount ++;"; - o->newline(-1) << "c->actioncount ++;"; - o->newline() << "if (c->actioncount > MAXACTION)"; - o->newline(1) << "errorcount ++;"; - o->newline(-1) << "if (errorcount)"; - o->newline(1) << "goto out;"; - o->indent(-1); + o->newline(); + o->newline() << "if (c->nesting+2 >= MAXNESTING) errorcount ++;"; + o->newline() << "c->actioncount ++;"; + o->newline() << "if (c->actioncount > MAXACTION) errorcount ++;"; + o->newline() << "if (errorcount) goto out;"; + o->newline(); // copy in actual arguments for (unsigned i=0; i<e->args.size(); i++) diff --git a/translate.h b/translate.h index f0bd973c..0627994b 100644 --- a/translate.h +++ b/translate.h @@ -1,7 +1,10 @@ // -*- C++ -*- -// Copyright 2005 Red Hat Inc. -// GPL - +// Copyright (C) 2005 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. #ifndef TRANSLATE_H #define TRANSLATE_H |