diff --git a/tools/widl/header.c b/tools/widl/header.c
index 24f27cbe03ee50c4a93a03f6d529269cd6f1eb9c..33bd3fb4fd6209b7e8b7f28b70501fffa4c60527 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -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)
diff --git a/tools/widl/header.h b/tools/widl/header.h
index d1d1a36f0388d572feb7bf61a44de0cae3deff08..68316605b183b5144308e05d4bbeab173f223b84 100644
--- a/tools/widl/header.h
+++ b/tools/widl/header.h
@@ -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
diff --git a/tools/widl/parser.h b/tools/widl/parser.h
index fb84ed6919dbe29b10dd9bb2db066eac89a71c99..20a7e2af4744088e798b487bf917cf11d569d40a 100644
--- a/tools/widl/parser.h
+++ b/tools/widl/parser.h
@@ -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
diff --git a/tools/widl/parser.l b/tools/widl/parser.l
index 6483293633d309d778307d05d1c0e66687644151..5c4c6e242442218ebff995b9631fa81f77271ef9 100644
--- a/tools/widl/parser.l
+++ b/tools/widl/parser.l
@@ -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)
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index a1e720f95cd5a0f3a3977c7bf7f26c516750f42e..3838b0ce757380840f2d15b73612f4509afdbf78 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -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;
+  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->type == EXPR_NUM) {
+  if (expr->is_const) {
+    e->is_const = TRUE;
     switch (type) {
     case EXPR_NEG:
-      expr->u.lval = -expr->u.lval;
-      return expr;
+      e->cval = -expr->cval;
+      break;
     default:
+      e->is_const = FALSE;
       break;
     }
   }
-  e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = expr;
-  e->u.lval = 0;
-  INIT_LINK(e);
   return e;
 }
 
 static expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2)
 {
   expr_t *e;
+  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->type == EXPR_NUM && expr2->type == EXPR_NUM) {
+  if (expr1->is_const && expr2->is_const) {
+    e->is_const = TRUE;
     switch (type) {
     case EXPR_ADD:
-      expr1->u.lval += expr2->u.lval;
-      free(expr2);
-      return expr1;
+      e->cval = expr1->cval + expr2->cval;
+      break;
     case EXPR_SUB:
-      expr1->u.lval -= expr2->u.lval;
-      free(expr2);
-      return expr1;
+      e->cval = expr1->cval - expr2->cval;
+      break;
     case EXPR_MUL:
-      expr1->u.lval *= expr2->u.lval;
-      free(expr2);
-      return expr1;
+      e->cval = expr1->cval * expr2->cval;
+      break;
     case EXPR_DIV:
-      expr1->u.lval /= expr2->u.lval;
-      free(expr2);
-      return expr1;
+      e->cval = expr1->cval / expr2->cval;
+      break;
     case EXPR_OR:
-      expr1->u.lval |= expr2->u.lval;
-      free(expr2);
-      return expr1;
+      e->cval = expr1->cval | expr2->cval;
+      break;
     case EXPR_AND:
-      expr1->u.lval &= expr2->u.lval;
-      free(expr2);
-      return expr1;
+      e->cval = expr1->cval & expr2->cval;
+      break;
     case EXPR_SHL:
-      expr1->u.lval <<= expr2->u.lval;
-      free(expr2);
-      return expr1;
+      e->cval = expr1->cval << expr2->cval;
+      break;
     case EXPR_SHR:
-      expr1->u.lval >>= expr2->u.lval;
-      free(expr2);
-      return expr1;
+      e->cval = expr1->cval >> expr2->cval;
+      break;
     default:
+      e->is_const = FALSE;
       break;
     }
   }
-  e = xmalloc(sizeof(expr_t));
-  e->type = type;
-  e->ref = expr1;
-  e->u.ext = expr2;
-  INIT_LINK(e);
   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;
+}
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 6607318bc19152f7e67f54b4c3447719bb8aad8e..9060bd17005edd566fda0c87cdb8b4168f059131 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -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 */