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)
42 YY_DECL;
43 
44 #define QPUTS(String) \
45    fputs (quotearg_style (c_quoting_style, String), yyout)
46 
47 static void at_directive_perform (int at_directive_argc,
48                                   char *at_directive_argv[],
49                                   char **outnamep, int *out_linenop);
50 static void fail_for_at_directive_too_many_args (char const *at_directive_name);
51 static void fail_for_at_directive_too_few_args (char const *at_directive_name);
52 static 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 
156 void
157 scan_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 
170 void
171 skel_scanner_free (void)
172 {
173   obstack_free (&obstack_for_string, 0);
174   /* Reclaim Flex's buffers.  */
175   yylex_destroy ();
176 }
177 
178 static void
179 at_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 
288 static void
289 fail_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 
295 static void
296 fail_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 
302 static void
303 fail_for_invalid_at (char const *at)
304 {
305   fatal ("invalid @ in skeleton: %s", at);
306 }
307