/** * \file annotator.cpp * \author Stefan Reuther */ INTERFACE: #include "ptree_visitor.h" #include "paranoid_visitor.h" #include "type_rep.h" #define HACK_EXPLICIT(typespec, storagespec) \ if (typespec->Eq("explicit")) { \ storagespec = Ptree::Snoc(storagespec, typespec); \ typespec = 0; \ } class Source; class Symbol_table; class Abstract_scope; class Block_scope; class Variable_symbol; class Expr_result; typedef int Annotator_RT; class Annotator : public Paranoid_visitor { Abstract_scope* current_scope; Block_scope* current_block; Ptree* output; public: }; IMPLEMENTATION: #include #include "ptree_util.h" #include "decl_read.h" #include "symbol_table.h" #include "downcast.h" #include "scope.h" #include "expr_annotator.h" #include "function.h" #include "namespace.h" #include "typedef.h" #include "variable.h" #include "symbol_name.h" #include "block.h" #include "implicit_conversion.h" #include "class.h" #include "template.h" /******************************* Annotator *******************************/ PUBLIC Annotator::Annotator(Source* s, Abstract_scope* scope) : Paranoid_visitor(s), Ptree_visitor(s), current_scope(scope), current_block(0), output(0) { assert(!dynamic_cast(scope)); } PUBLIC Annotator::Annotator(Source* s, Block_scope* scope) : Paranoid_visitor(s), Ptree_visitor(s), current_scope(scope), current_block(scope), output(0) { } class Simple_declaration_reader : public Declaration_reader { Storage_class_specifier storage; Function_specifier_set func; Source* source; Ptree* func_defn; Annotator* annotator; bool seen_var; Variable_symbol* seen_vsym; public: /* for variables */ Simple_declaration_reader(Abstract_scope* scope, Source* source, Annotator* annotator) : Declaration_reader(scope), storage(s_None), func(), source(source), func_defn(0), annotator(annotator), seen_var(false), seen_vsym(0) { } /* for functions */ Simple_declaration_reader(Abstract_scope* scope, Source* source, Arg_vec* args, Ptree* func_defn) : Declaration_reader(scope, args), storage(s_None), func(), source(source), func_defn(func_defn), annotator(0), seen_var(false), seen_vsym(0) { } Variable_symbol* get_vsym() const { return seen_vsym; } }; PUBLIC void Simple_declaration_reader::parse_specifiers(Ptree* tree) { ::parse_specifiers(tree, &storage, &func); } PUBLIC void Simple_declaration_reader::declare_variable(Type type, Ptree* name, Ptree* initializer, Ptree* bitsize) { if (type.get_kind() == Type::k_Function) { Function_specifier_set this_fs_set = func; Storage_class_specifier this_ss = storage; Symbol_name sym_name(name, get_scope(), true); if (sym_name.is_template()) compile_error("FIXME: template functions not yet supported"); if (!name) compile_error("unnamed functions are not allowed"); if (bitsize) compile_error("functions can't have bitsizes"); if (initializer) { if (initializer->Car()->Eq('=') && initializer->Second()->Eq('0')) { this_fs_set |= f_Abstract; initializer = 0; } else if (initializer->Car()->Eq(':')) { if (sym_name.get_kind() != Symbol_name::k_Constructor) compile_error("member initializer list only valid for constructors"); } else { compile_error("can't initialize a function"); } } switch(sym_name.get_kind()) { case Symbol_name::k_Alloc: if (dynamic_cast(get_scope())) { if (this_ss != s_None && this_ss != s_Static) compile_error("no storage class allowed for allocation function"); this_ss = s_Static; } else { if (this_ss != s_Extern && this_ss != s_None) compile_error("no storage class allowed for allocation function"); if (get_scope()->get_parent()) compile_error("allocation functions only allowed at global scope"); this_ss = s_Extern; } /* FALLTHROUGH */ case Symbol_name::k_Operator: case Symbol_name::k_Normal: if (type.get_return_type() == ctor_type) compile_error("need a return type for `" + sym_name.get_name() + "'"); break; case Symbol_name::k_Constructor: if (type.get_return_type() != ctor_type) compile_error("constructors can't have return types"); break; case Symbol_name::k_Destructor: if (type.get_return_type() != ctor_type) compile_error("destructors can't have return types"); break; case Symbol_name::k_Conversion: /* these don't have a declaration type. Make a faked type, so that "operator T()" is turned into "T __cvt(T*)", and "operator T&()" to "T __cvt(T&)". The dummy argument is for name mangling and overloading. It must be a pointer or reference so that add_parameter doesn't try to be smart. */ { if (type.get_num_function_args() != 0 || type.get_return_type() != ctor_type) compile_error("invalid type `" + type.get_human_readable_type() + "' for conversion operator"); Function_type_maker m; if (sym_name.get_type().get_kind() != Type::k_Reference) m.add_parameter(sym_name.get_type().make_pointer_type()); else m.add_parameter(sym_name.get_type()); Type tmp = m.make_function_type(sym_name.get_type()); tmp.copy_qualifiers(type); type = tmp; } break; } Function_signature* fsig = get_scope()->add_function_decl(this_ss, this_fs_set, type, sym_name); if (func_defn) { Block_scope* block = new Block_scope(fsig); Arg_vec* args = get_args(); for (unsigned i = 0; i < args->size(); ++i) block->add_variable(s_Parameter, (*args)[i].first, (*args)[i].second, 0, 0); get_scope()->add_function_implementation(fsig, block, func_defn, initializer); } func_defn = 0; } else { if (func) compile_error("function specifiers make no sense for variables"); if (type.is_void()) compile_error("can't define variables of type `void'"); Variable_symbol* vsym = get_scope()->add_variable(storage, type, name, initializer, bitsize); if (vsym && annotator) annotator->add_output(make_declaration(vsym)); if (vsym) { if (!seen_var) seen_var = true, seen_vsym = vsym; else seen_vsym = 0; } } } /** Name declaration. \param storagespec list of static/mutable/friend/virtual/inline/extern \param typespec list of type specifiers and cv-qualifiers, or type definition \param decllist list of declarators, separated by comma */ PUBLIC Annotator_RT Annotator::visit_name_declaration(Ptree* storagespec, Ptree* typespec, Ptree* decllist) { if (storagespec && (storagespec->Eq("friend") || storagespec->Car()->Eq("friend"))) { // FIXME? I think we can ignore friends because we don't do protection return 0; } // HACK around OpenC++ limitations: HACK_EXPLICIT(typespec, storagespec); Type type = parse_type(typespec, current_scope, 0, false); Simple_declaration_reader sdr(current_scope, get_source(), this); sdr.parse_specifiers(storagespec); sdr.parse_declarator_list(type, decllist); process_pending(); return 0; } PUBLIC Annotator_RT Annotator::visit_function(Ptree* storagespec, Ptree* typespec, PtreeDeclarator* decl, PtreeBlock* block) { HACK_EXPLICIT(typespec, storagespec); Type type = parse_type(typespec, current_scope, 0, false); Declaration_reader::Arg_vec args; Simple_declaration_reader sdr(current_scope, get_source(), &args, block); sdr.parse_specifiers(storagespec); sdr.parse_declarator(type, decl); process_pending(); return 0; } PUBLIC Annotator_RT Annotator::visit_templatedecl(PtreeTemplateDecl* p) { expect_ptree(p->Car(), "template"); expect_ptree(p->Second(), '<'); expect_ptree(p->Nth(3), '>'); ::visit_template(p->Third(), p->Nth(4), current_scope); process_pending(); return 0; } /************************* Linkage specification *************************/ PUBLIC Annotator_RT Annotator::visit_linkagespec(PtreeLinkageSpec* p) { expect_ptree(p->First(), "extern"); return visit(p->Third()); } PUBLIC Annotator_RT Annotator::visit_brace(PtreeBrace* p) { assert(!is_code()); expect_ptree(p->First(), '{'); expect_ptree(p->Third(), '}'); for (Ptree* content = p->Second(); content; content = content->Cdr()) visit_and_catch(content->Car()); return 0; } /******************************** Typedef ********************************/ /** Figure out the name of a typedef alias. When defining an alias to an unnamed type, that unnamed type is named by the typedef name (7.1.3p5). We simply plug an "int" into parse_declarator_list, and if we get out an "int" again, we found our type. */ class Typedef_name_reader : public Declaration_reader { Ptree* name_out; public: Typedef_name_reader(Abstract_scope* scope) : Declaration_reader(scope), name_out(0) { } Ptree* get_name() const { return name_out; } }; PUBLIC void Typedef_name_reader::declare_variable(Type type, Ptree* name, Ptree*, Ptree*) { if (name && type == int_type && !name_out) name_out = name; } /** Read typedef declaration. */ class Typedef_declaration_reader : public Declaration_reader { public: Typedef_declaration_reader(Abstract_scope* scope) : Declaration_reader(scope) { } }; PUBLIC void Typedef_declaration_reader::declare_variable(Type type, Ptree* name, Ptree* initializer, Ptree* bitsize) { if (!name) compile_error("typedef without a name makes no sense"); if (initializer || bitsize) compile_error("typedef can't have initializer or bitsize"); if (!name->IsLeaf()) { compile_error("complicated name not allowed in typedef"); } else { std::string my_name = name->ToString(); Symbol_pair p = get_scope()->lookup_here(my_name, true); /* if there is already a thing named identically, our typedef must refer there. */ if (p.tag) if (type.get_kind() != Type::k_Userdef || p.tag != type.get_type_symbol()) compile_error("typedef `" + my_name + "' conflicts with other type of the same name"); /* redefinition? allowed according to 7.1.3p2 */ if (Typedef_symbol* sym = dynamic_cast(p.untag)) { if (sym->get_type() != type) compile_error("`" + my_name + "' redefined to different type"); return; } /* add it */ Typedef_symbol* tdsym = new Typedef_symbol(type); get_scope()->add_symbol(my_name, tdsym); /* a typedef-name that names a class is a class-name, 7.1.3p4. this occupies the tag slot of the symbol table entry, so noone can put a class there. */ if (type.get_kind() == Type::k_Userdef) { Type_symbol* sym = type.get_type_symbol(); if (!p.tag) Symbol_table::get_instance().set_peer(tdsym, sym); } } } PUBLIC Annotator_RT Annotator::visit_typedef(PtreeTypedef* p) { /* [typedef type-specifier-list declarator-list ;] */ Ptree* typespec = p->Second(); Ptree* decllist = p->Third(); /* figure out the name for anonymous class definitions */ Typedef_name_reader nr(current_scope); nr.parse_declarator_list(int_type, decllist); /* parse actual typedef */ Type type = parse_type(typespec, current_scope, nr.get_name(), false); Typedef_declaration_reader tdr(current_scope); tdr.parse_declarator_list(type, decllist); process_pending(); return 0; } /** Type declaration, i.e.\ lone "class Foo" in program. */ PUBLIC Annotator_RT Annotator::visit_type_declaration(Ptree* storagespec, Ptree* typespec) { if (storagespec && (storagespec->Eq("friend") || storagespec->Car()->Eq("friend"))) { // FIXME? I think we can ignore friends because we don't do protection return 0; } if (storagespec) bogus_ptree_error("type declarations may not have storage specifiers", storagespec); if (!typespec) compile_warning("stray `;' in program", storagespec); else parse_type(typespec, current_scope, 0, true); process_pending(); return 0; } /** Access specifier (public/private/protected). We happily ignore these. Access checks are done by the compiler, so we only get programs where all access checks work. */ PUBLIC Annotator_RT Annotator::visit_accessspec(PtreeAccessSpec* p) { /* ignore */ return 0; } PUBLIC Annotator_RT Annotator::visit_namespacespec(PtreeNamespaceSpec* p) { /* [namespace name [{ [content] }] */ Ptree* nametree = p->Second(); Ptree* brace = p->Third(); expect_ptree(brace->First(), '{'); Ptree* content = brace->Second(); /* first, make a namespace node */ std::string name = nametree ? nametree->ToString() : Symbol_name::get_unnamed_namespace_name(); Symbol_pair pair = current_scope->lookup_here(name, true); Namespace_symbol* sym; Namespace_scope* current_ns = downcast(current_scope); if (pair && pair.untag->get_kind() == Symbol::k_Namespace) { /* we already know this namespace */ sym = downcast(pair.untag); } else if (pair.untag) { compile_error("can't define namespace `" + name + "' because we already have something named alike"); return 0; } else { sym = new Namespace_symbol(); current_scope->add_symbol(name, sym); } if (content) { Annotator x(get_source(), new Namespace_scope(current_ns, sym)); x.visit(content); add_output_list(x.get_output()); } return 0; } PUBLIC Annotator_RT Annotator::visit_nonleaf(NonLeaf* p) { for (Ptree* i = p; i != 0; i = i->Cdr()) visit_and_catch(i->Car()); return 0; } PUBLIC Annotator_RT Annotator::visit_using(PtreeUsing* p) { // [using namespace LEAF ;] // [using namespace [q-name] ;] // [using nil [qname] ;] if (p->Second()) { /* "using namespace" is allowed at namespace or block scope */ bogus_ptree_error("FIXME: `using' doesn't work yet", p); // ISO 14882 p.115ff } else { bogus_ptree_error("FIXME: `using non-namespace' doesn't work yet", p); } return 0; } /********************************** Code *********************************/ PUBLIC void Annotator::visit_stmt_or_block(Ptree* p) { if (dynamic_cast(p)) { for (Ptree* q = p->Second(); q; q = q->Cdr()) visit_and_catch(q->Car()); } else { visit(p); } } /** Visit a block. [ list-of-things ] */ PUBLIC Annotator_RT Annotator::visit_block(PtreeBlock* p) { assert(is_code()); expect_ptree(p->First(), '{'); expect_ptree(p->Third(), '}'); Annotator anno(get_source(), new Block_scope(current_block, false)); for (Ptree* q = p->Second(); q; q = q->Cdr()) anno.visit_and_catch(q->Car()); add_output(anno.get_output_as_block()); return 0; } PUBLIC Annotator_RT Annotator::visit_do(PtreeDoStatement* p) { /* [do stmt while ( expr ) ;] */ assert(is_code()); expect_ptree(p->First(), "do"); expect_ptree(p->Third(), "while"); expect_ptree(p->Nth(3), '('); expect_ptree(p->Nth(5), ')'); expect_ptree(p->Nth(6), ';'); Expr_result result = Expr_annotator(current_scope, get_source()).visit(p->Nth(4)); Implicit_conversion* ics = generate_implicit_conversion(result, bool_type, 0, true /* user-defined */, true /* copy init */, false /* not IOA */); if (!ics) compile_error("`do while' condition not convertible to `bool'"); Annotator anno(get_source(), new Block_scope(current_block, false)); anno.visit_stmt_or_block(p->Second()); add_output(new PtreeDoStatement(p->First(), Ptree::List(anno.get_output_as_block(), p->Nth(2), p->Nth(3), ics->make_tree(result).get_tree(), p->Nth(5), p->Nth(6)))); return 0; } PUBLIC Annotator_RT Annotator::visit_while(PtreeWhileStatement* p) { /* [while ( expr ) stmt] */ assert(is_code()); expect_ptree(p->First(), "while"); expect_ptree(p->Second(), '('); expect_ptree(p->Nth(3), ')'); if (p->Third()->IsA(Opencxx::ntDeclaration)) { /* all_anno will contain the body of the "while", i.e. the declaration, if, statement */ Annotator all_anno(get_source(), new Block_scope(current_block, false)); Variable_symbol* vsym = all_anno.parse_condition(p->Third()); /* convert the condition to bool */ Expr_result cond(make_name(vsym), vsym->get_type().sans_reference(), Expr_result::k_LValue); Implicit_conversion* ics = generate_implicit_conversion(cond, bool_type, 0, true /* user-defined */, true /* copy init */, false /* not IOA */); if (!ics) compile_error("`if' condition not convertible to `bool'"); /* construct the if */ all_anno.add_output(new PtreeIfStatement(make_static_leaf("if"), Ptree::List(make_static_leaf("("), make_prefix_expr(bool_type, make_static_leaf("!"), ics->make_tree(cond).get_tree()), make_static_leaf(")"), new PtreeBrace(make_static_leaf("{"), Ptree::List(Ptree::List(new PtreeBreakStatement(make_static_leaf("break"), Ptree::List(make_static_leaf(";")))), make_static_leaf("}")))))); all_anno.visit_stmt_or_block(p->Nth(4)); Leaf true_leaf("true", 4); add_output(new PtreeWhileStatement(p->First(), Ptree::List(p->Second(), new Annotated(bool_type, 0, true_leaf), p->Nth(3), all_anno.get_output_as_block()))); } else { Expr_result result = Expr_annotator(current_scope, get_source()).visit(p->Third()); Implicit_conversion* ics = generate_implicit_conversion(result, bool_type, 0, true /* user-defined */, true /* copy init */, false /* not IOA */); if (!ics) compile_error("`while' condition not convertible to `bool'"); Annotator anno(get_source(), new Block_scope(current_block, false)); anno.visit_stmt_or_block(p->Nth(4)); add_output(new PtreeWhileStatement(p->First(), Ptree::List(p->Second(), ics->make_tree(result).get_tree(), p->Nth(3), anno.get_output_as_block()))); } return 0; } PRIVATE Variable_symbol* Annotator::parse_condition (Ptree* decl) { Ptree* storagespec = decl->First(); Ptree* typespec = decl->Second(); Type type = parse_type(typespec, current_scope, 0, false); Simple_declaration_reader sdr(current_scope, get_source(), this); sdr.parse_specifiers(storagespec); sdr.parse_declarator_list(type, decl->Third()); if (!sdr.get_vsym()) compile_error("invalid condition in if/while/switch"); return sdr.get_vsym(); } PUBLIC Annotator_RT Annotator::visit_if (PtreeIfStatement* p) { /* [if ( expr ) stmt] [if ( expr ) stmt else stmt] */ assert(is_code()); expect_ptree(p->First(), "if"); expect_ptree(p->Second(), '('); expect_ptree(p->Nth(3), ')'); if (p->Third()->IsA(Opencxx::ntDeclaration)) { Annotator all_anno(get_source(), new Block_scope(current_block, false)); Variable_symbol* vsym = all_anno.parse_condition(p->Third()); Expr_result cond(make_name(vsym), vsym->get_type().sans_reference(), Expr_result::k_LValue); all_anno.process_if(cond, p, true); add_output(all_anno.get_output_as_block()); } else { Expr_result cond = Expr_annotator(current_block, get_source()).visit(p->Third()); process_if(cond, p, false); } return 0; } PRIVATE void Annotator::process_if(const Expr_result& cond, PtreeIfStatement* p, bool inherit) { Implicit_conversion* ics = generate_implicit_conversion(cond, bool_type, 0, true /* user-defined */, true /* copy init */, false /* not IOA */); if (!ics) compile_error("`if' condition not convertible to `bool'"); Annotator then_anno(get_source(), new Block_scope(current_block, inherit)); then_anno.visit_stmt_or_block(p->Nth(4)); Ptree* rv = new PtreeIfStatement(p->First(), Ptree::List(p->Second(), ics->make_tree(cond).get_tree(), p->Nth(3), then_anno.get_output_as_block())); if (p->Length() > 5) { expect_ptree(p->Nth(5), "else"); Annotator else_anno(get_source(), new Block_scope(current_block, inherit)); else_anno.visit_stmt_or_block(p->Nth(6)); Ptree::Snoc(rv, p->Nth(5)); Ptree::Snoc(rv, else_anno.get_output_as_block()); } add_output(rv); } /** Expression or null statement. */ PUBLIC Annotator_RT Annotator::visit_exprstatement(PtreeExprStatement* p) { assert(is_code()); expect_ptree(p->Second(), ';'); if (p->First()) { /* first might be null, empty statement */ Expr_result res = Expr_annotator(current_scope, get_source()).visit(p->First()); if (!res.is_value()) compile_error("invalid expression statement"); add_output(new PtreeExprStatement(res.get_tree(), p->Cdr())); } return 0; } PUBLIC Annotator_RT Annotator::visit_for(PtreeForStatement* p) { /* [for ( statement expr-or-null ; expr-or-null ) stmt] */ /* translate this into { statement for ( ; e ; e ) stmt } */ expect_ptree(p->First(), "for"); expect_ptree(p->Second(), '('); expect_ptree(p->Nth(4), ';'); expect_ptree(p->Nth(6), ')'); Block_scope* outer_scope = new Block_scope(current_block, false); Block_scope* inner_scope = new Block_scope(outer_scope, true); /* visit first part of the statement */ Annotator anno(get_source(), outer_scope); anno.visit(p->Third()); Ptree* out = new PtreeForStatement(p->First(), Ptree::List(p->Second(), make_null_statement())); /* visit second part */ if (p->Nth(3)) { Expr_result result = Expr_annotator(outer_scope, get_source()).visit(p->Nth(3)); if (!result.is_value()) compile_error("invalid second parameter to `for'"); Implicit_conversion* ics = generate_implicit_conversion(result, bool_type, 0, true, true, false); if (!ics) compile_error("`for' expects `bool'"); Ptree::Snoc(out, ics->make_tree(result).get_tree()); } else { Ptree::Snoc(out, 0); } Ptree::Snoc(out, p->Nth(4)); /* visit third part */ if (p->Nth(5)) { Expr_result result = Expr_annotator(outer_scope, get_source()).visit(p->Nth(5)); if (!result.is_value()) compile_error("invalid third parameter to `for'"); Ptree::Snoc(out, result.get_tree()); } else { Ptree::Snoc(out, 0); } Ptree::Snoc(out, p->Nth(6)); /* visit statement */ Annotator ianno(get_source(), inner_scope); ianno.visit_stmt_or_block(p->Nth(7)); Ptree::Snoc(out, ianno.get_output_as_block()); anno.add_output(out); add_output(anno.get_output_as_block()); return 0; } PUBLIC Annotator_RT Annotator::visit_return(PtreeReturnStatement* p) { assert(is_code()); Type rt = current_block->get_function()->get_return_type(); expect_ptree(p->First(), "return"); if (p->Length() == 2) { /* "return;" */ expect_ptree(p->Second(), ';'); if (rt.is_void() || rt.is_same_unqualified_type(ctor_type)) /* accept */; else compile_error("return without parameter in function returning non-void"); add_output(p); return 0; } else { /* "return EXPR;" */ expect_ptree(p->Third(), ';'); Expr_result res = Expr_annotator(current_scope, get_source()).visit(p->Second()); if (rt.is_void() || rt.is_same_unqualified_type(ctor_type)) { /* return type void <-> expression must have type void */ if (!res.is_value() || !res.get_type().is_void()) compile_error("invalid type for `return'"); add_output(new PtreeExprStatement(res.get_tree(), Ptree::List(make_static_leaf(";")))); add_output(new PtreeReturnStatement(p->First(), Ptree::List(p->Third()))); } else { /* non-void <-> convert type accordingly */ Implicit_conversion* ics = generate_implicit_conversion(res, rt, 0, true /* with user-defined */, true /* is copy-init */, false /* not IOA */); if (!ics) compile_error("unable to convert `" + res.get_type().get_human_readable_type() + "' into `" + rt.get_human_readable_type() + "'"); add_output(new PtreeReturnStatement(p->First(), Ptree::List(ics->make_tree(res).get_tree(), p->Third()))); } return 0; } } /********************************* Switch ********************************/ PRIVATE void Annotator::process_switch(Expr_result& res, PtreeSwitchStatement* p, bool inherit) { if (res.get_type().is_class_type()) { /* 6.4.2p2: class type with one conversion function to integral or enumeration type */ Conversion_op_map com; enumerate_conversion_ops(res, &com); Conversion_op_map::iterator found = com.end(), i; Type found_type; for (i = com.begin(); i != com.end(); ++i) { Type t = i->first->get_return_type().sans_reference().get_unqualified_type(); if (t.is_int() || t.is_enum_type()) { if (found != com.end() || i->second != 1) compile_error("conversion to scalar is ambiguous for `" + res.get_type().get_human_readable_type() + "' in `switch'"); found = i; found_type = t; } } if (found == com.end()) compile_error("no conversion to scalar for `switch'"); Implicit_conversion* ics = generate_implicit_conversion(res, found_type, 0, true /* userdef */, true /* copy-init */, false /* IOA */); if (!ics) compile_error("can't convert `" + res.get_type().get_human_readable_type() + "' into `" + found_type.get_human_readable_type() + "' for `switch'"); res = ics->make_tree(res); } if (!res.get_type().is_int() && !res.get_type().is_enum_type()) compile_error("argument to `switch' is not scalar"); Annotator anno(get_source(), new Block_scope(current_block, inherit)); anno.visit_stmt_or_block(p->Nth(4)); add_output(new PtreeSwitchStatement(p->First(), Ptree::List(p->Second(), res.get_tree(), p->Nth(3), anno.get_output_as_block()))); } PUBLIC Annotator_RT Annotator::visit_switch(PtreeSwitchStatement* p) { expect_ptree(p->First(), "switch"); expect_ptree(p->Second(), '('); expect_ptree(p->Nth(3), ')'); if (p->Third()->IsA(Opencxx::ntDeclaration)) { Annotator all_anno(get_source(), new Block_scope(current_block, false)); Variable_symbol* vsym = all_anno.parse_condition(p->Third()); Expr_result cond(make_name(vsym), vsym->get_type().sans_reference(), Expr_result::k_LValue); all_anno.process_switch(cond, p, true); add_output(all_anno.get_output_as_block()); } else { Expr_result res = Expr_annotator(current_scope, get_source()).visit(p->Third()); if (!res.is_value()) compile_error("invalid `switch' expression"); process_switch(res, p, false); } return 0; } /******************************* Goto & Co. ******************************/ static PtreeExprStatement* make_null_statement() { return new PtreeExprStatement(0, Ptree::List(make_static_leaf(";"))); } PUBLIC Annotator_RT Annotator::visit_label(PtreeLabelStatement* lbl) { /* [name : stmt] translate these into [label-form : ExprStatement@[null ;]] */ expect_ptree(lbl->Second(), ':'); add_output(new PtreeLabelStatement(lbl->First(), Ptree::List(lbl->Second(), make_null_statement()))); visit(lbl->Third()); return 0; } PUBLIC Annotator_RT Annotator::visit_default(PtreeDefaultStatement* lbl) { expect_ptree(lbl->First(), "default"); expect_ptree(lbl->Second(), ':'); add_output(new PtreeDefaultStatement(lbl->First(), Ptree::List(lbl->Second(), make_null_statement()))); visit(lbl->Third()); return 0; } PUBLIC Annotator_RT Annotator::visit_case(PtreeCaseStatement* c) { expect_ptree(c->First(), "case"); expect_ptree(c->Third(), ':'); Expr_result res = Expr_annotator(current_scope, get_source()).visit(c->Second()); if (!res.is_value() || !(res.get_type().is_int() || res.get_type().is_enum_type())) compile_error("invalid `case' label type"); // FIXME: maybe cast this to the enum selector's type add_output(new PtreeLabelStatement(c->First(), Ptree::List(res.get_tree(), c->Third(), make_null_statement()))); visit(c->Nth(3)); return 0; } PUBLIC Annotator_RT Annotator::visit_goto(PtreeGotoStatement* g) { expect_ptree(g->First(), "goto"); expect_ptree(g->Third(), ';'); add_output(g); return 0; } PUBLIC Annotator_RT Annotator::visit_continue(PtreeContinueStatement* c) { expect_ptree(c->First(), "continue"); expect_ptree(c->Second(), ';'); add_output(c); return 0; } PUBLIC Annotator_RT Annotator::visit_break(PtreeBreakStatement* b) { expect_ptree(b->First(), "break"); expect_ptree(b->Second(), ';'); add_output(b); return 0; } /***************************** Administrivia *****************************/ /** Process pending stuff. Call this after every nontrivial operation. In particular, this processes the deferred member function definitions. */ PUBLIC void Annotator::process_pending() { current_scope->process_pending(); } /** Add a node to the output list. */ PUBLIC void Annotator::add_output(Ptree* node) { assert(node); output = Ptree::Snoc(output, node); } /** Add a list of nodes to the output list. */ PUBLIC void Annotator::add_output_list(Ptree* nodes) { if (nodes) { assert(!nodes->IsLeaf()); output = Ptree::Append(output, nodes); } } /** Get output list accumulated so far. */ PUBLIC inline Ptree* Annotator::get_output() const { return output; } /** Get output list accumulated so far, wrapped into a PtreeBlock. */ PUBLIC PtreeBlock* Annotator::get_output_as_block() const { return new PtreeBlock(make_static_leaf("{"), Ptree::List(get_output(), make_static_leaf("}"))); } /** True iff we are inside code, false at namespace/class scope. */ PUBLIC inline bool Annotator::is_code() const { return current_block; }