From 08af01c2fc26eeb77afe3a667dded68c52ea3c37 Mon Sep 17 00:00:00 2001 From: "Joel E. Denny" Date: Sat, 6 Jan 2007 06:14:04 +0000 Subject: [PATCH] Don't use m4_divert since it makes m4_divert_push and m4_divert_pop unreliable -- especially when they're hidden inside another macro. * data/bison.m4, data/c++-skel.m4, data/c++.m4, data/c-skel.m4, data/c.m4: Remove m4_divert(-1). * data/glr.c, data/glr.cc, data/lalr1.cc, data/location.cc, data/push.c, data/yacc.c: Likewise, and replace m4_divert(0) with m4_divert_push(0) and m4_divert_pop(0). * data/output.c (output_skeleton): Don't add an m4_divert_push(0) and an m4_wrap([m4_divert_pop(0)]) to the M4. Diversion -1, which is pushed and popped by m4sugar, should be first on the stack. Provide warn, complain, and fatal function callbacks to the skeletons. This provides more flexibility than m4_fatal, improves the error message format, and captures messages for translation. Discussed starting at . * data/bison.m4 (b4_error): New, invoked by... (b4_warn, b4_complain, b4_fatal): ... these new macros to wrap the skeleton scanner's new @warn(...@), @complain(...@), and @fatal(...@) directives. Because these M4 macros might be called when the current diversion is -1 or 0, m4_divert_push and m4_divert_pop is used; thus the previous removal of uses of m4_divert, which caused trouble. (b4_check_percent_code_qualifiers): Use b4_complain instead of m4_fatal to report unrecognized %code qualifiers. * data/c++-skel.m4: Use b4_complain instead of m4_fatal to report C++ push parser requests. * data/glr.c: Use b4_complain instead of m4_fatal to report non-deterministic push parser requests. Update @output usage to @output(...@) form. * data/glr.cc, data/lalr1.cc: Use b4_fatal instead of m4_fatal to report missing %defines. Update @output usage to @output(...@) form. * data/location.cc, data/push.c, data/yacc.c: Update @output usage to @output(...@) form. * src/main.c (main): Invoke skel_scanner_free. * src/scan-skel.h (skel_scanner_free): Prototype new function. * src/scan-skel.l (FLEX_NO_OBSTACK): Don't define; we now need the obstack_for_string from flex-scanner.h. (YY_DECL): Use to declare skel_lex static. (decode_at_digraphs): Remove; now handled in the new SC_AT_DIRECTIVE_ARG start condition. (fail_for_at_directive_too_many_args, fail_for_invalid_at): New static functions. (at_directive_name, AT_DIRECTIVE_ARGC_MAX, at_directive_argc, at_directive_argv): New static globals. (INITIAL): Use fail_for_invalid_at. Don't parse `@output file_name\n' or `@basename(...@)'. Instead, recognize the start of a generalized `@directive(...@)' form and start... (SC_AT_DIRECTIVE_ARG): ... this new start condition to parse the directive args (using the new obstack_for_string), to decode the contained @ diagraphs, and to perform the directive. It recognizes @basename(...@), @warn(...@), @complain(...@), @fatal(...@), and @output(...@). (SC_AT_DIRECTIVE_SKIP_WS): New start condition started by SC_AT_DIRECTIVE_ARG to skip whitespace after the argument delimiter, `@,'. (scan_skel): Initialize obstack_for_string on the first call. (skel_scanner_free): New function to free obstack_for_string. * tests/input.at (Reject bad %code qualifiers): Update test output. --- ChangeLog | 62 +++++++++++++++ data/bison.m4 | 71 ++++++++++++++++- data/c++-skel.m4 | 4 +- data/c++.m4 | 2 +- data/c-skel.m4 | 2 +- data/c.m4 | 2 +- data/glr.c | 11 +-- data/glr.cc | 8 +- data/lalr1.cc | 14 ++-- data/location.cc | 10 +-- data/push.c | 9 ++- data/yacc.c | 9 ++- src/main.c | 2 + src/output.c | 3 - src/scan-skel.h | 1 + src/scan-skel.l | 202 +++++++++++++++++++++++++++++++++++------------ tests/input.at | 16 +++- 17 files changed, 334 insertions(+), 94 deletions(-) diff --git a/ChangeLog b/ChangeLog index d06290e3..b7e7ec94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,65 @@ +2007-01-05 Joel E. Denny + + Don't use m4_divert since it makes m4_divert_push and m4_divert_pop + unreliable -- especially when they're hidden inside another macro. + * data/bison.m4, data/c++-skel.m4, data/c++.m4, data/c-skel.m4, + data/c.m4: Remove m4_divert(-1). + * data/glr.c, data/glr.cc, data/lalr1.cc, data/location.cc, + data/push.c, data/yacc.c: Likewise, and replace m4_divert(0) with + m4_divert_push(0) and m4_divert_pop(0). + * data/output.c (output_skeleton): Don't add an m4_divert_push(0) and + an m4_wrap([m4_divert_pop(0)]) to the M4. Diversion -1, which is + pushed and popped by m4sugar, should be first on the stack. + + Provide warn, complain, and fatal function callbacks to the skeletons. + This provides more flexibility than m4_fatal, improves the error + message format, and captures messages for translation. Discussed + starting at + . + * data/bison.m4 (b4_error): New, invoked by... + (b4_warn, b4_complain, b4_fatal): ... these new macros to wrap the + skeleton scanner's new @warn(...@), @complain(...@), and @fatal(...@) + directives. Because these M4 macros might be called when the current + diversion is -1 or 0, m4_divert_push and m4_divert_pop is used; thus + the previous removal of uses of m4_divert, which caused trouble. + (b4_check_percent_code_qualifiers): Use b4_complain instead of + m4_fatal to report unrecognized %code qualifiers. + * data/c++-skel.m4: Use b4_complain instead of m4_fatal to report C++ + push parser requests. + * data/glr.c: Use b4_complain instead of m4_fatal to report + non-deterministic push parser requests. + Update @output usage to @output(...@) form. + * data/glr.cc, data/lalr1.cc: Use b4_fatal instead of m4_fatal to + report missing %defines. Update @output usage to @output(...@) form. + * data/location.cc, data/push.c, data/yacc.c: Update @output usage to + @output(...@) form. + * src/main.c (main): Invoke skel_scanner_free. + * src/scan-skel.h (skel_scanner_free): Prototype new function. + * src/scan-skel.l (FLEX_NO_OBSTACK): Don't define; we now need the + obstack_for_string from flex-scanner.h. + (YY_DECL): Use to declare skel_lex static. + (decode_at_digraphs): Remove; now handled in the new + SC_AT_DIRECTIVE_ARG start condition. + (fail_for_at_directive_too_many_args, fail_for_invalid_at): New static + functions. + (at_directive_name, AT_DIRECTIVE_ARGC_MAX, at_directive_argc, + at_directive_argv): New static globals. + (INITIAL): Use fail_for_invalid_at. + Don't parse `@output file_name\n' or `@basename(...@)'. Instead, + recognize the start of a generalized `@directive(...@)' form and + start... + (SC_AT_DIRECTIVE_ARG): ... this new start condition to parse the + directive args (using the new obstack_for_string), to decode the + contained @ diagraphs, and to perform the directive. It recognizes + @basename(...@), @warn(...@), @complain(...@), @fatal(...@), and + @output(...@). + (SC_AT_DIRECTIVE_SKIP_WS): New start condition started by + SC_AT_DIRECTIVE_ARG to skip whitespace after the argument delimiter, + `@,'. + (scan_skel): Initialize obstack_for_string on the first call. + (skel_scanner_free): New function to free obstack_for_string. + * tests/input.at (Reject bad %code qualifiers): Update test output. + 2007-01-04 Joel E. Denny Consolidate the 4 prologue alternative directives (%code, %requires, diff --git a/data/bison.m4 b/data/bison.m4 index 4f60e8cc..76f45509 100644 --- a/data/bison.m4 +++ b/data/bison.m4 @@ -1,4 +1,4 @@ -m4_divert(-1) -*- Autoconf -*- + -*- Autoconf -*- # Language-independent M4 Macros for Bison. # Copyright (C) 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. @@ -61,6 +61,71 @@ This special exception was added by the Free Software Foundation in version 2.2 of Bison.])]) +## ---------------- ## +## Error handling. ## +## ---------------- ## + +# b4_error(KIND, FORMAT, [ARG1], [ARG2], ...) +# --------------------------------------------------------------- +# Write @KIND(FORMAT@,ARG1@,ARG2@,...@) to diversion 0. +m4_define([b4_error], +[m4_divert_push(0)[@]$1[(]$2[]m4_if([$#], [2], [], +[m4_foreach([b4_arg], + m4_dquote(m4_shift(m4_shift($@))), + [[@,]b4_arg])])[@)]m4_divert_pop(0)]) + +# b4_warn(FORMAT, [ARG1], [ARG2], ...) +# -------------------------------------------------------- +# Write @warn(FORMAT@,ARG1@,ARG2@,...@) to diversion 0. +# +# As a simple test suite, this: +# +# m4_define([asdf], [ASDF]) +# m4_define([fsa], [FSA]) +# m4_define([fdsa], [FDSA]) +# b4_warn([[[asdf), asdf]]], [[[fsa), fsa]]], [[[fdsa), fdsa]]]) +# m4_divert(0) +# b4_warn([[asdf), asdf]], [[fsa), fsa]], [[fdsa), fdsa]]) +# m4_divert(0) +# b4_warn([asdf), asdf], [fsa), fsa], [fdsa), fdsa]) +# m4_divert(0) +# b4_warn +# m4_divert(0) +# b4_warn() +# m4_divert(0) +# b4_warn(1) +# m4_divert(0) +# b4_warn(1, 2) +# +# Should produce this: +# +# @warn([asdf), asdf]@,[fsa), fsa]@,[fdsa), fdsa]@) +# @warn(asdf), asdf@,fsa), fsa@,fdsa), fdsa@) +# @warn(ASDF), ASDF@,FSA), FSA@,FDSA), FDSA@) +# @warn(@) +# @warn(@) +# @warn(1@) +# @warn(1@,2@) +m4_define([b4_warn], +[b4_error([[warn]], $@)]) + +# b4_complain(FORMAT, [ARG1], [ARG2], ...) +# ------------------------------------------------------------ +# Write @complain(FORMAT@,ARG1@,ARG2@,...@) to diversion 0. +# +# See the test suite for b4_warn above. +m4_define([b4_complain], +[b4_error([[complain]], $@)]) + +# b4_fatal(FORMAT, [ARG1], [ARG2], ...) +# --------------------------------------------------------- +# Write @fatal(FORMAT@,ARG1@,ARG2@,...@) to diversion 0. +# +# See the test suite for b4_warn above. +m4_define([b4_fatal], +[b4_error([[fatal]], $@)]) + + ## ---------------- ## ## Default values. ## ## ---------------- ## @@ -223,6 +288,8 @@ m4_foreach([b4_qualifier], [m4_if(m4_index(m4_if($#, 0, [], [[,]m4_quote($*)[,]]), [,]m4_defn([b4_qualifier])[,]), [-1], - [m4_fatal([`]m4_defn([b4_qualifier])[' is not a recognized %code qualifier.])]) + [b4_complain([[`%s' is not a recognized %%code qualifier]], + [m4_defn([b4_qualifier])]) + ]) ]) ])]) diff --git a/data/c++-skel.m4 b/data/c++-skel.m4 index 183282b0..7a760bd4 100644 --- a/data/c++-skel.m4 +++ b/data/c++-skel.m4 @@ -1,4 +1,4 @@ -m4_divert(-1) -*- Autoconf -*- + -*- Autoconf -*- # C++ skeleton dispatching for Bison. # Copyright (C) 2006 Free Software Foundation, Inc. @@ -21,7 +21,7 @@ m4_divert(-1) -*- Autoconf -*- b4_glr_if( [m4_define([b4_used_skeleton], [b4_pkgdatadir/[glr.cc]])]) b4_nondeterministic_if([m4_define([b4_used_skeleton], [b4_pkgdatadir/[glr.cc]])]) -b4_push_if([m4_fatal([%push-parser is not supported by C++])]) +b4_push_if([b4_complain([[C++ push parsers are not supported]])]) m4_define_default([b4_used_skeleton], [b4_pkgdatadir/[lalr1.cc]]) m4_define_default([b4_skeleton], ["b4_basename(b4_used_skeleton)"]) diff --git a/data/c++.m4 b/data/c++.m4 index f6e3c56f..cef23a16 100644 --- a/data/c++.m4 +++ b/data/c++.m4 @@ -1,4 +1,4 @@ -m4_divert(-1) -*- Autoconf -*- + -*- Autoconf -*- # C++ skeleton for Bison diff --git a/data/c-skel.m4 b/data/c-skel.m4 index 4833d015..f8f598f8 100644 --- a/data/c-skel.m4 +++ b/data/c-skel.m4 @@ -1,4 +1,4 @@ -m4_divert(-1) -*- Autoconf -*- + -*- Autoconf -*- # C skeleton dispatching for Bison. # Copyright (C) 2006 Free Software Foundation, Inc. diff --git a/data/c.m4 b/data/c.m4 index 678b96ab..ffab4970 100644 --- a/data/c.m4 +++ b/data/c.m4 @@ -1,4 +1,4 @@ -m4_divert(-1) -*- Autoconf -*- + -*- Autoconf -*- # C M4 Macros for Bison. # Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. diff --git a/data/glr.c b/data/glr.c index 0e3608d9..7ed26df4 100644 --- a/data/glr.c +++ b/data/glr.c @@ -1,4 +1,4 @@ -m4_divert(-1) -*- C -*- + -*- C -*- # GLR skeleton for Bison # Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. @@ -23,7 +23,7 @@ m4_include(b4_pkgdatadir/[c.m4]) b4_check_percent_code_qualifiers([[requires]], [[provides]], [[top]]) b4_push_if([ -m4_fatal([Non-deterministic push parsers are not yet supported])]) +b4_complain([[non-deterministic push parsers are not yet supported]])]) ## ---------------- ## ## Default values. ## @@ -145,8 +145,8 @@ m4_define([b4_rhs_location], # We do want M4 expansion after # for CPP macros. m4_changecom() -m4_divert(0)dnl -@output b4_parser_file_name +m4_divert_push(0)dnl +@output(b4_parser_file_name@) b4_copyright([Skeleton implementation for Bison GLR parsers in C], [2002, 2003, 2004, 2005, 2006]) [ @@ -2640,7 +2640,7 @@ dnl glr.cc produces its own header. dnl m4_if(b4_skeleton, ["glr.c"], [b4_defines_if( -[@output b4_spec_defines_file +[@output(b4_spec_defines_file@) b4_copyright([Skeleton interface for Bison GLR parsers in C], [2002, 2003, 2004, 2005, 2006]) @@ -2652,3 +2652,4 @@ b4_locations_if([b4_pure_if([], [extern YYLTYPE b4_prefix[]lloc;]) ]) ])]) +m4_divert_pop(0) diff --git a/data/glr.cc b/data/glr.cc index 7120d229..80702a20 100644 --- a/data/glr.cc +++ b/data/glr.cc @@ -1,4 +1,4 @@ -m4_divert(-1) -*- C -*- + -*- C -*- # C++ GLR skeleton for Bison # Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. @@ -52,7 +52,7 @@ m4_define([b4_pure_flag], [1]) # The header is mandatory. b4_defines_if([], - [m4_fatal(b4_skeleton[: using %defines is mandatory])]) + [b4_fatal([b4_skeleton[: using %%defines is mandatory]])]) m4_include(b4_pkgdatadir/[c++.m4]) m4_include(b4_pkgdatadir/[location.cc]) @@ -216,7 +216,8 @@ m4_defn([b4_parse_param])))], m4_include(b4_pkgdatadir/[glr.c]) m4_popdef([b4_parse_param]) -@output b4_spec_defines_file +m4_divert_push(0) +@output(b4_spec_defines_file@) b4_copyright([Skeleton interface for Bison GLR parsers in C++], [2002, 2003, 2004, 2005, 2006])[ @@ -378,3 +379,4 @@ m4_ifset([b4_global_tokens_and_yystype], ]b4_user_code([b4_percent_code_provides])])[]dnl [#endif /* ! defined PARSER_HEADER_H */] +m4_divert_pop(0) diff --git a/data/lalr1.cc b/data/lalr1.cc index 8dcce38a..271cdb3e 100644 --- a/data/lalr1.cc +++ b/data/lalr1.cc @@ -1,5 +1,3 @@ -m4_divert(-1) - # C++ skeleton for Bison # Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. @@ -24,7 +22,7 @@ b4_check_percent_code_qualifiers([[requires]], [[provides]], [[top]]) # The header is mandatory. b4_defines_if([], - [m4_fatal(b4_skeleton[: using %defines is mandatory])]) + [b4_fatal([b4_skeleton[: using %%defines is mandatory]])]) # Backward compatibility. m4_define([b4_location_constructors]) @@ -32,9 +30,9 @@ m4_include(b4_pkgdatadir/[location.cc]) # We do want M4 expansion after # for CPP macros. m4_changecom() -m4_divert(0)dnl +m4_divert_push(0)dnl b4_defines_if( -[@output b4_spec_defines_file +[@output(b4_spec_defines_file@) b4_copyright([Skeleton interface for Bison LALR(1) parsers in C++], [2002, 2003, 2004, 2005, 2006]) dnl FIXME: This is wrong, we want computed header guards. @@ -302,7 +300,7 @@ m4_ifdef([b4_percent_code_provides], [#endif /* ! defined PARSER_HEADER_H */] ])dnl -@output b4_parser_file_name +@output(b4_parser_file_name@) b4_copyright([Skeleton implementation for Bison LALR(1) parsers in C++], [2002, 2003, 2004, 2005, 2006]) m4_ifdef([b4_percent_code_top], @@ -1060,7 +1058,7 @@ b4_error_verbose_if([, int tok])[) ]b4_epilogue dnl -@output b4_dir_prefix[]stack.hh +@output(b4_dir_prefix[]stack.hh@) b4_copyright([Stack handling for Bison parsers in C++], [2002, 2003, 2004, 2005, 2006])[ @@ -1159,4 +1157,4 @@ namespace ]b4_namespace[ } #endif // not BISON_STACK_HH] -m4_divert(-1) +m4_divert_pop(0) diff --git a/data/location.cc b/data/location.cc index 2d32bf77..80e712ea 100644 --- a/data/location.cc +++ b/data/location.cc @@ -1,5 +1,3 @@ -m4_divert(-1) - # C++ skeleton for Bison # Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. @@ -21,8 +19,8 @@ m4_divert(-1) # We do want M4 expansion after # for CPP macros. m4_changecom() -m4_divert(0)dnl -@output b4_dir_prefix[]position.hh +m4_divert_push(0)dnl +@output(b4_dir_prefix[]position.hh@) b4_copyright([Positions for Bison parsers in C++], [2002, 2003, 2004, 2005, 2006])[ @@ -147,7 +145,7 @@ namespace ]b4_namespace[ } #endif // not BISON_POSITION_HH] -@output b4_dir_prefix[]location.hh +@output(b4_dir_prefix[]location.hh@) b4_copyright([Locations for Bison parsers in C++], [2002, 2003, 2004, 2005, 2006])[ @@ -276,5 +274,5 @@ namespace ]b4_namespace[ } #endif // not BISON_LOCATION_HH] -m4_divert(-1) +m4_divert_pop(0) m4_changecom([#]) diff --git a/data/push.c b/data/push.c index c51859f4..25010509 100644 --- a/data/push.c +++ b/data/push.c @@ -1,4 +1,4 @@ -m4_divert(-1) -*- C -*- + -*- C -*- # Yacc compatible skeleton for Bison @@ -145,8 +145,8 @@ m4_define([b4_rhs_location], # We do want M4 expansion after # for CPP macros. m4_changecom() -m4_divert(0)dnl -@output b4_parser_file_name +m4_divert_push(0)dnl +@output(b4_parser_file_name@) b4_copyright([Skeleton implementation for Bison's Yacc-like parsers in C],dnl ' [1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006])[ @@ -1659,7 +1659,7 @@ yypushreturn: ]b4_epilogue b4_defines_if( -[@output b4_spec_defines_file +[@output(b4_spec_defines_file@) b4_copyright([Skeleton interface for Bison's Yacc-like parsers in C],dnl ' [1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006]) @@ -1726,3 +1726,4 @@ m4_ifdef([b4_percent_code_provides], [[/* Copy the %code "provides" blocks. */ ]b4_user_code([b4_percent_code_provides])])[] ])dnl b4_defines_if +m4_divert_pop(0) diff --git a/data/yacc.c b/data/yacc.c index 8975b2bf..a8bb367b 100644 --- a/data/yacc.c +++ b/data/yacc.c @@ -1,4 +1,4 @@ -m4_divert(-1) -*- C -*- + -*- C -*- # Yacc compatible skeleton for Bison @@ -137,8 +137,8 @@ m4_define([b4_rhs_location], # We do want M4 expansion after # for CPP macros. m4_changecom() -m4_divert(0)dnl -@output b4_parser_file_name +m4_divert_push(0)dnl +@output(b4_parser_file_name@) b4_copyright([Skeleton implementation for Bison's Yacc-like parsers in C],dnl ' [1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006])[ @@ -1496,7 +1496,7 @@ yyreturn: b4_epilogue b4_defines_if( -[@output b4_spec_defines_file +[@output(b4_spec_defines_file@) b4_copyright([Skeleton interface for Bison's Yacc-like parsers in C],dnl ' [1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006]) @@ -1544,3 +1544,4 @@ m4_ifdef([b4_percent_code_provides], [[/* Copy the %code "provides" blocks. */ ]b4_user_code([b4_percent_code_provides])])[] ])dnl b4_defines_if +m4_divert_pop(0) diff --git a/src/main.c b/src/main.c index 610d2c4e..50827098 100644 --- a/src/main.c +++ b/src/main.c @@ -46,6 +46,7 @@ #include "reduce.h" #include "scan-code.h" #include "scan-gram.h" +#include "scan-skel.h" #include "symtab.h" #include "tables.h" #include "uniqstr.h" @@ -175,6 +176,7 @@ main (int argc, char *argv[]) muscle_free (); uniqstrs_free (); code_scanner_free (); + skel_scanner_free (); quotearg_free (); timevar_pop (TV_FREE); diff --git a/src/output.c b/src/output.c index 2fea642b..8a4b64f3 100644 --- a/src/output.c +++ b/src/output.c @@ -536,9 +536,6 @@ output_skeleton (void) symbol_code_props_output (out, "printers", &symbol_printer_get); muscles_m4_output (out); - - fputs ("m4_wrap([m4_divert_pop(0)])\n", out); - fputs ("m4_divert_push(0)dnl\n", out); xfclose (out); /* Read and process m4's output. */ diff --git a/src/scan-skel.h b/src/scan-skel.h index a7e14c38..b6427ebd 100644 --- a/src/scan-skel.h +++ b/src/scan-skel.h @@ -26,3 +26,4 @@ extern FILE *skel_in; extern FILE *skel_out; extern int skel__flex_debug; extern int skel_lineno; +void skel_scanner_free (void); diff --git a/src/scan-skel.l b/src/scan-skel.l index 4bba4ac4..bd9ff841 100644 --- a/src/scan-skel.l +++ b/src/scan-skel.l @@ -29,7 +29,6 @@ #undef skel_wrap #define skel_wrap() 1 -#define FLEX_NO_OBSTACK #define FLEX_PREFIX(Id) skel_ ## Id #include "flex-scanner.h" @@ -42,13 +41,28 @@ #include "files.h" #include "scan-skel.h" -int skel_lex (void); +#define YY_DECL static int skel_lex (void) +YY_DECL; #define QPUTS(String) \ fputs (quotearg_style (c_quoting_style, String), yyout) -static char *decode_at_digraphs (char *in); +static void fail_for_at_directive_too_many_args (void); +static void fail_for_invalid_at (char const *at); + +/* In SC_AT_DIRECTIVE_ARG context, the name of the directive. */ +static char *at_directive_name; + +/* Currently, only the @warn, @complain, and @fatal directives take multiple + arguments, and they already can't take more than 5. */ +#define AT_DIRECTIVE_ARGC_MAX 5 +static int at_directive_argc = 0; +static char *at_directive_argv[AT_DIRECTIVE_ARGC_MAX]; %} + +%x SC_AT_DIRECTIVE_ARG +%x SC_AT_DIRECTIVE_SKIP_WS + %% %{ @@ -56,20 +70,6 @@ static char *decode_at_digraphs (char *in); char *outname = NULL; %} -"@output ".*\n { - char *file_name = yytext + sizeof "@output " - 1; - yytext[yyleng - 1] = '\0'; - if (outname) - { - free (outname); - xfclose (yyout); - } - outname = decode_at_digraphs (file_name); - output_file_name_check (outname); - yyout = xfopen (outname, "w"); - lineno = 1; -} - "@@" fputc ('@', yyout); "@{" fputc ('[', yyout); "@}" fputc (']', yyout); @@ -78,20 +78,18 @@ static char *decode_at_digraphs (char *in); "@ofile@" QPUTS (outname); "@dir_prefix@" QPUTS (dir_prefix); -"@basename(".*"@)" { - char *file_name = yytext + sizeof "@basename " - 1; - yytext[yyleng - 2] = '\0'; - file_name = decode_at_digraphs (file_name); - fputs (last_component (file_name), yyout); - free (file_name); +@[a-z_]+"(" { + yytext[yyleng-1] = '\0'; + at_directive_name = xstrdup (yytext); + BEGIN SC_AT_DIRECTIVE_ARG; } /* This pattern must not match more than the previous @ patterns. */ -@[^{}@\n]* fatal ("invalid @ in skeleton: %s", yytext); +@[^@{}(\n]* fail_for_invalid_at (yytext); \n lineno++; ECHO; [^@\n]+ ECHO; -<> { +<> { if (outname) { free (outname); @@ -99,6 +97,113 @@ static char *decode_at_digraphs (char *in); } return EOF; } + +{ + [^@\n]+ { STRING_GROW; } + \n { ++lineno; STRING_GROW; } + + "@@" { obstack_1grow (&obstack_for_string, '@'); } + "@{" { obstack_1grow (&obstack_for_string, '['); } + "@}" { obstack_1grow (&obstack_for_string, ']'); } + "@`" /* Emtpy. Useful for starting an argument + that begins with whitespace. */ + + @[,)] { + if (at_directive_argc >= AT_DIRECTIVE_ARGC_MAX) + fail_for_at_directive_too_many_args (); + + obstack_1grow (&obstack_for_string, '\0'); + at_directive_argv[at_directive_argc++] = + obstack_finish (&obstack_for_string); + + /* Like M4, skip whitespace after a comma. */ + if (yytext[1] == ',') + BEGIN SC_AT_DIRECTIVE_SKIP_WS; + else + { + if (0 == strcmp (at_directive_name, "@basename")) + { + if (at_directive_argc > 1) + fail_for_at_directive_too_many_args (); + fputs (last_component (at_directive_argv[0]), yyout); + } + else if (0 == strcmp (at_directive_name, "@warn") + || 0 == strcmp (at_directive_name, "@complain") + || 0 == strcmp (at_directive_name, "@fatal")) + { + void (*func)(char const *, ...); + switch (at_directive_name[1]) + { + case 'w': func = warn; break; + case 'c': func = complain; break; + case 'f': func = fatal; break; + default: aver (false); func = NULL; break; + } + switch (at_directive_argc) + { + case 1: + func (_(at_directive_argv[0])); + break; + case 2: + func (_(at_directive_argv[0]), at_directive_argv[1]); + break; + case 3: + func (_(at_directive_argv[0]), at_directive_argv[1], + at_directive_argv[2]); + break; + case 4: + func (_(at_directive_argv[0]), at_directive_argv[1], + at_directive_argv[2], at_directive_argv[3]); + break; + case 5: + func (_(at_directive_argv[0]), at_directive_argv[1], + at_directive_argv[2], at_directive_argv[3], + at_directive_argv[4]); + break; + default: + fail_for_at_directive_too_many_args (); + break; + } + } + else if (0 == strcmp (at_directive_name, "@output")) + { + if (at_directive_argc > 1) + fail_for_at_directive_too_many_args (); + if (outname) + { + free (outname); + xfclose (yyout); + } + outname = xstrdup (at_directive_argv[0]); + output_file_name_check (outname); + yyout = xfopen (outname, "w"); + lineno = 1; + } + else + fail_for_invalid_at (at_directive_name); + + obstack_free (&obstack_for_string, at_directive_argv[0]); + at_directive_argc = 0; + free (at_directive_name); + BEGIN INITIAL; + } + } + + @.? { fail_for_invalid_at (yytext); } +} + +{ + [ \t\r] + \n { ++lineno; } + . { yyless (0); BEGIN SC_AT_DIRECTIVE_ARG; } +} + +{ + <> { + fatal (_("unclosed %s directive in skeleton"), at_directive_name); + } +} + %% /*------------------------. @@ -108,6 +213,12 @@ static char *decode_at_digraphs (char *in); void scan_skel (FILE *in) { + static bool initialized = false; + if (!initialized) + { + initialized = true; + obstack_init (&obstack_for_string); + } skel_in = in; skel__flex_debug = trace_flag & trace_skeleton; skel_lex (); @@ -115,30 +226,21 @@ scan_skel (FILE *in) yylex_destroy (); } -static char * -decode_at_digraphs (char *in) +static void +fail_for_at_directive_too_many_args (void) { - char *out_start = xnmalloc (strlen (in)+1, sizeof *out_start); - char *out; - for (out = out_start; *in != '\0'; ++in, ++out) - { - if (*in == '@') - { - switch (*++in) - { - case '@': *out = '@'; break; - case '{': *out = '['; break; - case '}': *out = ']'; break; - default: - if (*in != '\0') - in[1] = '\0'; - fatal ("invalid @ in skeleton: %s", in-1); - break; - } - } - else - *out = *in; - } - *out = '\0'; - return out_start; + fatal (_("too many arguments for %s directive in skeleton"), + at_directive_name); +} + +static void +fail_for_invalid_at (char const *at) +{ + fatal ("invalid @ in skeleton: %s", at); +} + +void +skel_scanner_free (void) +{ + obstack_free (&obstack_for_string, 0); } diff --git a/tests/input.at b/tests/input.at index 8c286c05..0c385422 100644 --- a/tests/input.at +++ b/tests/input.at @@ -714,27 +714,35 @@ AT_DATA([input-c.y], %% start: ; ]]) -AT_CHECK([[bison input-c.y 2>&1 | grep 'error: `'"' is not a recognized" > /dev/null]]) +AT_CHECK([[bison input-c.y]], [1], [], +[[input-c.y: `' is not a recognized %code qualifier +]]) AT_DATA([input-c-glr.y], [[%code "bad" {} %% start: ; ]]) -AT_CHECK([[bison input-c-glr.y 2>&1 | grep 'error: `bad'"' is not a recognized" > /dev/null]]) +AT_CHECK([[bison input-c-glr.y]], [1], [], +[[input-c-glr.y: `bad' is not a recognized %code qualifier +]]) AT_DATA([input-c++.y], [[%code "bad" {} %% start: ; ]]) -AT_CHECK([[bison input-c++.y 2>&1 | grep 'error: `bad'"' is not a recognized" > /dev/null]]) +AT_CHECK([[bison input-c++.y]], [1], [], +[[input-c++.y: `bad' is not a recognized %code qualifier +]]) AT_DATA([input-c++-glr.y], [[%code "bad" {} %% start: ; ]]) -AT_CHECK([[bison input-c++-glr.y 2>&1 | grep 'error: `bad'"' is not a recognized" > /dev/null]]) +AT_CHECK([[bison input-c++-glr.y]], [1], [], +[[input-c++-glr.y: `bad' is not a recognized %code qualifier +]]) AT_CLEANUP -- 2.45.2