501 lines
8.8 KiB
Plaintext
501 lines
8.8 KiB
Plaintext
%{
|
|
#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<id> T_IDENT
|
|
%token<id> T_HEADERNAME
|
|
%token<str> T_STRING
|
|
|
|
%type<id> maybeident
|
|
%type<id> ident
|
|
%type<id> headerdef
|
|
%type<fund_type> fundtype
|
|
%type<type> type
|
|
%type<type> typeorvoid
|
|
%type<type> semitype
|
|
%type<primtype> primtype
|
|
%type<primtype> parent
|
|
%type<list> paramlist
|
|
%type<list> idlist
|
|
%type<methkind> methkind
|
|
%type<datakind> datakind
|
|
%type<methprot> methprot
|
|
%type<dataprot> dataprot
|
|
%type<list> classbody
|
|
%type<def> flagsdef
|
|
%type<def> enumdef
|
|
%type<def> classdef
|
|
%type<def> def
|
|
%type<list> paramtail
|
|
%type<param> param
|
|
%type<str> docstring
|
|
%type<member> member_def
|
|
%type<member> data_member_def
|
|
%type<member> method_def
|
|
%type<emit_def> emitdef
|
|
%type<bool> 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;
|
|
}
|