summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfche <fche>2005-06-02 19:43:55 +0000
committerfche <fche>2005-06-02 19:43:55 +0000
commit69c68955b910a9f284fa25b9ebb30eff5c040e0b (patch)
tree3fa502458891d0b54150d678368f7a2dee18fa0f
parentf37b5c92191dd81aad57ade2899a4999099a3e35 (diff)
downloadsystemtap-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--ChangeLog16
-rw-r--r--Makefile.in1
-rw-r--r--config.in3
-rwxr-xr-xconfigure11
-rw-r--r--configure.ac5
-rw-r--r--elaborate.cxx83
-rw-r--r--elaborate.h11
-rw-r--r--main.cxx18
-rw-r--r--parse.cxx149
-rw-r--r--parse.h12
-rw-r--r--staptree.cxx53
-rw-r--r--staptree.h30
-rwxr-xr-xtestsuite/parseko/eight.stp4
-rwxr-xr-xtestsuite/parseko/seven.stp6
-rwxr-xr-xtestsuite/parseko/three.stp5
-rwxr-xr-xtestsuite/parseok/eight.stp4
-rwxr-xr-xtestsuite/parseok/nine.stp15
-rwxr-xr-xtestsuite/semko/eleven.stp15
-rwxr-xr-xtestsuite/semok/eleven.stp38
-rwxr-xr-xtestsuite/semok/ten.stp19
-rw-r--r--translate.cxx56
-rw-r--r--translate.h9
22 files changed, 455 insertions, 108 deletions
diff --git a/ChangeLog b/ChangeLog
index 41576ba4..d53d4d45 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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@
diff --git a/config.in b/config.in
index 8297d4bd..f6042b1e 100644
--- a/config.in
+++ b/config.in
@@ -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
diff --git a/configure b/configure
index 8ecf2e47..9ab9ade7 100755
--- a/configure
+++ b/configure
@@ -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);
diff --git a/main.cxx b/main.cxx
index 94026001..4ab4e0bd 100644
--- a/main.cxx
+++ b/main.cxx
@@ -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
{
diff --git a/parse.cxx b/parse.cxx
index 5f3d6971..a117d1bc 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -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"
diff --git a/parse.h b/parse.h
index 3ccb58fe..28690e95 100644
--- a/parse.h
+++ b/parse.h
@@ -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);
diff --git a/staptree.h b/staptree.h
index 2d2c9fce..48862d05 100644
--- a/staptree.h
+++ b/staptree.h
@@ -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