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