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