/** * \file ptree_util.cpp */ INTERFACE: #include #include "ptree_nodes.h" enum { /* pseudo-keywords. OpenC++ doesn't recognize these, but we do. FIXME: translate the tree so that a leaf containing 'wchar_t' will be changed in to the appropriate reserved word. */ WCHAR_T = 9999, RESTRICT, EXPLICIT }; IMPLEMENTATION: #include #include #include #include "ptree_visitor.h" #include "source.h" #include "except.h" using namespace Opencxx; class Flat_maker : public Ptree_visitor { std::vector* v; public: Flat_maker(std::vector* v) : Ptree_visitor(&Source::instance()), v(v) { } int default_action(Ptree* t) { v->push_back(t); return 0; } int visit_nonleaf(NonLeaf* l) { return Ptree_visitor::default_action(l); } int visit_name(Ptree* t) { v->push_back(t); return 0; } }; void flatten_specifier_list(Ptree* tree, /*out*/ std::vector* nodes) { Flat_maker(nodes).visit(tree); } void flatten_ptree(Ptree* tree, /*out*/ std::vector* nodes) { if (!tree) { /* empty */ } else if (tree->IsLeaf()) { nodes->push_back(tree); } else { while (tree) { flatten_ptree(tree->Car(), nodes); tree = tree->Cdr(); } } } /** True iff the given tree is a name. LeafName doesn't respond to "IsA(ntName)". D'ooh! */ bool ptree_is_name(Ptree* tree) { return tree->IsA(ntName) || dynamic_cast(tree); } /** Convert an expression [[[a , b] , c] , d] into [a , b , c , d]. This is needed for expressions: "(foo)(1, 2, 3)" is parsed as [(foo) ( [[1 , 2] , 3] )] whereas the correct parse would be [[( foo )] ( [1 , 2 , 3] )]. */ Ptree* convert_comma_expr_to_list(Ptree* input) { Ptree* out = 0; while (PtreeCommaExpr* cx = dynamic_cast(input)) { out = Ptree::Cons(cx->Second(), Ptree::Cons(cx->Third(), out)); input = cx->First(); } out = Ptree::Cons(input, out); return out; } static Ptree* do_function(Ptree* lhs, Ptree* lpar, Ptree* args, Ptree* rpar) { Ptree* args_in = args; Ptree* args_out = 0; for (Ptree* p = args_in; p != 0; p = p->Cdr()) { if (p->Car()->Eq(',')) { args_out = Ptree::Snoc(args_out, p->Car()); } else { Ptree* pair = p->Car(); assert(pair->Length() == 2); args_out = Ptree::Snoc(args_out, convert_decl_to_expr(pair->First(), pair->Second())); } } return new PtreeFuncallExpr(lhs, Ptree::List(lpar, args_out, rpar)); } Ptree* convert_node_to_name(Ptree* p) { if (p->IsLeaf()) { Token tmp_tok = { p->GetPosition(), p->GetLength(), ntName }; return new LeafName(tmp_tok); } else { Encoding tmp_enc; return new PtreeName(p, tmp_enc); } } /** Convert a declaration (consisting of a type-specifier lhs and a declarator side rhs) into an expression. */ Ptree* convert_decl_to_expr(Ptree* lhs, Ptree* rhs) { /* lhs is a name, rhs is a declarator containing "[ x ]" or "( [list] )" */ /* first, convert lhs into a Name */ lhs = convert_node_to_name(lhs); /* now run through the declarator */ std::vector binop_list; Ptree* dlist = rhs; while (dlist && dlist->Car()) { Ptree* ele = dlist->Car(); if (ele->Eq('*') || ele->Eq('&')) { /* "* NAME" or "& NAME" */ if (!dlist->Cdr() || !dlist->Second()) compile_error("don't understand this expression"); Ptree* name = dlist->Second(); if (name->IsLeaf() && (name->Eq('(') || name->Eq('[') || name->Eq(':') || name->Eq('=') || name->Eq('*') || name->Eq(')') || name->IsA(CONST) || name->IsA(VOLATILE) || name->Eq("restrict"))) compile_error("don't understand this expression"); binop_list.push_back(lhs); binop_list.push_back(ele); lhs = convert_node_to_name(name); dlist = dlist->Cdr()->Cdr(); } else if (ele->Eq('[')) { /* "LHS [ x ]" */ expect_ptree(dlist->Third(), ']'); if (!dlist->Second()) compile_error("don't understand this array expression"); lhs = new PtreeArrayExpr(lhs, Ptree::List(ele, dlist->Second(), dlist->Third())); dlist = dlist->Cdr()->Cdr()->Cdr(); } else if (ele->Eq('(')) { /* "LHS ( list )" */ expect_ptree(dlist->Third(), ')'); lhs = do_function(lhs, ele, dlist->Second(), dlist->Third()); dlist = dlist->Cdr()->Cdr()->Cdr(); } else if (!ele->IsLeaf() && ele->Car()->Eq('(')) { /* also appears sometimes */ expect_ptree(ele->Third(), ')'); lhs = do_function(lhs, ele->Car(), ele->Second(), ele->Third()); dlist = dlist->Cdr(); } else { dlist->Display(); compile_error("don't understand this funky expression"); } } /* process pending "*" and "&" operators */ while (!binop_list.empty()) { Ptree* op = binop_list.back(); binop_list.pop_back(); Ptree* arg = binop_list.back(); binop_list.pop_back(); lhs = new PtreeInfixExpr(arg, Ptree::List(op, lhs)); } return lhs; }