]> git.draconx.ca Git - cdecl99.git/blob - src/scan.l
libcdecl: Consolidate most error messages.
[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
58 %s ENGLISH
59
60 IDENT [_[:alpha:]][_[:alnum:]]*
61 INTEGER 0x[[:xdigit:]]+|0[0-7]+|[[:digit:]]+
62
63 %%
64
65 %{
66         if (yyextra) {
67                 yyextra = 0;
68                 BEGIN(ENGLISH);
69                 return T_ENGLISH;
70         }
71 %}
72
73 "..." return T_ELLIPSIS;
74 ";"   return T_SEMICOLON;
75 "*"   return T_ASTERISK;
76 "("   return T_LPAREN;
77 ")"   return T_RPAREN;
78 "["   return T_LBRACKET;
79 "]"   return T_RBRACKET;
80 ","   return T_COMMA;
81
82 "typedef"    return T_TYPEDEF;
83 "extern"     return T_EXTERN;
84 "static"     return T_STATIC;
85 "auto"       return T_AUTO;
86 "register"   return T_REGISTER;
87
88 "restrict"   return T_RESTRICT;
89 "volatile"   return T_VOLATILE;
90 "const"      return T_CONST;
91
92 "inline"     return T_INLINE;
93
94 "void"       return T_VOID;
95 "char"       return T_CHAR;
96 "short"      return T_SHORT;
97 "int"        return T_INT;
98 "long"       return T_LONG;
99 "float"      return T_FLOAT;
100 "double"     return T_DOUBLE;
101 "signed"     return T_SIGNED;
102 "unsigned"   return T_UNSIGNED;
103 "_Bool"      return T_BOOL;
104 "_Complex"   return T_COMPLEX;
105 "_Imaginary" return T_IMAGINARY;
106
107 "struct"     return T_STRUCT;
108 "union"      return T_UNION;
109 "enum"       return T_ENUM;
110
111 {INTEGER} {
112         char *end;
113
114         errno = 0;
115         yylval->uintval = STRTOUMAX(yytext, &end, 0);
116         if (errno == ERANGE) {
117                 cdecl__errmsg(CDECL__ERANGE);
118                 return T_LEX_ERROR;
119         }
120         if (*end) {
121                 cdecl__errmsg(CDECL__EBADINT);
122                 return T_LEX_ERROR;
123         }
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         cdecl__err(CDECL_ENOPARSE, _("syntax error, unexpected '%s'"), buf);
169         return T_LEX_ERROR;
170 }