]> git.draconx.ca Git - cdecl99.git/blob - src/scan.l
Provide strtoumax fallback in the scanner.
[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
33 #if HAVE_STRTOUMAX
34 /* Best case, implementation provides strtoumax. */
35 #  define STRTOUMAX strtoumax
36 #elif HAVE_STRTOULL
37 /* Fall back to strtoull, with possibly reduced range. */
38 #define STRTOUMAX strtoull
39 #elif HAVE___STRTOULL
40 /* HP-UX 11 has __strtoull in <inttypes.h> */
41 #define STRTOUMAX __strtoull
42 #else
43 /* Fall back to strtoul, with possibly reduced range. */
44 #define STRTOUMAX strtoul
45 #endif
46
47 #define lex_error(...) do { \
48         cdecl__err(CDECL_ENOPARSE, __VA_ARGS__); \
49         return T_LEX_ERROR; \
50 } while(0)
51
52 #define dup_token() do { \
53         yylval->strval = malloc(yyleng+1); \
54         if (!yylval->strval) { \
55                 cdecl__err(CDECL_ENOMEM); \
56                 return T_LEX_ERROR; \
57         } \
58         strcpy(yylval->strval, yytext); \
59 } while(0)
60 %}
61
62 %s ENGLISH
63
64 IDENT [_[:alpha:]][_[:alnum:]]*
65 INTEGER 0x[[:xdigit:]]+|0[0-7]+|[[:digit:]]+
66
67 %%
68
69 %{
70         if (yyextra) {
71                 yyextra = 0;
72                 BEGIN(ENGLISH);
73                 return T_ENGLISH;
74         }
75 %}
76
77 "..." return T_ELLIPSIS;
78 ";"   return T_SEMICOLON;
79 "*"   return T_ASTERISK;
80 "("   return T_LPAREN;
81 ")"   return T_RPAREN;
82 "["   return T_LBRACKET;
83 "]"   return T_RBRACKET;
84 ","   return T_COMMA;
85
86 "typedef"    return T_TYPEDEF;
87 "extern"     return T_EXTERN;
88 "static"     return T_STATIC;
89 "auto"       return T_AUTO;
90 "register"   return T_REGISTER;
91
92 "restrict"   return T_RESTRICT;
93 "volatile"   return T_VOLATILE;
94 "const"      return T_CONST;
95
96 "inline"     return T_INLINE;
97
98 "void"       return T_VOID;
99 "char"       return T_CHAR;
100 "short"      return T_SHORT;
101 "int"        return T_INT;
102 "long"       return T_LONG;
103 "float"      return T_FLOAT;
104 "double"     return T_DOUBLE;
105 "signed"     return T_SIGNED;
106 "unsigned"   return T_UNSIGNED;
107 "_Bool"      return T_BOOL;
108 "_Complex"   return T_COMPLEX;
109 "_Imaginary" return T_IMAGINARY;
110
111 "struct"     return T_STRUCT;
112 "union"      return T_UNION;
113 "enum"       return T_ENUM;
114
115 {INTEGER} {
116         char *end;
117
118         errno = 0;
119         yylval->uintval = STRTOUMAX(yytext, &end, 0);
120         if (errno == ERANGE)
121                 lex_error(_("integer constant out of range"));
122         if (*end)
123                 lex_error(_("invalid integer constant"));
124
125         return T_UINT;
126 }
127
128 <ENGLISH>{
129         "variable-length" return T_VLA;
130         "type"            return T_TYPE;
131         "declare"         return T_DECLARE;
132         "pointer"         return T_POINTER;
133         "function"        return T_FUNCTION;
134         "returning"       return T_RETURNING;
135         "array"           return T_ARRAY;
136         "to"              return T_TO;
137         "of"              return T_OF;
138         "as"              return T_AS;
139 }
140
141 {IDENT} { dup_token(); return T_IDENT; }
142
143 [[:space:]]+
144 . {
145         char buf[5] = { yytext[0] };
146         unsigned char c = buf[0];
147
148         if (!isprint(c) || c == '\\' || c == '\'') {
149                 /* Encode nonprinting characters with C-style escapes */
150                 buf[0] = '\\';
151                 switch (c) {
152                 case '\a': buf[1] = 'a'; break;
153                 case '\b': buf[1] = 'b'; break;
154                 case '\f': buf[1] = 'f'; break;
155                 case '\n': buf[1] = 'n'; break;
156                 case '\r': buf[1] = 'r'; break;
157                 case '\t': buf[1] = 't'; break;
158                 case '\v': buf[1] = 'v'; break;
159                 case '\\': buf[1] = '\\'; break;
160                 case '\'': buf[1] = '\''; break;
161                 default:
162                         buf[1] = '0' + ((c >> 6) & 3);
163                         buf[2] = '0' + ((c >> 3) & 7);
164                         buf[3] = '0' + ((c >> 0) & 7);
165                 }
166         }
167
168         lex_error(_("syntax error, unexpected '%s'"), buf);
169 }