/* -*-C-*- * IDL Compiler * * Copyright 2002 Ove Kaaven * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ %option bison-bridge %option bison-locations %option stack %option noinput nounput noyy_top_state %option noyywrap %option 8bit never-interactive prefix="parser_" ws [ \f\t\r] hd [0-9a-fA-F] uuid {hd}{8}-{hd}{4}-{hd}{4}-{hd}{4}-{hd}{12} %x ATTR %x PP_LINE %x PP_FILE %x PP_PRAGMA %{ #include "config.h" #include #include #include #include #include #include #include #define YY_NO_UNISTD_H #include "widl.h" #include "utils.h" #include "parser.h" #include "wpp_private.h" #define YYerror PARSER_error #define YYSTYPE PARSER_STYPE #define YYLTYPE PARSER_LTYPE #define YYUNDEF PARSER_UNDEF #define yyerror parser_error #include "parser.tab.h" static void reset_location( struct location *where, const char *input_name ); static void update_location( struct location *where, const char *yytext ); static void end_of_line( struct location *where ); #define YY_USER_INIT reset_location( yylloc, input_name ) #define YY_USER_ACTION update_location( yylloc, yytext ); static void switch_to_acf(void); static warning_list_t *disabled_warnings = NULL; struct import_state { YY_BUFFER_STATE buffer; char *input_name; struct location where; struct list entry; }; static struct list import_stack = LIST_INIT( import_stack ); int parse_only = 0; struct import { const char *name; struct list entry; }; static struct list imports = LIST_INIT( imports ); static struct location previous_location; /* converts an integer in string form to an unsigned long and prints an error * on overflow */ static unsigned int xstrtoul(const char *nptr, char **endptr, int base) { unsigned long val; errno = 0; val = strtoul(nptr, endptr, base); if ((val == ULONG_MAX && errno == ERANGE) || ((unsigned int)val != val)) error_loc("integer constant %s is too large\n", nptr); return val; } static int token_uuid( const char *str, YYSTYPE *yylval ) { struct uuid *uuid; char tmp[3] = {0}; if (*str == '\"') str++; uuid = xmalloc( sizeof(*uuid) ); uuid->Data1 = strtoul( str , NULL, 16 ); uuid->Data2 = strtoul( str + 9, NULL, 16 ); uuid->Data3 = strtoul( str + 14, NULL, 16 ); memcpy( tmp, str + 19, 2 ); uuid->Data4[0] = strtoul( tmp, NULL, 16 ); memcpy( tmp, str + 21, 2 ); uuid->Data4[1] = strtoul( tmp, NULL, 16 ); memcpy( tmp, str + 24, 2 ); uuid->Data4[2] = strtoul( tmp, NULL, 16 ); memcpy( tmp, str + 26, 2 ); uuid->Data4[3] = strtoul( tmp, NULL, 16 ); memcpy( tmp, str + 28, 2 ); uuid->Data4[4] = strtoul( tmp, NULL, 16 ); memcpy( tmp, str + 30, 2 ); uuid->Data4[5] = strtoul( tmp, NULL, 16 ); memcpy( tmp, str + 32, 2 ); uuid->Data4[6] = strtoul( tmp, NULL, 16 ); memcpy( tmp, str + 34, 2 ); uuid->Data4[7] = strtoul( tmp, NULL, 16 ); yylval->uuid = uuid; return aUUID; } static int token_str( int token, const char *str, YYSTYPE *yylval ) { char *tmp = xstrdup( str ); if (token == aWSTRING || token == aSTRING || token == aSQSTRING) { char *src, *dst; src = dst = ++tmp; /* skip first quote */ while (*src) { if (*src == '\\') src++; *dst++ = *src++; } dst[-1] = 0; /* strip last quote */ } yylval->str = tmp; return token; } static int token_num( const char *yytext, YYSTYPE *yylval, int is_hex ) { yylval->integer.value = xstrtoul( yytext, NULL, 0 ); yylval->integer.is_hex = is_hex; yylval->integer.is_long = !!strchr(yytext, 'l'); yylval->integer.is_unsigned = !!strchr(yytext, 'u'); return is_hex ? aHEXNUM : aNUM; } static int token_ident( const char *str, YYSTYPE *yylval ) { return token_str( is_type( str ) ? aKNOWNTYPE : aIDENTIFIER, str, yylval ); } static int token_winrt( int token, const char *str, YYSTYPE *yylval ) { if (winrt_mode) return token; return token_ident( str, yylval ); } static void winrt_enable( int ns_prefix ) { if (!list_empty( &import_stack ) && !winrt_mode) error_loc( "WinRT IDL file imported in non-winrt mode.\n" ); use_abi_namespace = ns_prefix; winrt_mode = TRUE; } %} /* ************************************************************************** * The flexer starts here ************************************************************************** */ %% { midl_echo/"(" { yy_pop_state(); yylloc->first_line -= 1; return tCPPQUOTE; } winrt{ws}+ns_prefix[^\n]* { yy_pop_state(); yylloc->first_line -= 1; winrt_enable( TRUE ); } winrt[^\n]* { yy_pop_state(); yylloc->first_line -= 1; winrt_enable( FALSE ); } [^\n]* { yy_pop_state(); yylloc->first_line -= 1; return token_str( aPRAGMA, yytext, yylval ); } } [0-9]+{ws}* { yylloc->first_line = strtoul( yytext, NULL, 10 ) - 1; yylloc->last_line = yylloc->first_line; yy_pop_state(); yy_push_state(PP_FILE); } \"(\\[^n]|[^"\\\n])*\"{ws}* { input_name = xstrdup( yytext + 1 ); *strchr( input_name, '"' ) = 0; yylloc->input_name = input_name; } [^"][^\n]* { yy_pop_state(); } { \] { yy_pop_state(); return ']'; } ({uuid}|\"{uuid}\") { return token_uuid( yytext, yylval ); } activatable { return token_winrt( tACTIVATABLE, yytext, yylval ); } aggregatable { return tAGGREGATABLE; } agile { return token_winrt( tAGILE, yytext, yylval ); } all_nodes { return tALLNODES; } allocate { return tALLOCATE; } annotation { return tANNOTATION; } apartment { return tAPARTMENT; } appobject { return tAPPOBJECT; } async { return tASYNC; } async_uuid { return tASYNCUUID; } auto_handle { return tAUTOHANDLE; } bindable { return tBINDABLE; } both { return tBOTH; } broadcast { return tBROADCAST; } byte_count { return tBYTECOUNT; } call_as { return tCALLAS; } callback { return tCALLBACK; } code { return tCODE; } comm_status { return tCOMMSTATUS; } composable { return token_winrt( tCOMPOSABLE, yytext, yylval ); } context_handle { return tCONTEXTHANDLE; } context_handle_noserialize { return tCONTEXTHANDLENOSERIALIZE; } context_handle_serialize { return tCONTEXTHANDLENOSERIALIZE; } contract { return token_winrt( tCONTRACT, yytext, yylval ); } contractversion { return token_winrt( tCONTRACTVERSION, yytext, yylval ); } control { return tCONTROL; } custom { return tCUSTOM; } decode { return tDECODE; } default_overload { return tDEFAULT_OVERLOAD; } defaultbind { return tDEFAULTBIND; } defaultcollelem { return tDEFAULTCOLLELEM; } defaultvalue { return tDEFAULTVALUE; } defaultvtable { return tDEFAULTVTABLE; } deprecated { return token_winrt( tDEPRECATED, yytext, yylval ); } disable_consistency_check { return tDISABLECONSISTENCYCHECK; } displaybind { return tDISPLAYBIND; } dllname { return tDLLNAME; } dont_free { return tDONTFREE; } dual { return tDUAL; } enable_allocate { return tENABLEALLOCATE; } encode { return tENCODE; } endpoint { return tENDPOINT; } entry { return tENTRY; } eventadd { return token_winrt( tEVENTADD, yytext, yylval ); } eventremove { return token_winrt( tEVENTREMOVE, yytext, yylval ); } exclusiveto { return token_winrt( tEXCLUSIVETO, yytext, yylval ); } explicit_handle { return tEXPLICITHANDLE; } fault_status { return tFAULTSTATUS; } flags { return token_winrt( tFLAGS, yytext, yylval ); } force_allocate { return tFORCEALLOCATE; } free { return tFREE; } handle { return tHANDLE; } helpcontext { return tHELPCONTEXT; } helpfile { return tHELPFILE; } helpstring { return tHELPSTRING; } helpstringcontext { return tHELPSTRINGCONTEXT; } helpstringdll { return tHELPSTRINGDLL; } hidden { return tHIDDEN; } id { return tID; } idempotent { return tIDEMPOTENT; } ignore { return tIGNORE; } iid_is { return tIIDIS; } immediatebind { return tIMMEDIATEBIND; } implicit_handle { return tIMPLICITHANDLE; } in { return tIN; } in_line { return tIN_LINE; } input_sync { return tINPUTSYNC; } lcid { return tLCID; } length_is { return tLENGTHIS; } licensed { return tLICENSED; } local { return tLOCAL; } marshaling_behavior { return token_winrt( tMARSHALINGBEHAVIOR, yytext, yylval ); } maybe { return tMAYBE; } message { return tMESSAGE; } mta { return tMTA; } neutral { return tNEUTRAL; } nocode { return tNOCODE; } nonbrowsable { return tNONBROWSABLE; } noncreatable { return tNONCREATABLE; } none { return token_winrt( tNONE, yytext, yylval ); } nonextensible { return tNONEXTENSIBLE; } notify { return tNOTIFY; } notify_flag { return tNOTIFYFLAG; } object { return tOBJECT; } odl { return tODL; } oleautomation { return tOLEAUTOMATION; } optimize { return tOPTIMIZE; } optional { return tOPTIONAL; } out { return tOUT; } overload { return tOVERLOAD; } partial_ignore { return tPARTIALIGNORE; } pointer_default { return tPOINTERDEFAULT; } progid { return tPROGID; } propget { return tPROPGET; } propput { return tPROPPUT; } propputref { return tPROPPUTREF; } protected { return tPROTECTED; } proxy { return tPROXY; } ptr { return tPTR; } public { return tPUBLIC; } range { return tRANGE; } readonly { return tREADONLY; } ref { return tREF; } represent_as { return tREPRESENTAS; } requestedit { return tREQUESTEDIT; } restricted { return tRESTRICTED; } retval { return tRETVAL; } single { return tSINGLE; } single_node { return tSINGLENODE; } size_is { return tSIZEIS; } source { return tSOURCE; } standard { return token_winrt( tSTANDARD, yytext, yylval ); } static { return token_winrt( tSTATIC, yytext, yylval ); } strict_context_handle { return tSTRICTCONTEXTHANDLE; } string { return tSTRING; } switch_is { return tSWITCHIS; } switch_type { return tSWITCHTYPE; } threading { return tTHREADING; } transmit_as { return tTRANSMITAS; } uidefault { return tUIDEFAULT; } unique { return tUNIQUE; } user_marshal { return tUSERMARSHAL; } usesgetlasterror { return tUSESGETLASTERROR; } uuid { return tUUID; } v1_enum { return tV1ENUM; } vararg { return tVARARG; } version { return tVERSION; } vi_progid { return tVIPROGID; } wire_marshal { return tWIREMARSHAL; } } { ^{ws}*\#{ws}*pragma{ws}+ { yy_push_state( PP_PRAGMA ); } ^{ws}*midl_pragma{ws}+warning { return tPRAGMA_WARNING; } [0-9]+\.[0-9]+([eE][+-]?[0-9]+)* { yylval->dbl = strtod( yytext, NULL ); return aDOUBLE; } } SAFEARRAY{ws}*/\( return tSAFEARRAY; { ^{ws}*\#{ws}* { yy_push_state(PP_LINE); } \[ { yy_push_state(ATTR); return '['; } FALSE { return tFALSE; } NULL { return tNULL; } TRUE { return tTRUE; } _?_?cdecl { return token_str( tCDECL, "__cdecl", yylval ); } _?_?pascal { return token_str( tPASCAL, "__pascal", yylval ); } _?_?stdcall { return token_str( tSTDCALL, "__stdcall", yylval ); } __?fastcall { return token_str( tFASTCALL, "__fastcall", yylval ); } __int32 { return tINT32; } __int3264 { return tINT3264; } __int64 { return tINT64; } apicontract { return token_winrt( tAPICONTRACT, yytext, yylval ); } boolean { return tBOOLEAN; } byte { return tBYTE; } case { return tCASE; } char { return tCHAR; } coclass { return tCOCLASS; } const { return tCONST; } cpp_quote { return tCPPQUOTE; } declare { return token_winrt( tDECLARE, yytext, yylval ); } default { return tDEFAULT; } delegate { return token_winrt( tDELEGATE, yytext, yylval ); } dispinterface { return tDISPINTERFACE; } double { return tDOUBLE; } enum { return tENUM; } error_status_t { return tERRORSTATUST; } extern { return tEXTERN; } float { return tFLOAT; } handle_t { return tHANDLET; } hyper { return tHYPER; } import { return tIMPORT; } importlib { return tIMPORTLIB; } inline { return tINLINE; } int { return tINT; } interface { return tINTERFACE; } library { return tLIBRARY; } long { return tLONG; } methods { return tMETHODS; } module { return tMODULE; } namespace { return token_winrt( tNAMESPACE, yytext, yylval ); } properties { return tPROPERTIES; } register { return tREGISTER; } requires { return token_winrt( tREQUIRES, yytext, yylval ); } runtimeclass { return token_winrt( tRUNTIMECLASS, yytext, yylval ); } short { return tSHORT; } signed { return tSIGNED; } sizeof { return tSIZEOF; } small { return tSMALL; } static { return tSTATIC; } struct { return tSTRUCT; } switch { return tSWITCH; } typedef { return tTYPEDEF; } union { return tUNION; } unsigned { return tUNSIGNED; } void { return tVOID; } wchar_t { return tWCHAR; } [a-zA-Z_][0-9a-zA-Z_]* { return token_ident( yytext, yylval ); } 0[xX]{hd}+[uU]?[lL]? { return token_num( yytext, yylval, TRUE ); } [0-9]+[uU]?[lL]? { return token_num( yytext, yylval, FALSE ); } L\"(\\.|[^"\\])*\" { return token_str( aWSTRING, yytext + 1, yylval ); } \"(\\.|[^"\\])*\" { return token_str( aSTRING, yytext, yylval ); } \'(\\.|[^'\\])*\' { return token_str( aSQSTRING, yytext, yylval ); } \n { end_of_line( yylloc ); } {ws} {} \<\< { return SHL; } \>\> { return SHR; } \-\> { return MEMBERPTR; } == { return EQUALITY; } != { return INEQUALITY; } \>= { return GREATEREQUAL; } \<= { return LESSEQUAL; } \|\| { return LOGICALOR; } && { return LOGICALAND; } \.\.\. { return ELLIPSIS; } . { return yytext[0]; } } <> { if (!list_empty( &import_stack )) return aEOF; if (acf_name) { switch_to_acf(); return aACF; } yyterminate(); } %% static void print_imports(void) { struct import_state *state, *next; if (list_empty( &import_stack )) return; fprintf( stderr, "In file included from " ); LIST_FOR_EACH_ENTRY_SAFE_REV( state, next, &import_stack, struct import_state, entry ) { if (&next->entry == &import_stack) break; fprintf( stderr, "%s:%d,\n", state->input_name, state->where.first_line ); fprintf( stderr, " from "); } fprintf( stderr, "%s:%d:\n", state->input_name, state->where.first_line ); } struct location pop_import(void) { struct list *entry = list_head( &import_stack ); struct import_state *state; struct location where; assert( entry ); state = LIST_ENTRY( entry, struct import_state, entry ); list_remove( &state->entry ); parse_only = !list_empty( &import_stack ); if (yyin) fclose( yyin ); yy_delete_buffer( YY_CURRENT_BUFFER ); yy_switch_to_buffer( state->buffer ); input_name = state->input_name; where = state->where; free( state ); return where; } void push_import( const char *import_name, struct location *where ) { struct import_state *state; struct import *import; FILE *file; state = xmalloc( sizeof(struct import_state )); list_add_head( &import_stack, &state->entry ); parse_only = !list_empty( &import_stack ); state->buffer = YY_CURRENT_BUFFER; state->input_name = input_name; state->where = *where; input_name = NULL; /* reset buffer for <>, in case import fails or already imported */ yy_scan_string( "" ); LIST_FOR_EACH_ENTRY( import, &imports, struct import, entry ) if (!strcmp( import->name, import_name )) return; /* already imported */ if (!strcmp( idl_name, import_name )) return; /* already imported */ import = xmalloc( sizeof(struct import) ); import->name = xstrdup( import_name ); list_add_tail( &imports, &import->entry ); input_name = find_input_file( import_name, state->input_name ); file = open_input_file( input_name ); reset_location( where, input_name ); yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) ); } static void switch_to_acf(void) { FILE *file; if (yyin) fclose( yyin ); yy_delete_buffer( YY_CURRENT_BUFFER ); input_name = xstrdup( acf_name ); file = open_input_file( input_name ); acf_name = NULL; yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) ); } void close_all_inputs(void) { while (!list_empty( &import_stack )) pop_import(); if (yyin) fclose( yyin ); } static void reset_location( struct location *where, const char *input_name ) { where->first_line = 1; where->last_line = 1; where->first_column = 1; where->last_column = 1; where->input_name = xstrdup( input_name ); } static void update_location( struct location *where, const char *yytext ) { int len = strlen( yytext ); previous_location = *where; where->first_column = where->last_column; where->last_column += len; } static void end_of_line( struct location *where ) { where->first_line++; where->last_line++; where->first_column = 1; where->last_column = 1; } void init_location( struct location *where, const struct location *begin, const struct location *end ) { if (!begin) begin = &previous_location; *where = *begin; if (end) { where->last_line = end->last_line; where->last_column = end->last_column; } else { where->first_line = begin->last_line; where->first_column = begin->last_column; } } static void diagnostic( const struct location *where, const char *type, const char *message ) { char buffer[1024], *line = NULL; FILE *file; int i; if (!where) where = &previous_location; print_imports(); fprintf( stderr, "%s:%d:%d: %s: %s\n", where->input_name, where->first_line, where->first_column, type, message ); if (!where->input_name || !(file = fopen( where->input_name, "r" ))) return; for (i = 0; i < where->first_line; i++) if (!(line = fgets( buffer, sizeof(buffer), file ))) break; fclose( file ); if (!line) return; fprintf( stderr, "%s", line ); line = buffer; for (i = 0; i < where->first_column - 1; i++) line += sprintf( line, " " ); line += sprintf( line, "^" ); for (i = where->first_column + 1; i < where->last_column; i++) line += sprintf( line, "~" ); fprintf( stderr, "%s\n", buffer ); } void parser_error( const struct location *where, const char *message ) { diagnostic( where, "error", message ); } void parser_warning( const struct location *where, const char *message ) { diagnostic( where, "warning", message ); } static void warning_disable(int warning) { warning_t *warning_entry; LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry) if(warning_entry->num == warning) return; warning_entry = xmalloc( sizeof(*warning_entry) ); warning_entry->num = warning; list_add_tail(disabled_warnings, &warning_entry->entry); } static void warning_enable(int warning) { warning_t *warning_entry; LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry) if(warning_entry->num == warning) { list_remove(&warning_entry->entry); free(warning_entry); break; } } int do_warning(const char *toggle, warning_list_t *wnum) { warning_t *warning, *next; int ret = 1; if(!disabled_warnings) { disabled_warnings = xmalloc( sizeof(*disabled_warnings) ); list_init( disabled_warnings ); } if(!strcmp(toggle, "disable")) LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry) warning_disable(warning->num); else if(!strcmp(toggle, "enable") || !strcmp(toggle, "default")) LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry) warning_enable(warning->num); else ret = 0; LIST_FOR_EACH_ENTRY_SAFE(warning, next, wnum, warning_t, entry) free(warning); return ret; } int is_warning_enabled(int warning) { warning_t *warning_entry; if(!disabled_warnings) return 1; LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry) if(warning_entry->num == warning) return 0; return 1; }