widl: Only recognize attribute keywords inside an attribute list.
[wine/multimedia.git] / tools / widl / parser.l
blobe7caf155c8644abab1fae4d9a542f7cb4038b229
1 /* -*-C-*-
2  * IDL Compiler
3  *
4  * Copyright 2002 Ove Kaaven
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
21 %option stack
22 %option nounput noyy_top_state
23 %option 8bit never-interactive prefix="parser_"
25 nl      \r?\n
26 ws      [ \f\t\r]
27 cident  [a-zA-Z_][0-9a-zA-Z_]*
28 int     [0-9]+
29 hexd    [0-9a-fA-F]
30 hex     0x{hexd}+
31 uuid    {hexd}{8}-{hexd}{4}-{hexd}{4}-{hexd}{4}-{hexd}{12}
33 %x QUOTE
34 %x attr
35 %x pp_line
39 #include "config.h"
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <assert.h>
46 #ifdef HAVE_UNISTD_H
47 # include <unistd.h>
48 #endif
50 #include "widl.h"
51 #include "utils.h"
52 #include "parser.h"
53 #include "wine/wpp.h"
55 #include "parser.tab.h"
57 extern char *temp_name;
59 static void addcchar(char c);
60 static char *get_buffered_cstring(void);
62 static char *cbuffer;
63 static int cbufidx;
64 static int cbufalloc = 0;
66 static int kw_token(const char *kw);
67 static int attr_token(const char *kw);
69 #define MAX_IMPORT_DEPTH 10
70 struct {
71   YY_BUFFER_STATE state;
72   char *input_name;
73   int   line_number;
74   char *temp_name;
75 } import_stack[MAX_IMPORT_DEPTH];
76 int import_stack_ptr = 0;
78 static void pop_import(void);
80 static UUID* parse_uuid(const char*u)
82   UUID* uuid = xmalloc(sizeof(UUID));
83   char b[3];
84   /* it would be nice to use UuidFromStringA */
85   uuid->Data1 = strtoul(u, NULL, 16);
86   uuid->Data2 = strtoul(u+9, NULL, 16);
87   uuid->Data3 = strtoul(u+14, NULL, 16);
88   b[2] = 0;
89   memcpy(b, u+19, 2); uuid->Data4[0] = strtoul(b, NULL, 16);
90   memcpy(b, u+21, 2); uuid->Data4[1] = strtoul(b, NULL, 16);
91   memcpy(b, u+24, 2); uuid->Data4[2] = strtoul(b, NULL, 16);
92   memcpy(b, u+26, 2); uuid->Data4[3] = strtoul(b, NULL, 16);
93   memcpy(b, u+28, 2); uuid->Data4[4] = strtoul(b, NULL, 16);
94   memcpy(b, u+30, 2); uuid->Data4[5] = strtoul(b, NULL, 16);
95   memcpy(b, u+32, 2); uuid->Data4[6] = strtoul(b, NULL, 16);
96   memcpy(b, u+34, 2); uuid->Data4[7] = strtoul(b, NULL, 16);
97   return uuid;
103  **************************************************************************
104  * The flexer starts here
105  **************************************************************************
106  */
108 <INITIAL,attr>^{ws}*\#{ws}*     yy_push_state(pp_line);
109 <pp_line>[^\n]*         {
110                             int lineno;
111                             char *cptr, *fname;
112                             yy_pop_state();
113                             lineno = (int)strtol(yytext, &cptr, 10);
114                             if(!lineno)
115                                 parser_error("Malformed '#...' line-directive; invalid linenumber");
116                             fname = strchr(cptr, '"');
117                             if(!fname)
118                                 parser_error("Malformed '#...' line-directive; missing filename");
119                             fname++;
120                             cptr = strchr(fname, '"');
121                             if(!cptr)
122                                 parser_error("Malformed '#...' line-directive; missing terminating \"");
123                             *cptr = '\0';
124                             line_number = lineno - 1;  /* We didn't read the newline */
125                             free( input_name );
126                             input_name = xstrdup(fname);
127                         }
128 <INITIAL,attr>\"        yy_push_state(QUOTE); cbufidx = 0;
129 <QUOTE>\"               {
130                                 yy_pop_state();
131                                 parser_lval.str = get_buffered_cstring();
132                                 return aSTRING;
133                         }
134 <QUOTE>\\\\             |
135 <QUOTE>\\\"             addcchar(yytext[1]);
136 <QUOTE>\\.              addcchar('\\'); addcchar(yytext[1]);
137 <QUOTE>.                addcchar(yytext[0]);
138 <INITIAL,attr>\[        yy_push_state(attr); return '[';
139 <attr>\]                yy_pop_state(); return ']';
140 <attr>{cident}          return attr_token(yytext);
141 <attr>{uuid}                    {
142                                 parser_lval.uuid = parse_uuid(yytext);
143                                 return aUUID;
144                         }
145 <INITIAL,attr>{hex}     {
146                                 parser_lval.num = strtoul(yytext, NULL, 0);
147                                 return aHEXNUM;
148                         }
149 <INITIAL,attr>{int}     {
150                                 parser_lval.num = strtoul(yytext, NULL, 0);
151                                 return aNUM;
152                         }
153 SAFEARRAY{ws}*/\(       return tSAFEARRAY;
154 {cident}                return kw_token(yytext);
155 <INITIAL,attr>\n        line_number++;
156 <INITIAL,attr>{ws}
157 <INITIAL,attr>\<\<      return SHL;
158 <INITIAL,attr>\>\>      return SHR;
159 <INITIAL,attr>.         return yytext[0];
160 <<EOF>>                 {
161                                 if (import_stack_ptr) {
162                                         pop_import();
163                                         return aEOF;
164                                 }
165                                 else yyterminate();
166                         }
169 #ifndef parser_wrap
170 int parser_wrap(void)
172         return 1;
174 #endif
176 struct keyword {
177         const char *kw;
178         int token;
181 static const struct keyword keywords[] = {
182         {"FALSE",                       tFALSE},
183         {"TRUE",                        tTRUE},
184         {"__cdecl",                     tCDECL},
185         {"__int64",                     tINT64},
186         {"__stdcall",                   tSTDCALL},
187         {"_stdcall",                    tSTDCALL},
188         {"boolean",                     tBOOLEAN},
189         {"byte",                        tBYTE},
190         {"callback",                    tCALLBACK},
191         {"case",                        tCASE},
192         {"char",                        tCHAR},
193         {"coclass",                     tCOCLASS},
194         {"code",                        tCODE},
195         {"comm_status",                 tCOMMSTATUS},
196         {"const",                       tCONST},
197         {"control",                     tCONTROL},
198         {"cpp_quote",                   tCPPQUOTE},
199         {"default",                     tDEFAULT},
200         {"dispinterface",               tDISPINTERFACE},
201         {"double",                      tDOUBLE},
202         {"enum",                        tENUM},
203         {"error_status_t",              tERRORSTATUST},
204         {"extern",                      tEXTERN},
205         {"float",                       tFLOAT},
206         {"handle_t",                    tHANDLET},
207         {"hyper",                       tHYPER},
208         {"import",                      tIMPORT},
209         {"importlib",                   tIMPORTLIB},
210         {"in_line",                     tINLINE},
211         {"int",                         tINT},
212         {"interface",                   tINTERFACE},
213         {"library",                     tLIBRARY},
214         {"long",                        tLONG},
215         {"methods",                     tMETHODS},
216         {"module",                      tMODULE},
217         {"properties",                  tPROPERTIES},
218         {"short",                       tSHORT},
219         {"signed",                      tSIGNED},
220         {"sizeof",                      tSIZEOF},
221         {"small",                       tSMALL},
222         {"struct",                      tSTRUCT},
223         {"switch",                      tSWITCH},
224         {"typedef",                     tTYPEDEF},
225         {"union",                       tUNION},
226         {"unsigned",                    tUNSIGNED},
227         {"void",                        tVOID},
228         {"wchar_t",                     tWCHAR},
230 #define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
232 /* keywords only recognized in attribute lists */
233 static const struct keyword attr_keywords[] =
235         {"aggregatable",                tAGGREGATABLE},
236         {"allocate",                    tALLOCATE},
237         {"appobject",                   tAPPOBJECT},
238         {"async",                       tASYNC},
239         {"async_uuid",                  tASYNCUUID},
240         {"auto_handle",                 tAUTOHANDLE},
241         {"bindable",                    tBINDABLE},
242         {"broadcast",                   tBROADCAST},
243         {"byte_count",                  tBYTECOUNT},
244         {"call_as",                     tCALLAS},
245         {"context_handle",              tCONTEXTHANDLE},
246         {"context_handle_noserialize",  tCONTEXTHANDLENOSERIALIZE},
247         {"context_handle_serialize",    tCONTEXTHANDLENOSERIALIZE},
248         {"defaultcollelem",             tDEFAULTCOLLELEM},
249         {"defaultvalue",                tDEFAULTVALUE},
250         {"defaultvtable",               tDEFAULTVTABLE},
251         {"displaybind",                 tDISPLAYBIND},
252         {"dllname",                     tDLLNAME},
253         {"dual",                        tDUAL},
254         {"endpoint",                    tENDPOINT},
255         {"entry",                       tENTRY},
256         {"explicit_handle",             tEXPLICITHANDLE},
257         {"handle",                      tHANDLE},
258         {"helpcontext",                 tHELPCONTEXT},
259         {"helpfile",                    tHELPFILE},
260         {"helpstring",                  tHELPSTRING},
261         {"helpstringcontext",           tHELPSTRINGCONTEXT},
262         {"helpstringdll",               tHELPSTRINGDLL},
263         {"hidden",                      tHIDDEN},
264         {"id",                          tID},
265         {"idempotent",                  tIDEMPOTENT},
266         {"iid_is",                      tIIDIS},
267         {"immediatebind",               tIMMEDIATEBIND},
268         {"implicit_handle",             tIMPLICITHANDLE},
269         {"in",                          tIN},
270         {"input_sync",                  tINPUTSYNC},
271         {"lcid",                        tLCID},
272         {"length_is",                   tLENGTHIS},
273         {"local",                       tLOCAL},
274         {"nonbrowsable",                tNONBROWSABLE},
275         {"noncreatable",                tNONCREATABLE},
276         {"nonextensible",               tNONEXTENSIBLE},
277         {"object",                      tOBJECT},
278         {"odl",                         tODL},
279         {"oleautomation",               tOLEAUTOMATION},
280         {"optional",                    tOPTIONAL},
281         {"out",                         tOUT},
282         {"pointer_default",             tPOINTERDEFAULT},
283         {"propget",                     tPROPGET},
284         {"propput",                     tPROPPUT},
285         {"propputref",                  tPROPPUTREF},
286         {"ptr",                         tPTR},
287         {"public",                      tPUBLIC},
288         {"range",                       tRANGE},
289         {"readonly",                    tREADONLY},
290         {"ref",                         tREF},
291         {"requestedit",                 tREQUESTEDIT},
292         {"restricted",                  tRESTRICTED},
293         {"retval",                      tRETVAL},
294         {"single",                      tSINGLE},
295         {"size_is",                     tSIZEIS},
296         {"source",                      tSOURCE},
297         {"string",                      tSTRING},
298         {"switch_is",                   tSWITCHIS},
299         {"switch_type",                 tSWITCHTYPE},
300         {"transmit_as",                 tTRANSMITAS},
301         {"unique",                      tUNIQUE},
302         {"uuid",                        tUUID},
303         {"v1_enum",                     tV1ENUM},
304         {"vararg",                      tVARARG},
305         {"version",                     tVERSION},
306         {"wire_marshal",                tWIREMARSHAL},
310 #define KWP(p) ((const struct keyword *)(p))
312 static int kw_cmp_func(const void *s1, const void *s2)
314         return strcmp(KWP(s1)->kw, KWP(s2)->kw);
317 static int kw_token(const char *kw)
319         struct keyword key, *kwp;
320         key.kw = kw;
321         kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
322         if (kwp) {
323                 parser_lval.str = xstrdup(kwp->kw);
324                 return kwp->token;
325         }
326         parser_lval.str = xstrdup(kw);
327         return is_type(kw) ? aKNOWNTYPE : aIDENTIFIER;
330 static int attr_token(const char *kw)
332         struct keyword key, *kwp;
333         key.kw = kw;
334         kwp = bsearch(&key, attr_keywords, sizeof(attr_keywords)/sizeof(attr_keywords[0]),
335                       sizeof(attr_keywords[0]), kw_cmp_func);
336         if (kwp) {
337             parser_lval.str = xstrdup(kwp->kw);
338             return kwp->token;
339         }
340         return kw_token(kw);
343 static void addcchar(char c)
345         if(cbufidx >= cbufalloc)
346         {
347                 cbufalloc += 1024;
348                 cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0]));
349                 if(cbufalloc > 65536)
350                         parser_warning("Reallocating string buffer larger than 64kB");
351         }
352         cbuffer[cbufidx++] = c;
355 static char *get_buffered_cstring(void)
357         addcchar(0);
358         return xstrdup(cbuffer);
361 static void pop_import(void)
363         int ptr = import_stack_ptr-1;
365         fclose(yyin);
366         yy_delete_buffer( YY_CURRENT_BUFFER );
367         yy_switch_to_buffer( import_stack[ptr].state );
368         if (temp_name) {
369                 unlink(temp_name);
370                 free(temp_name);
371         }
372         temp_name = import_stack[ptr].temp_name;
373         free( input_name );
374         input_name = import_stack[ptr].input_name;
375         line_number = import_stack[ptr].line_number;
376         import_stack_ptr--;
379 struct imports {
380         char *name;
381         struct imports *next;
382 } *first_import;
384 int do_import(char *fname)
386         FILE *f;
387         char *hname, *path, *p;
388         struct imports *import;
389         int ptr = import_stack_ptr;
390         int ret;
392         if (!parse_only && do_header) {
393                 hname = dup_basename(fname, ".idl");
394                 p = hname + strlen(hname) - 2;
395                 if (p <= hname || strcmp( p, ".h" )) strcat(hname, ".h");
397                 fprintf(header, "#include <%s>\n", hname);
398                 free(hname);
399         }
401         import = first_import;
402         while (import && strcmp(import->name, fname))
403                 import = import->next;
404         if (import) return 0; /* already imported */
406         import = xmalloc(sizeof(struct imports));
407         import->name = xstrdup(fname);
408         import->next = first_import;
409         first_import = import;
411         if (!(path = wpp_find_include( fname, input_name )))
412             parser_error("Unable to open include file %s", fname);
414         import_stack[ptr].temp_name = temp_name;
415         import_stack[ptr].input_name = input_name;
416         import_stack[ptr].line_number = line_number;
417         import_stack_ptr++;
418         input_name = path;
419         line_number = 1;
421         ret = wpp_parse_temp( path, NULL, &temp_name );
422         if (ret) exit(1);
424         if((f = fopen(temp_name, "r")) == NULL)
425                 parser_error("Unable to open %s", temp_name);
427         import_stack[ptr].state = YY_CURRENT_BUFFER;
428         yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
429         return 1;
432 void abort_import(void)
434         int ptr;
436         for (ptr=0; ptr<import_stack_ptr; ptr++)
437                 unlink(import_stack[ptr].temp_name);