| %{ |
| /* |
| * IDL Compiler |
| * |
| * Copyright 2002 Ove Kaaven |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "config.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <assert.h> |
| #include <ctype.h> |
| #include <string.h> |
| #ifdef HAVE_ALLOCA_H |
| #include <alloca.h> |
| #endif |
| |
| #include "widl.h" |
| #include "utils.h" |
| #include "parser.h" |
| #include "header.h" |
| |
| #if defined(YYBYACC) |
| /* Berkeley yacc (byacc) doesn't seem to know about these */ |
| /* Some *BSD supplied versions do define these though */ |
| # ifndef YYEMPTY |
| # define YYEMPTY (-1) /* Empty lookahead value of yychar */ |
| # endif |
| # ifndef YYLEX |
| # define YYLEX yylex() |
| # endif |
| |
| #elif defined(YYBISON) |
| /* Bison was used for original development */ |
| /* #define YYEMPTY -2 */ |
| /* #define YYLEX yylex() */ |
| |
| #else |
| /* No yacc we know yet */ |
| # if !defined(YYEMPTY) || !defined(YYLEX) |
| # error Yacc version/type unknown. This version needs to be verified for settings of YYEMPTY and YYLEX. |
| # elif defined(__GNUC__) /* gcc defines the #warning directive */ |
| # warning Yacc version/type unknown. It defines YYEMPTY and YYLEX, but is not tested |
| /* #else we just take a chance that it works... */ |
| # endif |
| #endif |
| |
| static attr_t *make_attr(enum attr_type type); |
| static attr_t *make_attrv(enum attr_type type, DWORD val); |
| static attr_t *make_attrp(enum attr_type type, void *val); |
| static type_t *make_type(BYTE type, type_t *ref); |
| static typeref_t *make_tref(char *name, type_t *ref); |
| static typeref_t *uniq_tref(typeref_t *ref); |
| static type_t *type_ref(typeref_t *ref); |
| static void set_type(var_t *v, typeref_t *ref); |
| static var_t *make_var(char *name); |
| static func_t *make_func(var_t *def, var_t *args); |
| |
| static type_t *reg_type(type_t *type, char *name, int t); |
| static type_t *reg_types(type_t *type, var_t *names, int t); |
| static type_t *find_type(char *name, int t); |
| 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); |
| |
| #define tsENUM 1 |
| #define tsSTRUCT 2 |
| #define tsUNION 3 |
| |
| static type_t std_int = { "int" }; |
| |
| %} |
| %union { |
| attr_t *attr; |
| type_t *type; |
| typeref_t *tref; |
| var_t *var; |
| func_t *func; |
| char *str; |
| int num; |
| } |
| |
| %token <str> aIDENTIFIER |
| %token <str> aKNOWNTYPE |
| %token <num> aNUM |
| %token <str> aSTRING |
| %token <uuid> aUUID |
| %token SHL SHR |
| %token tAGGREGATABLE tALLOCATE tAPPOBJECT tARRAYS tASYNC tASYNCUUID |
| %token tAUTOHANDLE tBINDABLE tBOOLEAN tBROADCAST tBYTE tBYTECOUNT |
| %token tCALLAS tCALLBACK tCASE tCDECL tCHAR tCOCLASS tCODE tCOMMSTATUS |
| %token tCONST tCONTEXTHANDLE tCONTEXTHANDLENOSERIALIZE |
| %token tCONTEXTHANDLESERIALIZE tCONTROL tCPPQUOTE |
| %token tDEFAULT |
| %token tDOUBLE |
| %token tENUM |
| %token tEXTERN |
| %token tFLOAT |
| %token tHYPER |
| %token tIIDIS |
| %token tIMPORT tIMPORTLIB |
| %token tIN tINCLUDE tINLINE |
| %token tINT tINT64 |
| %token tINTERFACE |
| %token tLENGTHIS |
| %token tLOCAL |
| %token tLONG |
| %token tOBJECT tODL tOLEAUTOMATION |
| %token tOUT |
| %token tPOINTERDEFAULT |
| %token tREF |
| %token tSHORT |
| %token tSIGNED |
| %token tSIZEIS tSIZEOF |
| %token tSTDCALL |
| %token tSTRING tSTRUCT |
| %token tSWITCH tSWITCHIS tSWITCHTYPE |
| %token tTYPEDEF |
| %token tUNION |
| %token tUNIQUE |
| %token tUNSIGNED |
| %token tUUID |
| %token tV1ENUM |
| %token tVERSION |
| %token tVOID |
| %token tWCHAR tWIREMARSHAL |
| |
| /* used in attr_t */ |
| %token tPOINTERTYPE |
| |
| %type <attr> m_attributes attributes attrib_list attribute |
| %type <type> inherit interface interfacedef |
| %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 |
| %type <var> m_ident t_ident ident p_ident pident pident_list |
| %type <func> funcdef statements |
| %type <num> expr pointer_type |
| |
| %left ',' |
| %left '|' |
| %left '&' |
| %left '-' '+' |
| %left '*' '/' |
| %left SHL SHR |
| %right CAST |
| %right PPTR |
| %right NEG |
| |
| %% |
| |
| statements: { $$ = NULL; } |
| | statements funcdef ';' { LINK($2, $1); $$ = $2; } |
| | statements statement |
| ; |
| |
| statement: ';' {} |
| | constdef {} |
| | cppquote {} |
| | enumdef ';' { if (!parse_only) { write_type(header, $1, NULL, NULL); fprintf(header, ";\n"); } } |
| | externdef ';' {} |
| | import {} |
| | interface ';' {} |
| | interfacedef {} |
| | structdef ';' { if (!parse_only) { write_type(header, $1, NULL, NULL); fprintf(header, ";\n"); } } |
| | typedef ';' {} |
| | uniondef ';' { if (!parse_only) { write_type(header, $1, NULL, NULL); fprintf(header, ";\n"); } } |
| ; |
| |
| cppquote: tCPPQUOTE '(' aSTRING ')' { if (!parse_only) fprintf(header, "%s\n", $3); } |
| ; |
| import: tIMPORT aSTRING ';' { do_import($2); } |
| ; |
| |
| m_args: { $$ = NULL; } |
| | args |
| ; |
| |
| no_args: tVOID { $$ = NULL; } |
| ; |
| |
| args: arg |
| | args ',' arg { LINK($3, $1); $$ = $3; } |
| | no_args |
| ; |
| |
| /* split into two rules to get bison to resolve a tVOID conflict */ |
| arg: attributes type pident array { $$ = $3; |
| set_type($$, $2); |
| $$->attrs = $1; /* FIXME: array */ |
| } |
| | type pident array { $$ = $2; |
| set_type($$, $1); /* FIXME: array */ |
| } |
| ; |
| |
| aexprs: |
| | aexpr_list |
| ; |
| |
| aexpr_list: aexpr |
| | aexprs ',' aexpr |
| ; |
| |
| aexpr: aNUM {} |
| | aIDENTIFIER {} |
| | aexpr '|' aexpr |
| | aexpr '&' aexpr |
| | aexpr '+' aexpr |
| | aexpr '-' aexpr |
| | aexpr '*' aexpr |
| | aexpr '/' aexpr |
| | '-' aexpr %prec NEG |
| | '*' aexpr %prec PPTR |
| | '(' type ')' aexpr %prec CAST |
| | '(' aexpr ')' |
| | tSIZEOF '(' type ')' |
| ; |
| |
| array: |
| | '[' aexprs ']' |
| | '[' '*' ']' |
| ; |
| |
| m_attributes: { $$ = NULL; } |
| | attributes |
| ; |
| |
| attributes: |
| m_attributes '[' attrib_list ']' { LINK_LAST($3, $1); $$ = $3; } |
| ; |
| |
| attrib_list: attribute |
| | attrib_list ',' attribute { LINK_SAFE($3, $1); $$ = $3; /* FIXME: don't use SAFE */ } |
| ; |
| |
| attribute: |
| tASYNC { $$ = make_attr(ATTR_ASYNC); } |
| | tCALLAS '(' ident ')' { $$ = make_attrp(ATTR_CALLAS, $3); } |
| | tCASE '(' expr_list ')' { $$ = NULL; } |
| | tCONTEXTHANDLE { $$ = NULL; } |
| | tCONTEXTHANDLENOSERIALIZE { $$ = NULL; } |
| | tCONTEXTHANDLESERIALIZE { $$ = NULL; } |
| | tDEFAULT { $$ = make_attr(ATTR_DEFAULT); } |
| | tIIDIS '(' ident ')' { $$ = make_attrp(ATTR_IIDIS, $3); } |
| | tIN { $$ = make_attr(ATTR_IN); } |
| | tLENGTHIS '(' aexprs ')' { $$ = 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; } |
| | tSTRING { $$ = make_attr(ATTR_STRING); } |
| | tSWITCHIS '(' aexpr ')' { $$ = NULL; } |
| | tSWITCHTYPE '(' type ')' { $$ = NULL; } |
| | tUUID '(' aUUID ')' { $$ = NULL; } |
| | tV1ENUM { $$ = make_attr(ATTR_V1ENUM); } |
| | tVERSION '(' version ')' { $$ = NULL; } |
| | tWIREMARSHAL '(' type ')' { $$ = make_attrp(ATTR_WIREMARSHAL, type_ref($3)); } |
| | pointer_type { $$ = make_attrv(ATTR_POINTERTYPE, $1); } |
| ; |
| |
| callconv: |
| | tSTDCALL |
| ; |
| |
| cases: |
| | cases case |
| ; |
| |
| case: tCASE expr ':' field |
| | tDEFAULT ':' field |
| ; |
| |
| constdef: tCONST type ident '=' expr |
| ; |
| |
| enums: |
| | enum_list ',' |
| | enum_list |
| ; |
| |
| enum_list: enum |
| | enum_list ',' enum |
| ; |
| |
| enum: ident '=' expr {} |
| | ident {} |
| ; |
| |
| enumdef: tENUM t_ident '{' enums '}' { $$ = get_typev(RPC_FC_SHORT /* FIXME */, $2, tsENUM); |
| $$->defined = TRUE; |
| } |
| ; |
| |
| expr_list: expr {} |
| | expr_list ',' expr {} |
| ; |
| |
| expr: aNUM |
| | aIDENTIFIER {} |
| | expr '|' expr {} |
| | expr SHL expr {} |
| | expr SHR expr {} |
| | '-' expr %prec NEG {} |
| ; |
| |
| externdef: tEXTERN tCONST type ident |
| ; |
| |
| fields: { $$ = NULL; } |
| | fields field { LINK($2, $1); $$ = $2; } |
| ; |
| |
| field: m_attributes type pident array ';' { $$ = $3; set_type($$, $2); $$->attrs = $1; /* FIXME: array */ } |
| | m_attributes uniondef ';' { $$ = make_var(NULL); $$->type = $2; $$->attrs = $1; } |
| | attributes ';' { $$ = make_var(NULL); $$->attrs = $1; } |
| | ';' { $$ = NULL; } |
| ; |
| |
| funcdef: |
| m_attributes type callconv pident |
| '(' m_args ')' { set_type($4, $2); |
| $4->attrs = $1; |
| $$ = make_func($4, $6); |
| } |
| ; |
| |
| m_ident: { $$ = NULL; } |
| | ident |
| ; |
| |
| t_ident: { $$ = NULL; } |
| | aIDENTIFIER { $$ = make_var($1); } |
| | aKNOWNTYPE { $$ = make_var($1); } |
| ; |
| |
| ident: aIDENTIFIER { $$ = make_var($1); } |
| ; |
| |
| base_type: tBYTE { $$ = make_type(RPC_FC_BYTE, NULL); } |
| | tCHAR { $$ = make_type(RPC_FC_CHAR, NULL); } |
| | tUNSIGNED tCHAR { $$ = make_type(RPC_FC_CHAR, NULL); } |
| | tWCHAR { $$ = make_type(RPC_FC_WCHAR, NULL); } |
| | int_std |
| | tSIGNED int_std { $$ = $2; /* FIXME */ } |
| | tUNSIGNED int_std { $$ = $2; /* FIXME */ } |
| | tFLOAT { $$ = make_type(RPC_FC_FLOAT, NULL); } |
| | tDOUBLE { $$ = make_type(RPC_FC_DOUBLE, NULL); } |
| | tBOOLEAN { $$ = make_type(RPC_FC_BYTE, NULL); /* ? */ } |
| ; |
| |
| m_int: |
| | tINT |
| ; |
| |
| int_std: tINT { $$ = make_type(RPC_FC_LONG, &std_int); } /* win32 only */ |
| | tSHORT m_int { $$ = make_type(RPC_FC_SHORT, NULL); } |
| | tLONG m_int { $$ = make_type(RPC_FC_LONG, NULL); } |
| | tHYPER m_int { $$ = make_type(RPC_FC_HYPER, NULL); } |
| | tINT64 { $$ = make_type(RPC_FC_HYPER, NULL); } |
| ; |
| |
| inherit: { $$ = NULL; } |
| | ':' aKNOWNTYPE { $$ = find_type2($2, 0); } |
| ; |
| |
| interface: tINTERFACE aIDENTIFIER { $$ = get_type(RPC_FC_IP, $2, 0); if (!parse_only) write_forward($$); } |
| | tINTERFACE aKNOWNTYPE { $$ = get_type(RPC_FC_IP, $2, 0); if (!parse_only) write_forward($$); } |
| ; |
| |
| interfacedef: attributes interface inherit |
| '{' statements '}' { $$ = $2; |
| if ($$->defined) yyerror("multiple definition error\n"); |
| $$->ref = $3; |
| $$->attrs = $1; |
| $$->funcs = $5; |
| $$->defined = TRUE; |
| if (!parse_only) write_interface($$); |
| } |
| ; |
| |
| p_ident: '*' pident %prec PPTR { $$ = $2; $$->ptr_level++; } |
| | tCONST p_ident { $$ = $2; } |
| ; |
| |
| pident: ident |
| | p_ident |
| | '(' pident ')' { $$ = $2; } |
| ; |
| |
| pident_list: |
| pident |
| | pident_list ',' pident { LINK($3, $1); $$ = $3; } |
| ; |
| |
| pointer_type: |
| tREF { $$ = RPC_FC_RP; } |
| | tUNIQUE { $$ = RPC_FC_UP; } |
| ; |
| |
| structdef: tSTRUCT t_ident '{' fields '}' { $$ = get_typev(RPC_FC_STRUCT, $2, tsSTRUCT); |
| $$->fields = $4; |
| $$->defined = TRUE; |
| } |
| ; |
| |
| type: tVOID { $$ = make_tref(NULL, make_type(0, NULL)); } |
| | aKNOWNTYPE { $$ = make_tref($1, find_type($1, 0)); } |
| | base_type { $$ = make_tref(NULL, $1); } |
| | tCONST type { $$ = uniq_tref($2); $$->ref->is_const = TRUE; } |
| | enumdef { $$ = make_tref(NULL, $1); } |
| | tENUM aIDENTIFIER { $$ = make_tref(NULL, find_type2($2, tsENUM)); } |
| | structdef { $$ = make_tref(NULL, $1); } |
| | tSTRUCT aIDENTIFIER { $$ = make_tref(NULL, get_type(RPC_FC_STRUCT, $2, tsSTRUCT)); } |
| | uniondef { $$ = make_tref(NULL, $1); } |
| | tUNION aIDENTIFIER { $$ = make_tref(NULL, find_type2($2, tsUNION)); } |
| ; |
| |
| typedef: tTYPEDEF m_attributes type pident_list { typeref_t *tref = uniq_tref($3); |
| $4->tname = tref->name; |
| tref->name = NULL; |
| $$ = type_ref(tref); |
| $$->attrs = $2; |
| if (!parse_only) write_typedef($$, $4); |
| reg_types($$, $4, 0); |
| } |
| ; |
| |
| uniondef: tUNION t_ident '{' fields '}' { $$ = get_typev(RPC_FC_NON_ENCAPSULATED_UNION, $2, tsUNION); |
| $$->fields = $4; |
| $$->defined = TRUE; |
| } |
| | tUNION t_ident |
| tSWITCH '(' type ident ')' |
| m_ident '{' cases '}' { $$ = get_typev(RPC_FC_ENCAPSULATED_UNION, $2, tsUNION); |
| $$->defined = TRUE; |
| } |
| ; |
| |
| version: |
| aNUM {} |
| | aNUM '.' aNUM {} |
| ; |
| |
| %% |
| |
| static attr_t *make_attr(enum attr_type type) |
| { |
| attr_t *a = xmalloc(sizeof(attr_t)); |
| a->type = type; |
| a->u.ival = 0; |
| return a; |
| } |
| |
| static attr_t *make_attrv(enum attr_type type, DWORD val) |
| { |
| attr_t *a = xmalloc(sizeof(attr_t)); |
| a->type = type; |
| a->u.ival = val; |
| return a; |
| } |
| |
| static attr_t *make_attrp(enum attr_type type, void *val) |
| { |
| attr_t *a = xmalloc(sizeof(attr_t)); |
| a->type = type; |
| a->u.pval = val; |
| return a; |
| } |
| |
| static type_t *make_type(BYTE type, type_t *ref) |
| { |
| type_t *t = xmalloc(sizeof(type_t)); |
| t->name = NULL; |
| t->type = type; |
| t->ref = ref; |
| t->rname = NULL; |
| t->attrs = NULL; |
| t->funcs = NULL; |
| t->fields = NULL; |
| t->ignore = parse_only; |
| t->is_const = FALSE; |
| t->defined = FALSE; |
| t->written = FALSE; |
| INIT_LINK(t); |
| return t; |
| } |
| |
| static typeref_t *make_tref(char *name, type_t *ref) |
| { |
| typeref_t *t = xmalloc(sizeof(typeref_t)); |
| t->name = name; |
| t->ref = ref; |
| t->uniq = ref ? 0 : 1; |
| return t; |
| } |
| |
| static typeref_t *uniq_tref(typeref_t *ref) |
| { |
| typeref_t *t = ref; |
| type_t *tp; |
| if (t->uniq) return t; |
| tp = make_type(0, t->ref); |
| tp->name = t->name; |
| t->name = NULL; |
| t->ref = tp; |
| t->uniq = 1; |
| return t; |
| } |
| |
| static type_t *type_ref(typeref_t *ref) |
| { |
| type_t *t = ref->ref; |
| if (ref->name) free(ref->name); |
| free(ref); |
| return t; |
| } |
| |
| static void set_type(var_t *v, typeref_t *ref) |
| { |
| v->type = ref->ref; |
| v->tname = ref->name; |
| ref->name = NULL; |
| free(ref); |
| } |
| |
| static var_t *make_var(char *name) |
| { |
| var_t *v = xmalloc(sizeof(var_t)); |
| v->name = name; |
| v->ptr_level = 0; |
| v->type = NULL; |
| v->tname = NULL; |
| v->attrs = NULL; |
| INIT_LINK(v); |
| return v; |
| } |
| |
| static func_t *make_func(var_t *def, var_t *args) |
| { |
| func_t *f = xmalloc(sizeof(func_t)); |
| f->def = def; |
| f->args = args; |
| f->ignore = parse_only; |
| f->idx = -1; |
| INIT_LINK(f); |
| return f; |
| } |
| |
| struct rtype { |
| char *name; |
| type_t *type; |
| int t; |
| struct rtype *next; |
| }; |
| |
| struct rtype *first; |
| |
| static type_t *reg_type(type_t *type, char *name, int t) |
| { |
| struct rtype *nt; |
| if (!name) { |
| yyerror("registering named type without name\n"); |
| return type; |
| } |
| nt = xmalloc(sizeof(struct rtype)); |
| nt->name = name; |
| nt->type = type; |
| nt->t = t; |
| nt->next = first; |
| first = nt; |
| return type; |
| } |
| |
| static type_t *reg_types(type_t *type, var_t *names, int t) |
| { |
| type_t *ptr = type; |
| int ptrc = 0; |
| |
| while (names) { |
| var_t *next = NEXT_LINK(names); |
| if (names->name) { |
| type_t *cur = ptr; |
| int cptr = names->ptr_level; |
| if (cptr > ptrc) { |
| while (cptr > ptrc) { |
| cur = ptr = make_type(RPC_FC_FP, cur); /* FIXME: pointer type from attrs? */ |
| ptrc++; |
| } |
| } else { |
| while (cptr < ptrc) { |
| cur = cur->ref; |
| cptr++; |
| } |
| } |
| reg_type(cur, names->name, t); |
| } |
| free(names); |
| names = next; |
| } |
| return type; |
| } |
| |
| static type_t *find_type(char *name, int t) |
| { |
| struct rtype *cur = first; |
| while (cur && (cur->t != t || strcmp(cur->name, name))) |
| cur = cur->next; |
| if (!cur) { |
| yyerror("type %s not found\n", name); |
| return NULL; |
| } |
| return cur->type; |
| } |
| |
| static type_t *find_type2(char *name, int t) |
| { |
| type_t *tp = find_type(name, t); |
| free(name); |
| return tp; |
| } |
| |
| int is_type(const char *name) |
| { |
| struct rtype *cur = first; |
| while (cur && (cur->t || strcmp(cur->name, name))) |
| cur = cur->next; |
| if (cur) return TRUE; |
| return FALSE; |
| } |
| |
| static type_t *get_type(BYTE type, char *name, int t) |
| { |
| struct rtype *cur = NULL; |
| type_t *tp; |
| if (name) { |
| cur = first; |
| while (cur && (cur->t != t || strcmp(cur->name, name))) |
| cur = cur->next; |
| } |
| if (cur) { |
| free(name); |
| return cur->type; |
| } |
| tp = make_type(type, NULL); |
| tp->name = name; |
| if (!name) return tp; |
| return reg_type(tp, name, t); |
| } |
| |
| static type_t *get_typev(BYTE type, var_t *name, int t) |
| { |
| char *sname = NULL; |
| if (name) { |
| sname = name->name; |
| free(name); |
| } |
| return get_type(type, sname, t); |
| } |