4 * Copyright 2002 Ove Kaaven
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.
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.
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
22 %option bison-locations
24 %option noinput nounput noyy_top_state
26 %option 8bit never-interactive prefix="parser_"
30 uuid {hd}{8}-{hd}{4}-{hd}{4}-{hd}{4}-{hd}{12}
48 #define YY_NO_UNISTD_H
53 #include "wpp_private.h"
55 #define YYerror PARSER_error
56 #define YYSTYPE PARSER_STYPE
57 #define YYLTYPE PARSER_LTYPE
58 #define YYUNDEF PARSER_UNDEF
59 #define yyerror parser_error
61 #include "parser.tab.h"
63 static void reset_location( struct location *where, const char *input_name );
64 static void update_location( struct location *where, const char *yytext );
65 static void end_of_line( struct location *where );
67 #define YY_USER_INIT reset_location( yylloc, input_name )
68 #define YY_USER_ACTION update_location( yylloc, yytext );
70 static void switch_to_acf(void);
72 static warning_list_t *disabled_warnings = NULL;
76 YY_BUFFER_STATE buffer;
78 struct location where;
81 static struct list import_stack = LIST_INIT( import_stack );
89 static struct list imports = LIST_INIT( imports );
90 static struct location previous_location;
92 /* converts an integer in string form to an unsigned long and prints an error
94 static unsigned int xstrtoul(const char *nptr, char **endptr, int base)
99 val = strtoul(nptr, endptr, base);
100 if ((val == ULONG_MAX && errno == ERANGE) || ((unsigned int)val != val))
101 error_loc("integer constant %s is too large\n", nptr);
105 static int token_uuid( const char *str, YYSTYPE *yylval )
110 if (*str == '\"') str++;
112 uuid = xmalloc( sizeof(*uuid) );
113 uuid->Data1 = strtoul( str , NULL, 16 );
114 uuid->Data2 = strtoul( str + 9, NULL, 16 );
115 uuid->Data3 = strtoul( str + 14, NULL, 16 );
116 memcpy( tmp, str + 19, 2 );
117 uuid->Data4[0] = strtoul( tmp, NULL, 16 );
118 memcpy( tmp, str + 21, 2 );
119 uuid->Data4[1] = strtoul( tmp, NULL, 16 );
120 memcpy( tmp, str + 24, 2 );
121 uuid->Data4[2] = strtoul( tmp, NULL, 16 );
122 memcpy( tmp, str + 26, 2 );
123 uuid->Data4[3] = strtoul( tmp, NULL, 16 );
124 memcpy( tmp, str + 28, 2 );
125 uuid->Data4[4] = strtoul( tmp, NULL, 16 );
126 memcpy( tmp, str + 30, 2 );
127 uuid->Data4[5] = strtoul( tmp, NULL, 16 );
128 memcpy( tmp, str + 32, 2 );
129 uuid->Data4[6] = strtoul( tmp, NULL, 16 );
130 memcpy( tmp, str + 34, 2 );
131 uuid->Data4[7] = strtoul( tmp, NULL, 16 );
137 static int token_str( int token, const char *str, YYSTYPE *yylval )
139 char *tmp = xstrdup( str );
141 if (token == aWSTRING || token == aSTRING || token == aSQSTRING)
144 src = dst = ++tmp; /* skip first quote */
147 if (*src == '\\') src++;
150 dst[-1] = 0; /* strip last quote */
157 static int token_num( int token, const char *yytext, YYSTYPE *yylval )
159 yylval->num = xstrtoul( yytext, NULL, 0 );
163 static int token_ident( const char *str, YYSTYPE *yylval )
165 return token_str( is_type( str ) ? aKNOWNTYPE : aIDENTIFIER, str, yylval );
168 static int token_winrt( int token, const char *str, YYSTYPE *yylval )
170 if (winrt_mode) return token;
171 return token_ident( str, yylval );
174 static void winrt_enable( int ns_prefix )
176 if (!list_empty( &import_stack ) && !winrt_mode) error_loc( "WinRT IDL file imported in non-winrt mode.\n" );
178 use_abi_namespace = ns_prefix;
185 **************************************************************************
186 * The flexer starts here
187 **************************************************************************
193 yylloc->first_line -= 1;
196 winrt{ws}+ns_prefix[^\n]* {
198 yylloc->first_line -= 1;
199 winrt_enable( TRUE );
203 yylloc->first_line -= 1;
204 winrt_enable( FALSE );
208 yylloc->first_line -= 1;
209 return token_str( aPRAGMA, yytext, yylval );
212 <PP_LINE>[0-9]+{ws}* {
213 yylloc->first_line = strtoul( yytext, NULL, 10 ) - 1;
214 yylloc->last_line = yylloc->first_line;
216 yy_push_state(PP_FILE);
218 <PP_FILE>\"(\\[^n]|[^"\\\n])*\"{ws}* {
219 input_name = xstrdup( yytext + 1 );
220 *strchr( input_name, '"' ) = 0;
221 yylloc->input_name = input_name;
223 <PP_FILE>[^"][^\n]* { yy_pop_state(); }
226 \] { yy_pop_state(); return ']'; }
228 ({uuid}|\"{uuid}\") { return token_uuid( yytext, yylval ); }
229 activatable { return token_winrt( tACTIVATABLE, yytext, yylval ); }
230 aggregatable { return tAGGREGATABLE; }
231 agile { return token_winrt( tAGILE, yytext, yylval ); }
232 all_nodes { return tALLNODES; }
233 allocate { return tALLOCATE; }
234 annotation { return tANNOTATION; }
235 apartment { return tAPARTMENT; }
236 appobject { return tAPPOBJECT; }
237 async { return tASYNC; }
238 async_uuid { return tASYNCUUID; }
239 auto_handle { return tAUTOHANDLE; }
240 bindable { return tBINDABLE; }
241 both { return tBOTH; }
242 broadcast { return tBROADCAST; }
243 byte_count { return tBYTECOUNT; }
244 call_as { return tCALLAS; }
245 callback { return tCALLBACK; }
246 code { return tCODE; }
247 comm_status { return tCOMMSTATUS; }
248 composable { return token_winrt( tCOMPOSABLE, yytext, yylval ); }
249 context_handle { return tCONTEXTHANDLE; }
250 context_handle_noserialize { return tCONTEXTHANDLENOSERIALIZE; }
251 context_handle_serialize { return tCONTEXTHANDLENOSERIALIZE; }
252 contract { return token_winrt( tCONTRACT, yytext, yylval ); }
253 contractversion { return token_winrt( tCONTRACTVERSION, yytext, yylval ); }
254 control { return tCONTROL; }
255 custom { return tCUSTOM; }
256 decode { return tDECODE; }
257 defaultbind { return tDEFAULTBIND; }
258 defaultcollelem { return tDEFAULTCOLLELEM; }
259 defaultvalue { return tDEFAULTVALUE; }
260 defaultvtable { return tDEFAULTVTABLE; }
261 deprecated { return token_winrt( tDEPRECATED, yytext, yylval ); }
262 disable_consistency_check { return tDISABLECONSISTENCYCHECK; }
263 displaybind { return tDISPLAYBIND; }
264 dllname { return tDLLNAME; }
265 dont_free { return tDONTFREE; }
266 dual { return tDUAL; }
267 enable_allocate { return tENABLEALLOCATE; }
268 encode { return tENCODE; }
269 endpoint { return tENDPOINT; }
270 entry { return tENTRY; }
271 eventadd { return token_winrt( tEVENTADD, yytext, yylval ); }
272 eventremove { return token_winrt( tEVENTREMOVE, yytext, yylval ); }
273 exclusiveto { return token_winrt( tEXCLUSIVETO, yytext, yylval ); }
274 explicit_handle { return tEXPLICITHANDLE; }
275 fault_status { return tFAULTSTATUS; }
276 flags { return token_winrt( tFLAGS, yytext, yylval ); }
277 force_allocate { return tFORCEALLOCATE; }
278 free { return tFREE; }
279 handle { return tHANDLE; }
280 helpcontext { return tHELPCONTEXT; }
281 helpfile { return tHELPFILE; }
282 helpstring { return tHELPSTRING; }
283 helpstringcontext { return tHELPSTRINGCONTEXT; }
284 helpstringdll { return tHELPSTRINGDLL; }
285 hidden { return tHIDDEN; }
287 idempotent { return tIDEMPOTENT; }
288 ignore { return tIGNORE; }
289 iid_is { return tIIDIS; }
290 immediatebind { return tIMMEDIATEBIND; }
291 implicit_handle { return tIMPLICITHANDLE; }
293 in_line { return tIN_LINE; }
294 input_sync { return tINPUTSYNC; }
295 lcid { return tLCID; }
296 length_is { return tLENGTHIS; }
297 licensed { return tLICENSED; }
298 local { return tLOCAL; }
299 marshaling_behavior { return token_winrt( tMARSHALINGBEHAVIOR, yytext, yylval ); }
300 maybe { return tMAYBE; }
301 message { return tMESSAGE; }
303 neutral { return tNEUTRAL; }
304 nocode { return tNOCODE; }
305 nonbrowsable { return tNONBROWSABLE; }
306 noncreatable { return tNONCREATABLE; }
307 none { return token_winrt( tNONE, yytext, yylval ); }
308 nonextensible { return tNONEXTENSIBLE; }
309 notify { return tNOTIFY; }
310 notify_flag { return tNOTIFYFLAG; }
311 object { return tOBJECT; }
313 oleautomation { return tOLEAUTOMATION; }
314 optimize { return tOPTIMIZE; }
315 optional { return tOPTIONAL; }
317 overload { return tOVERLOAD; }
318 partial_ignore { return tPARTIALIGNORE; }
319 pointer_default { return tPOINTERDEFAULT; }
320 progid { return tPROGID; }
321 propget { return tPROPGET; }
322 propput { return tPROPPUT; }
323 propputref { return tPROPPUTREF; }
324 protected { return tPROTECTED; }
325 proxy { return tPROXY; }
327 public { return tPUBLIC; }
328 range { return tRANGE; }
329 readonly { return tREADONLY; }
331 represent_as { return tREPRESENTAS; }
332 requestedit { return tREQUESTEDIT; }
333 restricted { return tRESTRICTED; }
334 retval { return tRETVAL; }
335 single { return tSINGLE; }
336 single_node { return tSINGLENODE; }
337 size_is { return tSIZEIS; }
338 source { return tSOURCE; }
339 standard { return token_winrt( tSTANDARD, yytext, yylval ); }
340 static { return token_winrt( tSTATIC, yytext, yylval ); }
341 strict_context_handle { return tSTRICTCONTEXTHANDLE; }
342 string { return tSTRING; }
343 switch_is { return tSWITCHIS; }
344 switch_type { return tSWITCHTYPE; }
345 threading { return tTHREADING; }
346 transmit_as { return tTRANSMITAS; }
347 uidefault { return tUIDEFAULT; }
348 unique { return tUNIQUE; }
349 user_marshal { return tUSERMARSHAL; }
350 usesgetlasterror { return tUSESGETLASTERROR; }
351 uuid { return tUUID; }
352 v1_enum { return tV1ENUM; }
353 vararg { return tVARARG; }
354 version { return tVERSION; }
355 vi_progid { return tVIPROGID; }
356 wire_marshal { return tWIREMARSHAL; }
360 ^{ws}*\#{ws}*pragma{ws}+ { yy_push_state( PP_PRAGMA ); }
361 ^{ws}*midl_pragma{ws}+warning { return tPRAGMA_WARNING; }
363 [0-9]+\.[0-9]+([eE][+-]?[0-9]+)* {
364 yylval->dbl = strtod( yytext, NULL );
369 SAFEARRAY{ws}*/\( return tSAFEARRAY;
372 ^{ws}*\#{ws}* { yy_push_state(PP_LINE); }
373 \[ { yy_push_state(ATTR); return '['; }
375 FALSE { return tFALSE; }
376 NULL { return tNULL; }
377 TRUE { return tTRUE; }
378 _?_?cdecl { return token_str( tCDECL, "__cdecl", yylval ); }
379 _?_?pascal { return token_str( tPASCAL, "__pascal", yylval ); }
380 _?_?stdcall { return token_str( tSTDCALL, "__stdcall", yylval ); }
381 __?fastcall { return token_str( tFASTCALL, "__fastcall", yylval ); }
382 __int32 { return tINT32; }
383 __int3264 { return tINT3264; }
384 __int64 { return tINT64; }
385 apicontract { return token_winrt( tAPICONTRACT, yytext, yylval ); }
386 boolean { return tBOOLEAN; }
387 byte { return tBYTE; }
388 case { return tCASE; }
389 char { return tCHAR; }
390 coclass { return tCOCLASS; }
391 const { return tCONST; }
392 cpp_quote { return tCPPQUOTE; }
393 declare { return token_winrt( tDECLARE, yytext, yylval ); }
394 default { return tDEFAULT; }
395 delegate { return token_winrt( tDELEGATE, yytext, yylval ); }
396 dispinterface { return tDISPINTERFACE; }
397 double { return tDOUBLE; }
398 enum { return tENUM; }
399 error_status_t { return tERRORSTATUST; }
400 extern { return tEXTERN; }
401 float { return tFLOAT; }
402 handle_t { return tHANDLET; }
403 hyper { return tHYPER; }
404 import { return tIMPORT; }
405 importlib { return tIMPORTLIB; }
406 inline { return tINLINE; }
408 interface { return tINTERFACE; }
409 library { return tLIBRARY; }
410 long { return tLONG; }
411 methods { return tMETHODS; }
412 module { return tMODULE; }
413 namespace { return token_winrt( tNAMESPACE, yytext, yylval ); }
414 properties { return tPROPERTIES; }
415 register { return tREGISTER; }
416 requires { return token_winrt( tREQUIRES, yytext, yylval ); }
417 runtimeclass { return token_winrt( tRUNTIMECLASS, yytext, yylval ); }
418 short { return tSHORT; }
419 signed { return tSIGNED; }
420 sizeof { return tSIZEOF; }
421 small { return tSMALL; }
422 static { return tSTATIC; }
423 struct { return tSTRUCT; }
424 switch { return tSWITCH; }
425 typedef { return tTYPEDEF; }
426 union { return tUNION; }
427 unsigned { return tUNSIGNED; }
428 void { return tVOID; }
429 wchar_t { return tWCHAR; }
431 [a-zA-Z_][0-9a-zA-Z_]* { return token_ident( yytext, yylval ); }
433 0[xX]{hd}+([lL][uU]?|[uU][lL]?)? { return token_num( aHEXNUM, yytext, yylval ); }
434 [0-9]+([lL][uU]?|[uU][lL]?)? { return token_num( aNUM, yytext, yylval ); }
436 L\"(\\.|[^"\\])*\" { return token_str( aWSTRING, yytext + 1, yylval ); }
437 \"(\\.|[^"\\])*\" { return token_str( aSTRING, yytext, yylval ); }
438 \'(\\.|[^'\\])*\' { return token_str( aSQSTRING, yytext, yylval ); }
440 \n { end_of_line( yylloc ); }
444 \-\> { return MEMBERPTR; }
445 == { return EQUALITY; }
446 != { return INEQUALITY; }
447 \>= { return GREATEREQUAL; }
448 \<= { return LESSEQUAL; }
449 \|\| { return LOGICALOR; }
450 && { return LOGICALAND; }
451 \.\.\. { return ELLIPSIS; }
452 . { return yytext[0]; }
456 if (!list_empty( &import_stack ))
467 static void print_imports(void)
469 struct import_state *state, *next;
471 if (list_empty( &import_stack )) return;
473 fprintf( stderr, "In file included from " );
474 LIST_FOR_EACH_ENTRY_SAFE_REV( state, next, &import_stack, struct import_state, entry )
476 if (&next->entry == &import_stack) break;
477 fprintf( stderr, "%s:%d,\n", state->input_name, state->where.first_line );
478 fprintf( stderr, " from ");
480 fprintf( stderr, "%s:%d:\n", state->input_name, state->where.first_line );
483 void pop_import( struct location *where )
485 struct list *entry = list_head( &import_stack );
486 struct import_state *state;
489 state = LIST_ENTRY( entry, struct import_state, entry );
490 list_remove( &state->entry );
491 parse_only = !list_empty( &import_stack );
493 if (yyin) fclose( yyin );
494 yy_delete_buffer( YY_CURRENT_BUFFER );
495 yy_switch_to_buffer( state->buffer );
497 input_name = state->input_name;
498 *where = state->where;
502 void push_import( const char *import_name, struct location *where )
504 struct import_state *state;
505 struct import *import;
508 state = xmalloc( sizeof(struct import_state ));
509 list_add_head( &import_stack, &state->entry );
510 parse_only = !list_empty( &import_stack );
512 state->buffer = YY_CURRENT_BUFFER;
513 state->input_name = input_name;
514 state->where = *where;
517 /* reset buffer for <<EOF>>, in case import fails or already imported */
518 yy_scan_string( "" );
520 LIST_FOR_EACH_ENTRY( import, &imports, struct import, entry )
521 if (!strcmp( import->name, import_name )) return; /* already imported */
523 import = xmalloc( sizeof(struct import) );
524 import->name = xstrdup( import_name );
525 list_add_tail( &imports, &import->entry );
527 input_name = find_input_file( import_name, state->input_name );
528 file = open_input_file( input_name );
529 reset_location( where, input_name );
531 yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) );
534 static void switch_to_acf(void)
538 if (yyin) fclose( yyin );
539 yy_delete_buffer( YY_CURRENT_BUFFER );
541 input_name = xstrdup( acf_name );
542 file = open_input_file( input_name );
545 yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) );
548 static void reset_location( struct location *where, const char *input_name )
550 where->first_line = 1;
551 where->last_line = 1;
552 where->first_column = 1;
553 where->last_column = 1;
554 where->input_name = xstrdup( input_name );
557 static void update_location( struct location *where, const char *yytext )
559 int len = strlen( yytext );
560 previous_location = *where;
561 where->first_column = where->last_column;
562 where->last_column += len;
565 static void end_of_line( struct location *where )
569 where->first_column = 1;
570 where->last_column = 1;
573 void init_location( struct location *where, const struct location *begin, const struct location *end )
575 if (!begin) begin = &previous_location;
580 where->last_line = end->last_line;
581 where->last_column = end->last_column;
585 where->first_line = begin->last_line;
586 where->first_column = begin->last_column;
590 static void diagnostic( const struct location *where, const char *type, const char *message )
592 char buffer[1024], *line = NULL;
596 if (!where) where = &previous_location;
600 fprintf( stderr, "%s:%d:%d: %s: %s\n", where->input_name, where->first_line, where->first_column, type, message );
602 if (!where->input_name || !(file = fopen( where->input_name, "r" ))) return;
603 for (i = 0; i < where->first_line; i++) if (!(line = fgets( buffer, sizeof(buffer), file ))) break;
606 fprintf( stderr, "%s", line );
609 for (i = 0; i < where->first_column - 1; i++) line += sprintf( line, " " );
610 line += sprintf( line, "^" );
611 for (i = where->first_column + 1; i < where->last_column; i++) line += sprintf( line, "~" );
612 fprintf( stderr, "%s\n", buffer );
615 void parser_error( const struct location *where, const char *message )
617 diagnostic( where, "error", message );
620 void parser_warning( const struct location *where, const char *message )
622 diagnostic( where, "warning", message );
625 static void warning_disable(int warning)
627 warning_t *warning_entry;
628 LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
629 if(warning_entry->num == warning)
631 warning_entry = xmalloc( sizeof(*warning_entry) );
632 warning_entry->num = warning;
633 list_add_tail(disabled_warnings, &warning_entry->entry);
636 static void warning_enable(int warning)
638 warning_t *warning_entry;
639 LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
640 if(warning_entry->num == warning)
642 list_remove(&warning_entry->entry);
648 int do_warning(const char *toggle, warning_list_t *wnum)
650 warning_t *warning, *next;
652 if(!disabled_warnings)
654 disabled_warnings = xmalloc( sizeof(*disabled_warnings) );
655 list_init( disabled_warnings );
658 if(!strcmp(toggle, "disable"))
659 LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
660 warning_disable(warning->num);
661 else if(!strcmp(toggle, "enable") || !strcmp(toggle, "default"))
662 LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
663 warning_enable(warning->num);
667 LIST_FOR_EACH_ENTRY_SAFE(warning, next, wnum, warning_t, entry)
672 int is_warning_enabled(int warning)
674 warning_t *warning_entry;
675 if(!disabled_warnings)
677 LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
678 if(warning_entry->num == warning)