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