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