From: Rémi Bernon rbernon@codeweavers.com
--- tools/widl/parser.h | 8 ++- tools/widl/parser.l | 43 +++++++++++++--- tools/widl/parser.y | 114 ++++++++++++++++++++++++++++++++++++----- tools/widl/typetree.c | 5 +- tools/widl/utils.c | 53 ++++--------------- tools/widl/utils.h | 2 +- tools/widl/widltypes.h | 3 -- 7 files changed, 157 insertions(+), 71 deletions(-)
diff --git a/tools/widl/parser.h b/tools/widl/parser.h index 81418fca160..a59b439a4d3 100644 --- a/tools/widl/parser.h +++ b/tools/widl/parser.h @@ -21,16 +21,20 @@ #ifndef __WIDL_PARSER_H #define __WIDL_PARSER_H
+#include "widltypes.h" + int parser_parse(void);
+extern void parser_warning( const struct location *where, const char *message ); +extern void parser_error( const struct location *where, const char *error ); +extern void init_location( struct location *copy, const struct location *begin, const struct location *end ); + extern FILE *parser_in; extern char *parser_text; extern int parser_debug; extern int yy_flex_debug;
extern int parse_only; -void push_import( char *import_name ); -void pop_import(void);
int is_type(const char *name);
diff --git a/tools/widl/parser.l b/tools/widl/parser.l index 9fc6a10c501..ef1e2dba52c 100644 --- a/tools/widl/parser.l +++ b/tools/widl/parser.l @@ -19,6 +19,7 @@ */
%option bison-bridge +%option bison-locations %option stack %option noinput nounput noyy_top_state %option noyywrap @@ -53,11 +54,15 @@ uuid {hd}{8}-{hd}{4}-{hd}{4}-{hd}{4}-{hd}{12}
#define YYerror PARSER_error #define YYSTYPE PARSER_STYPE +#define YYLTYPE PARSER_LTYPE #define YYUNDEF PARSER_UNDEF #define yyerror parser_error
#include "parser.tab.h"
+#define YY_USER_INIT parser_loc_reset( yylloc, input_name ) +#define YY_USER_ACTION parser_loc_update( yylloc, yytext ); + static void switch_to_acf(void);
static warning_list_t *disabled_warnings = NULL; @@ -65,8 +70,8 @@ static warning_list_t *disabled_warnings = NULL; struct import_state { YY_BUFFER_STATE buffer; + YYLTYPE yylloc; char *input_name; - int line_number; struct list entry; }; static struct list import_stack = LIST_INIT( import_stack ); @@ -180,29 +185,35 @@ static void winrt_enable( int ns_prefix ) <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( 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 ); } } <PP_LINE>[0-9]+{ws}* { - line_number = strtoul( yytext, NULL, 10 ) - 1; /* We didn't read the newline */ + 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(); }
@@ -418,7 +429,7 @@ SAFEARRAY{ws}*/( return tSAFEARRAY; "(\.|[^"\])*" { return token_str( aSTRING, yytext, yylval ); } '(\.|[^'\])*' { return token_str( aSQSTRING, yytext, yylval ); }
- \n { line_number++; } + \n { parser_loc_eol( yylloc ); } {ws} {} << { return SHL; } >> { return SHR; } @@ -445,7 +456,23 @@ SAFEARRAY{ws}*/( return tSAFEARRAY; } %%
-void pop_import(void) +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->yylloc.first_line ); + fprintf( stderr, " from "); + } + fprintf( stderr, "%s:%d:\n", state->input_name, state->yylloc.first_line ); +} + +void pop_import( YYLTYPE *yylloc ) { struct list *entry = list_head( &import_stack ); struct import_state *state; @@ -460,11 +487,11 @@ void pop_import(void) yy_switch_to_buffer( state->buffer );
input_name = state->input_name; - line_number = state->line_number; + *yylloc = state->yylloc; free( state ); }
-void push_import( char *import_name ) +void push_import( const char *import_name, YYLTYPE *yylloc ) { struct import_state *state; struct import *import; @@ -476,7 +503,7 @@ void push_import( char *import_name )
state->buffer = YY_CURRENT_BUFFER; state->input_name = input_name; - state->line_number = line_number; + state->yylloc = *yylloc; input_name = NULL;
/* reset buffer for <<EOF>>, in case import fails or already imported */ @@ -491,8 +518,8 @@ void push_import( char *import_name )
input_name = find_input_file( import_name, state->input_name ); file = open_input_file( input_name ); - line_number = 1;
+ parser_loc_reset( yylloc, input_name ); yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) ); }
diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 5b45c000163..650c39ec3d0 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -124,13 +124,111 @@ static typelib_t *current_typelib; %code provides {
-int parser_lex( PARSER_STYPE *yylval ); +int parser_lex( PARSER_STYPE *yylval, PARSER_LTYPE *yylloc );
+void print_imports(void); +void push_import( const char *fname, PARSER_LTYPE *yylloc ); +void pop_import( PARSER_LTYPE *yylloc ); + +void parser_loc_reset( PARSER_LTYPE *yylloc, const char *input_name ); +void parser_loc_eol( PARSER_LTYPE *yylloc ); +void parser_loc_update( PARSER_LTYPE *yylloc, const char *yytext ); + +# define YYLLOC_DEFAULT( cur, rhs, n ) \ + do { if (n) init_location( &(cur), &YYRHSLOC( rhs, 1 ), &YYRHSLOC( rhs, n ) ); \ + else init_location( &(cur), &YYRHSLOC( rhs, 0 ), NULL ); } while(0) + +} + +%code +{ + +static YYLTYPE parser_prev_loc; + +void parser_loc_reset( YYLTYPE *yylloc, const char *input_name ) +{ + yylloc->first_line = 1; + yylloc->last_line = 1; + yylloc->first_column = 1; + yylloc->last_column = 1; + yylloc->input_name = xstrdup( input_name ); +} + +void parser_loc_eol( YYLTYPE *yylloc ) +{ + yylloc->first_line++; + yylloc->last_line++; + yylloc->first_column = 1; + yylloc->last_column = 1; +} + +void parser_loc_update( YYLTYPE *yylloc, const char *yytext ) +{ + int len = strlen( yytext ); + parser_prev_loc = *yylloc; + yylloc->first_column = yylloc->last_column; + yylloc->last_column += len; }
+void init_location( YYLTYPE *where, const YYLTYPE *begin, const YYLTYPE *end ) +{ + if (!begin) begin = &parser_prev_loc; + *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 YYLTYPE *yylloc, const char *type, const char *message ) +{ + char buffer[1024], *line = NULL; + FILE *file; + int i; + + if (!yylloc) yylloc = &parser_prev_loc; + + print_imports(); + + fprintf( stderr, "%s:%d:%d: %s: %s\n", yylloc->input_name, yylloc->first_line, yylloc->first_column, type, message ); + + if (!yylloc->input_name || !(file = fopen( yylloc->input_name, "r" ))) return; + for (i = 0; i < yylloc->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 < yylloc->first_column - 1; i++) line += sprintf( line, " " ); + line += sprintf( line, "^" ); + for (i = yylloc->first_column + 1; i < yylloc->last_column; i++) line += sprintf( line, "~" ); + fprintf( stderr, "%s\n", buffer ); +} + +void parser_error( const YYLTYPE *yylloc, const char *message ) +{ + diagnostic( yylloc, "error", message ); +} + +void parser_warning( const YYLTYPE *yylloc, const char *message ) +{ + diagnostic( yylloc, "warning", message ); +} + +} + +%define api.location.type {struct location} %define api.prefix {parser_} %define api.pure full %define parse.error verbose +%locations
%union { attr_t *attr; @@ -507,9 +605,9 @@ typedecl: cppquote: tCPPQUOTE '(' aSTRING ')' { $$ = $3; } ;
-import_start: tIMPORT aSTRING ';' { $$ = $2; push_import($2); } +import_start: tIMPORT aSTRING ';' { $$ = $2; push_import($2, &yylloc ); } ; -import: import_start imp_statements aEOF { pop_import(); } +import: import_start imp_statements aEOF { pop_import( &yylloc ); } ;
importlib: tIMPORTLIB '(' aSTRING ')' @@ -1970,7 +2068,7 @@ var_t *make_var(char *name) init_declspec(&v->declspec, NULL); v->attrs = NULL; v->eval = NULL; - init_location( &v->where ); + init_location( &v->where, NULL, NULL ); v->declonly = FALSE; return v; } @@ -3389,14 +3487,6 @@ static statement_list_t *append_statement(statement_list_t *list, statement_t *s return list; }
-void init_location( struct location *where ) -{ - where->input_name = input_name ? input_name : "stdin"; - where->near_text = parser_text; - where->first_line = line_number; - where->last_line = line_number; -} - type_t *find_parameterized_type(type_t *type, typeref_list_t *params) { char *name = format_parameterized_type_name(type, params); diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index 8d4837b7943..345eee6efc5 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -27,6 +27,7 @@ #include "widl.h" #include "utils.h" #include "parser.h" +#include "parser.tab.h" #include "typetree.h" #include "header.h" #include "hash.h" @@ -65,7 +66,7 @@ type_t *make_type(enum type_type type) t->tfswrite = FALSE; t->checked = FALSE; t->typelib_idx = -1; - init_location( &t->where ); + init_location( &t->where, NULL, NULL ); return t; }
@@ -478,7 +479,7 @@ type_t *type_new_alias(const decl_spec_t *t, const char *name) a->name = xstrdup(name); a->attrs = NULL; a->details.alias.aliasee = *t; - init_location( &a->where ); + init_location( &a->where, NULL, NULL );
return a; } diff --git a/tools/widl/utils.c b/tools/widl/utils.c index 979851e1b44..4f2e9d3d602 100644 --- a/tools/widl/utils.c +++ b/tools/widl/utils.c @@ -32,52 +32,16 @@ #include "utils.h" #include "parser.h"
-#define CURRENT_LOCATION { input_name ? input_name : "stdin", parser_text, line_number, 0, line_number, 0 } - -static const int want_near_indication = 0; - -static void make_print(char *str) -{ - while(*str) - { - if(!isprint(*str)) - *str = ' '; - str++; - } -} - -static void generic_msg( const struct location *where, const char *s, const char *t, va_list ap ) -{ - fprintf( stderr, "%s:%d: %s: ", where->input_name, where->first_line, t ); - vfprintf( stderr, s, ap ); - - if (want_near_indication) - { - char *cpy; - if (where->near_text) - { - cpy = xstrdup( where->near_text ); - make_print( cpy ); - fprintf( stderr, " near '%s'", cpy ); - free( cpy ); - } - } -} - - -/* yyerror: yacc assumes this is not newline terminated. */ -void parser_error(const char *s) -{ - error_loc("%s\n", s); -} - void error_at( const struct location *where, const char *s, ... ) { - struct location cur_loc = CURRENT_LOCATION; + char buffer[1024]; + va_list ap; va_start( ap, s ); - generic_msg( where ? where : &cur_loc, s, "error", ap ); + vsnprintf( buffer, sizeof(buffer), s, ap ); va_end( ap ); + + parser_error( where, buffer ); exit( 1 ); }
@@ -102,11 +66,14 @@ void warning(const char *s, ...)
void warning_at( const struct location *where, const char *s, ... ) { - struct location cur_loc = CURRENT_LOCATION; + char buffer[1024]; + va_list ap; va_start( ap, s ); - generic_msg( where ? where : &cur_loc, s, "warning", ap ); + vsnprintf( buffer, sizeof(buffer), s, ap ); va_end( ap ); + + parser_warning( where, buffer ); }
void chat(const char *s, ...) diff --git a/tools/widl/utils.h b/tools/widl/utils.h index 0196dce95fd..2a6bc7d7930 100644 --- a/tools/widl/utils.h +++ b/tools/widl/utils.h @@ -22,8 +22,8 @@ #define __WIDL_UTILS_H
#include "widltypes.h" +#include "parser.h"
-void parser_error(const char *s) __attribute__((noreturn)); void error(const char *s, ...) __attribute__((format (printf, 1, 2))) __attribute__((noreturn)); void error_at( const struct location *, const char *s, ... ) __attribute__((format( printf, 2, 3 ))) __attribute__((noreturn)); #define error_loc( ... ) error_at( NULL, ## __VA_ARGS__ ) diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h index 4311811f051..fd108ecc473 100644 --- a/tools/widl/widltypes.h +++ b/tools/widl/widltypes.h @@ -313,7 +313,6 @@ enum type_basic_type struct location { const char *input_name; - const char *near_text; int first_line; int last_line; int first_column; @@ -656,8 +655,6 @@ type_t *reg_type(type_t *type, const char *name, struct namespace *namespace, in var_t *make_var(char *name); var_list_t *append_var(var_list_t *list, var_t *var);
-void init_location( struct location * ); - char *format_namespace(struct namespace *namespace, const char *prefix, const char *separator, const char *suffix, const char *abi_prefix); char *format_parameterized_type_name(type_t *type, typeref_list_t *params);