| /* -*-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 <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include <assert.h> | |
| #include <errno.h> | |
| #include <limits.h> | |
| #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 ) | |
| { | |
| int len = strlen( str ); | |
| char *tmp = xmalloc( len + 1 ); | |
| strcpy( tmp, 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 */ | |
| } | |
| else if (token == aIDENTIFIER) | |
| { | |
| if (len > 255) | |
| { | |
| warning( "truncating identifier that exceeds 255 character limit\n" ); | |
| tmp[255] = 0; | |
| } | |
| } | |
| 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(void) | |
| { | |
| if (!list_empty( &import_stack ) && !winrt_mode) error_loc( "WinRT IDL file imported in non-winrt mode.\n" ); | |
| winrt_mode = TRUE; | |
| } | |
| %} | |
| /* | |
| ************************************************************************** | |
| * The flexer starts here | |
| ************************************************************************** | |
| */ | |
| %% | |
| <PP_PRAGMA>{ | |
| 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(); | |
| if (list_empty( &import_stack )) use_abi_namespace = TRUE; | |
| } | |
| winrt[^\n]* { | |
| yy_pop_state(); | |
| yylloc->first_line -= 1; | |
| winrt_enable(); | |
| } | |
| [^\n]* { | |
| yy_pop_state(); | |
| yylloc->first_line -= 1; | |
| return token_str( aPRAGMA, yytext, yylval ); | |
| } | |
| } | |
| <PP_LINE>[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); | |
| } | |
| <PP_FILE>\"(\\[^n]|[^"\\\n])*\"{ws}* { | |
| input_name = xstrdup( yytext + 1 ); | |
| *strchr( input_name, '"' ) = 0; | |
| yylloc->input_name = input_name; | |
| } | |
| <PP_FILE>[^"][^\n]* { yy_pop_state(); } | |
| <ATTR>{ | |
| \] { 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; } | |
| } | |
| <INITIAL>{ | |
| ^{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; | |
| <INITIAL,ATTR>{ | |
| ^{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]; } | |
| } | |
| <<EOF>> { | |
| 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 <<EOF>>, 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++ = ' '; | |
| *line++ = '^'; | |
| for (i = where->first_column + 1; i < where->last_column; i++) *line++ = '~'; | |
| *line = '\0'; | |
| 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; | |
| } |