treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / scripts / kconfig / lexer.l
blob6354c905b006f66e673d9b098c2ae50ef29271c4
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 %{
10 #include <assert.h>
11 #include <limits.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.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 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         int str = 0;
89         int ts, i;
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"|"---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);
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         .
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         }
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         }
247 <<EOF>> {
248         BEGIN(INITIAL);
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);
254         if (current_file) {
255                 zconf_endfile();
256                 return T_EOL;
257         }
258         fclose(yyin);
259         yyterminate();
264 /* second stage lexer */
265 int yylex(void)
267         int token;
269 repeat:
270         token = yylex1();
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         }
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);
292         prev_prev_token = prev_token;
293         prev_token = token;
295         return token;
298 static char *expand_token(const char *in, size_t n)
300         char *out;
301         int c;
302         char c2;
303         const char *rest, *end;
305         new_string();
306         append_string(in, n);
308         /* get the whole line because we do not know the end of token. */
309         while ((c = input()) != EOF) {
310                 if (c == '\n') {
311                         unput(c);
312                         break;
313                 }
314                 c2 = c;
315                 append_string(&c2, 1);
316         }
318         rest = text;
319         out = expand_one_token(&rest);
321         /* push back unused characters to the input stream */
322         end = rest + strlen(rest);
323         while (end > rest)
324                 unput(*--end);
326         free(text);
328         return out;
331 static void append_expanded_string(const char *str)
333         const char *end;
334         char *res;
336         str++;
338         res = expand_dollar(&str);
340         /* push back unused characters to the input stream */
341         end = str + strlen(str);
342         while (end > str)
343                 unput(*--end);
345         append_string(res, strlen(res));
347         free(res);
350 void zconf_starthelp(void)
352         new_string();
353         last_ts = first_ts = 0;
354         BEGIN(HELP);
357 static void zconf_endhelp(void)
359         yylval.string = text;
360         BEGIN(INITIAL);
365  * Try to open specified file with following names:
366  * ./name
367  * $(srctree)/name
368  * The latter is used when srctree is separate from objtree
369  * when compiling the kernel.
370  * Return NULL if file is not found.
371  */
372 FILE *zconf_fopen(const char *name)
374         char *env, fullname[PATH_MAX+1];
375         FILE *f;
377         f = fopen(name, "r");
378         if (!f && name != NULL && name[0] != '/') {
379                 env = getenv(SRCTREE);
380                 if (env) {
381                         snprintf(fullname, sizeof(fullname),
382                                  "%s/%s", env, name);
383                         f = fopen(fullname, "r");
384                 }
385         }
386         return f;
389 void zconf_initscan(const char *name)
391         yyin = zconf_fopen(name);
392         if (!yyin) {
393                 fprintf(stderr, "can't find file %s\n", name);
394                 exit(1);
395         }
397         current_buf = xmalloc(sizeof(*current_buf));
398         memset(current_buf, 0, sizeof(*current_buf));
400         current_file = file_lookup(name);
401         yylineno = 1;
404 void zconf_nextfile(const char *name)
406         struct file *iter;
407         struct file *file = file_lookup(name);
408         struct buffer *buf = xmalloc(sizeof(*buf));
409         memset(buf, 0, sizeof(*buf));
411         current_buf->state = YY_CURRENT_BUFFER;
412         yyin = zconf_fopen(file->name);
413         if (!yyin) {
414                 fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
415                         zconf_curname(), zconf_lineno(), file->name);
416                 exit(1);
417         }
418         yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
419         buf->parent = current_buf;
420         current_buf = buf;
422         current_file->lineno = yylineno;
423         file->parent = current_file;
425         for (iter = current_file; iter; iter = iter->parent) {
426                 if (!strcmp(iter->name, file->name)) {
427                         fprintf(stderr,
428                                 "Recursive inclusion detected.\n"
429                                 "Inclusion path:\n"
430                                 "  current file : %s\n", file->name);
431                         iter = file;
432                         do {
433                                 iter = iter->parent;
434                                 fprintf(stderr, "  included from: %s:%d\n",
435                                         iter->name, iter->lineno - 1);
436                         } while (strcmp(iter->name, file->name));
437                         exit(1);
438                 }
439         }
441         yylineno = 1;
442         current_file = file;
445 static void zconf_endfile(void)
447         struct buffer *parent;
449         current_file = current_file->parent;
450         if (current_file)
451                 yylineno = current_file->lineno;
453         parent = current_buf->parent;
454         if (parent) {
455                 fclose(yyin);
456                 yy_delete_buffer(YY_CURRENT_BUFFER);
457                 yy_switch_to_buffer(parent->state);
458         }
459         free(current_buf);
460         current_buf = parent;
463 int zconf_lineno(void)
465         return current_pos.lineno;
468 const char *zconf_curname(void)
470         return current_pos.file ? current_pos.file->name : "<none>";