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