3 * Scanner for C declarations.
4 * Copyright © 2011, 2021, 2023-2024 Nick Bowler
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /* Disable various generated code we don't use */
25 #define YY_INPUT(a, b, c) do {} while (0)
30 * The flex-generated scanner defines a huge pile of external functions of
31 * which we use almost none elsewhere. Explicitly declare any unneeded
32 * functions static, which allows better optimization (especially wrt.
33 * dead code elimination).
35 #if !cdecl__yyIN_HEADER
38 # define static __attribute__((__unused__)) static
41 static struct yy_buffer_state *cdecl__yy_create_buffer(FILE *, int, void *);
42 static struct yy_buffer_state *cdecl__yy_scan_bytes(const char *, int, void *);
43 static struct yy_buffer_state *cdecl__yy_scan_buffer(char *, size_t, void *);
44 static void cdecl__yy_switch_to_buffer(struct yy_buffer_state *, void *);
45 static void cdecl__yy_flush_buffer(struct yy_buffer_state *, void *);
46 static void cdecl__yypush_buffer_state(struct yy_buffer_state *, void *);
47 static void cdecl__yypop_buffer_state(void *);
48 static void cdecl__yyrestart(FILE *, void *);
49 static int cdecl__yylex_init(void **);
51 static int cdecl__yyget_extra(void *);
52 static YYLTYPE *cdecl__yyget_lloc(void *);
53 static YYSTYPE *cdecl__yyget_lval(void *);
54 static char *cdecl__yyget_text(void *);
55 static FILE *cdecl__yyget_out(void *);
56 static FILE *cdecl__yyget_in(void *);
57 static int cdecl__yyget_debug(void *);
58 static int cdecl__yyget_lineno(void *);
59 static int cdecl__yyget_column(void *);
60 static int cdecl__yyget_leng(void *);
62 static void cdecl__yyset_extra(int, void *);
63 static void cdecl__yyset_lloc(YYLTYPE *, void *);
64 static void cdecl__yyset_lval(YYSTYPE *, void *);
65 static void cdecl__yyset_in(FILE *, void *);
66 static void cdecl__yyset_out(FILE *, void *);
67 static void cdecl__yyset_debug(int, void *);
68 static void cdecl__yyset_lineno(int, void *);
69 static void cdecl__yyset_column(int, void *);
71 static void *cdecl__yyrealloc(void *, size_t, void *);
72 static void *cdecl__yyalloc(size_t, void *);
73 static void cdecl__yyfree(void *, void *);
80 %option nodefault noyywrap bison-locations reentrant never-interactive
81 %option extra-type="int"
82 %option prefix="cdecl__yy"
86 #include "cdecl-internal.h"
91 static char *to_octal(char *dst, unsigned val)
95 for (i = 0; i < 3; i++) {
96 *dst++ = '0' + ((val >> 6) & 7u);
104 * Convert a single character to a C-style character constant, including quote
105 * characters. At most 7 bytes are written to the buffer for the longest
106 * octal encoding, e.g., '\177'
108 static void to_readable_ch(char *dst, char c)
110 unsigned char uc = c;
115 * The 7 standard C control characters are contiguous in ASCII,
116 * permitting a simple and compact lookup table; separating their
117 * handling from backslash and quote characters hopefully allows
118 * the compiler to recognize that.
121 case '\a': i = 0; break;
122 case '\b': i = 1; break;
123 case '\t': i = 2; break;
124 case '\n': i = 3; break;
125 case '\v': i = 4; break;
126 case '\f': i = 5; break;
127 case '\r': i = 6; break;
128 default: i = 7; break;
132 /* Otherwise printable characters that should still be escaped. */
134 case '\\': case '\'': esc = c; break;
141 } else if (isprint(uc)) {
145 dst = to_octal(dst, uc);
153 IDENT [_[:alpha:]][-_[:alnum:]]*
163 unsigned char *match;
164 static const unsigned char tab[2][8] = {
167 PACK_TOKEN(T_ASTERISK),
168 PACK_TOKEN(T_LBRACKET),
169 PACK_TOKEN(T_RBRACKET),
170 PACK_TOKEN(T_LPAREN),
171 PACK_TOKEN(T_RPAREN),
173 PACK_TOKEN(T_ELLIPSIS),
174 PACK_TOKEN(T_SEMICOLON)
178 match = memchr(&tab, yytext[0], sizeof tab[0]);
179 return UNPACK_TOKEN(match[sizeof tab[0]]);
182 0[0-7]* { intconv_base = INTCONV_OCTAL; goto int_parse; }
183 [1-9][0-9]* { intconv_base = INTCONV_DECIMAL; goto int_parse; }
189 intconv_base = INTCONV_HEXADECIMAL;
191 for (v = 0; (d = *yytext++);) {
192 if (!intconv_shift(&v, intconv_base, intconv_digit(d))) {
193 cdecl__errmsg(CDECL__ERANGE);
202 cdecl__errmsg(CDECL__EBADINT);
207 int len = yyleng, tok;
210 x = cdecl__to_keyword(yytext, len, yyextra);
211 yylval->spectype = UNPACK_SPEC(x & 0xff);
212 if ((tok = (x >> 8)) == PACK_TOKEN(T_IDENT)) {
214 * Our IDENT pattern includes hyphens so we can match
215 * "variable-length" as a keyword. In all other cases a
216 * hyphen is an error.
218 * We could use yyless to re-scan the hyphen and hit the
219 * error catch-all, but jumping straight to the error code
220 * seems to produce better results with gcc with no obvious
224 if ((c = memchr(yytext, '-', len)))
227 yyless(strcspn(yytext, "-"));
229 if (!(yylval->item = cdecl__alloc_item(len+1)))
231 memcpy(yylval->item->s, yytext, len+1);
233 return UNPACK_TOKEN(tok);
242 to_readable_ch(buf, *c);
243 cdecl__err(_("syntax error, unexpected %s"), buf);