summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--TODO16
-rw-r--r--elaborate.cxx157
-rw-r--r--main.cxx29
-rw-r--r--parse.cxx25
-rw-r--r--staptree.cxx1
-rwxr-xr-xtestsuite/parseok/semko.stp6
-rwxr-xr-xtestsuite/semko/eight.stp2
-rwxr-xr-xtestsuite/semko/four.stp2
-rwxr-xr-xtestsuite/semko/three.stp3
-rwxr-xr-xtestsuite/semko/two.stp2
-rwxr-xr-xtestsuite/transok/four.stp13
-rw-r--r--translate.cxx86
13 files changed, 252 insertions, 103 deletions
diff --git a/ChangeLog b/ChangeLog
index f7c7e1db..a5063923 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2005-06-03 Frank Ch. Eigler <fche@redhat.com>
+ * TODO: Removed entries already represented in bugzilla.
+ * elaborate.cxx: Rewrite type inference for several operators.
+ * main.cxx (main): For -p2 runs, print types of function/probe locals.
+ * parse.cxx (scan): Identify more two-character operators.
+ (parse_comparison): Support the whole suite.
+ * translate.cxx (visit_unary_expression, logical_or_expr,
+ logical_and_expr, comparison,ternary_expression): New support.
+ * testsuite/parseok/semok.stp: Clever new test.
+ * testsuite/transok/four.stp: New test.
+ * testsuite/*: Some tweaked tests for syntax changes.
+
+2005-06-03 Frank Ch. Eigler <fche@redhat.com>
+
* parse.cxx (scan): Support C and C++ comment styles.
* testsuite/parseok/four.stp: Test them some ...
* testsuite/parseko/nine.stp: ... and some more.
diff --git a/TODO b/TODO
index 55d3040e..0179b67f 100644
--- a/TODO
+++ b/TODO
@@ -1,8 +1,6 @@
LANGUAGE
for/while/break/continue statements
lock (var) { block } (http://tinyurl.com/5rpzg)
- "in" predicate / looping construct
- /* */ and // comments
builtin functions
varargs/overloaded functions (?)
syntax for dereferencing C structures (http://tinyurl.com/4tpgh);
@@ -13,7 +11,6 @@ LANGUAGE
TRANSLATOR
lots of "XXX" markers
- use "restrict" pointers for context*
deal with (warn/elide?) local variables only written or read
RUNTIME
@@ -29,15 +26,8 @@ OPROFILE/timers
PROVIDERS
lkst("process_contextswitch")
- syscall("name").return
- syscall("*")
- kernel.function("wait_for_godot")
kernel.function("wait_for_godot").callees
kernel.function("batman").calledfrom("commissioner")
- kernel.function("name").line(10)
- kernel.source("mempool.c").line(5004)
- kernel.address(0xdeadbeef)
- kernel.module("driver.ko").function("name").return
kernel.module("cpqarray.ko").jumptable("ida_fops")
kernel.watch("datasymbol").write
user("fche").inode("/bin/vi").function("refresh")
@@ -45,15 +35,9 @@ PROVIDERS
time.real.hz(500)
time.virtual.jiffies(100)
perfcounter("tlbmiss").count(4000)
- resource.freemembelow(50) # pages?
- begin
- end
KPROBES
- smp friendliness: no kprobes-wide lock held during probe execution
- multiple probes at same address
user-level probe points (via ptrace mechanism?)
- separate stack
treatment of nested probe hits (prefer no permanent disablement; require
flagging of occurrence)
self-monitoring of performance overhead
diff --git a/elaborate.cxx b/elaborate.cxx
index 7a6c2359..e733132f 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -546,14 +546,43 @@ typeresolution_info::visit_logical_and_expr (logical_and_expr *e)
void
typeresolution_info::visit_comparison (comparison *e)
{
- visit_binary_expression (e);
+ if (t == pe_stats || t == pe_string)
+ invalid (e->tok, t);
+
+ t = (e->right->type != pe_unknown) ? e->right->type : pe_unknown;
+ e->left->visit (this);
+ t = (e->left->type != pe_unknown) ? e->left->type : pe_unknown;
+ e->right->visit (this);
+
+ if (e->left->type != pe_unknown &&
+ e->right->type != pe_unknown &&
+ e->left->type != e->right->type)
+ mismatch (e->tok, e->left->type, e->right->type);
+
+ if (e->type == pe_unknown)
+ {
+ e->type = pe_long;
+ resolved (e->tok, e->type);
+ }
}
void
typeresolution_info::visit_concatenation (concatenation *e)
{
- visit_binary_expression (e);
+ if (t != pe_unknown && t != pe_string)
+ invalid (e->tok, t);
+
+ t = pe_string;
+ e->left->visit (this);
+ t = pe_string;
+ e->right->visit (this);
+
+ if (e->type == pe_unknown)
+ {
+ e->type = pe_string;
+ resolved (e->tok, e->type);
+ }
}
@@ -567,89 +596,86 @@ typeresolution_info::visit_exponentiation (exponentiation *e)
void
typeresolution_info::visit_assignment (assignment *e)
{
- visit_binary_expression (e);
-}
-
+ if (t == pe_stats)
+ invalid (e->tok, t);
-void
-typeresolution_info::visit_binary_expression (binary_expression* e)
-{
if (e->op == "<<<") // stats aggregation
{
- exp_type t1 = t;
+ if (t == pe_string)
+ invalid (e->tok, t);
+
t = pe_stats;
e->left->visit (this);
t = pe_long;
e->right->visit (this);
- if (t1 == pe_stats || t1 == pe_string)
- invalid (e->tok, t1);
- else if (e->type == pe_unknown)
+ if (e->type == pe_unknown)
{
e->type = pe_long;
resolved (e->tok, e->type);
}
}
- else if (e->op == ".") // string concatenation
+ else if (e->op == "+=" || // numeric only
+ false)
{
- exp_type t1 = t;
- t = pe_string;
- e->left->visit (this);
- t = pe_string;
- e->right->visit (this);
- if (t1 == pe_long || t1 == pe_stats)
- mismatch (e->tok, t1, pe_string);
- else if (e->type == pe_unknown)
- {
- e->type = pe_string;
- resolved (e->tok, e->type);
- }
- }
- else if (e->op == "=="
- || false) // XXX: other comparison operators
- {
- exp_type t1 = t;
- t = pe_unknown;
- e->left->visit (this);
- t = pe_unknown;
- e->right->visit (this);
- if (t1 == pe_string || t1 == pe_stats)
- mismatch (e->tok, t1, pe_long);
- else if (e->type == pe_unknown)
- {
- e->type = pe_long;
- resolved (e->tok, e->type);
- }
+ visit_binary_expression (e);
}
- else // general arithmetic operators?
+ else // overloaded for string & numeric operands
{
- // propagate e->type downward
+ // logic similar to ternary_expression
exp_type sub_type = t;
- if ((sub_type == pe_unknown) && (e->type != pe_unknown))
+
+ // Infer types across the l/r values
+ if (sub_type == pe_unknown && e->type != pe_unknown)
sub_type = e->type;
- t = sub_type;
+
+ t = (sub_type != pe_unknown) ? sub_type :
+ (e->right->type != pe_unknown) ? e->right->type :
+ pe_unknown;
e->left->visit (this);
- t = sub_type;
+ t = (sub_type != pe_unknown) ? sub_type :
+ (e->left->type != pe_unknown) ? e->left->type :
+ pe_unknown;
e->right->visit (this);
-
- if ((sub_type == pe_unknown) && (e->type != pe_unknown))
- ; // already resolved
- else if ((sub_type != pe_unknown) && (e->type == pe_unknown))
+
+ if ((sub_type != pe_unknown) && (e->type == pe_unknown))
{
e->type = sub_type;
resolved (e->tok, e->type);
}
- else if ((sub_type == pe_unknown) && (e->left->type != pe_unknown))
+ if ((sub_type == pe_unknown) && (e->left->type != pe_unknown))
{
e->type = e->left->type;
resolved (e->tok, e->type);
}
- else if ((sub_type == pe_unknown) && (e->right->type != pe_unknown))
- {
- e->type = e->right->type;
- resolved (e->tok, e->type);
- }
- else if (e->type != sub_type)
- mismatch (e->tok, sub_type, e->type);
+
+ if (e->left->type != pe_unknown &&
+ e->right->type != pe_unknown &&
+ e->left->type != e->right->type)
+ mismatch (e->tok, e->left->type, e->right->type);
+ }
+}
+
+
+void
+typeresolution_info::visit_binary_expression (binary_expression* e)
+{
+ if (t == pe_stats || t == pe_string)
+ invalid (e->tok, t);
+
+ t = pe_long;
+ e->left->visit (this);
+ t = pe_long;
+ e->right->visit (this);
+
+ if (e->left->type != pe_unknown &&
+ e->right->type != pe_unknown &&
+ e->left->type != e->right->type)
+ mismatch (e->tok, e->left->type, e->right->type);
+
+ if (e->type == pe_unknown)
+ {
+ e->type = pe_long;
+ resolved (e->tok, e->type);
}
}
@@ -671,16 +697,13 @@ typeresolution_info::visit_post_crement (post_crement *e)
void
typeresolution_info::visit_unary_expression (unary_expression* e)
{
- // all unary operators only work on numerics
- exp_type t1 = t;
+ if (t == pe_stats || t == pe_string)
+ invalid (e->tok, t);
+
t = pe_long;
e->operand->visit (this);
- if (t1 == pe_unknown && e->type != pe_unknown)
- ; // already resolved
- else if (t1 == pe_string || t1 == pe_stats)
- mismatch (e->tok, t1, pe_long);
- else if (e->type == pe_unknown)
+ if (e->type == pe_unknown)
{
e->type = pe_long;
resolved (e->tok, e->type);
@@ -688,7 +711,6 @@ typeresolution_info::visit_unary_expression (unary_expression* e)
}
-
void
typeresolution_info::visit_ternary_expression (ternary_expression* e)
{
@@ -697,8 +719,7 @@ typeresolution_info::visit_ternary_expression (ternary_expression* e)
t = pe_long;
e->cond->visit (this);
- // Match ordinary binary_expression type inference for the true/false
- // arms of the ternary expression.
+ // Infer types across the true/false arms of the ternary expression.
if (sub_type == pe_unknown && e->type != pe_unknown)
sub_type = e->type;
diff --git a/main.cxx b/main.cxx
index 1de14576..6a9b70dc 100644
--- a/main.cxx
+++ b/main.cxx
@@ -175,26 +175,49 @@ main (int argc, char * const argv [])
rc = semantic_pass (s);
if (last_pass == 2 && rc == 0)
{
- s.op->line() << "# globals";
+ if (s.globals.size() > 0)
+ s.op->line() << "# globals";
for (unsigned i=0; i<s.globals.size(); i++)
{
vardecl* v = s.globals[i];
v->printsig (s.op->newline());
}
- s.op->newline() << "# functions";
+ if (s.functions.size() > 0)
+ s.op->newline() << "# functions";
for (unsigned i=0; i<s.functions.size(); i++)
{
functiondecl* f = s.functions[i];
f->printsig (s.op->newline());
+ s.op->indent(1);
+ if (f->locals.size() > 0)
+ s.op->newline(1) << "# locals";
+ for (unsigned j=0; j<f->locals.size(); j++)
+ {
+ vardecl* v = f->locals[j];
+ v->printsig (s.op->newline());
+ }
+ s.op->indent(-1);
}
- s.op->newline() << "# probes";
+ if (s.probes.size() > 0)
+ s.op->newline() << "# probes";
for (unsigned i=0; i<s.probes.size(); i++)
{
derived_probe* p = s.probes[i];
p->printsig (s.op->newline());
+ s.op->indent(1);
+ if (p->locals.size() > 0)
+ s.op->newline() << "# locals";
+ for (unsigned j=0; j<p->locals.size(); j++)
+ {
+ vardecl* v = p->locals[j];
+ v->printsig (s.op->newline());
+ }
+ s.op->indent(-1);
}
+
+ s.op->newline();
}
// PASS 3: TRANSLATION
diff --git a/parse.cxx b/parse.cxx
index 2e350b4d..5595f359 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -286,14 +286,17 @@ lexer::scan ()
// handle two-character operators
if ((c == '=' && c2 == '=') ||
+ (c == '!' && c2 == '=') ||
+ (c == '<' && c2 == '=') ||
+ (c == '>' && c2 == '=') ||
(c == '+' && c2 == '+') ||
(c == '-' && c2 == '-') ||
(c == '|' && c2 == '|') ||
(c == '&' && c2 == '&') ||
- (c == '<' && c2 == '<') ||
+ // (c == '<' && c2 == '<') ||
+ // (c == '>' && c2 == '>') ||
(c == '+' && c2 == '=') ||
(c == '-' && c2 == '=') ||
- (c == ':' && c2 == ':') ||
(c == '-' && c2 == '>') ||
false) // XXX: etc.
n->content.push_back ((char) input_get ());
@@ -301,9 +304,15 @@ lexer::scan ()
// handle three-character operator
if (c == '<' && c2 == '<')
{
+ input_get (); // swallow c2
int c3 = input.peek ();
if (c3 == '<')
- n->content.push_back ((char) input_get ());
+ {
+ input_get (); // swallow c3
+ n->content = "<<<";
+ }
+ else
+ n->content = "<<";
}
return n;
@@ -843,7 +852,7 @@ parser::parse_assignment ()
next ();
e->right = parse_expression ();
op1 = e;
- // XXX: map assign/accumlate operators like +=, /=
+ // XXX: map assign/accumulate operators like +=, /=
// to ordinary assignment + nested binary_expression
}
@@ -994,7 +1003,13 @@ parser::parse_comparison ()
const token* t = peek ();
while (t && t->type == tok_operator
- && (t->content == ">" || t->content == "==")) // xxx: more
+ && (t->content == ">" ||
+ t->content == "<" ||
+ t->content == "==" ||
+ t->content == "!=" ||
+ t->content == "<=" ||
+ t->content == ">=" ||
+ false )) // xxx: more
{
comparison* e = new comparison;
e->left = op1;
diff --git a/staptree.cxx b/staptree.cxx
index d0fd79be..a8651d1d 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -373,7 +373,6 @@ void probe::printsig (ostream& o)
o << (i>0 ? ", " : "");
locations[i]->print (o);
}
- o << endl;
}
diff --git a/testsuite/parseok/semko.stp b/testsuite/parseok/semko.stp
new file mode 100755
index 00000000..11f2a2da
--- /dev/null
+++ b/testsuite/parseok/semko.stp
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+# make sure that we can *parse* all semko test files, to ensure
+# that it is semantic (elaboration) checks that fail, not parse errors
+
+./stap -p1 -I${SRCDIR}/testsuite/semko -e 'global nothing'
diff --git a/testsuite/semko/eight.stp b/testsuite/semko/eight.stp
index 7d297295..d95e225f 100755
--- a/testsuite/semko/eight.stp
+++ b/testsuite/semko/eight.stp
@@ -1,5 +1,5 @@
#! stap -p2
probe foo {
- stats << "string" # stats only collect numbers
+ stats <<< "string" # stats only collect numbers
}
diff --git a/testsuite/semko/four.stp b/testsuite/semko/four.stp
index fd2b3928..21e2be20 100755
--- a/testsuite/semko/four.stp
+++ b/testsuite/semko/four.stp
@@ -1,6 +1,6 @@
#! stap -p2
-global a, b; # types unknown
+global a, b # types unknown
function bar ()
{
diff --git a/testsuite/semko/three.stp b/testsuite/semko/three.stp
index 423dbcdf..7a64a93c 100755
--- a/testsuite/semko/three.stp
+++ b/testsuite/semko/three.stp
@@ -1,6 +1,7 @@
#! stap -p2
+global b
probe foo {
- a << 2;
+ a <<< 2;
b[a] = 4; # must not index with stats variable
}
diff --git a/testsuite/semko/two.stp b/testsuite/semko/two.stp
index acf0a973..5906687c 100755
--- a/testsuite/semko/two.stp
+++ b/testsuite/semko/two.stp
@@ -1,6 +1,6 @@
#! stap -p2
-function zoo (p) { p << 5; return 0 } # passing stats as function arg
+function zoo (p) { p <<< 5; return 0 } # passing stats as function arg
probe foo {
bar = 2 + "string"; # mixing integer+string arithmetic
diff --git a/testsuite/transok/four.stp b/testsuite/transok/four.stp
new file mode 100755
index 00000000..daad4f5d
--- /dev/null
+++ b/testsuite/transok/four.stp
@@ -0,0 +1,13 @@
+#! stap
+
+function f () {
+ return 0
+}
+
+probe end {
+ a = 0 as = ""
+ b = a * (b + c) - d bs = as . "bs" . as
+ c = (a > b) ? (a == b) : (a != b) cs = (as > bs) ? (as == bs) : (as != bs)
+ d = (a > b) + (a >= b) + (a < b) + (a <= b)
+ if (a) b else c if (cs) 0 else 1
+}
diff --git a/translate.cxx b/translate.cxx
index f53e2952..972e188c 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -709,7 +709,7 @@ c_unparser::visit_binary_expression (binary_expression* e)
if (e->type != pe_long ||
e->left->type != pe_long ||
e->right->type != pe_long)
- throw semantic_error ("expected string types", e->tok);
+ throw semantic_error ("expected numeric types", e->tok);
o->line() << "(";
e->left->visit (this);
@@ -722,36 +722,66 @@ c_unparser::visit_binary_expression (binary_expression* e)
throw semantic_error ("not yet implemented", e->tok);
}
+
void
c_unparser::visit_unary_expression (unary_expression* e)
{
- throw semantic_error ("not yet implemented", e->tok);
+ if (e->type != pe_long ||
+ e->operand->type != pe_long)
+ throw semantic_error ("expected numeric types", e->tok);
+
+ o->line() << e->op << " (";
+ e->operand->visit (this);
+ o->line() << ")";
}
+
void
c_unparser::visit_pre_crement (pre_crement* e)
{
throw semantic_error ("not yet implemented", e->tok);
}
+
void
c_unparser::visit_post_crement (post_crement* e)
{
throw semantic_error ("not yet implemented", e->tok);
}
+
void
c_unparser::visit_logical_or_expr (logical_or_expr* e)
{
- throw semantic_error ("not yet implemented", e->tok);
+ if (e->type != pe_long ||
+ e->left->type != pe_long ||
+ e->right->type != pe_long)
+ throw semantic_error ("expected numeric types", e->tok);
+
+ o->line() << "(";
+ e->left->visit (this);
+ o->line() << ") " << e->op << " (";
+ e->right->visit (this);
+ o->line() << ")";
}
+
void
c_unparser::visit_logical_and_expr (logical_and_expr* e)
{
- throw semantic_error ("not yet implemented", e->tok);
+ if (e->type != pe_long ||
+ e->left->type != pe_long ||
+ e->right->type != pe_long)
+ throw semantic_error ("expected numeric types", e->tok);
+
+ o->line() << "(";
+ e->left->visit (this);
+ o->line() << ") " << e->op << " (";
+ e->right->visit (this);
+ o->line() << ")";
}
+
void
c_unparser::visit_array_in (array_in* e)
{
@@ -762,7 +792,37 @@ c_unparser::visit_array_in (array_in* e)
void
c_unparser::visit_comparison (comparison* e)
{
- throw semantic_error ("not yet implemented", e->tok);
+ o->line() << "(";
+
+ if (e->left->type == pe_string)
+ {
+ if (e->left->type != pe_string ||
+ e->right->type != pe_string)
+ throw semantic_error ("expected string types", e->tok);
+
+ o->line() << "strncmp (";
+ e->left->visit (this);
+ o->line() << ", ";
+ e->right->visit (this);
+ o->line() << ", MAXSTRINGLEN";
+ o->line() << ") " << e->op << " 0";
+ }
+ else if (e->left->type == pe_long)
+ {
+ if (e->left->type != pe_long ||
+ e->right->type != pe_long)
+ throw semantic_error ("expected numeric types", e->tok);
+
+ o->line() << "(";
+ e->left->visit (this);
+ o->line() << ") " << e->op << " (";
+ e->right->visit (this);
+ o->line() << ")";
+ }
+ else
+ throw semantic_error ("unexpected type", e->left->tok);
+
+ o->line() << ")";
}
@@ -811,7 +871,21 @@ c_unparser::visit_exponentiation (exponentiation* e)
void
c_unparser::visit_ternary_expression (ternary_expression* e)
{
- throw semantic_error ("not yet implemented", e->tok);
+ if (e->cond->type != pe_long)
+ throw semantic_error ("expected numeric condition", e->cond->tok);
+
+ if (e->truevalue->type != e->falsevalue->type ||
+ e->type != e->truevalue->type ||
+ (e->truevalue->type != pe_long && e->truevalue->type != pe_string))
+ throw semantic_error ("expected matching types", e->tok);
+
+ o->line() << "((";
+ e->cond->visit (this);
+ o->line() << ") ? (";
+ e->truevalue->visit (this);
+ o->line() << ") : (";
+ e->falsevalue->visit (this);
+ o->line() << "))";
}