diff options
Diffstat (limited to 'translate.cxx')
-rw-r--r-- | translate.cxx | 479 |
1 files changed, 307 insertions, 172 deletions
diff --git a/translate.cxx b/translate.cxx index 1c9724d9..dcccf1bd 100644 --- a/translate.cxx +++ b/translate.cxx @@ -112,7 +112,6 @@ struct c_unparser: public unparser, public visitor void visit_array_in (array_in* e); void visit_comparison (comparison* e); void visit_concatenation (concatenation* e); - void visit_exponentiation (exponentiation* e); void visit_ternary_expression (ternary_expression* e); void visit_assignment (assignment* e); void visit_symbol (symbol* e); @@ -142,8 +141,6 @@ resolution_pass (systemtap_session& s) s.probes.push_back (dp); } - // XXX: merge functiondecls - // XXX: handle library files // XXX: add builtin variables/functions return rc; } @@ -267,16 +264,15 @@ struct c_tmpcounter: public traversing_visitor // void visit_foreach_loop (foreach_loop* s); // void visit_return_statement (return_statement* s); // void visit_delete_statement (delete_statement* s); - // void visit_binary_expression (binary_expression* e); + void visit_binary_expression (binary_expression* e); // void visit_unary_expression (unary_expression* e); - // void visit_pre_crement (pre_crement* e); - // void visit_post_crement (post_crement* e); + void visit_pre_crement (pre_crement* e); + void visit_post_crement (post_crement* e); // void visit_logical_or_expr (logical_or_expr* e); // void visit_logical_and_expr (logical_and_expr* e); // void visit_array_in (array_in* e); // void visit_comparison (comparison* e); void visit_concatenation (concatenation* e); - // void visit_exponentiation (exponentiation* e); // void visit_ternary_expression (ternary_expression* e); void visit_assignment (assignment* e); void visit_arrayindex (arrayindex* e); @@ -387,7 +383,23 @@ c_unparser::emit_module_init () o->newline() << "int STARTUP () {"; o->newline(1) << "int anyrc = 0;"; o->newline() << "int rc;"; - // XXX: initialize globals + + for (unsigned i=0; i<session->globals.size(); i++) + { + vardecl* v = session->globals[i]; + if (v->index_types.size() > 0) // array? + throw semantic_error ("array init not yet implemented", v->tok); + else if (v->type == pe_long) + o->newline() << "global_" << c_varname (v->name) + << " = 0;"; + else if (v->type == pe_string) + o->newline() << "global_" << c_varname (v->name) + << "[0] = '\\0';"; + else + throw semantic_error ("unsupported global variable type", + v->tok); + } + for (unsigned i=0; i<session->probes.size(); i++) { session->probes[i]->emit_registrations (o, i); @@ -401,8 +413,7 @@ c_unparser::emit_module_init () o->newline() << "goto out;"; o->newline(-1) << "}"; } - o->newline(-1) << "out:"; - o->indent(1); + o->newline() << "out:"; o->newline() << "return anyrc; /* if (anyrc) log badness */"; o->newline(-1) << "}" << endl; } @@ -448,7 +459,7 @@ c_unparser::emit_function (functiondecl* v) for (unsigned i=0; i<v->locals.size(); i++) { if (v->locals[i]->index_types.size() > 0) // array? - throw semantic_error ("not yet implemented", v->tok); + throw semantic_error ("array locals not supported", v->tok); else if (v->locals[i]->type == pe_long) o->newline() << "l->" << c_varname (v->locals[i]->name) << " = 0;"; @@ -491,7 +502,7 @@ c_unparser::emit_probe (derived_probe* v, unsigned i) for (unsigned j=0; j<v->locals.size(); j++) { if (v->locals[j]->index_types.size() > 0) // array? - throw semantic_error ("not yet implemented", v->tok); + throw semantic_error ("array locals not supported", v->tok); else if (v->locals[j]->type == pe_long) o->newline() << "l->" << c_varname (v->locals[j]->name) << " = 0;"; @@ -690,7 +701,7 @@ c_unparser::visit_for_loop (for_loop *s) void c_unparser::visit_foreach_loop (foreach_loop *s) { - throw semantic_error ("not yet implemented", s->tok); + throw semantic_error ("foreach loop not yet implemented", s->tok); } @@ -722,7 +733,7 @@ c_unparser::visit_next_statement (next_statement* s) void c_unparser::visit_delete_statement (delete_statement* s) { - throw semantic_error ("not yet implemented", s->tok); + throw semantic_error ("delete statement not yet implemented", s->tok); } @@ -763,28 +774,77 @@ c_unparser::visit_literal_number (literal_number* e) } + +void +c_tmpcounter::visit_binary_expression (binary_expression* e) +{ + if (e->op == "/" || e->op == "%") + { + parent->o->newline() + << parent->c_typename (pe_long) + << " __tmp" << tmpvar_counter ++ << ";"; + parent->o->newline() + << parent->c_typename (pe_long) + << " __tmp" << tmpvar_counter ++ << ";"; + } + + e->left->visit (this); + e->right->visit (this); +} + + void 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 numeric types", e->tok); + if (e->op == "+" || e->op == "-" || e->op == "*" || - false) // XXX: other simple arithmetic operators + e->op == "&" || + e->op == "|" || + e->op == "^" || + e->op == "<<" || + e->op == ">>") { - 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() << "("; + o->line() << "(("; + e->left->visit (this); + o->line() << ") " << e->op << " ("; + e->right->visit (this); + o->line() << "))"; + } + else if (e->op == "/" || + e->op == "%") + { + // % and / need a division-by-zero check; and thus two temporaries + // for proper evaluation order + unsigned tmpidx1 = tmpvar_counter++; + unsigned tmpidx2 = tmpvar_counter++; + string tmp1 = "l->__tmp" + stringify (tmpidx1); + string tmp2 = "l->__tmp" + stringify (tmpidx2); + o->line() << "({"; + + o->newline(1) << tmp1 << " = "; e->left->visit (this); - o->line() << " " << e->op << " "; + o->line() << ";"; + + o->newline() << tmp2 << " = "; e->right->visit (this); - o->line() << ")"; + o->line() << ";"; + + o->newline() << "if (" << tmp2 << " == 0) {"; + o->newline(1) << "errorcount ++;"; + o->newline() << tmp2 << " = 1;"; + o->newline(-1) << "}"; + + o->newline() << tmp1 << " " << e->op << " " << tmp2 << ";"; + o->newline(-1) << "})"; } - // XXX: % and / need a division-by-zero check else - throw semantic_error ("not yet implemented", e->tok); + throw semantic_error ("operator not yet implemented", e->tok); } @@ -795,26 +855,11 @@ c_unparser::visit_unary_expression (unary_expression* e) e->operand->type != pe_long) throw semantic_error ("expected numeric types", e->tok); - o->line() << e->op << " ("; + 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); + o->line() << "))"; } - void c_unparser::visit_logical_or_expr (logical_or_expr* e) { @@ -823,11 +868,11 @@ c_unparser::visit_logical_or_expr (logical_or_expr* e) e->right->type != pe_long) throw semantic_error ("expected numeric types", e->tok); - o->line() << "("; + o->line() << "(("; e->left->visit (this); o->line() << ") " << e->op << " ("; e->right->visit (this); - o->line() << ")"; + o->line() << "))"; } @@ -839,18 +884,18 @@ c_unparser::visit_logical_and_expr (logical_and_expr* e) e->right->type != pe_long) throw semantic_error ("expected numeric types", e->tok); - o->line() << "("; + o->line() << "(("; e->left->visit (this); o->line() << ") " << e->op << " ("; e->right->visit (this); - o->line() << ")"; + o->line() << "))"; } void c_unparser::visit_array_in (array_in* e) { - throw semantic_error ("not yet implemented", e->tok); + throw semantic_error ("array-in expression not yet implemented", e->tok); } @@ -878,11 +923,11 @@ c_unparser::visit_comparison (comparison* e) e->right->type != pe_long) throw semantic_error ("expected numeric types", e->tok); - o->line() << "("; + o->line() << "(("; e->left->visit (this); o->line() << ") " << e->op << " ("; e->right->visit (this); - o->line() << ")"; + o->line() << "))"; } else throw semantic_error ("unexpected type", e->left->tok); @@ -895,8 +940,7 @@ void c_tmpcounter::visit_concatenation (concatenation* e) { parent->o->newline() << parent->c_typename (e->type) - << " __tmp" << tmpvar_counter ++ << ";" - << " /* " << e->op << " result */"; + << " __tmp" << tmpvar_counter ++ << ";"; e->left->visit (this); e->right->visit (this); } @@ -927,13 +971,6 @@ c_unparser::visit_concatenation (concatenation* e) void -c_unparser::visit_exponentiation (exponentiation* e) -{ - throw semantic_error ("not yet implemented", e->tok); -} - - -void c_unparser::visit_ternary_expression (ternary_expression* e) { if (e->cond->type != pe_long) @@ -959,9 +996,13 @@ struct c_unparser_assignment: public throwing_visitor c_unparser* parent; string op; expression* rvalue; + bool pre; c_unparser_assignment (c_unparser* p, const string& o, expression* e): throwing_visitor ("invalid lvalue type"), - parent (p), op (o), rvalue (e) {} + parent (p), op (o), rvalue (e), pre (false) {} + c_unparser_assignment (c_unparser* p, const string& o, bool pp): + throwing_visitor ("invalid lvalue type"), + parent (p), op (o), rvalue (0), pre (pp) {} // only symbols and arrayindex nodes are possible lvalues void visit_symbol (symbol *e); @@ -1003,13 +1044,46 @@ c_unparser::visit_assignment (assignment* e) throw semantic_error ("type mismatch", e->right->tok, "vs", e->left->tok); - if (e->op == "=" || e->op == "<<<") - { - c_unparser_assignment tav (this, e->op, e->right); - e->left->visit (& tav); - } - else - throw semantic_error ("not yet implemented ", e->tok); + c_unparser_assignment tav (this, e->op, e->right); + e->left->visit (& tav); +} + + +void +c_tmpcounter::visit_pre_crement (pre_crement* e) +{ + c_tmpcounter_assignment tav (this, e->op, 0); + e->operand->visit (& tav); +} + +void +c_unparser::visit_pre_crement (pre_crement* e) +{ + if (e->type != pe_long || + e->type != e->operand->type) + throw semantic_error ("expected numeric type", e->tok); + + c_unparser_assignment tav (this, e->op, true); + e->operand->visit (& tav); +} + + +void +c_tmpcounter::visit_post_crement (post_crement* e) +{ + c_tmpcounter_assignment tav (this, e->op, 0); + e->operand->visit (& tav); +} + +void +c_unparser::visit_post_crement (post_crement* e) +{ + if (e->type != pe_long || + e->type != e->operand->type) + throw semantic_error ("expected numeric type", e->tok); + + c_unparser_assignment tav (this, e->op, false); + e->operand->visit (& tav); } @@ -1077,16 +1151,46 @@ c_unparser::visit_symbol (symbol* e) } + + +// Assignment expansion is tricky. +// +// Because assignments are nestable expressions, we have +// to emit C constructs that are nestable expressions too. +// We have to evaluate the given expressions the proper number of times, +// including array indices. +// We have to lock the lvalue (if global) against concurrent modification, +// especially with modify-assignment operations (+=, ++). +// We have to check the rvalue (for division-by-zero checks). + +// In the normal "pre=false" case, for (A op B) emit: +// ({ tmp = B; check(B); lock(A); res = A op tmp; A = res; unlock(A); res; }) +// In the "pre=true" case, emit instead: +// ({ tmp = B; check(B); lock(A); res = A; A = res op tmp; unlock(A); res; }) +// +// (op is the plain operator portion of a combined calculate/assignment: +// "+" for "+=", and so on. It is in the "macop" variable below.) +// +// For array assignments, additional temporaries are used for each +// index, which are expanded before the "tmp=B" expression, in order +// to consistently order evaluation of lhs before rhs. +// + void c_tmpcounter_assignment::visit_symbol (symbol *e) { + // tmp parent->parent->o->newline() << parent->parent->c_typename (e->type) - << " __tmp" << parent->tmpvar_counter ++ << ";" - << " /* " << e->name << " rvalue */"; - rvalue->visit (parent); -} + << " __tmp" << parent->tmpvar_counter ++ << ";"; + // res + parent->parent->o->newline() + << parent->parent->c_typename (e->type) + << " __tmp" << parent->tmpvar_counter ++ << ";"; + if (rvalue) + rvalue->visit (parent); +} void c_unparser_assignment::visit_symbol (symbol *e) @@ -1097,104 +1201,152 @@ c_unparser_assignment::visit_symbol (symbol *e) derived_probe* current_probe = parent->current_probe; systemtap_session* session = parent->session; - if (op != "=") - throw semantic_error ("not yet implemented", e->tok); - if (r->index_types.size() != 0) - throw semantic_error ("invalid reference to array", e->tok); - - // XXX: handle special macro symbols + throw semantic_error ("unexpected reference to array", e->tok); unsigned tmpidx = parent->tmpvar_counter ++; + unsigned residx = parent->tmpvar_counter ++; string tmp_base = "l->__tmp"; - - // NB: because assignments are nestable expressions, we have - // to emit C constructs that are nestable expressions too. - // ... (A = B) ... ==> - // ... ({ tmp = B; store(A,tmp); tmp; }) ... - + string tmpvar = tmp_base + stringify (tmpidx); + string resvar = tmp_base + stringify (residx); o->line() << "({ "; o->indent(1); - parent->c_assign (tmp_base + stringify (tmpidx), rvalue, "assignment"); + // part 1: "tmp = B" + if (rvalue) + parent->c_assign (tmpvar, rvalue, "assignment"); + else + { + if (op == "++" || op == "--") + o->newline() << tmpvar << " = 1;"; + else + // internal error + throw semantic_error ("need rvalue for assignment", e->tok); + } + // OPT: literal rvalues could be used without a tmp* copy - // XXX: strings may be passed safely via a char*, without - // a full copy in tmpNNN + // part 2: "check (B)" + if (op == "/=" || op == "%=") + { + // need division-by-zero check + o->newline() << "if (" << tmpvar << " == 0) {"; + o->newline(1) << "errorcount ++;"; + o->newline() << tmpvar << " = 1;"; + o->newline(-1) << "}"; + } // maybe the variable is a local - if (current_probe) - { - for (unsigned i=0; i<current_probe->locals.size(); i++) - { - vardecl* rr = current_probe->locals[i]; - if (rr == r) // comparison of pointers is sufficient - { - parent->c_assign ("l->" + parent->c_varname (r->name), - tmp_base + stringify (tmpidx), - rvalue->type, - "local variable assignment", rvalue->tok); + string lvaluename; + bool lock_global = false; - o->newline() << tmp_base << tmpidx << ";"; - o->newline(-1) << "})"; - return; - } - } - } - else if (current_function) + if (current_probe) + for (unsigned i=0; i<current_probe->locals.size(); i++) + if (current_probe->locals[i] == r) + lvaluename = "l->" + parent->c_varname (r->name); + if (current_function) { for (unsigned i=0; i<current_function->locals.size(); i++) - { - vardecl* rr = current_function->locals[i]; - if (rr == r) // comparison of pointers is sufficient - { - parent->c_assign ("l->" + parent->c_varname (r->name), - tmp_base + stringify (tmpidx), - rvalue->type, - "local variable assignment", rvalue->tok); + if (current_function->locals[i] == r) + lvaluename = "l->" + parent->c_varname (r->name); + + for (unsigned i=0; i<current_function->formal_args.size(); i++) + if (current_function->formal_args[i] == r) + lvaluename = "l->" + parent->c_varname (r->name); + } + if (lvaluename == "") + for (unsigned i=0; i<session->globals.size(); i++) + if (session->globals[i] == r) + { + lvaluename = "global_" + parent->c_varname (r->name); + lock_global = true; + } - o->newline() << tmp_base << tmpidx << ";"; - o->newline(-1) << "})"; - return; - } - } + if (lvaluename == "") + throw semantic_error ("unresolved assignment to ", e->tok); - for (unsigned i=0; i<current_function->formal_args.size(); i++) - { - vardecl* rr = current_function->formal_args[i]; - if (rr == r) // comparison of pointers is sufficient - { - parent->c_assign ("l->" + parent->c_varname (r->name), - tmp_base + stringify (tmpidx), - rvalue->type, - "formal argument assignment", rvalue->tok); + // part 3: "lock(A)" + if (lock_global) + o->newline() << "/* XXX lock " << lvaluename << " */"; - o->newline() << tmp_base << tmpidx << ";"; - o->newline(-1) << "})"; - return; - } - } + // part 4/5 + if (e->type == pe_string) + { + if (pre) + throw semantic_error ("pre assignment on strings not supported", + e->tok); + if (op == "=") + { + o->newline() << "strncpy (" << lvaluename + << ", " << tmpvar + << ", MAXSTRINGLEN);"; + // no need for second copy + resvar = tmpvar; + } + else if (op == ".=") + { + // shortcut two-step construction of concatenated string in + // empty resvar, then copy to tmpvar: instead concatenate + // to lvalue directly, then copy back to resvar + o->newline() << "strncat (" << lvaluename + << ", " << tmpvar + << ", MAXSTRINGLEN);"; + o->newline() << "strncpy (" << resvar + << ", " << lvaluename + << ", MAXSTRINGLEN);"; + } + else + throw semantic_error ("string assignment operator " + + op + " unsupported", e->tok); } - - // it better be a global - for (unsigned i=0; i<session->globals.size(); i++) + else if (e->type == pe_long) { - 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) << "})"; - return; - } + // a lot of operators come through this "gate": + // - vanilla assignment "=" + // - stats aggregation "<<<" + // - modify-accumulate "+=" and many friends + // - pre/post-crement "++"/"--" + + // compute the modify portion of a modify-accumulate + string macop; + unsigned oplen = op.size(); + if (op == "=") + macop = "* 0 +"; // clever (?) trick to select rvalue (tmp) only + else if (oplen > 1 && op[oplen-1] == '=') // for +=, %=, <<=, etc... + macop = op.substr(0, oplen-1); + else if (op == "<<<") + throw semantic_error ("stats aggregation not yet implemented", e->tok); + else if (op == "++") + macop = "+"; + else if (op == "--") + macop = "-"; + else + // internal error + throw semantic_error ("unknown macop for assignment", e->tok); + + // part 4 + if (pre) + o->newline() << resvar << " = " << lvaluename << ";"; + else + o->newline() << resvar << " = " + << lvaluename << " " << macop << " " << tmpvar << ";"; + + // part 5 + if (pre) + o->newline() << lvaluename << " = " + << resvar << " " << macop << " " << tmpvar << ";"; + else + o->newline() << lvaluename << " = " << resvar << ";"; } + else + throw semantic_error ("assignment type not yet implemented", e->tok); - throw semantic_error ("unresolved symbol", e->tok); + // part 6: "unlock(A)" + if (lock_global) + o->newline() << "/* XXX unlock " << lvaluename << " */"; + + // part 7: "res" + o->newline() << resvar << ";"; + o->newline(-1) << "})"; } @@ -1206,13 +1358,11 @@ c_tmpcounter::visit_arrayindex (arrayindex *e) for (unsigned i=0; i<r->index_types.size(); i++) parent->o->newline() << parent->c_typename (r->index_types[i]) - << " __tmp" << tmpvar_counter ++ << ";" - << " /* " << e->base << " idx #" << i << " */"; + << " __tmp" << tmpvar_counter ++ << ";"; // now the result parent->o->newline() << parent->c_typename (r->type) - << " __tmp" << tmpvar_counter ++ << ";" - << " /* " << e->base << "value */"; + << " __tmp" << tmpvar_counter ++ << ";"; for (unsigned i=0; i<e->indexes.size(); i++) e->indexes[i]->visit (this); @@ -1228,6 +1378,8 @@ c_unparser::visit_arrayindex (arrayindex* e) r->index_types.size() != e->indexes.size()) throw semantic_error ("invalid array reference", e->tok); + throw semantic_error ("array read not supported", e->tok); + o->line() << "({"; o->indent(1); @@ -1241,6 +1393,7 @@ c_unparser::visit_arrayindex (arrayindex* e) // reentrancy issues that pop up with nested expressions: // e.g. a[a[c]=5] could deadlock + unsigned tmpidx_base = tmpvar_counter; tmpvar_counter += r->index_types.size() + 1 /* result */; string tmp_base = "l->__tmp"; @@ -1258,23 +1411,6 @@ c_unparser::visit_arrayindex (arrayindex* e) } 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++) - { - if (session->globals[i] == r) - { - // XXX: acquire read lock on global; copy value - // into local temporary - o->line() << "global_" << c_varname (r->name); - return; - } - } - - throw semantic_error ("unresolved symbol", e->tok); -#endif - o->newline() << tmp_base << residx << ";"; o->newline(-1) << "})"; @@ -1289,7 +1425,7 @@ c_tmpcounter_assignment::visit_arrayindex (arrayindex *e) void c_unparser_assignment::visit_arrayindex (arrayindex *e) { - throw semantic_error ("not yet implemented", e->tok); + throw semantic_error ("array write not supported", e->tok); } @@ -1301,8 +1437,7 @@ c_tmpcounter::visit_functioncall (functioncall *e) for (unsigned i=0; i<r->formal_args.size(); i++) parent->o->newline() << parent->c_typename (r->formal_args[i]->type) - << " __tmp" << tmpvar_counter ++ << ";" - << " /* " << e->function << " arg #" << i << " */"; + << " __tmp" << tmpvar_counter ++ << ";"; for (unsigned i=0; i<e->args.size(); i++) e->args[i]->visit (this); |