]> git.draconx.ca Git - cdecl99.git/blob - src/scan.l
0a4db93bb2ec74e4b64b7ca8085cd82873c7225b
[cdecl99.git] / src / scan.l
1 %top{
2 /*
3  *  Scanner for C declarations.
4  *  Copyright © 2011, 2021, 2023 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 "parse.h"
22 }
23
24 %option nodefault noyywrap bison-locations reentrant never-interactive
25 %option extra-type="_Bool"
26 %option prefix="cdecl__yy"
27
28 %{
29 #include <ctype.h>
30 #include "cdecl-internal.h"
31 #include "cdecl.h"
32 #include "errmsg.h"
33
34 #if HAVE_STRTOUMAX
35 /* Best case, implementation provides strtoumax. */
36 #  define STRTOUMAX strtoumax
37 #elif HAVE_STRTOULL
38 /* Fall back to strtoull, with possibly reduced range. */
39 #define STRTOUMAX strtoull
40 #elif HAVE___STRTOULL
41 /* HP-UX 11 has __strtoull in <inttypes.h> */
42 #define STRTOUMAX __strtoull
43 #else
44 /* Fall back to strtoul, with possibly reduced range. */
45 #define STRTOUMAX strtoul
46 #endif
47
48 #define dup_token() do { \
49         yylval->strval = malloc(yyleng+1); \
50         if (!yylval->strval) { \
51                 cdecl__errmsg(CDECL__ENOMEM); \
52                 return T_LEX_ERROR; \
53         } \
54         strcpy(yylval->strval, yytext); \
55 } while(0)
56
57 static char *to_octal(char *dst, unsigned val)
58 {
59         unsigned i;
60
61         for (i = 0; i < 3; i++) {
62                 *dst++ = '0' + ((val >> 6) & 7u);
63                 val <<= 3;
64         }
65
66         return dst;
67 }
68
69 /*
70  * Convert a single character to a C-style character constant, including quote
71  * characters.  At most 7 bytes are written to the buffer for the longest
72  * octal encoding, e.g., '\177'
73  */
74 static void to_readable_ch(char *dst, char c)
75 {
76         unsigned char uc = c;
77         unsigned i;
78         char esc;
79
80         /*
81          * The 7 standard C control characters are contiguous in ASCII,
82          * permitting a simple and compact lookup table; separating their
83          * handling from backslash and quote characters hopefully allows
84          * the compiler to recognize that.
85          */
86         switch (c) {
87         case '\a': i = 0; break;
88         case '\b': i = 1; break;
89         case '\t': i = 2; break;
90         case '\n': i = 3; break;
91         case '\v': i = 4; break;
92         case '\f': i = 5; break;
93         case '\r': i = 6; break;
94         default:   i = 7; break;
95         }
96         esc = "abtnvfr"[i];
97
98         /* Otherwise printable characters that should still be escaped. */
99         switch (c) {
100         case '\\': case '\'': esc = c; break;
101         }
102
103         *dst++ = '\'';
104         if (esc) {
105                 *dst++ = '\\';
106                 *dst++ = esc;
107         } else if (isprint(uc)) {
108                 *dst++ = c;
109         } else {
110                 *dst++ = '\\';
111                 dst = to_octal(dst, uc);
112         }
113         *dst++ = '\'';
114         *dst++ = 0;
115 }
116
117 %}
118
119 %s ENGLISH
120
121 IDENT [_[:alpha:]][_[:alnum:]]*
122 INTEGER 0x[[:xdigit:]]+|0[0-7]+|[[:digit:]]+
123
124 %%
125
126 %{
127         if (yyextra) {
128                 yyextra = 0;
129                 BEGIN(ENGLISH);
130                 return T_ENGLISH;
131         }
132 %}
133
134 "..." return T_ELLIPSIS;
135 ";"   return T_SEMICOLON;
136 "*"   return T_ASTERISK;
137 "("   return T_LPAREN;
138 ")"   return T_RPAREN;
139 "["   return T_LBRACKET;
140 "]"   return T_RBRACKET;
141 ","   return T_COMMA;
142
143 "typedef"    return T_TYPEDEF;
144 "extern"     return T_EXTERN;
145 "static"     return T_STATIC;
146 "auto"       return T_AUTO;
147 "register"   return T_REGISTER;
148
149 "restrict"   return T_RESTRICT;
150 "volatile"   return T_VOLATILE;
151 "const"      return T_CONST;
152
153 "inline"     return T_INLINE;
154
155 "void"       return T_VOID;
156 "char"       return T_CHAR;
157 "short"      return T_SHORT;
158 "int"        return T_INT;
159 "long"       return T_LONG;
160 "float"      return T_FLOAT;
161 "double"     return T_DOUBLE;
162 "signed"     return T_SIGNED;
163 "unsigned"   return T_UNSIGNED;
164 "_Bool"      return T_BOOL;
165 "_Complex"   return T_COMPLEX;
166 "_Imaginary" return T_IMAGINARY;
167
168 "struct"     return T_STRUCT;
169 "union"      return T_UNION;
170 "enum"       return T_ENUM;
171
172 {INTEGER} {
173         char *end;
174
175         errno = 0;
176         yylval->uintval = STRTOUMAX(yytext, &end, 0);
177         if (errno == ERANGE) {
178                 cdecl__errmsg(CDECL__ERANGE);
179                 return T_LEX_ERROR;
180         }
181         if (*end) {
182                 cdecl__errmsg(CDECL__EBADINT);
183                 return T_LEX_ERROR;
184         }
185
186         return T_UINT;
187 }
188
189 <ENGLISH>{
190         "variable-length" return T_VLA;
191         "type"            return T_TYPE;
192         "declare"         return T_DECLARE;
193         "pointer"         return T_POINTER;
194         "function"        return T_FUNCTION;
195         "returning"       return T_RETURNING;
196         "array"           return T_ARRAY;
197         "to"              return T_TO;
198         "of"              return T_OF;
199         "as"              return T_AS;
200 }
201
202 {IDENT} { dup_token(); return T_IDENT; }
203
204 [[:space:]]+
205 . {
206         char buf[8];
207
208         to_readable_ch(buf, yytext[0]);
209         cdecl__err(CDECL_ENOPARSE, _("syntax error, unexpected %s"), buf);
210         return T_LEX_ERROR;
211 }