1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Lexical analysis for genksyms. 4 * Copyright 1996, 1997 Linux International. 5 * 6 * New implementation contributed by Richard Henderson <rth@tamu.edu> 7 * Based on original work by Bjorn Ekwall <bj0rn@blox.se> 8 * 9 * Taken from Linux modutils 2.4.22. 10 */ 11 12 %{ 13 14 #include <limits.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <ctype.h> 18 19 #include "genksyms.h" 20 #include "parse.tab.h" 21 22 /* We've got a two-level lexer here. We let flex do basic tokenization 23 and then we categorize those basic tokens in the second stage. */ 24 #define YY_DECL static int yylex1(void) 25 26 %} 27 28 IDENT [A-Za-z_\$][A-Za-z0-9_\$]* 29 30 O_INT 0[0-7]* 31 D_INT [1-9][0-9]* 32 X_INT 0[Xx][0-9A-Fa-f]+ 33 I_SUF [Uu]|[Ll]|[Uu][Ll]|[Ll][Uu] 34 INT ({O_INT}|{D_INT}|{X_INT}){I_SUF}? 35 36 FRAC ([0-9]*\.[0-9]+)|([0-9]+\.) 37 EXP [Ee][+-]?[0-9]+ 38 F_SUF [FfLl] 39 REAL ({FRAC}{EXP}?{F_SUF}?)|([0-9]+{EXP}{F_SUF}?) 40 41 STRING L?\"([^\\\"]*\\.)*[^\\\"]*\" 42 CHAR L?\'([^\\\']*\\.)*[^\\\']*\' 43 44 MC_TOKEN ([~%^&*+=|<>/-]=)|(&&)|("||")|(->)|(<<)|(>>) 45 46 /* We don't do multiple input files. */ 47 %option noyywrap 48 49 %option noinput 50 51 %% 52 53 54 /* Keep track of our location in the original source files. */ 55 ^#[ \t]+{INT}[ \t]+\"[^\"\n]+\".*\n return FILENAME; 56 ^#.*\n cur_line++; 57 \n cur_line++; 58 59 /* Ignore all other whitespace. */ 60 [ \t\f\v\r]+ ; 61 62 63 {STRING} return STRING; 64 {CHAR} return CHAR; 65 {IDENT} return IDENT; 66 67 /* The Pedant requires that the other C multi-character tokens be 68 recognized as tokens. We don't actually use them since we don't 69 parse expressions, but we do want whitespace to be arranged 70 around them properly. */ 71 {MC_TOKEN} return OTHER; 72 {INT} return INT; 73 {REAL} return REAL; 74 75 "..." return DOTS; 76 77 /* All other tokens are single characters. */ 78 . return yytext[0]; 79 80 81 %% 82 83 /* Bring in the keyword recognizer. */ 84 85 #include "keywords.c" 86 87 88 /* Macros to append to our phrase collection list. */ 89 90 /* 91 * We mark any token, that that equals to a known enumerator, as 92 * SYM_ENUM_CONST. The parser will change this for struct and union tags later, 93 * the only problem is struct and union members: 94 * enum e { a, b }; struct s { int a, b; } 95 * but in this case, the only effect will be, that the ABI checksums become 96 * more volatile, which is acceptable. Also, such collisions are quite rare, 97 * so far it was only observed in include/linux/telephony.h. 98 */ 99 #define _APP(T,L) do { \ 100 cur_node = next_node; \ 101 next_node = xmalloc(sizeof(*next_node)); \ 102 next_node->next = cur_node; \ 103 cur_node->string = memcpy(xmalloc(L+1), T, L+1); \ 104 cur_node->tag = \ 105 find_symbol(cur_node->string, SYM_ENUM_CONST, 1)?\ 106 SYM_ENUM_CONST : SYM_NORMAL ; \ 107 cur_node->in_source_file = in_source_file; \ 108 } while (0) 109 110 #define APP _APP(yytext, yyleng) 111 112 113 /* The second stage lexer. Here we incorporate knowledge of the state 114 of the parser to tailor the tokens that are returned. */ 115 116 int 117 yylex(void) 118 { 119 static enum { 120 ST_NOTSTARTED, ST_NORMAL, ST_ATTRIBUTE, ST_ASM, ST_TYPEOF, ST_TYPEOF_1, 121 ST_BRACKET, ST_BRACE, ST_EXPRESSION, ST_STATIC_ASSERT, 122 } lexstate = ST_NOTSTARTED; 123 124 static int suppress_type_lookup, dont_want_brace_phrase; 125 static struct string_list *next_node; 126 static char *source_file; 127 128 int token, count = 0; 129 struct string_list *cur_node; 130 131 if (lexstate == ST_NOTSTARTED) 132 { 133 next_node = xmalloc(sizeof(*next_node)); 134 next_node->next = NULL; 135 lexstate = ST_NORMAL; 136 } 137 138 repeat: 139 token = yylex1(); 140 141 if (token == 0) 142 return 0; 143 else if (token == FILENAME) 144 { 145 char *file, *e; 146 147 /* Save the filename and line number for later error messages. */ 148 149 if (cur_filename) 150 free(cur_filename); 151 152 file = strchr(yytext, '\"')+1; 153 e = strchr(file, '\"'); 154 *e = '\0'; 155 cur_filename = memcpy(xmalloc(e-file+1), file, e-file+1); 156 cur_line = atoi(yytext+2); 157 158 if (!source_file) { 159 source_file = xstrdup(cur_filename); 160 in_source_file = 1; 161 } else { 162 in_source_file = (strcmp(cur_filename, source_file) == 0); 163 } 164 165 goto repeat; 166 } 167 168 switch (lexstate) 169 { 170 case ST_NORMAL: 171 switch (token) 172 { 173 case IDENT: 174 APP; 175 { 176 int r = is_reserved_word(yytext, yyleng); 177 if (r >= 0) 178 { 179 switch (token = r) 180 { 181 case ATTRIBUTE_KEYW: 182 lexstate = ST_ATTRIBUTE; 183 count = 0; 184 goto repeat; 185 case ASM_KEYW: 186 lexstate = ST_ASM; 187 count = 0; 188 goto repeat; 189 case TYPEOF_KEYW: 190 lexstate = ST_TYPEOF; 191 count = 0; 192 goto repeat; 193 194 case STRUCT_KEYW: 195 case UNION_KEYW: 196 case ENUM_KEYW: 197 dont_want_brace_phrase = 3; 198 suppress_type_lookup = 2; 199 goto fini; 200 201 case EXPORT_SYMBOL_KEYW: 202 goto fini; 203 204 case STATIC_ASSERT_KEYW: 205 lexstate = ST_STATIC_ASSERT; 206 count = 0; 207 goto repeat; 208 } 209 } 210 if (!suppress_type_lookup) 211 { 212 if (find_symbol(yytext, SYM_TYPEDEF, 1)) 213 token = TYPE; 214 } 215 } 216 break; 217 218 case '[': 219 APP; 220 lexstate = ST_BRACKET; 221 count = 1; 222 goto repeat; 223 224 case '{': 225 APP; 226 if (dont_want_brace_phrase) 227 break; 228 lexstate = ST_BRACE; 229 count = 1; 230 goto repeat; 231 232 case '=': case ':': 233 APP; 234 lexstate = ST_EXPRESSION; 235 break; 236 237 default: 238 APP; 239 break; 240 } 241 break; 242 243 case ST_ATTRIBUTE: 244 APP; 245 switch (token) 246 { 247 case '(': 248 ++count; 249 goto repeat; 250 case ')': 251 if (--count == 0) 252 { 253 lexstate = ST_NORMAL; 254 token = ATTRIBUTE_PHRASE; 255 break; 256 } 257 goto repeat; 258 default: 259 goto repeat; 260 } 261 break; 262 263 case ST_ASM: 264 APP; 265 switch (token) 266 { 267 case '(': 268 ++count; 269 goto repeat; 270 case ')': 271 if (--count == 0) 272 { 273 lexstate = ST_NORMAL; 274 token = ASM_PHRASE; 275 break; 276 } 277 goto repeat; 278 default: 279 goto repeat; 280 } 281 break; 282 283 case ST_TYPEOF_1: 284 if (token == IDENT) 285 { 286 if (is_reserved_word(yytext, yyleng) >= 0 287 || find_symbol(yytext, SYM_TYPEDEF, 1)) 288 { 289 yyless(0); 290 unput('('); 291 lexstate = ST_NORMAL; 292 token = TYPEOF_KEYW; 293 break; 294 } 295 _APP("(", 1); 296 } 297 lexstate = ST_TYPEOF; 298 /* FALLTHRU */ 299 300 case ST_TYPEOF: 301 switch (token) 302 { 303 case '(': 304 if ( ++count == 1 ) 305 lexstate = ST_TYPEOF_1; 306 else 307 APP; 308 goto repeat; 309 case ')': 310 APP; 311 if (--count == 0) 312 { 313 lexstate = ST_NORMAL; 314 token = TYPEOF_PHRASE; 315 break; 316 } 317 goto repeat; 318 default: 319 APP; 320 goto repeat; 321 } 322 break; 323 324 case ST_BRACKET: 325 APP; 326 switch (token) 327 { 328 case '[': 329 ++count; 330 goto repeat; 331 case ']': 332 if (--count == 0) 333 { 334 lexstate = ST_NORMAL; 335 token = BRACKET_PHRASE; 336 break; 337 } 338 goto repeat; 339 default: 340 goto repeat; 341 } 342 break; 343 344 case ST_BRACE: 345 APP; 346 switch (token) 347 { 348 case '{': 349 ++count; 350 goto repeat; 351 case '}': 352 if (--count == 0) 353 { 354 lexstate = ST_NORMAL; 355 token = BRACE_PHRASE; 356 break; 357 } 358 goto repeat; 359 default: 360 goto repeat; 361 } 362 break; 363 364 case ST_EXPRESSION: 365 switch (token) 366 { 367 case '(': case '[': case '{': 368 ++count; 369 APP; 370 goto repeat; 371 case '}': 372 /* is this the last line of an enum declaration? */ 373 if (count == 0) 374 { 375 /* Put back the token we just read so's we can find it again 376 after registering the expression. */ 377 unput(token); 378 379 lexstate = ST_NORMAL; 380 token = EXPRESSION_PHRASE; 381 break; 382 } 383 /* FALLTHRU */ 384 case ')': case ']': 385 --count; 386 APP; 387 goto repeat; 388 case ',': case ';': 389 if (count == 0) 390 { 391 /* Put back the token we just read so's we can find it again 392 after registering the expression. */ 393 unput(token); 394 395 lexstate = ST_NORMAL; 396 token = EXPRESSION_PHRASE; 397 break; 398 } 399 APP; 400 goto repeat; 401 default: 402 APP; 403 goto repeat; 404 } 405 break; 406 407 case ST_STATIC_ASSERT: 408 APP; 409 switch (token) 410 { 411 case '(': 412 ++count; 413 goto repeat; 414 case ')': 415 if (--count == 0) 416 { 417 lexstate = ST_NORMAL; 418 token = STATIC_ASSERT_PHRASE; 419 break; 420 } 421 goto repeat; 422 default: 423 goto repeat; 424 } 425 break; 426 427 default: 428 exit(1); 429 } 430 fini: 431 432 if (suppress_type_lookup > 0) 433 --suppress_type_lookup; 434 if (dont_want_brace_phrase > 0) 435 --dont_want_brace_phrase; 436 437 yylval = &next_node->next; 438 439 return token; 440 } 441