%{ #include "gcg.h" #include "parse.h" #define YYDEBUG 1 static Package* current_package; Module* current_module; static ObjectDef* current_class; static Method* current_method; static PrimType* root_class; static GSList* imports_list; %} %union { GSList* list; Id id; GString* str; PrimType* primtype; MethodKind methkind; DataMemberKind datakind; MethProtection methprot; DataProtection dataprot; MethodKind kind; Def* def; ObjectDef* class_def; Member* member; Param* param; EmitDef emit_def; gboolean bool; Type type; TypeKind fund_type; }; %token T_MODULE %token T_ENUM %token T_FLAGS %token T_READ_WRITE %token T_READ_ONLY %token T_PRIVATE %token T_PROTECTED %token T_PUBLIC %token T_CLASS %token T_PRE_EMIT %token T_POST_EMIT %token T_DUAL_EMIT %token T_SCOPE %token T_ABSTRACT %token T_EMPTY %token T_DIRECT %token T_STATIC %token T_CONST %token T_TYPE %token T_END %token T_OPEN_B %token T_POINTER %token T_NOTNULLPTR %token T_CLOSE_B %token T_INHERITANCE %token T_ATTRIBUTE %token T_HEADER %token T_OPEN_P %token T_HEADER %token T_CLOSE_P %token T_COMMA %token T_IMPORT %token T_OPAQUE %token T_VOID %token T_INT %token T_DOUBLE %token T_BOXED %token T_SIGNAL %token T_FOREIGN %token T_PACKAGE %token T_ROOT %token T_CHAR %token T_IDENT %token T_HEADERNAME %token T_STRING %type maybeident %type ident %type headerdef %type fundtype %type type %type typeorvoid %type semitype %type primtype %type parent %type paramlist %type idlist %type methkind %type datakind %type methprot %type dataprot %type classbody %type flagsdef %type enumdef %type classdef %type def %type paramtail %type param %type docstring %type member_def %type data_member_def %type method_def %type emitdef %type const_def; %% /* Grammar rules and actions follow */ start_symbol: deffile ; deffile: declarations definitions; declarations: /* empty */ | declarations package | declarations rootdef; rootdef: T_ROOT primtype T_END { if($2->kind != TYPE_OBJECT) g_error("Bad root type: %s.%s", $2->module->package->name, $2->name); root_class = $2; }; definitions: current_module_def deflist; deflist: /* empty */ | deflist def { put_def($2); } | deflist import; import: T_IMPORT importlist T_END; importlist: ident { Package* p = get_pkg($1); if(!p) g_error("Attempt to import unknown package %s", $1); imports_list = g_slist_prepend(imports_list, p); } | importlist T_COMMA ident { Package* p = get_pkg($3); if(!p) g_error("Attempt to import unknown package %s", $3); imports_list = g_slist_prepend(imports_list, p); } package: T_PACKAGE maybeident headerdef T_OPEN_B { Package* p; Id i = $2; if(!i) i = GET_ID(""); p = get_pkg(i); if(!p){ p = g_new(Package, 1); p->name = i; p->type_hash = g_hash_table_new(NULL, NULL); p->mod_hash = g_hash_table_new(NULL, NULL); p->headerbase = $3; put_pkg(p); } current_package = p; } modulelist T_CLOSE_B { current_package = NULL; }; current_module_def: T_MODULE ident T_SCOPE ident T_END { Package* p = get_pkg($2); Module* m; if(!p) g_error("Unknown package %s", $2); m = get_mod(p, $4); if(!m) g_error("Unknown module %s.%s", $2, $4); current_module = m; } modulelist: /* empty */ | modulelist simpledecl | modulelist module; headerdef: /* empty */ { $$ = NULL; }| T_HEADERNAME; maybeident: ident | /* empty */ { $$ = NULL; }; module: T_MODULE maybeident headerdef T_OPEN_B { Module* m = get_mod(current_package, $2); if(!m){ m = g_new(Module, 1); m->package = current_package; m->name = $2; m->header = $3; put_mod(m); } current_module = m; } decllist T_CLOSE_B { current_module = NULL; }; decllist: /* empty */ | decllist decl; decl: simpledecl ;/* | classdecl | opaquedecl | protclassdecl;*/ fundtype: T_INT { $$ = TYPE_INT; } | T_DOUBLE { $$ = TYPE_DOUBLE; } | T_CLASS { $$ = TYPE_OBJECT; } | T_ENUM { $$ = TYPE_ENUM; } | T_FLAGS { $$ = TYPE_FLAGS; } | T_BOXED { $$ = TYPE_BOXED; } | T_FOREIGN { $$ = TYPE_FOREIGN; } | T_CHAR { $$ = TYPE_CHAR; }; simpledecl: fundtype ident T_END { PrimType* t = g_new(PrimType, 1); if(current_module) t->module = current_module; else{ Module* m; g_assert(!get_mod(current_package, $2)); m = g_new(Module, 1); m->package = current_package; m->name = $2; m->header = NULL; put_mod(m); t->module = m; } t->name = $2; t->kind = $1; put_type(t); }; semitype: const_def primtype { $$.is_const = $1; $$.indirection = 0; $$.notnull = FALSE; $$.prim = $2; } | semitype T_POINTER { $$ = $1; $$.indirection++; }; type: semitype { if(!$$.indirection){ g_assert($$.prim->kind != TYPE_OBJECT); g_assert($$.prim->kind != TYPE_BOXED); } } | semitype T_NOTNULLPTR { $$ = $1; $$.indirection++; $$.notnull = TRUE; }; ident: T_IDENT; typeorvoid: type | T_VOID { $$.prim = NULL; $$.indirection = 0; $$.is_const = FALSE; $$.notnull = FALSE; }; primtype: maybeident T_SCOPE ident { Id i = $1; Package* p; PrimType* t; if(!i) i = GET_ID(""); p = get_pkg(i); if(!p) g_error("Unknown package %s!", i); t = get_type(p, $3); if(!t) g_error("Unknown type %s:%s", i, $3); $$ = t; } | ident { Package* p = current_module->package; PrimType* t; GSList* l = imports_list; t = get_type(p, $1); while(l && !t){ t = get_type(l->data, $1); l = l->next; } if(!t) g_error("Couldn't find type %s in import list", $1); $$ = t; }; paramlist: /* empty */ { $$ = NULL; } | param paramtail { $$ = g_slist_prepend($2, $1); }; paramtail: /* empty */ { $$ = NULL; } | T_COMMA param paramtail { $$ = g_slist_prepend($3, $2); }; param: type ident docstring { $$=g_new(Param, 1); $$->method=current_method; $$->doc=$3; $$->name=$2; $$->type=$1; }; methkind: T_ABSTRACT { $$ = METH_VIRTUAL; } | T_DIRECT { $$ = METH_DIRECT; } | /* empty */ { $$ = METH_DIRECT; } | T_STATIC { $$ = METH_STATIC; } | T_PRE_EMIT { $$ = METH_EMIT_PRE; } | T_POST_EMIT { $$ = METH_EMIT_POST; } | T_DUAL_EMIT { $$ = METH_EMIT_BOTH; }; datakind: T_ABSTRACT { $$ = DATA_STATIC_VIRTUAL; } | T_DIRECT { $$ = DATA_DIRECT; } | /* empty */ { $$ = DATA_DIRECT; } | T_STATIC { $$ = DATA_STATIC; }; methprot: T_PROTECTED{ $$ = METH_PROTECTED; } | T_PUBLIC { $$ = METH_PUBLIC; }; dataprot: /* empty */ { $$ = DATA_PROTECTED; } | T_READ_ONLY { $$ = DATA_READONLY; } | T_READ_WRITE { $$ = DATA_READWRITE; }; emitdef: /* empty */ { $$ = EMIT_NONE; } | T_PRE_EMIT { $$ = EMIT_PRE; } | T_POST_EMIT { $$ = EMIT_POST; }; docstring: T_STRING { $$ = $1; } | /* empty */ { $$ = NULL; }; idlist: ident { $$ = g_slist_prepend(NULL, (gpointer)($1)); } | idlist T_COMMA ident { $$ = g_slist_append($1, (gpointer)($3)); }; def: classdef | enumdef | flagsdef; enumdef: T_ENUM primtype docstring T_OPEN_B idlist T_CLOSE_B { EnumDef* d=g_new(EnumDef, 1); g_assert($2->kind==TYPE_ENUM); d->alternatives = $5; $$=DEF(d); $$->type=$2; $$->doc=$3; }; flagsdef: T_FLAGS primtype docstring T_OPEN_B idlist T_CLOSE_B T_END { FlagsDef* d=g_new(FlagsDef, 1); g_assert($2->kind==TYPE_ENUM); d->flags = $5; $$=DEF(d); $$->type=$2; $$->doc=$3; }; parent: /* empty */{ g_assert(root_class); $$ = root_class; } | T_INHERITANCE primtype{ $$=$2; } classdef: T_CLASS primtype parent docstring T_OPEN_B { g_assert($2->kind==TYPE_OBJECT); g_assert(!$3 || $3->kind==TYPE_OBJECT); g_assert($2->module == current_module); current_class=g_new(ObjectDef, 1); } classbody T_CLOSE_B { Type t; t.is_const = FALSE; t.indirection = 1; t.notnull = TRUE; t.prim = $2; current_class->self_type[0]=t; t.is_const=TRUE; current_class->self_type[1]=t; current_class->parent = $3; current_class->members = g_slist_reverse($7); $$=DEF(current_class); current_class=NULL; $$->type = $2; $$->doc = $4; }; member_def: data_member_def | method_def; data_member_def: dataprot datakind type ident emitdef docstring T_END { DataMember* m = g_new(DataMember, 1); m->prot = $1; m->type = $3; m->kind = $2; $$ = MEMBER(m); $$->membertype = MEMBER_DATA; $$->name = $4; /* $$->emit = $5; */ $$->doc = $6; }; method_def: methprot methkind typeorvoid ident T_OPEN_P { current_method = g_new(Method, 1); } paramlist T_CLOSE_P const_def emitdef docstring T_END { current_method->prot = $1; current_method->ret_type = $3; current_method->self_const = $9; current_method->params = $7; current_method->kind = $2; $$=MEMBER(current_method); current_method=NULL; $$->membertype = MEMBER_METHOD; $$->name = $4; /* $$->emit = $10; */ $$->doc = $11; }; const_def: T_CONST { $$ = TRUE; } | /* empty */ { $$ = FALSE; }; classbody: /* empty */ { $$ = NULL; } | classbody member_def{ $2->my_class=current_class; $$ = g_slist_prepend($1, $2); }; %% #define YYDEBUG 1 GHashTable* type_hash; GHashTable* class_hash; gboolean in_ident; int yyerror (char* s){ g_error ("Parser error: %s", s); return 0; }