1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 4 */ 5 %option nostdinit noyywrap never-interactive full ecs 6 %option 8bit nodefault yylineno 7 %x ASSIGN_VAL HELP STRING 8 %{ 9 10 #include <assert.h> 11 #include <limits.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include "lkc.h" 17 #include "parser.tab.h" 18 19 #define YY_DECL static int yylex1(void) 20 21 #define START_STRSIZE 16 22 23 static struct { 24 struct file *file; 25 int lineno; 26 } current_pos; 27 28 static int prev_prev_token = T_EOL; 29 static int prev_token = T_EOL; 30 static char *text; 31 static int text_size, text_asize; 32 33 struct buffer { 34 struct buffer *parent; 35 YY_BUFFER_STATE state; 36 }; 37 38 static struct buffer *current_buf; 39 40 static int last_ts, first_ts; 41 42 static char *expand_token(const char *in, size_t n); 43 static void append_expanded_string(const char *in); 44 static void zconf_endhelp(void); 45 static void zconf_endfile(void); 46 47 static void new_string(void) 48 { 49 text = xmalloc(START_STRSIZE); 50 text_asize = START_STRSIZE; 51 text_size = 0; 52 *text = 0; 53 } 54 55 static void append_string(const char *str, int size) 56 { 57 int new_size = text_size + size + 1; 58 if (new_size > text_asize) { 59 new_size += START_STRSIZE - 1; 60 new_size &= -START_STRSIZE; 61 text = xrealloc(text, new_size); 62 text_asize = new_size; 63 } 64 memcpy(text + text_size, str, size); 65 text_size += size; 66 text[text_size] = 0; 67 } 68 69 static void alloc_string(const char *str, int size) 70 { 71 text = xmalloc(size + 1); 72 memcpy(text, str, size); 73 text[size] = 0; 74 } 75 76 static void warn_ignored_character(char chr) 77 { 78 fprintf(stderr, 79 "%s:%d:warning: ignoring unsupported character '%c'\n", 80 current_file->name, yylineno, chr); 81 } 82 %} 83 84 n [A-Za-z0-9_-] 85 86 %% 87 int str = 0; 88 int ts, i; 89 90 #.* /* ignore comment */ 91 [ \t]* /* whitespaces */ 92 \\\n /* escaped new line */ 93 \n return T_EOL; 94 "allnoconfig_y" return T_ALLNOCONFIG_Y; 95 "bool" return T_BOOL; 96 "choice" return T_CHOICE; 97 "comment" return T_COMMENT; 98 "config" return T_CONFIG; 99 "def_bool" return T_DEF_BOOL; 100 "def_tristate" return T_DEF_TRISTATE; 101 "default" return T_DEFAULT; 102 "defconfig_list" return T_DEFCONFIG_LIST; 103 "depends" return T_DEPENDS; 104 "endchoice" return T_ENDCHOICE; 105 "endif" return T_ENDIF; 106 "endmenu" return T_ENDMENU; 107 "help" return T_HELP; 108 "hex" return T_HEX; 109 "if" return T_IF; 110 "imply" return T_IMPLY; 111 "int" return T_INT; 112 "mainmenu" return T_MAINMENU; 113 "menu" return T_MENU; 114 "menuconfig" return T_MENUCONFIG; 115 "modules" return T_MODULES; 116 "on" return T_ON; 117 "option" return T_OPTION; 118 "optional" return T_OPTIONAL; 119 "prompt" return T_PROMPT; 120 "range" return T_RANGE; 121 "select" return T_SELECT; 122 "source" return T_SOURCE; 123 "string" return T_STRING; 124 "tristate" return T_TRISTATE; 125 "visible" return T_VISIBLE; 126 "||" return T_OR; 127 "&&" return T_AND; 128 "=" return T_EQUAL; 129 "!=" return T_UNEQUAL; 130 "<" return T_LESS; 131 "<=" return T_LESS_EQUAL; 132 ">" return T_GREATER; 133 ">=" return T_GREATER_EQUAL; 134 "!" return T_NOT; 135 "(" return T_OPEN_PAREN; 136 ")" return T_CLOSE_PAREN; 137 ":=" return T_COLON_EQUAL; 138 "+=" return T_PLUS_EQUAL; 139 \"|\' { 140 str = yytext[0]; 141 new_string(); 142 BEGIN(STRING); 143 } 144 {n}+ { 145 alloc_string(yytext, yyleng); 146 yylval.string = text; 147 return T_WORD; 148 } 149 ({n}|$)+ { 150 /* this token includes at least one '$' */ 151 yylval.string = expand_token(yytext, yyleng); 152 if (strlen(yylval.string)) 153 return T_WORD; 154 free(yylval.string); 155 } 156 . warn_ignored_character(*yytext); 157 158 <ASSIGN_VAL>{ 159 [^[:blank:]\n]+.* { 160 alloc_string(yytext, yyleng); 161 yylval.string = text; 162 return T_ASSIGN_VAL; 163 } 164 \n { BEGIN(INITIAL); return T_EOL; } 165 . 166 } 167 168 <STRING>{ 169 "$".* append_expanded_string(yytext); 170 [^$'"\\\n]+ { 171 append_string(yytext, yyleng); 172 } 173 \\.? { 174 append_string(yytext + 1, yyleng - 1); 175 } 176 \'|\" { 177 if (str == yytext[0]) { 178 BEGIN(INITIAL); 179 yylval.string = text; 180 return T_WORD_QUOTE; 181 } else 182 append_string(yytext, 1); 183 } 184 \n { 185 fprintf(stderr, 186 "%s:%d:warning: multi-line strings not supported\n", 187 zconf_curname(), zconf_lineno()); 188 unput('\n'); 189 BEGIN(INITIAL); 190 yylval.string = text; 191 return T_WORD_QUOTE; 192 } 193 <<EOF>> { 194 BEGIN(INITIAL); 195 yylval.string = text; 196 return T_WORD_QUOTE; 197 } 198 } 199 200 <HELP>{ 201 [ \t]+ { 202 ts = 0; 203 for (i = 0; i < yyleng; i++) { 204 if (yytext[i] == '\t') 205 ts = (ts & ~7) + 8; 206 else 207 ts++; 208 } 209 last_ts = ts; 210 if (first_ts) { 211 if (ts < first_ts) { 212 zconf_endhelp(); 213 return T_HELPTEXT; 214 } 215 ts -= first_ts; 216 while (ts > 8) { 217 append_string(" ", 8); 218 ts -= 8; 219 } 220 append_string(" ", ts); 221 } 222 } 223 [ \t]*\n/[^ \t\n] { 224 zconf_endhelp(); 225 return T_HELPTEXT; 226 } 227 [ \t]*\n { 228 append_string("\n", 1); 229 } 230 [^ \t\n].* { 231 while (yyleng) { 232 if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) 233 break; 234 yyleng--; 235 } 236 append_string(yytext, yyleng); 237 if (!first_ts) 238 first_ts = last_ts; 239 } 240 <<EOF>> { 241 zconf_endhelp(); 242 return T_HELPTEXT; 243 } 244 } 245 246 <<EOF>> { 247 BEGIN(INITIAL); 248 249 if (prev_token != T_EOL && prev_token != T_HELPTEXT) 250 fprintf(stderr, "%s:%d:warning: no new line at end of file\n", 251 current_file->name, yylineno); 252 253 if (current_file) { 254 zconf_endfile(); 255 return T_EOL; 256 } 257 fclose(yyin); 258 yyterminate(); 259 } 260 261 %% 262 263 /* second stage lexer */ 264 int yylex(void) 265 { 266 int token; 267 268 repeat: 269 token = yylex1(); 270 271 if (prev_token == T_EOL || prev_token == T_HELPTEXT) { 272 if (token == T_EOL) { 273 /* Do not pass unneeded T_EOL to the parser. */ 274 goto repeat; 275 } else { 276 /* 277 * For the parser, update file/lineno at the first token 278 * of each statement. Generally, \n is a statement 279 * terminator in Kconfig, but it is not always true 280 * because \n could be escaped by a backslash. 281 */ 282 current_pos.file = current_file; 283 current_pos.lineno = yylineno; 284 } 285 } 286 287 if (prev_prev_token == T_EOL && prev_token == T_WORD && 288 (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL)) 289 BEGIN(ASSIGN_VAL); 290 291 prev_prev_token = prev_token; 292 prev_token = token; 293 294 return token; 295 } 296 297 static char *expand_token(const char *in, size_t n) 298 { 299 char *out; 300 int c; 301 char c2; 302 const char *rest, *end; 303 304 new_string(); 305 append_string(in, n); 306 307 /* get the whole line because we do not know the end of token. */ 308 while ((c = input()) != EOF) { 309 if (c == '\n') { 310 unput(c); 311 break; 312 } 313 c2 = c; 314 append_string(&c2, 1); 315 } 316 317 rest = text; 318 out = expand_one_token(&rest); 319 320 /* push back unused characters to the input stream */ 321 end = rest + strlen(rest); 322 while (end > rest) 323 unput(*--end); 324 325 free(text); 326 327 return out; 328 } 329 330 static void append_expanded_string(const char *str) 331 { 332 const char *end; 333 char *res; 334 335 str++; 336 337 res = expand_dollar(&str); 338 339 /* push back unused characters to the input stream */ 340 end = str + strlen(str); 341 while (end > str) 342 unput(*--end); 343 344 append_string(res, strlen(res)); 345 346 free(res); 347 } 348 349 void zconf_starthelp(void) 350 { 351 new_string(); 352 last_ts = first_ts = 0; 353 BEGIN(HELP); 354 } 355 356 static void zconf_endhelp(void) 357 { 358 yylval.string = text; 359 BEGIN(INITIAL); 360 } 361 362 363 /* 364 * Try to open specified file with following names: 365 * ./name 366 * $(srctree)/name 367 * The latter is used when srctree is separate from objtree 368 * when compiling the kernel. 369 * Return NULL if file is not found. 370 */ 371 FILE *zconf_fopen(const char *name) 372 { 373 char *env, fullname[PATH_MAX+1]; 374 FILE *f; 375 376 f = fopen(name, "r"); 377 if (!f && name != NULL && name[0] != '/') { 378 env = getenv(SRCTREE); 379 if (env) { 380 snprintf(fullname, sizeof(fullname), 381 "%s/%s", env, name); 382 f = fopen(fullname, "r"); 383 } 384 } 385 return f; 386 } 387 388 void zconf_initscan(const char *name) 389 { 390 yyin = zconf_fopen(name); 391 if (!yyin) { 392 fprintf(stderr, "can't find file %s\n", name); 393 exit(1); 394 } 395 396 current_buf = xmalloc(sizeof(*current_buf)); 397 memset(current_buf, 0, sizeof(*current_buf)); 398 399 current_file = file_lookup(name); 400 yylineno = 1; 401 } 402 403 void zconf_nextfile(const char *name) 404 { 405 struct file *iter; 406 struct file *file = file_lookup(name); 407 struct buffer *buf = xmalloc(sizeof(*buf)); 408 memset(buf, 0, sizeof(*buf)); 409 410 current_buf->state = YY_CURRENT_BUFFER; 411 yyin = zconf_fopen(file->name); 412 if (!yyin) { 413 fprintf(stderr, "%s:%d: can't open file \"%s\"\n", 414 zconf_curname(), zconf_lineno(), file->name); 415 exit(1); 416 } 417 yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); 418 buf->parent = current_buf; 419 current_buf = buf; 420 421 current_file->lineno = yylineno; 422 file->parent = current_file; 423 424 for (iter = current_file; iter; iter = iter->parent) { 425 if (!strcmp(iter->name, file->name)) { 426 fprintf(stderr, 427 "Recursive inclusion detected.\n" 428 "Inclusion path:\n" 429 " current file : %s\n", file->name); 430 iter = file; 431 do { 432 iter = iter->parent; 433 fprintf(stderr, " included from: %s:%d\n", 434 iter->name, iter->lineno - 1); 435 } while (strcmp(iter->name, file->name)); 436 exit(1); 437 } 438 } 439 440 yylineno = 1; 441 current_file = file; 442 } 443 444 static void zconf_endfile(void) 445 { 446 struct buffer *parent; 447 448 current_file = current_file->parent; 449 if (current_file) 450 yylineno = current_file->lineno; 451 452 parent = current_buf->parent; 453 if (parent) { 454 fclose(yyin); 455 yy_delete_buffer(YY_CURRENT_BUFFER); 456 yy_switch_to_buffer(parent->state); 457 } 458 free(current_buf); 459 current_buf = parent; 460 } 461 462 int zconf_lineno(void) 463 { 464 return current_pos.lineno; 465 } 466 467 const char *zconf_curname(void) 468 { 469 return current_pos.file ? current_pos.file->name : "<none>"; 470 } 471