Handle encapsulated unions in a cleaner (and less buggy) way. Emit the
names "DUMMYUNIONNAME" and "DUMMYSTRUCTNAME" for anonymous unions and structs. Support const and extern definitions. Retain tokens (and whether numbers are hex or not) used for computing constant expressions, so that the full expression can be written to the header file instead of the computed integer result of the expression. Parse the sizeof() operator. Compute and remember constant definitions and enum values so they can be used in expressions. Improved identifier lookup speed. Fixed some bugs.
This commit is contained in:
parent
75e9c468bd
commit
34e2f87f8f
|
@ -78,8 +78,8 @@ static void write_array(FILE *h, expr_t *v)
|
|||
while (NEXT_LINK(v)) v = NEXT_LINK(v);
|
||||
fprintf(h, "[");
|
||||
while (v) {
|
||||
if (v->type == EXPR_NUM)
|
||||
fprintf(h, "%ld", v->u.lval); /* statically sized array */
|
||||
if (v->is_const)
|
||||
fprintf(h, "%ld", v->cval); /* statically sized array */
|
||||
else
|
||||
fprintf(h, "1"); /* dynamically sized array */
|
||||
if (PREV_LINK(v))
|
||||
|
@ -99,6 +99,21 @@ static void write_field(FILE *h, var_t *v)
|
|||
fprintf(h, " ");
|
||||
write_pident(h, v);
|
||||
}
|
||||
else {
|
||||
/* not all C/C++ compilers support anonymous structs and unions */
|
||||
switch (v->type->type) {
|
||||
case RPC_FC_STRUCT:
|
||||
case RPC_FC_ENCAPSULATED_UNION:
|
||||
fprintf(h, " DUMMYSTRUCTNAME");
|
||||
break;
|
||||
case RPC_FC_NON_ENCAPSULATED_UNION:
|
||||
fprintf(h, " DUMMYUNIONNAME");
|
||||
break;
|
||||
default:
|
||||
/* ? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_array(h, v->array);
|
||||
fprintf(h, ";\n");
|
||||
}
|
||||
|
@ -124,8 +139,10 @@ static void write_enums(FILE *h, var_t *v)
|
|||
if (get_name(v)) {
|
||||
indent(0);
|
||||
write_name(h, v);
|
||||
if (v->has_val)
|
||||
fprintf(h, " = %ld", v->lval);
|
||||
if (v->eval) {
|
||||
fprintf(h, " = ");
|
||||
write_expr(h, v->eval);
|
||||
}
|
||||
}
|
||||
if (PREV_LINK(v))
|
||||
fprintf(h, ",\n");
|
||||
|
@ -181,6 +198,7 @@ void write_type(FILE *h, type_t *t, var_t *v, char *n)
|
|||
if (t->defined && !t->written) {
|
||||
if (t->name) fprintf(h, "enum %s {\n", t->name);
|
||||
else fprintf(h, "enum {\n");
|
||||
t->written = TRUE;
|
||||
indentation++;
|
||||
write_enums(h, t->fields);
|
||||
indent(-1);
|
||||
|
@ -189,29 +207,13 @@ void write_type(FILE *h, type_t *t, var_t *v, char *n)
|
|||
else fprintf(h, "enum %s", t->name);
|
||||
break;
|
||||
case RPC_FC_STRUCT:
|
||||
if (t->defined && !t->written) {
|
||||
if (t->name) fprintf(h, "struct %s {\n", t->name);
|
||||
else fprintf(h, "struct {\n");
|
||||
indentation++;
|
||||
write_fields(h, t->fields);
|
||||
indent(-1);
|
||||
fprintf(h, "}");
|
||||
}
|
||||
else fprintf(h, "struct %s", t->name);
|
||||
break;
|
||||
case RPC_FC_ENCAPSULATED_UNION:
|
||||
if (t->defined && !t->written) {
|
||||
var_t *d = t->fields;
|
||||
if (t->name) fprintf(h, "struct %s {\n", t->name);
|
||||
else fprintf(h, "struct {\n");
|
||||
t->written = TRUE;
|
||||
indentation++;
|
||||
write_field(h, d);
|
||||
indent(0);
|
||||
fprintf(h, "union {\n");
|
||||
indentation++;
|
||||
write_fields(h, NEXT_LINK(d));
|
||||
indent(-1);
|
||||
fprintf(h, "} u;\n");
|
||||
write_fields(h, t->fields);
|
||||
indent(-1);
|
||||
fprintf(h, "}");
|
||||
}
|
||||
|
@ -221,6 +223,7 @@ void write_type(FILE *h, type_t *t, var_t *v, char *n)
|
|||
if (t->defined && !t->written) {
|
||||
if (t->name) fprintf(h, "union %s {\n", t->name);
|
||||
else fprintf(h, "union {\n");
|
||||
t->written = TRUE;
|
||||
indentation++;
|
||||
write_fields(h, t->fields);
|
||||
indent(-1);
|
||||
|
@ -262,6 +265,89 @@ void write_typedef(type_t *type, var_t *names)
|
|||
fprintf(header, ";\n\n");
|
||||
}
|
||||
|
||||
static void do_write_expr(FILE *h, expr_t *e, int p)
|
||||
{
|
||||
switch (e->type) {
|
||||
case EXPR_VOID:
|
||||
break;
|
||||
case EXPR_NUM:
|
||||
fprintf(h, "%ld", e->u.lval);
|
||||
break;
|
||||
case EXPR_HEXNUM:
|
||||
fprintf(h, "0x%lx", e->u.lval);
|
||||
break;
|
||||
case EXPR_IDENTIFIER:
|
||||
fprintf(h, "%s", e->u.sval);
|
||||
break;
|
||||
case EXPR_NEG:
|
||||
fprintf(h, "-");
|
||||
do_write_expr(h, e->ref, 1);
|
||||
break;
|
||||
case EXPR_PPTR:
|
||||
fprintf(h, "*");
|
||||
do_write_expr(h, e->ref, 1);
|
||||
break;
|
||||
case EXPR_CAST:
|
||||
fprintf(h, "(");
|
||||
write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
|
||||
fprintf(h, ")");
|
||||
do_write_expr(h, e->ref, 1);
|
||||
break;
|
||||
case EXPR_SIZEOF:
|
||||
fprintf(h, "sizeof(");
|
||||
write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
|
||||
fprintf(h, ")");
|
||||
break;
|
||||
case EXPR_SHL:
|
||||
case EXPR_SHR:
|
||||
case EXPR_MUL:
|
||||
case EXPR_DIV:
|
||||
case EXPR_ADD:
|
||||
case EXPR_SUB:
|
||||
case EXPR_AND:
|
||||
case EXPR_OR:
|
||||
if (p) fprintf(h, "(");
|
||||
do_write_expr(h, e->ref, 1);
|
||||
switch (e->type) {
|
||||
case EXPR_SHL: fprintf(h, " << "); break;
|
||||
case EXPR_SHR: fprintf(h, " >> "); break;
|
||||
case EXPR_MUL: fprintf(h, " * "); break;
|
||||
case EXPR_DIV: fprintf(h, " / "); break;
|
||||
case EXPR_ADD: fprintf(h, " + "); break;
|
||||
case EXPR_SUB: fprintf(h, " - "); break;
|
||||
case EXPR_AND: fprintf(h, " & "); break;
|
||||
case EXPR_OR: fprintf(h, " | "); break;
|
||||
default: break;
|
||||
}
|
||||
do_write_expr(h, e->u.ext, 1);
|
||||
if (p) fprintf(h, ")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write_expr(FILE *h, expr_t *e)
|
||||
{
|
||||
do_write_expr(h, e, 0);
|
||||
}
|
||||
|
||||
void write_constdef(var_t *v)
|
||||
{
|
||||
fprintf(header, "#define %s (", get_name(v));
|
||||
write_expr(header, v->eval);
|
||||
fprintf(header, ")\n\n");
|
||||
}
|
||||
|
||||
void write_externdef(var_t *v)
|
||||
{
|
||||
fprintf(header, "extern const ");
|
||||
write_type(header, v->type, NULL, v->tname);
|
||||
if (get_name(v)) {
|
||||
fprintf(header, " ");
|
||||
write_pident(header, v);
|
||||
}
|
||||
fprintf(header, ";\n\n");
|
||||
}
|
||||
|
||||
/********** INTERFACES **********/
|
||||
|
||||
uuid_t *get_uuid(attr_t *a)
|
||||
|
|
|
@ -32,5 +32,8 @@ extern void write_method_args(FILE *h, var_t *arg, char *name);
|
|||
extern void write_forward(type_t *iface);
|
||||
extern void write_interface(type_t *iface);
|
||||
extern void write_typedef(type_t *type, var_t *names);
|
||||
extern void write_expr(FILE *h, expr_t *e);
|
||||
extern void write_constdef(var_t *v);
|
||||
extern void write_externdef(var_t *v);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,7 +31,7 @@ extern int yy_flex_debug;
|
|||
int yylex(void);
|
||||
|
||||
extern int import_stack_ptr;
|
||||
void do_import(char *fname);
|
||||
int do_import(char *fname);
|
||||
void abort_import(void);
|
||||
|
||||
#define parse_only import_stack_ptr
|
||||
|
|
|
@ -118,7 +118,10 @@ static uuid_t* parse_uuid(const char*u)
|
|||
yylval.uuid = parse_uuid(yytext);
|
||||
return aUUID;
|
||||
}
|
||||
{hex} |
|
||||
{hex} {
|
||||
yylval.num = strtol(yytext, NULL, 0);
|
||||
return aHEXNUM;
|
||||
}
|
||||
{int} {
|
||||
yylval.num = strtol(yytext, NULL, 0);
|
||||
return aNUM;
|
||||
|
@ -145,7 +148,7 @@ int yywrap(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
static struct keyword {
|
||||
const char *kw;
|
||||
int token;
|
||||
int val;
|
||||
|
@ -241,16 +244,34 @@ static struct {
|
|||
{"version", tVERSION},
|
||||
{"void", tVOID},
|
||||
{"wchar_t", tWCHAR},
|
||||
{"wire_marshal", tWIREMARSHAL},
|
||||
{NULL}
|
||||
{"wire_marshal", tWIREMARSHAL}
|
||||
};
|
||||
#define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
|
||||
#define KWP(p) ((struct keyword *)(p))
|
||||
|
||||
static int kw_cmp_func(const void *s1, const void *s2)
|
||||
{
|
||||
return strcmp(KWP(s1)->kw, KWP(s2)->kw);
|
||||
}
|
||||
|
||||
#define KW_BSEARCH
|
||||
static int kw_token(const char *kw)
|
||||
{
|
||||
int i;
|
||||
for (i=0; keywords[i].kw; i++)
|
||||
if (strcmp(kw, keywords[i].kw) == 0)
|
||||
return keywords[i].token;
|
||||
struct keyword key, *kwp;
|
||||
key.kw = kw;
|
||||
#ifdef KW_BSEARCH
|
||||
kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
for (kwp=NULL, i=0; i < NKEYWORDS; i++)
|
||||
if (!kw_cmp_func(&key, &keywords[i])) {
|
||||
kwp = &keywords[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (kwp) return kwp->token;
|
||||
yylval.str = xstrdup(kw);
|
||||
return is_type(kw) ? aKNOWNTYPE : aIDENTIFIER;
|
||||
}
|
||||
|
@ -293,7 +314,7 @@ struct imports {
|
|||
struct imports *next;
|
||||
} *first_import;
|
||||
|
||||
void do_import(char *fname)
|
||||
int do_import(char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
char *hname, *path;
|
||||
|
@ -312,7 +333,7 @@ void do_import(char *fname)
|
|||
import = first_import;
|
||||
while (import && strcmp(import->name, fname))
|
||||
import = import->next;
|
||||
if (import) return; /* already imported */
|
||||
if (import) return 0; /* already imported */
|
||||
|
||||
import = xmalloc(sizeof(struct imports));
|
||||
import->name = xstrdup(fname);
|
||||
|
@ -334,6 +355,7 @@ void do_import(char *fname)
|
|||
|
||||
import_stack[ptr].state = YY_CURRENT_BUFFER;
|
||||
yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void abort_import(void)
|
||||
|
|
|
@ -67,6 +67,7 @@ static attr_t *make_attrp(enum attr_type type, void *val);
|
|||
static expr_t *make_expr(enum expr_type type);
|
||||
static expr_t *make_exprl(enum expr_type type, long val);
|
||||
static expr_t *make_exprs(enum expr_type type, char *val);
|
||||
static expr_t *make_exprt(enum expr_type type, typeref_t *tref, expr_t *expr);
|
||||
static expr_t *make_expr1(enum expr_type type, expr_t *expr);
|
||||
static expr_t *make_expr2(enum expr_type type, expr_t *exp1, expr_t *exp2);
|
||||
static type_t *make_type(BYTE type, type_t *ref);
|
||||
|
@ -84,6 +85,9 @@ static type_t *find_type2(char *name, int t);
|
|||
static type_t *get_type(BYTE type, char *name, int t);
|
||||
static type_t *get_typev(BYTE type, var_t *name, int t);
|
||||
|
||||
static var_t *reg_const(var_t *var);
|
||||
static var_t *find_const(char *name, int f);
|
||||
|
||||
#define tsENUM 1
|
||||
#define tsSTRUCT 2
|
||||
#define tsUNION 3
|
||||
|
@ -106,7 +110,7 @@ static type_t std_int = { "int" };
|
|||
|
||||
%token <str> aIDENTIFIER
|
||||
%token <str> aKNOWNTYPE
|
||||
%token <num> aNUM
|
||||
%token <num> aNUM aHEXNUM
|
||||
%token <str> aSTRING
|
||||
%token <uuid> aUUID
|
||||
%token aEOF
|
||||
|
@ -154,16 +158,16 @@ static type_t std_int = { "int" };
|
|||
%token tPOINTERTYPE
|
||||
|
||||
%type <attr> m_attributes attributes attrib_list attribute
|
||||
%type <expr> aexprs aexpr_list aexpr array
|
||||
%type <expr> exprs expr_list expr array expr_const
|
||||
%type <type> inherit interface interfacehdr interfacedef lib_statements
|
||||
%type <type> base_type int_std
|
||||
%type <type> enumdef structdef typedef uniondef
|
||||
%type <tref> type
|
||||
%type <var> m_args no_args args arg
|
||||
%type <var> fields field s_field cases case enums enum_list enum constdef
|
||||
%type <var> fields field s_field cases case enums enum_list enum constdef externdef
|
||||
%type <var> m_ident t_ident ident p_ident pident pident_list
|
||||
%type <func> funcdef int_statements
|
||||
%type <num> expr pointer_type
|
||||
%type <num> pointer_type
|
||||
|
||||
%left ','
|
||||
%left '|'
|
||||
|
@ -193,10 +197,10 @@ int_statements: { $$ = NULL; }
|
|||
;
|
||||
|
||||
statement: ';' {}
|
||||
| constdef {}
|
||||
| constdef ';' { if (!parse_only) { write_constdef($1); } }
|
||||
| cppquote {}
|
||||
| enumdef ';' { if (!parse_only) { write_type(header, $1, NULL, NULL); fprintf(header, ";\n\n"); } }
|
||||
| externdef ';' {}
|
||||
| externdef ';' { if (!parse_only) { write_externdef($1); } }
|
||||
| import {}
|
||||
/* | interface ';' {} */
|
||||
/* | interfacedef {} */
|
||||
|
@ -207,7 +211,8 @@ statement: ';' {}
|
|||
|
||||
cppquote: tCPPQUOTE '(' aSTRING ')' { if (!parse_only) fprintf(header, "%s\n", $3); }
|
||||
;
|
||||
import_start: tIMPORT aSTRING ';' { do_import($2); }
|
||||
import_start: tIMPORT aSTRING ';' { assert(yychar == YYEMPTY);
|
||||
if (!do_import($2)) yychar = aEOF; }
|
||||
;
|
||||
import: import_start input aEOF {}
|
||||
;
|
||||
|
@ -234,33 +239,8 @@ arg: attributes type pident array { $$ = $3;
|
|||
}
|
||||
;
|
||||
|
||||
aexprs: { $$ = make_expr(EXPR_VOID); }
|
||||
| aexpr_list
|
||||
;
|
||||
|
||||
aexpr_list: aexpr
|
||||
| aexpr_list ',' aexpr { LINK($3, $1); $$ = $3; }
|
||||
;
|
||||
|
||||
aexpr: aNUM { $$ = make_exprl(EXPR_NUM, $1); }
|
||||
| aIDENTIFIER { $$ = make_exprs(EXPR_IDENTIFIER, $1); }
|
||||
| aexpr '|' aexpr { $$ = make_expr2(EXPR_OR , $1, $3); }
|
||||
| aexpr '&' aexpr { $$ = make_expr2(EXPR_AND, $1, $3); }
|
||||
| aexpr '+' aexpr { $$ = make_expr2(EXPR_ADD, $1, $3); }
|
||||
| aexpr '-' aexpr { $$ = make_expr2(EXPR_SUB, $1, $3); }
|
||||
| aexpr '*' aexpr { $$ = make_expr2(EXPR_MUL, $1, $3); }
|
||||
| aexpr '/' aexpr { $$ = make_expr2(EXPR_DIV, $1, $3); }
|
||||
| aexpr SHL aexpr { $$ = make_expr2(EXPR_SHL, $1, $3); }
|
||||
| aexpr SHR aexpr { $$ = make_expr2(EXPR_SHR, $1, $3); }
|
||||
| '-' aexpr %prec NEG { $$ = make_expr1(EXPR_NEG, $2); }
|
||||
| '*' aexpr %prec PPTR { $$ = make_expr1(EXPR_PPTR, $2); }
|
||||
| '(' type ')' aexpr %prec CAST { $$ = $4; /* FIXME */ free($2); }
|
||||
| '(' aexpr ')' { $$ = $2; }
|
||||
| tSIZEOF '(' type ')' { $$ = make_exprl(EXPR_NUM, 0); /* FIXME */ free($3); warning("can't do sizeof() yet\n"); }
|
||||
;
|
||||
|
||||
array: { $$ = NULL; }
|
||||
| '[' aexprs ']' { $$ = $2; }
|
||||
| '[' exprs ']' { $$ = $2; }
|
||||
| '[' '*' ']' { $$ = make_expr(EXPR_VOID); }
|
||||
;
|
||||
|
||||
|
@ -286,15 +266,15 @@ attribute:
|
|||
| tDEFAULT { $$ = make_attr(ATTR_DEFAULT); }
|
||||
| tIIDIS '(' ident ')' { $$ = make_attrp(ATTR_IIDIS, $3); }
|
||||
| tIN { $$ = make_attr(ATTR_IN); }
|
||||
| tLENGTHIS '(' aexprs ')' { $$ = NULL; }
|
||||
| tLENGTHIS '(' exprs ')' { $$ = NULL; }
|
||||
| tLOCAL { $$ = make_attr(ATTR_LOCAL); }
|
||||
| tOBJECT { $$ = make_attr(ATTR_OBJECT); }
|
||||
| tOLEAUTOMATION { $$ = make_attr(ATTR_OLEAUTOMATION); }
|
||||
| tOUT { $$ = make_attr(ATTR_OUT); }
|
||||
| tPOINTERDEFAULT '(' pointer_type ')' { $$ = make_attrv(ATTR_POINTERDEFAULT, $3); }
|
||||
| tSIZEIS '(' aexprs ')' { $$ = NULL; }
|
||||
| tSIZEIS '(' exprs ')' { $$ = NULL; }
|
||||
| tSTRING { $$ = make_attr(ATTR_STRING); }
|
||||
| tSWITCHIS '(' aexpr ')' { $$ = NULL; }
|
||||
| tSWITCHIS '(' expr ')' { $$ = NULL; }
|
||||
| tSWITCHTYPE '(' type ')' { $$ = NULL; }
|
||||
| tUUID '(' aUUID ')' { $$ = make_attrp(ATTR_UUID, $3); }
|
||||
| tV1ENUM { $$ = make_attr(ATTR_V1ENUM); }
|
||||
|
@ -308,17 +288,25 @@ callconv:
|
|||
;
|
||||
|
||||
cases: { $$ = NULL; }
|
||||
| cases case { LINK($2, $1); $$ = $2; }
|
||||
| cases case { if ($2) { LINK($2, $1); $$ = $2; }
|
||||
else { $$ = $1; }
|
||||
}
|
||||
;
|
||||
|
||||
case: tCASE expr ':' field { $$ = $4; }
|
||||
| tDEFAULT ':' field { $$ = $3; }
|
||||
case: tCASE expr ':' field { /* attr_t *a = NULL; */ /* FIXME */
|
||||
$$ = $4; if (!$$) $$ = make_var(NULL);
|
||||
/* LINK(a, $$->attrs); $$->attrs = a; */
|
||||
}
|
||||
| tDEFAULT ':' field { attr_t *a = make_attr(ATTR_DEFAULT);
|
||||
$$ = $3; if (!$$) $$ = make_var(NULL);
|
||||
LINK(a, $$->attrs); $$->attrs = a;
|
||||
}
|
||||
;
|
||||
|
||||
constdef: tCONST type ident '=' expr { $$ = $3;
|
||||
constdef: tCONST type ident '=' expr_const { $$ = reg_const($3);
|
||||
set_type($$, $2, NULL);
|
||||
$$->has_val = TRUE;
|
||||
$$->lval = $5;
|
||||
$$->eval = $5;
|
||||
$$->lval = $5->cval;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -328,14 +316,19 @@ enums: { $$ = NULL; }
|
|||
;
|
||||
|
||||
enum_list: enum
|
||||
| enum_list ',' enum { LINK($3, $1); $$ = $3; }
|
||||
| enum_list ',' enum { LINK($3, $1); $$ = $3;
|
||||
if ($1 && !$3->eval)
|
||||
$3->lval = $1->lval + 1;
|
||||
}
|
||||
;
|
||||
|
||||
enum: ident '=' expr { $$ = $1;
|
||||
$$->has_val = TRUE;
|
||||
$$->lval = $3;
|
||||
enum: ident '=' expr_const { $$ = reg_const($1);
|
||||
$$->eval = $3;
|
||||
$$->lval = $3->cval;
|
||||
}
|
||||
| ident { $$ = reg_const($1);
|
||||
$$->lval = 0; /* default for first enum entry */
|
||||
}
|
||||
| ident { $$ = $1; }
|
||||
;
|
||||
|
||||
enumdef: tENUM t_ident '{' enums '}' { $$ = get_typev(RPC_FC_ENUM16, $2, tsENUM);
|
||||
|
@ -344,24 +337,46 @@ enumdef: tENUM t_ident '{' enums '}' { $$ = get_typev(RPC_FC_ENUM16, $2, tsENUM
|
|||
}
|
||||
;
|
||||
|
||||
expr_list: expr {}
|
||||
| expr_list ',' expr {}
|
||||
exprs: { $$ = make_expr(EXPR_VOID); }
|
||||
| expr_list
|
||||
;
|
||||
|
||||
expr: aNUM
|
||||
| aIDENTIFIER { $$ = 0; /* FIXME */ }
|
||||
| expr '|' expr { $$ = $1 | $3; }
|
||||
| expr '&' expr { $$ = $1 & $3; }
|
||||
| expr SHL expr { $$ = $1 << $3; }
|
||||
| expr SHR expr { $$ = $1 >> $3; }
|
||||
| '-' expr %prec NEG { $$ = -$2; }
|
||||
expr_list: expr
|
||||
| expr_list ',' expr { LINK($3, $1); $$ = $3; }
|
||||
;
|
||||
|
||||
externdef: tEXTERN tCONST type ident
|
||||
expr: aNUM { $$ = make_exprl(EXPR_NUM, $1); }
|
||||
| aHEXNUM { $$ = make_exprl(EXPR_HEXNUM, $1); }
|
||||
| aIDENTIFIER { $$ = make_exprs(EXPR_IDENTIFIER, $1); }
|
||||
| expr '|' expr { $$ = make_expr2(EXPR_OR , $1, $3); }
|
||||
| expr '&' expr { $$ = make_expr2(EXPR_AND, $1, $3); }
|
||||
| expr '+' expr { $$ = make_expr2(EXPR_ADD, $1, $3); }
|
||||
| expr '-' expr { $$ = make_expr2(EXPR_SUB, $1, $3); }
|
||||
| expr '*' expr { $$ = make_expr2(EXPR_MUL, $1, $3); }
|
||||
| expr '/' expr { $$ = make_expr2(EXPR_DIV, $1, $3); }
|
||||
| expr SHL expr { $$ = make_expr2(EXPR_SHL, $1, $3); }
|
||||
| expr SHR expr { $$ = make_expr2(EXPR_SHR, $1, $3); }
|
||||
| '-' expr %prec NEG { $$ = make_expr1(EXPR_NEG, $2); }
|
||||
| '*' expr %prec PPTR { $$ = make_expr1(EXPR_PPTR, $2); }
|
||||
| '(' type ')' expr %prec CAST { $$ = make_exprt(EXPR_CAST, $2, $4); }
|
||||
| tSIZEOF '(' type ')' { $$ = make_exprt(EXPR_SIZEOF, $3, NULL); }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
expr_const: expr { $$ = $1;
|
||||
if (!$$->is_const) yyerror("expression is not constant\n");
|
||||
}
|
||||
;
|
||||
|
||||
externdef: tEXTERN tCONST type ident { $$ = $4;
|
||||
set_type($$, $3, NULL);
|
||||
}
|
||||
;
|
||||
|
||||
fields: { $$ = NULL; }
|
||||
| fields field { LINK($2, $1); $$ = $2; }
|
||||
| fields field { if ($2) { LINK($2, $1); $$ = $2; }
|
||||
else { $$ = $1; }
|
||||
}
|
||||
;
|
||||
|
||||
field: s_field ';' { $$ = $1; }
|
||||
|
@ -508,8 +523,13 @@ uniondef: tUNION t_ident '{' fields '}' { $$ = get_typev(RPC_FC_NON_ENCAPSULATE
|
|||
}
|
||||
| tUNION t_ident
|
||||
tSWITCH '(' s_field ')'
|
||||
m_ident '{' cases '}' { $$ = get_typev(RPC_FC_ENCAPSULATED_UNION, $2, tsUNION);
|
||||
LINK($5, $9); $$->fields = $5;
|
||||
m_ident '{' cases '}' { var_t *u = $7;
|
||||
$$ = get_typev(RPC_FC_ENCAPSULATED_UNION, $2, tsUNION);
|
||||
if (!u) u = make_var("tagged_union");
|
||||
u->type = make_type(RPC_FC_NON_ENCAPSULATED_UNION, NULL);
|
||||
u->type->fields = $9;
|
||||
u->type->defined = TRUE;
|
||||
LINK(u, $5); $$->fields = u;
|
||||
$$->defined = TRUE;
|
||||
}
|
||||
;
|
||||
|
@ -554,6 +574,7 @@ static expr_t *make_expr(enum expr_type type)
|
|||
e->type = type;
|
||||
e->ref = NULL;
|
||||
e->u.lval = 0;
|
||||
e->is_const = FALSE;
|
||||
INIT_LINK(e);
|
||||
return e;
|
||||
}
|
||||
|
@ -564,90 +585,121 @@ static expr_t *make_exprl(enum expr_type type, long val)
|
|||
e->type = type;
|
||||
e->ref = NULL;
|
||||
e->u.lval = val;
|
||||
e->is_const = FALSE;
|
||||
INIT_LINK(e);
|
||||
/* check for numeric constant */
|
||||
if (type == EXPR_NUM || type == EXPR_HEXNUM) {
|
||||
e->is_const = TRUE;
|
||||
e->cval = val;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr_t *make_exprs(enum expr_type type, char *val)
|
||||
{
|
||||
expr_t *e = xmalloc(sizeof(expr_t));
|
||||
/* FIXME: if type is EXPR_IDENTIFIER, we could check for match against const
|
||||
* declaration, and change to appropriate type and value if so */
|
||||
expr_t *e;
|
||||
e = xmalloc(sizeof(expr_t));
|
||||
e->type = type;
|
||||
e->ref = NULL;
|
||||
e->u.sval = val;
|
||||
e->is_const = FALSE;
|
||||
INIT_LINK(e);
|
||||
/* check for predefined constants */
|
||||
if (type == EXPR_IDENTIFIER) {
|
||||
var_t *c = find_const(val, 0);
|
||||
if (c) {
|
||||
e->u.sval = c->name;
|
||||
free(val);
|
||||
e->is_const = TRUE;
|
||||
e->cval = c->lval;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr_t *make_exprt(enum expr_type type, typeref_t *tref, expr_t *expr)
|
||||
{
|
||||
expr_t *e;
|
||||
e = xmalloc(sizeof(expr_t));
|
||||
e->type = type;
|
||||
e->ref = expr;
|
||||
e->u.tref = tref;
|
||||
e->is_const = FALSE;
|
||||
INIT_LINK(e);
|
||||
/* check for cast of constant expression */
|
||||
if (type == EXPR_CAST && expr->is_const) {
|
||||
e->is_const = TRUE;
|
||||
e->cval = expr->cval;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr_t *make_expr1(enum expr_type type, expr_t *expr)
|
||||
{
|
||||
expr_t *e;
|
||||
/* check for compile-time optimization */
|
||||
if (expr->type == EXPR_NUM) {
|
||||
switch (type) {
|
||||
case EXPR_NEG:
|
||||
expr->u.lval = -expr->u.lval;
|
||||
return expr;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
e = xmalloc(sizeof(expr_t));
|
||||
e->type = type;
|
||||
e->ref = expr;
|
||||
e->u.lval = 0;
|
||||
e->is_const = FALSE;
|
||||
INIT_LINK(e);
|
||||
/* check for compile-time optimization */
|
||||
if (expr->is_const) {
|
||||
e->is_const = TRUE;
|
||||
switch (type) {
|
||||
case EXPR_NEG:
|
||||
e->cval = -expr->cval;
|
||||
break;
|
||||
default:
|
||||
e->is_const = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2)
|
||||
{
|
||||
expr_t *e;
|
||||
/* check for compile-time optimization */
|
||||
if (expr1->type == EXPR_NUM && expr2->type == EXPR_NUM) {
|
||||
switch (type) {
|
||||
case EXPR_ADD:
|
||||
expr1->u.lval += expr2->u.lval;
|
||||
free(expr2);
|
||||
return expr1;
|
||||
case EXPR_SUB:
|
||||
expr1->u.lval -= expr2->u.lval;
|
||||
free(expr2);
|
||||
return expr1;
|
||||
case EXPR_MUL:
|
||||
expr1->u.lval *= expr2->u.lval;
|
||||
free(expr2);
|
||||
return expr1;
|
||||
case EXPR_DIV:
|
||||
expr1->u.lval /= expr2->u.lval;
|
||||
free(expr2);
|
||||
return expr1;
|
||||
case EXPR_OR:
|
||||
expr1->u.lval |= expr2->u.lval;
|
||||
free(expr2);
|
||||
return expr1;
|
||||
case EXPR_AND:
|
||||
expr1->u.lval &= expr2->u.lval;
|
||||
free(expr2);
|
||||
return expr1;
|
||||
case EXPR_SHL:
|
||||
expr1->u.lval <<= expr2->u.lval;
|
||||
free(expr2);
|
||||
return expr1;
|
||||
case EXPR_SHR:
|
||||
expr1->u.lval >>= expr2->u.lval;
|
||||
free(expr2);
|
||||
return expr1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
e = xmalloc(sizeof(expr_t));
|
||||
e->type = type;
|
||||
e->ref = expr1;
|
||||
e->u.ext = expr2;
|
||||
e->is_const = FALSE;
|
||||
INIT_LINK(e);
|
||||
/* check for compile-time optimization */
|
||||
if (expr1->is_const && expr2->is_const) {
|
||||
e->is_const = TRUE;
|
||||
switch (type) {
|
||||
case EXPR_ADD:
|
||||
e->cval = expr1->cval + expr2->cval;
|
||||
break;
|
||||
case EXPR_SUB:
|
||||
e->cval = expr1->cval - expr2->cval;
|
||||
break;
|
||||
case EXPR_MUL:
|
||||
e->cval = expr1->cval * expr2->cval;
|
||||
break;
|
||||
case EXPR_DIV:
|
||||
e->cval = expr1->cval / expr2->cval;
|
||||
break;
|
||||
case EXPR_OR:
|
||||
e->cval = expr1->cval | expr2->cval;
|
||||
break;
|
||||
case EXPR_AND:
|
||||
e->cval = expr1->cval & expr2->cval;
|
||||
break;
|
||||
case EXPR_SHL:
|
||||
e->cval = expr1->cval << expr2->cval;
|
||||
break;
|
||||
case EXPR_SHR:
|
||||
e->cval = expr1->cval >> expr2->cval;
|
||||
break;
|
||||
default:
|
||||
e->is_const = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
@ -718,7 +770,7 @@ static var_t *make_var(char *name)
|
|||
v->tname = NULL;
|
||||
v->attrs = NULL;
|
||||
v->array = NULL;
|
||||
v->has_val = FALSE;
|
||||
v->eval = NULL;
|
||||
v->lval = 0;
|
||||
INIT_LINK(v);
|
||||
return v;
|
||||
|
@ -735,6 +787,22 @@ static func_t *make_func(var_t *def, var_t *args)
|
|||
return f;
|
||||
}
|
||||
|
||||
#define HASHMAX 64
|
||||
|
||||
static int hash_ident(const char *name)
|
||||
{
|
||||
const char *p = name;
|
||||
int sum = 0;
|
||||
/* a simple sum hash is probably good enough */
|
||||
while (*p) {
|
||||
sum += *p;
|
||||
p++;
|
||||
}
|
||||
return sum & (HASHMAX-1);
|
||||
}
|
||||
|
||||
/***** type repository *****/
|
||||
|
||||
struct rtype {
|
||||
char *name;
|
||||
type_t *type;
|
||||
|
@ -742,21 +810,23 @@ struct rtype {
|
|||
struct rtype *next;
|
||||
};
|
||||
|
||||
struct rtype *first_type;
|
||||
struct rtype *type_hash[HASHMAX];
|
||||
|
||||
static type_t *reg_type(type_t *type, char *name, int t)
|
||||
{
|
||||
struct rtype *nt;
|
||||
int hash;
|
||||
if (!name) {
|
||||
yyerror("registering named type without name\n");
|
||||
return type;
|
||||
}
|
||||
hash = hash_ident(name);
|
||||
nt = xmalloc(sizeof(struct rtype));
|
||||
nt->name = name;
|
||||
nt->type = type;
|
||||
nt->t = t;
|
||||
nt->next = first_type;
|
||||
first_type = nt;
|
||||
nt->next = type_hash[hash];
|
||||
type_hash[hash] = nt;
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -791,7 +861,7 @@ static type_t *reg_types(type_t *type, var_t *names, int t)
|
|||
|
||||
static type_t *find_type(char *name, int t)
|
||||
{
|
||||
struct rtype *cur = first_type;
|
||||
struct rtype *cur = type_hash[hash_ident(name)];
|
||||
while (cur && (cur->t != t || strcmp(cur->name, name)))
|
||||
cur = cur->next;
|
||||
if (!cur) {
|
||||
|
@ -810,7 +880,7 @@ static type_t *find_type2(char *name, int t)
|
|||
|
||||
int is_type(const char *name)
|
||||
{
|
||||
struct rtype *cur = first_type;
|
||||
struct rtype *cur = type_hash[hash_ident(name)];
|
||||
while (cur && (cur->t || strcmp(cur->name, name)))
|
||||
cur = cur->next;
|
||||
if (cur) return TRUE;
|
||||
|
@ -822,7 +892,7 @@ static type_t *get_type(BYTE type, char *name, int t)
|
|||
struct rtype *cur = NULL;
|
||||
type_t *tp;
|
||||
if (name) {
|
||||
cur = first_type;
|
||||
cur = type_hash[hash_ident(name)];
|
||||
while (cur && (cur->t != t || strcmp(cur->name, name)))
|
||||
cur = cur->next;
|
||||
}
|
||||
|
@ -845,3 +915,42 @@ static type_t *get_typev(BYTE type, var_t *name, int t)
|
|||
}
|
||||
return get_type(type, sname, t);
|
||||
}
|
||||
|
||||
/***** constant repository *****/
|
||||
|
||||
struct rconst {
|
||||
char *name;
|
||||
var_t *var;
|
||||
struct rconst *next;
|
||||
};
|
||||
|
||||
struct rconst *const_hash[HASHMAX];
|
||||
|
||||
static var_t *reg_const(var_t *var)
|
||||
{
|
||||
struct rconst *nc;
|
||||
int hash;
|
||||
if (!var->name) {
|
||||
yyerror("registering constant without name\n");
|
||||
return var;
|
||||
}
|
||||
hash = hash_ident(var->name);
|
||||
nc = xmalloc(sizeof(struct rconst));
|
||||
nc->name = var->name;
|
||||
nc->var = var;
|
||||
nc->next = const_hash[hash];
|
||||
const_hash[hash] = nc;
|
||||
return var;
|
||||
}
|
||||
|
||||
static var_t *find_const(char *name, int f)
|
||||
{
|
||||
struct rconst *cur = const_hash[hash_ident(name)];
|
||||
while (cur && strcmp(cur->name, name))
|
||||
cur = cur->next;
|
||||
if (!cur) {
|
||||
if (f) yyerror("constant %s not found\n", name);
|
||||
return NULL;
|
||||
}
|
||||
return cur->var;
|
||||
}
|
||||
|
|
|
@ -67,10 +67,12 @@ enum expr_type
|
|||
{
|
||||
EXPR_VOID,
|
||||
EXPR_NUM,
|
||||
EXPR_HEXNUM,
|
||||
EXPR_IDENTIFIER,
|
||||
EXPR_NEG,
|
||||
EXPR_PPTR,
|
||||
EXPR_CAST,
|
||||
EXPR_SIZEOF,
|
||||
EXPR_SHL,
|
||||
EXPR_SHR,
|
||||
EXPR_MUL,
|
||||
|
@ -98,7 +100,10 @@ struct _expr_t {
|
|||
long lval;
|
||||
char *sval;
|
||||
expr_t *ext;
|
||||
typeref_t *tref;
|
||||
} u;
|
||||
int is_const;
|
||||
long cval;
|
||||
/* parser-internal */
|
||||
DECL_LINK(expr_t)
|
||||
};
|
||||
|
@ -131,7 +136,7 @@ struct _var_t {
|
|||
type_t *type;
|
||||
char *tname;
|
||||
attr_t *attrs;
|
||||
int has_val;
|
||||
expr_t *eval;
|
||||
long lval;
|
||||
|
||||
/* parser-internal */
|
||||
|
|
Loading…
Reference in New Issue