- /* This is an approximation, but we don't need more. */
-^"#output \""[^\"]+\"\n {
- yytext[yyleng - 2] = '\0';
- XFREE (yyoutname);
- yyoutname = xstrdup (yytext + strlen ("#output \""));
- yyout = xfopen (yyoutname, "w");
- yylineno = 1;
- }
-
-"@<:@" fputc ('[', yyout);
-"@:>@" fputc (']', yyout);
-
-"__oline__" fprintf (yyout, "%d", yylineno+1);
-"__ofile__" fprintf (yyout, "%s", yyoutname);
-[^@_\n]+ ECHO;
-\n+ yylineno += yyleng; ECHO;
-. ECHO;
-
-<<EOF>> xfclose (yyout); free (yyoutname); return EOF;
+
+%{
+ int out_lineno PACIFY_CC (= 0);
+ char *outname = NULL;
+
+ /* Currently, only the @warn, @complain, @fatal, @warn_at, @complain_at, and
+ @fatal_at directives take multiple arguments, and the last three already
+ can't take more than 7. argv[0] is the directive name. */
+ #define ARGC_MAX 8
+ int argc = 0;
+ char *argv[ARGC_MAX];
+%}
+
+"@@" fputc ('@', yyout);
+"@{" fputc ('[', yyout);
+"@}" fputc (']', yyout);
+"@`" continue; /* Used by b4_cat in ../data/bison.m4. */
+@\n continue;
+
+"@oline@" fprintf (yyout, "%d", out_lineno + 1);
+"@ofile@" fputs (quotearg_style (c_quoting_style, outname), yyout);
+
+@[a-z_]+"(" {
+ yytext[yyleng-1] = '\0';
+ obstack_grow (&obstack_for_string, yytext, yyleng);
+ argv[argc++] = obstack_finish (&obstack_for_string);
+ BEGIN SC_AT_DIRECTIVE_ARGS;
+}
+
+ /* This pattern must not match more than the previous @ patterns. */
+@[^@{}`(\n]* fail_for_invalid_at (yytext);
+\n out_lineno++; ECHO;
+[^@\n]+ ECHO;
+
+<INITIAL><<EOF>> {
+ if (outname)
+ {
+ free (outname);
+ xfclose (yyout);
+ }
+ return EOF;
+}
+
+<SC_AT_DIRECTIVE_ARGS>
+{
+ [^@]+ STRING_GROW;
+
+ "@@" obstack_1grow (&obstack_for_string, '@');
+ "@{" obstack_1grow (&obstack_for_string, '[');
+ "@}" obstack_1grow (&obstack_for_string, ']');
+ "@`" continue; /* For starting an argument that begins with whitespace. */
+ @\n continue;
+
+ @[,)] {
+ if (argc >= ARGC_MAX)
+ fail_for_at_directive_too_many_args (argv[0]);
+
+ argv[argc++] = obstack_finish0 (&obstack_for_string);
+
+ /* Like M4, skip whitespace after a comma. */
+ if (yytext[1] == ',')
+ BEGIN SC_AT_DIRECTIVE_SKIP_WS;
+ else
+ {
+ at_directive_perform (argc, argv, &outname, &out_lineno);
+ obstack_free (&obstack_for_string, argv[0]);
+ argc = 0;
+ BEGIN INITIAL;
+ }
+ }
+
+ @.? fail_for_invalid_at (yytext);
+}
+
+<SC_AT_DIRECTIVE_SKIP_WS>
+{
+ [ \t\r\n] continue;
+ . yyless (0); BEGIN SC_AT_DIRECTIVE_ARGS;
+}
+
+<SC_AT_DIRECTIVE_ARGS,SC_AT_DIRECTIVE_SKIP_WS>
+{
+ <<EOF>> complain (NULL, fatal, _("unclosed %s directive in skeleton"), argv[0]);
+}
+