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 default_overload { return tDEFAULT_OVERLOAD; }
258 defaultbind { return tDEFAULTBIND; }
259 defaultcollelem { return tDEFAULTCOLLELEM; }
260 defaultvalue { return tDEFAULTVALUE; }
261 defaultvtable { return tDEFAULTVTABLE; }
262 deprecated { return token_winrt( tDEPRECATED, yytext, yylval ); }
263 disable_consistency_check { return tDISABLECONSISTENCYCHECK; }
264 displaybind { return tDISPLAYBIND; }
265 dllname { return tDLLNAME; }
266 dont_free { return tDONTFREE; }
267 dual { return tDUAL; }
268 enable_allocate { return tENABLEALLOCATE; }
269 encode { return tENCODE; }
270 endpoint { return tENDPOINT; }
271 entry { return tENTRY; }
272 eventadd { return token_winrt( tEVENTADD, yytext, yylval ); }
273 eventremove { return token_winrt( tEVENTREMOVE, yytext, yylval ); }
274 exclusiveto { return token_winrt( tEXCLUSIVETO, yytext, yylval ); }
275 explicit_handle { return tEXPLICITHANDLE; }
276 fault_status { return tFAULTSTATUS; }
277 flags { return token_winrt( tFLAGS, yytext, yylval ); }
278 force_allocate { return tFORCEALLOCATE; }
279 free { return tFREE; }
280 handle { return tHANDLE; }
281 helpcontext { return tHELPCONTEXT; }
282 helpfile { return tHELPFILE; }
283 helpstring { return tHELPSTRING; }
284 helpstringcontext { return tHELPSTRINGCONTEXT; }
285 helpstringdll { return tHELPSTRINGDLL; }
286 hidden { return tHIDDEN; }
288 idempotent { return tIDEMPOTENT; }
289 ignore { return tIGNORE; }
290 iid_is { return tIIDIS; }
291 immediatebind { return tIMMEDIATEBIND; }
292 implicit_handle { return tIMPLICITHANDLE; }
294 in_line { return tIN_LINE; }
295 input_sync { return tINPUTSYNC; }
296 lcid { return tLCID; }
297 length_is { return tLENGTHIS; }
298 licensed { return tLICENSED; }
299 local { return tLOCAL; }
300 marshaling_behavior { return token_winrt( tMARSHALINGBEHAVIOR, yytext, yylval ); }
301 maybe { return tMAYBE; }
302 message { return tMESSAGE; }
304 neutral { return tNEUTRAL; }
305 nocode { return tNOCODE; }
306 nonbrowsable { return tNONBROWSABLE; }
307 noncreatable { return tNONCREATABLE; }
308 none { return token_winrt( tNONE, yytext, yylval ); }
309 nonextensible { return tNONEXTENSIBLE; }
310 notify { return tNOTIFY; }
311 notify_flag { return tNOTIFYFLAG; }
312 object { return tOBJECT; }
314 oleautomation { return tOLEAUTOMATION; }
315 optimize { return tOPTIMIZE; }
316 optional { return tOPTIONAL; }
318 overload { return tOVERLOAD; }
319 partial_ignore { return tPARTIALIGNORE; }
320 pointer_default { return tPOINTERDEFAULT; }
321 progid { return tPROGID; }
322 propget { return tPROPGET; }
323 propput { return tPROPPUT; }
324 propputref { return tPROPPUTREF; }
325 protected { return tPROTECTED; }
326 proxy { return tPROXY; }
328 public { return tPUBLIC; }
329 range { return tRANGE; }
330 readonly { return tREADONLY; }
332 represent_as { return tREPRESENTAS; }
333 requestedit { return tREQUESTEDIT; }
334 restricted { return tRESTRICTED; }
335 retval { return tRETVAL; }
336 single { return tSINGLE; }
337 single_node { return tSINGLENODE; }
338 size_is { return tSIZEIS; }
339 source { return tSOURCE; }
340 standard { return token_winrt( tSTANDARD, yytext, yylval ); }
341 static { return token_winrt( tSTATIC, yytext, yylval ); }
342 strict_context_handle { return tSTRICTCONTEXTHANDLE; }
343 string { return tSTRING; }
344 switch_is { return tSWITCHIS; }
345 switch_type { return tSWITCHTYPE; }
346 threading { return tTHREADING; }
347 transmit_as { return tTRANSMITAS; }
348 uidefault { return tUIDEFAULT; }
349 unique { return tUNIQUE; }
350 user_marshal { return tUSERMARSHAL; }
351 usesgetlasterror { return tUSESGETLASTERROR; }
352 uuid { return tUUID; }
353 v1_enum { return tV1ENUM; }
354 vararg { return tVARARG; }
355 version { return tVERSION; }
356 vi_progid { return tVIPROGID; }
357 wire_marshal { return tWIREMARSHAL; }
361 ^{ws}*\#{ws}*pragma{ws}+ { yy_push_state( PP_PRAGMA ); }
362 ^{ws}*midl_pragma{ws}+warning { return tPRAGMA_WARNING; }
364 [0-9]+\.[0-9]+([eE][+-]?[0-9]+)* {
365 yylval->dbl = strtod( yytext, NULL );
370 SAFEARRAY{ws}*/\( return tSAFEARRAY;
373 ^{ws}*\#{ws}* { yy_push_state(PP_LINE); }
374 \[ { yy_push_state(ATTR); return '['; }
376 FALSE { return tFALSE; }
377 NULL { return tNULL; }
378 TRUE { return tTRUE; }
379 _?_?cdecl { return token_str( tCDECL, "__cdecl", yylval ); }
380 _?_?pascal { return token_str( tPASCAL, "__pascal", yylval ); }
381 _?_?stdcall { return token_str( tSTDCALL, "__stdcall", yylval ); }
382 __?fastcall { return token_str( tFASTCALL, "__fastcall", yylval ); }
383 __int32 { return tINT32; }
384 __int3264 { return tINT3264; }
385 __int64 { return tINT64; }
386 apicontract { return token_winrt( tAPICONTRACT, yytext, yylval ); }
387 boolean { return tBOOLEAN; }
388 byte { return tBYTE; }
389 case { return tCASE; }
390 char { return tCHAR; }
391 coclass { return tCOCLASS; }
392 const { return tCONST; }
393 cpp_quote { return tCPPQUOTE; }
394 declare { return token_winrt( tDECLARE, yytext, yylval ); }
395 default { return tDEFAULT; }
396 delegate { return token_winrt( tDELEGATE, yytext, yylval ); }
397 dispinterface { return tDISPINTERFACE; }
398 double { return tDOUBLE; }
399 enum { return tENUM; }
400 error_status_t { return tERRORSTATUST; }
401 extern { return tEXTERN; }
402 float { return tFLOAT; }
403 handle_t { return tHANDLET; }
404 hyper { return tHYPER; }
405 import { return tIMPORT; }
406 importlib { return tIMPORTLIB; }
407 inline { return tINLINE; }
409 interface { return tINTERFACE; }
410 library { return tLIBRARY; }
411 long { return tLONG; }
412 methods { return tMETHODS; }
413 module { return tMODULE; }
414 namespace { return token_winrt( tNAMESPACE, yytext, yylval ); }
415 properties { return tPROPERTIES; }
416 register { return tREGISTER; }
417 requires { return token_winrt( tREQUIRES, yytext, yylval ); }
418 runtimeclass { return token_winrt( tRUNTIMECLASS, yytext, yylval ); }
419 short { return tSHORT; }
420 signed { return tSIGNED; }
421 sizeof { return tSIZEOF; }
422 small { return tSMALL; }
423 static { return tSTATIC; }
424 struct { return tSTRUCT; }
425 switch { return tSWITCH; }
426 typedef { return tTYPEDEF; }
427 union { return tUNION; }
428 unsigned { return tUNSIGNED; }
429 void { return tVOID; }
430 wchar_t { return tWCHAR; }
432 [a-zA-Z_][0-9a-zA-Z_]* { return token_ident( yytext, yylval ); }
434 0[xX]{hd}+([lL][uU]?|[uU][lL]?)? { return token_num( aHEXNUM, yytext, yylval ); }
435 [0-9]+([lL][uU]?|[uU][lL]?)? { return token_num( aNUM, yytext, yylval ); }
437 L\"(\\.|[^"\\])*\" { return token_str( aWSTRING, yytext + 1, yylval ); }
438 \"(\\.|[^"\\])*\" { return token_str( aSTRING, yytext, yylval ); }
439 \'(\\.|[^'\\])*\' { return token_str( aSQSTRING, yytext, yylval ); }
441 \n { end_of_line( yylloc ); }
445 \-\> { return MEMBERPTR; }
446 == { return EQUALITY; }
447 != { return INEQUALITY; }
448 \>= { return GREATEREQUAL; }
449 \<= { return LESSEQUAL; }
450 \|\| { return LOGICALOR; }
451 && { return LOGICALAND; }
452 \.\.\. { return ELLIPSIS; }
453 . { return yytext[0]; }
457 if (!list_empty( &import_stack ))
468 static void print_imports(void)
470 struct import_state *state, *next;
472 if (list_empty( &import_stack )) return;
474 fprintf( stderr, "In file included from " );
475 LIST_FOR_EACH_ENTRY_SAFE_REV( state, next, &import_stack, struct import_state, entry )
477 if (&next->entry == &import_stack) break;
478 fprintf( stderr, "%s:%d,\n", state->input_name, state->where.first_line );
479 fprintf( stderr, " from ");
481 fprintf( stderr, "%s:%d:\n", state->input_name, state->where.first_line );
484 void pop_import( struct location *where )
486 struct list *entry = list_head( &import_stack );
487 struct import_state *state;
490 state = LIST_ENTRY( entry, struct import_state, entry );
491 list_remove( &state->entry );
492 parse_only = !list_empty( &import_stack );
494 if (yyin) fclose( yyin );
495 yy_delete_buffer( YY_CURRENT_BUFFER );
496 yy_switch_to_buffer( state->buffer );
498 input_name = state->input_name;
499 *where = state->where;
503 void push_import( const char *import_name, struct location *where )
505 struct import_state *state;
506 struct import *import;
509 state = xmalloc( sizeof(struct import_state ));
510 list_add_head( &import_stack, &state->entry );
511 parse_only = !list_empty( &import_stack );
513 state->buffer = YY_CURRENT_BUFFER;
514 state->input_name = input_name;
515 state->where = *where;
518 /* reset buffer for <<EOF>>, in case import fails or already imported */
519 yy_scan_string( "" );
521 LIST_FOR_EACH_ENTRY( import, &imports, struct import, entry )
522 if (!strcmp( import->name, import_name )) return; /* already imported */
523 if (!strcmp( idl_name, import_name )) return; /* already imported */
525 import = xmalloc( sizeof(struct import) );
526 import->name = xstrdup( import_name );
527 list_add_tail( &imports, &import->entry );
529 input_name = find_input_file( import_name, state->input_name );
530 file = open_input_file( input_name );
531 reset_location( where, input_name );
533 yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) );
536 static void switch_to_acf(void)
540 if (yyin) fclose( yyin );
541 yy_delete_buffer( YY_CURRENT_BUFFER );
543 input_name = xstrdup( acf_name );
544 file = open_input_file( input_name );
547 yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) );
550 static void reset_location( struct location *where, const char *input_name )
552 where->first_line = 1;
553 where->last_line = 1;
554 where->first_column = 1;
555 where->last_column = 1;
556 where->input_name = xstrdup( input_name );
559 static void update_location( struct location *where, const char *yytext )
561 int len = strlen( yytext );
562 previous_location = *where;
563 where->first_column = where->last_column;
564 where->last_column += len;
567 static void end_of_line( struct location *where )
571 where->first_column = 1;
572 where->last_column = 1;
575 void init_location( struct location *where, const struct location *begin, const struct location *end )
577 if (!begin) begin = &previous_location;
582 where->last_line = end->last_line;
583 where->last_column = end->last_column;
587 where->first_line = begin->last_line;
588 where->first_column = begin->last_column;
592 static void diagnostic( const struct location *where, const char *type, const char *message )
594 char buffer[1024], *line = NULL;
598 if (!where) where = &previous_location;
602 fprintf( stderr, "%s:%d:%d: %s: %s\n", where->input_name, where->first_line, where->first_column, type, message );
604 if (!where->input_name || !(file = fopen( where->input_name, "r" ))) return;
605 for (i = 0; i < where->first_line; i++) if (!(line = fgets( buffer, sizeof(buffer), file ))) break;
608 fprintf( stderr, "%s", line );
611 for (i = 0; i < where->first_column - 1; i++) line += sprintf( line, " " );
612 line += sprintf( line, "^" );
613 for (i = where->first_column + 1; i < where->last_column; i++) line += sprintf( line, "~" );
614 fprintf( stderr, "%s\n", buffer );
617 void parser_error( const struct location *where, const char *message )
619 diagnostic( where, "error", message );
622 void parser_warning( const struct location *where, const char *message )
624 diagnostic( where, "warning", message );
627 static void warning_disable(int warning)
629 warning_t *warning_entry;
630 LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
631 if(warning_entry->num == warning)
633 warning_entry = xmalloc( sizeof(*warning_entry) );
634 warning_entry->num = warning;
635 list_add_tail(disabled_warnings, &warning_entry->entry);
638 static void warning_enable(int warning)
640 warning_t *warning_entry;
641 LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
642 if(warning_entry->num == warning)
644 list_remove(&warning_entry->entry);
650 int do_warning(const char *toggle, warning_list_t *wnum)
652 warning_t *warning, *next;
654 if(!disabled_warnings)
656 disabled_warnings = xmalloc( sizeof(*disabled_warnings) );
657 list_init( disabled_warnings );
660 if(!strcmp(toggle, "disable"))
661 LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
662 warning_disable(warning->num);
663 else if(!strcmp(toggle, "enable") || !strcmp(toggle, "default"))
664 LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
665 warning_enable(warning->num);
669 LIST_FOR_EACH_ENTRY_SAFE(warning, next, wnum, warning_t, entry)
674 int is_warning_enabled(int warning)
676 warning_t *warning_entry;
677 if(!disabled_warnings)
679 LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
680 if(warning_entry->num == warning)