1/* Scan Bison Skeletons.                                       -*- C -*-
2
3   Copyright (C) 2001-2007, 2009-2012 Free Software Foundation, Inc.
4
5   This file is part of Bison, the GNU Compiler Compiler.
6
7   This program is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20%option nodefault noyywrap noinput nounput never-interactive debug
21%option prefix="skel_" outfile="lex.yy.c"
22
23%{
24/* Work around a bug in flex 2.5.31.  See Debian bug 333231
25   <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>.  */
26#undef skel_wrap
27#define skel_wrap() 1
28
29#define FLEX_PREFIX(Id) skel_ ## Id
30#include "flex-scanner.h"
31
32#include <dirname.h>
33#include <error.h>
34#include <quotearg.h>
35
36#include "complain.h"
37#include "getargs.h"
38#include "files.h"
39#include "scan-skel.h"
40
41#define YY_DECL static int skel_lex (void)
42YY_DECL;
43
44#define QPUTS(String) \
45   fputs (quotearg_style (c_quoting_style, String), yyout)
46
47static void at_directive_perform (int at_directive_argc,
48                                  char *at_directive_argv[],
49                                  char **outnamep, int *out_linenop);
50static void fail_for_at_directive_too_many_args (char const *at_directive_name);
51static void fail_for_at_directive_too_few_args (char const *at_directive_name);
52static void fail_for_invalid_at (char const *at);
53%}
54
55%x SC_AT_DIRECTIVE_ARGS
56%x SC_AT_DIRECTIVE_SKIP_WS
57
58%%
59
60%{
61  int out_lineno PACIFY_CC (= 0);
62  char *outname = NULL;
63
64  /* Currently, only the @warn, @complain, @fatal, @warn_at, @complain_at, and
65     @fatal_at directives take multiple arguments, and the last three already
66     can't take more than 7.  at_directive_argv[0] is the directive name.  */
67  #define AT_DIRECTIVE_ARGC_MAX 8
68  int at_directive_argc = 0;
69  char *at_directive_argv[AT_DIRECTIVE_ARGC_MAX];
70%}
71
72"@@" fputc ('@', yyout);
73"@{" fputc ('[', yyout);
74"@}" fputc (']', yyout);
75"@`" continue;  /* Used by b4_cat in ../data/bison.m4.  */
76@\n  continue;
77
78"@oline@"  fprintf (yyout, "%d", out_lineno + 1);
79"@ofile@"  QPUTS (outname);
80
81@[a-z_]+"(" {
82  yytext[yyleng-1] = '\0';
83  obstack_grow (&obstack_for_string, yytext, yyleng);
84  at_directive_argv[at_directive_argc++] =
85    obstack_finish (&obstack_for_string);
86  BEGIN SC_AT_DIRECTIVE_ARGS;
87}
88
89  /* This pattern must not match more than the previous @ patterns. */
90@[^@{}`(\n]*  fail_for_invalid_at (yytext);
91\n            out_lineno++; ECHO;
92[^@\n]+       ECHO;
93
94<INITIAL><<EOF>> {
95  if (outname)
96    {
97      free (outname);
98      xfclose (yyout);
99    }
100  return EOF;
101}
102
103<SC_AT_DIRECTIVE_ARGS>
104{
105  [^@]+  STRING_GROW;
106
107  "@@"   obstack_1grow (&obstack_for_string, '@');
108  "@{"   obstack_1grow (&obstack_for_string, '[');
109  "@}"   obstack_1grow (&obstack_for_string, ']');
110  "@`"   continue; /* For starting an argument that begins with whitespace. */
111  @\n    continue;
112
113  @[,)] {
114    if (at_directive_argc >= AT_DIRECTIVE_ARGC_MAX)
115      fail_for_at_directive_too_many_args (at_directive_argv[0]);
116
117    obstack_1grow (&obstack_for_string, '\0');
118    at_directive_argv[at_directive_argc++] =
119      obstack_finish (&obstack_for_string);
120
121    /* Like M4, skip whitespace after a comma.  */
122    if (yytext[1] == ',')
123      BEGIN SC_AT_DIRECTIVE_SKIP_WS;
124    else
125      {
126        at_directive_perform (at_directive_argc, at_directive_argv,
127                              &outname, &out_lineno);
128        obstack_free (&obstack_for_string, at_directive_argv[0]);
129        at_directive_argc = 0;
130        BEGIN INITIAL;
131      }
132  }
133
134  @.?  fail_for_invalid_at (yytext);
135}
136
137<SC_AT_DIRECTIVE_SKIP_WS>
138{
139  [ \t\r\n]    continue;
140  .            { yyless (0); BEGIN SC_AT_DIRECTIVE_ARGS; }
141}
142
143<SC_AT_DIRECTIVE_ARGS,SC_AT_DIRECTIVE_SKIP_WS>
144{
145  <<EOF>> {
146    fatal (_("unclosed %s directive in skeleton"), at_directive_argv[0]);
147  }
148}
149
150%%
151
152/*------------------------.
153| Scan a Bison skeleton.  |
154`------------------------*/
155
156void
157scan_skel (FILE *in)
158{
159  static bool initialized = false;
160  if (!initialized)
161    {
162      initialized = true;
163      obstack_init (&obstack_for_string);
164    }
165  skel_in = in;
166  skel__flex_debug = trace_flag & trace_skeleton;
167  skel_lex ();
168}
169
170void
171skel_scanner_free (void)
172{
173  obstack_free (&obstack_for_string, 0);
174  /* Reclaim Flex's buffers.  */
175  yylex_destroy ();
176}
177
178static void
179at_directive_perform (int at_directive_argc,
180                      char *at_directive_argv[],
181                      char **outnamep, int *out_linenop)
182{
183  if (0 == strcmp (at_directive_argv[0], "@basename"))
184    {
185      if (at_directive_argc > 2)
186        fail_for_at_directive_too_many_args (at_directive_argv[0]);
187      fputs (last_component (at_directive_argv[1]), yyout);
188    }
189  else if (0 == strcmp (at_directive_argv[0], "@warn")
190           || 0 == strcmp (at_directive_argv[0], "@complain")
191           || 0 == strcmp (at_directive_argv[0], "@fatal"))
192    {
193      void (*func)(char const *, ...);
194      switch (at_directive_argv[0][1])
195        {
196          case 'w': func = warn; break;
197          case 'c': func = complain; break;
198          case 'f': func = fatal; break;
199          default: aver (false); break;
200        }
201      switch (at_directive_argc)
202        {
203          case 2:
204            func (_(at_directive_argv[1]));
205            break;
206          case 3:
207            func (_(at_directive_argv[1]), at_directive_argv[2]);
208            break;
209          case 4:
210            func (_(at_directive_argv[1]), at_directive_argv[2],
211                  at_directive_argv[3]);
212            break;
213          case 5:
214            func (_(at_directive_argv[1]), at_directive_argv[2],
215                  at_directive_argv[3], at_directive_argv[4]);
216            break;
217          case 6:
218            func (_(at_directive_argv[1]), at_directive_argv[2],
219                  at_directive_argv[3], at_directive_argv[4],
220                  at_directive_argv[5]);
221            break;
222          default:
223            fail_for_at_directive_too_many_args (at_directive_argv[0]);
224            break;
225        }
226    }
227  else if (0 == strcmp (at_directive_argv[0], "@warn_at")
228           || 0 == strcmp (at_directive_argv[0], "@complain_at")
229           || 0 == strcmp (at_directive_argv[0], "@fatal_at"))
230    {
231      void (*func)(location, char const *, ...);
232      location loc;
233      if (at_directive_argc < 4)
234        fail_for_at_directive_too_few_args (at_directive_argv[0]);
235      switch (at_directive_argv[0][1])
236        {
237          case 'w': func = warn_at; break;
238          case 'c': func = complain_at; break;
239          case 'f': func = fatal_at; break;
240          default: aver (false); break;
241        }
242      boundary_set_from_string (&loc.start, at_directive_argv[1]);
243      boundary_set_from_string (&loc.end, at_directive_argv[2]);
244      switch (at_directive_argc)
245        {
246          case 4:
247            func (loc, _(at_directive_argv[3]));
248            break;
249          case 5:
250            func (loc, _(at_directive_argv[3]), at_directive_argv[4]);
251            break;
252          case 6:
253            func (loc, _(at_directive_argv[3]), at_directive_argv[4],
254                  at_directive_argv[5]);
255            break;
256          case 7:
257            func (loc, _(at_directive_argv[3]), at_directive_argv[4],
258                  at_directive_argv[5], at_directive_argv[6]);
259            break;
260          case 8:
261            func (loc, _(at_directive_argv[3]), at_directive_argv[4],
262                  at_directive_argv[5], at_directive_argv[6],
263                  at_directive_argv[7]);
264            break;
265          default:
266            fail_for_at_directive_too_many_args (at_directive_argv[0]);
267            break;
268        }
269    }
270  else if (0 == strcmp (at_directive_argv[0], "@output"))
271    {
272      if (at_directive_argc > 2)
273        fail_for_at_directive_too_many_args (at_directive_argv[0]);
274      if (*outnamep)
275        {
276          free (*outnamep);
277          xfclose (yyout);
278        }
279      *outnamep = xstrdup (at_directive_argv[1]);
280      output_file_name_check (outnamep);
281      yyout = xfopen (*outnamep, "w");
282      *out_linenop = 1;
283    }
284  else
285    fail_for_invalid_at (at_directive_argv[0]);
286}
287
288static void
289fail_for_at_directive_too_few_args (char const *at_directive_name)
290{
291  fatal (_("too few arguments for %s directive in skeleton"),
292         at_directive_name);
293}
294
295static void
296fail_for_at_directive_too_many_args (char const *at_directive_name)
297{
298  fatal (_("too many arguments for %s directive in skeleton"),
299         at_directive_name);
300}
301
302static void
303fail_for_invalid_at (char const *at)
304{
305  fatal ("invalid @ in skeleton: %s", at);
306}
307