]> git.draconx.ca Git - cdecl99.git/blob - src/scan.l
libcdecl: Remove error code argument from cdecl__err.
[cdecl99.git] / src / scan.l
1 %top{
2 /*
3  *  Scanner for C declarations.
4  *  Copyright © 2011, 2021, 2023-2024 Nick Bowler
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include "parse.h"
23
24 /* Disable various generated code we don't use */
25 #define YY_INPUT(a, b, c) do {} while (0)
26 #define YY_NO_INPUT 1
27 #define YY_NO_UNPUT 1
28
29 /*
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).
34  */
35 static struct yy_buffer_state *cdecl__yy_create_buffer(FILE *, int, void *);
36 static struct yy_buffer_state *cdecl__yy_scan_bytes(const char *, int, void *);
37 static struct yy_buffer_state *cdecl__yy_scan_buffer(char *, size_t, void *);
38 static void cdecl__yy_switch_to_buffer(struct yy_buffer_state *, void *);
39 static void cdecl__yy_flush_buffer(struct yy_buffer_state *, void *);
40 static void yypush_buffer_state(struct yy_buffer_state *, void *);
41 static void cdecl__yypop_buffer_state(void *);
42 static void cdecl__yyrestart(FILE *, void *);
43 static int cdecl__yylex_init(void **);
44
45 static int cdecl__yyget_extra(void *);
46 static YYLTYPE *cdecl__yyget_lloc(void *);
47 static YYSTYPE *cdecl__yyget_lval(void *);
48 static char *cdecl__yyget_text(void *);
49 static FILE *cdecl__yyget_out(void *);
50 static FILE *cdecl__yyget_in(void *);
51 static int cdecl__yyget_debug(void *);
52 static int cdecl__yyget_lineno(void *);
53 static int cdecl__yyget_column(void *);
54 static int cdecl__yyget_leng(void *);
55
56 static void cdecl__yyset_extra(int, void *);
57 static void cdecl__yyset_lloc(YYLTYPE *, void *);
58 static void cdecl__yyset_lval(YYSTYPE *, void *);
59 static void cdecl__yyset_in(FILE *, void *);
60 static void cdecl__yyset_out(FILE *, void *);
61 static void cdecl__yyset_debug(int, void *);
62 static void cdecl__yyset_lineno(int, void *);
63 static void cdecl__yyset_column(int, void *);
64 static void cdecl__yyset_leng(int, void *);
65
66 static void *cdecl__yyrealloc(void *, size_t, void *);
67 static void *cdecl__yyalloc(size_t, void *);
68 static void cdecl__yyfree(void *, void *);
69 }
70
71 %option nodefault noyywrap bison-locations reentrant never-interactive
72 %option extra-type="int"
73 %option prefix="cdecl__yy"
74
75 %{
76 #include <ctype.h>
77 #include "cdecl-internal.h"
78 #include "cdecl.h"
79 #include "errmsg.h"
80 #include "intconv.h"
81
82 static char *to_octal(char *dst, unsigned val)
83 {
84         unsigned i;
85
86         for (i = 0; i < 3; i++) {
87                 *dst++ = '0' + ((val >> 6) & 7u);
88                 val <<= 3;
89         }
90
91         return dst;
92 }
93
94 /*
95  * Convert a single character to a C-style character constant, including quote
96  * characters.  At most 7 bytes are written to the buffer for the longest
97  * octal encoding, e.g., '\177'
98  */
99 static void to_readable_ch(char *dst, char c)
100 {
101         unsigned char uc = c;
102         unsigned i;
103         char esc;
104
105         /*
106          * The 7 standard C control characters are contiguous in ASCII,
107          * permitting a simple and compact lookup table; separating their
108          * handling from backslash and quote characters hopefully allows
109          * the compiler to recognize that.
110          */
111         switch (c) {
112         case '\a': i = 0; break;
113         case '\b': i = 1; break;
114         case '\t': i = 2; break;
115         case '\n': i = 3; break;
116         case '\v': i = 4; break;
117         case '\f': i = 5; break;
118         case '\r': i = 6; break;
119         default:   i = 7; break;
120         }
121         esc = "abtnvfr"[i];
122
123         /* Otherwise printable characters that should still be escaped. */
124         switch (c) {
125         case '\\': case '\'': esc = c; break;
126         }
127
128         *dst++ = '\'';
129         if (esc) {
130                 *dst++ = '\\';
131                 *dst++ = esc;
132         } else if (isprint(uc)) {
133                 *dst++ = c;
134         } else {
135                 *dst++ = '\\';
136                 dst = to_octal(dst, uc);
137         }
138         *dst++ = '\'';
139         *dst++ = 0;
140 }
141
142 %}
143
144 IDENT [_[:alpha:]][-_[:alnum:]]*
145
146 %%
147
148 %{
149         int intconv_base;
150         char *c;
151 %}
152
153 "..."|[][;*(),] {
154         unsigned char *match;
155         static const unsigned char tab[2][8] = {
156                 "*[](),.;",
157                 {
158                         PACK_TOKEN(T_ASTERISK),
159                         PACK_TOKEN(T_LBRACKET),
160                         PACK_TOKEN(T_RBRACKET),
161                         PACK_TOKEN(T_LPAREN),
162                         PACK_TOKEN(T_RPAREN),
163                         PACK_TOKEN(T_COMMA),
164                         PACK_TOKEN(T_ELLIPSIS),
165                         PACK_TOKEN(T_SEMICOLON)
166                 }
167         };
168
169         match = memchr(&tab, yytext[0], sizeof tab[0]);
170         return UNPACK_TOKEN(match[sizeof tab[0]]);
171 }
172
173 0[0-7]* { intconv_base = INTCONV_OCTAL; goto int_parse; }
174 [1-9][0-9]* { intconv_base = INTCONV_DECIMAL; goto int_parse; }
175 0[Xx][[:xdigit:]]+ {
176         unsigned char d;
177         uintmax_t v;
178
179         yytext += 2;
180         intconv_base = INTCONV_HEXADECIMAL;
181 int_parse:
182         for (v = 0; (d = *yytext++);) {
183                 if (!intconv_shift(&v, intconv_base, intconv_digit(d))) {
184                         cdecl__errmsg(CDECL__ERANGE);
185                         return T_LEX_ERROR;
186                 }
187         }
188
189         yylval->uintval = v;
190         return T_UINT;
191 }
192 0[Xx]|[0-9]+ {
193         cdecl__errmsg(CDECL__EBADINT);
194         return T_LEX_ERROR;
195 }
196
197 {IDENT} {
198         int len = yyleng, tok;
199         unsigned x;
200
201         x = cdecl__to_keyword(yytext, len, yyextra);
202         yylval->spectype = UNPACK_SPEC(x & 0xff);
203         if ((tok = (x >> 8)) == PACK_TOKEN(T_IDENT)) {
204                 /*
205                  * Our IDENT pattern includes hyphens so we can match
206                  * "variable-length" as a keyword.  In all other cases a
207                  * hyphen is an error.
208                  *
209                  * We could use yyless to re-scan the hyphen and hit the
210                  * error catch-all, but jumping straight to the error code
211                  * seems to produce better results with gcc with no obvious
212                  * downsides.
213                  */
214 #if 1
215                 if ((c = memchr(yytext, '-', len)))
216                         goto invalid_char;
217 #else
218                 yyless(strcspn(yytext, "-"));
219 #endif
220                 if (!(yylval->item = cdecl__alloc_item(len+1)))
221                         return T_LEX_ERROR;
222                 memcpy(yylval->item->s, yytext, len+1);
223         }
224         return UNPACK_TOKEN(tok);
225 }
226
227 [[:space:]]+
228 . {
229         char buf[8];
230
231         c = yytext;
232 invalid_char:
233         to_readable_ch(buf, *c);
234         cdecl__err(_("syntax error, unexpected %s"), buf);
235         return T_LEX_ERROR;
236 }