// cdecl.gr // demonstration of resolving C ident/type ambiguity // cdecl solves it using reduction cancellation (cf. cdecl2) verbatim [ #include // cout #include "trace.h" // trace #include "locstr.h" // LocString #include "strhash.h" // StringHash #include "objlist.h" // ObjList #include "parssppt.h" // ParseTreeAndTokens #define D(msg) \ trace("cdecl") << msg << endl #define R0 return 0 ] // parsing action state context_class ParseEnv : public UserActions { public: StringRef intType; // "int" ObjList types; // stack of hashes which identify names of types public: ParseEnv(StringTable &table); ~ParseEnv(); void enterScope(); void leaveScope(); void addType(StringRef type); bool isType(StringRef name); }; impl_verbatim [ // bit of a hack.. ParseTables *tables; class CCLang; UserActions *makeUserActions(StringTable &table, CCLang &lang) { ParseEnv *ret = new ParseEnv(table); tables = ret->makeTables(); return ret; } ParseTables *make_ParseEnv_tables(); ParseTables *makeParseTables() { return tables; } ParseEnv::ParseEnv(StringTable &table) { intType = table.add("int"); } ParseEnv::~ParseEnv() {} static char const *identity(void *data) { return (char const*)data; } void ParseEnv::enterScope() { types.prepend(new StringHash(identity)); } void ParseEnv::leaveScope() { delete types.removeAt(0); } void ParseEnv::addType(StringRef type) { StringHash *h = types.first(); if (h->get(type)) { cout << "duplicate entry for " << type << " -- will ignore\n"; } else { h->add(type, (void*)type); } } bool ParseEnv::isType(StringRef name) { if (name == intType) { return true; } FOREACH_OBJLIST(StringHash, types, iter) { if (iter.data()->get(name)) { return true; } } return false; } #if 0 void doit(int argc, char **argv) { traceAddSys("progress"); //traceAddSys("parse-tree"); SemanticValue treeTop; ParseTreeAndTokens tree(treeTop); ParseEnv env(tree); treeMain(tree, argc, argv); cout << "final parse result: " << treeTop << endl; } int main(int argc, char **argv) { doit(argc, argv); //malloc_stats(); return 0; } #endif // 0 ] // end impl_verbatim terminals { // grab the lexer's token list include("../../c/c.tok") token[StringRef] L2_NAME { fun dup(s) [ return s; ] fun del() [] } } nonterm[int] Start -> Stmts [ D("exiting scope"); leaveScope(); R0; ] nonterm[int] Stmts { -> empty [ D("entering scope"); enterScope(); R0; ] -> Stmts Stmt [ R0; ] } nonterm[int] Stmt { -> t:TypeName "(" n:VarName ")" ";" [ // declaration D("declaration of " << n << ", type " << t); R0; ] -> f:VarName "(" a:VarName ")" ";" [ // function call D("call of " << f << " with arg " << a); R0; ] -> "typedef" t:TypeName n:L2_NAME ";" [ // typedef: introduce type name D("typedef of " << n << " as type " << t); addType(n); R0; ] -> "{" Stmts "}" [ // scope D("exiting scope"); leaveScope(); R0; ] } nonterm[StringRef] VarName { fun keep(n) [ return !isType(n); ] -> n:L2_NAME [ return n; ] } nonterm[StringRef] TypeName { fun keep(n) [ return isType(n); ] -> n:L2_NAME [ return n; ] // this is a little bit of a hack, but in some sense it's valid // to regard the global strings as another stringtable.. of course, // equality won't work, but I don't need it for the moment -> L2_INT [ return intType; ] }