treewide: Move device_tree to commonlib
[coreboot2.git] / util / kconfig / lexer.l
blobfa3f3543539a827bc3eb7b086cd48d9374e9ffe3
1 /* SPDX-License-Identifier: GPL-2.0-only */
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 %{
10 #include <assert.h>
11 #include <glob.h>
12 #include <limits.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
17 #include "lkc.h"
18 #include "parser.tab.h"
20 #define YY_DECL         static int yylex1(void)
22 #define START_STRSIZE   16
24 static struct {
25         struct file *file;
26         int lineno;
27 } current_pos;
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;
34 struct buffer {
35         struct buffer *parent;
36         YY_BUFFER_STATE state;
39 static struct buffer *current_buf;
41 static int last_ts, first_ts;
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);
48 static void new_string(void)
50         text = xmalloc(START_STRSIZE);
51         text_asize = START_STRSIZE;
52         text_size = 0;
53         *text = 0;
56 static void append_string(const char *str, int size)
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;
70 static void alloc_string(const char *str, int size)
72         text = xmalloc(size + 1);
73         memcpy(text, str, size);
74         text[size] = 0;
77 static void warn_ignored_character(char chr)
79         fprintf(stderr,
80                 "%s:%d:warning: ignoring unsupported character '%c'\n",
81                 current_file->name, yylineno, chr);
85 n       [A-Za-z0-9_-]
88         char open_quote = 0;
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                                 open_quote = 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);
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         .
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 (open_quote == 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         }
197 <HELP>{
198         [ \t]+  {
199                 int ts, i;
201                 ts = 0;
202                 for (i = 0; i < yyleng; i++) {
203                         if (yytext[i] == '\t')
204                                 ts = (ts & ~7) + 8;
205                         else
206                                 ts++;
207                 }
208                 last_ts = ts;
209                 if (first_ts) {
210                         if (ts < first_ts) {
211                                 zconf_endhelp();
212                                 return T_HELPTEXT;
213                         }
214                         ts -= first_ts;
215                         while (ts > 8) {
216                                 append_string("        ", 8);
217                                 ts -= 8;
218                         }
219                         append_string("        ", ts);
220                 }
221         }
222         [ \t]*\n/[^ \t\n] {
223                 zconf_endhelp();
224                 return T_HELPTEXT;
225         }
226         [ \t]*\n        {
227                 append_string("\n", 1);
228         }
229         [^ \t\n].* {
230                 while (yyleng) {
231                         if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
232                                 break;
233                         yyleng--;
234                 }
235                 append_string(yytext, yyleng);
236                 if (!first_ts)
237                         first_ts = last_ts;
238         }
239         <<EOF>> {
240                 zconf_endhelp();
241                 return T_HELPTEXT;
242         }
245 <<EOF>> {
246         BEGIN(INITIAL);
248         if (prev_token != T_EOL && prev_token != T_HELPTEXT)
249                 fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
250                         current_file->name, yylineno);
252         if (current_file) {
253                 zconf_endfile();
254                 return T_EOL;
255         }
256         fclose(yyin);
257         yyterminate();
262 /* second stage lexer */
263 int yylex(void)
265         int token;
267 repeat:
268         token = yylex1();
270         if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
271                 if (token == T_EOL) {
272                         /* Do not pass unneeded T_EOL to the parser. */
273                         goto repeat;
274                 } else {
275                         /*
276                          * For the parser, update file/lineno at the first token
277                          * of each statement. Generally, \n is a statement
278                          * terminator in Kconfig, but it is not always true
279                          * because \n could be escaped by a backslash.
280                          */
281                         current_pos.file = current_file;
282                         current_pos.lineno = yylineno;
283                 }
284         }
286         if (prev_prev_token == T_EOL && prev_token == T_WORD &&
287             (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL))
288                 BEGIN(ASSIGN_VAL);
290         prev_prev_token = prev_token;
291         prev_token = token;
293         return token;
296 static char *expand_token(const char *in, size_t n)
298         char *out;
299         int c;
300         char c2;
301         const char *rest, *end;
303         new_string();
304         append_string(in, n);
306         /* get the whole line because we do not know the end of token. */
307         while ((c = input()) != EOF) {
308                 if (c == '\n') {
309                         unput(c);
310                         break;
311                 }
312                 c2 = c;
313                 append_string(&c2, 1);
314         }
316         rest = text;
317         out = expand_one_token(&rest);
319         /* push back unused characters to the input stream */
320         end = rest + strlen(rest);
321         while (end > rest)
322                 unput(*--end);
324         free(text);
326         return out;
329 static void append_expanded_string(const char *str)
331         const char *end;
332         char *res;
334         str++;
336         res = expand_dollar(&str);
338         /* push back unused characters to the input stream */
339         end = str + strlen(str);
340         while (end > str)
341                 unput(*--end);
343         append_string(res, strlen(res));
345         free(res);
348 void zconf_starthelp(void)
350         new_string();
351         last_ts = first_ts = 0;
352         BEGIN(HELP);
355 static void zconf_endhelp(void)
357         yylval.string = text;
358         BEGIN(INITIAL);
363  * Try to open specified file with following names:
364  * ./name
365  * $(srctree)/name
366  * The latter is used when srctree is separate from objtree
367  * when compiling the kernel.
368  * Return NULL if file is not found.
369  */
370 FILE *zconf_fopen(const char *name)
372         char *env, fullname[PATH_MAX+1];
373         FILE *f;
375         f = fopen(name, "r");
376         if (!f && name != NULL && name[0] != '/') {
377                 env = getenv(SRCTREE);
378                 if (env) {
379                         snprintf(fullname, sizeof(fullname),
380                                  "%s/%s", env, name);
381                         f = fopen(fullname, "r");
382                 }
383         }
384         return f;
387 void zconf_initscan(const char *name)
389         yyin = zconf_fopen(name);
390         if (!yyin) {
391                 fprintf(stderr, "can't find file %s\n", name);
392                 exit(1);
393         }
395         current_buf = xmalloc(sizeof(*current_buf));
396         memset(current_buf, 0, sizeof(*current_buf));
398         current_file = file_lookup(name);
399         yylineno = 1;
402 void zconf_nextfile(const char *name)
404         struct file *iter;
405         struct file *file = file_lookup(name);
406         struct buffer *buf = xmalloc(sizeof(*buf));
407         memset(buf, 0, sizeof(*buf));
409         current_buf->state = YY_CURRENT_BUFFER;
410         yyin = zconf_fopen(file->name);
411         if (!yyin) {
412                 fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
413                         zconf_curname(), zconf_lineno(), file->name);
414                 exit(1);
415         }
416         yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
417         buf->parent = current_buf;
418         current_buf = buf;
420         current_file->lineno = yylineno;
421         file->parent = current_file;
423         for (iter = current_file; iter; iter = iter->parent) {
424                 if (!strcmp(iter->name, file->name)) {
425                         fprintf(stderr,
426                                 "Recursive inclusion detected.\n"
427                                 "Inclusion path:\n"
428                                 "  current file : %s\n", file->name);
429                         iter = file;
430                         do {
431                                 iter = iter->parent;
432                                 fprintf(stderr, "  included from: %s:%d\n",
433                                         iter->name, iter->lineno - 1);
434                         } while (strcmp(iter->name, file->name));
435                         exit(1);
436                 }
437         }
439         yylineno = 1;
440         current_file = file;
443 void zconf_nextfiles(const char *wildcard)
445         glob_t g;
446         char **w;
447         int i;
449         if (glob(wildcard, 0, NULL, &g) != 0) {
450                 return;
451         }
452         if (g.gl_pathv == NULL) {
453                 globfree(&g);
454                 return;
455         }
457         /* working through files backwards, since
458          * we're first pushing them on a stack
459          * before actually handling them.
460          */
461         for (i = g.gl_pathc; i > 0; i--) {
462                 w = &g.gl_pathv[i - 1];
463                 zconf_nextfile(*w);
464         }
466         globfree(&g);
469 static void zconf_endfile(void)
471         struct buffer *parent;
473         current_file = current_file->parent;
474         if (current_file)
475                 yylineno = current_file->lineno;
477         parent = current_buf->parent;
478         if (parent) {
479                 fclose(yyin);
480                 yy_delete_buffer(YY_CURRENT_BUFFER);
481                 yy_switch_to_buffer(parent->state);
482         }
483         free(current_buf);
484         current_buf = parent;
487 int zconf_lineno(void)
489         return current_pos.lineno;
492 const char *zconf_curname(void)
494         return current_pos.file ? current_pos.file->name : "<none>";