Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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}