diff options
author | Joel E. Denny <jdenny@ces.clemson.edu> | 2007-01-06 06:14:04 +0000 |
---|---|---|
committer | Joel E. Denny <jdenny@ces.clemson.edu> | 2007-01-06 06:14:04 +0000 |
commit | 08af01c2fc26eeb77afe3a667dded68c52ea3c37 (patch) | |
tree | 957605812db50e734574a2a083e6abd58bdf2386 /src/scan-skel.l | |
parent | 8e0a5e9e735620ef5196a155eed1f8cf4d3aab5f (diff) | |
download | bison-08af01c2fc26eeb77afe3a667dded68c52ea3c37.tar.gz |
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
<http://lists.gnu.org/archive/html/bison-patches/2006-12/msg00063.html>.
* 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.
Diffstat (limited to 'src/scan-skel.l')
-rw-r--r-- | src/scan-skel.l | 202 |
1 files changed, 152 insertions, 50 deletions
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; -<<EOF>> { +<INITIAL><<EOF>> { if (outname) { free (outname); @@ -99,6 +97,113 @@ static char *decode_at_digraphs (char *in); } return EOF; } + +<SC_AT_DIRECTIVE_ARG>{ + [^@\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); } +} + +<SC_AT_DIRECTIVE_SKIP_WS>{ + [ \t\r] + \n { ++lineno; } + . { yyless (0); BEGIN SC_AT_DIRECTIVE_ARG; } +} + +<SC_AT_DIRECTIVE_ARG,SC_AT_DIRECTIVE_SKIP_WS>{ + <<EOF>> { + 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); } |