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