1bb372868ecf1d65f42f4bd68b7eeaa43ebf1053
[sfrench/cifs-2.6.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
16 #include "lkc.h"
17 #include "preprocess.h"
18
19 #include "parser.tab.h"
20
21 #define YY_DECL         static int yylex1(void)
22
23 #define START_STRSIZE   16
24
25 static struct {
26         struct file *file;
27         int lineno;
28 } current_pos;
29
30 static int prev_prev_token = T_EOL;
31 static int prev_token = T_EOL;
32 static char *text;
33 static int text_size, text_asize;
34
35 struct buffer {
36         struct buffer *parent;
37         YY_BUFFER_STATE state;
38         int yylineno;
39 };
40
41 static struct buffer *current_buf;
42
43 static int last_ts, first_ts;
44
45 static char *expand_token(const char *in, size_t n);
46 static void append_expanded_string(const char *in);
47 static void zconf_endhelp(void);
48 static void zconf_endfile(void);
49
50 static void new_string(void)
51 {
52         text = xmalloc(START_STRSIZE);
53         text_asize = START_STRSIZE;
54         text_size = 0;
55         *text = 0;
56 }
57
58 static void append_string(const char *str, int size)
59 {
60         int new_size = text_size + size + 1;
61         if (new_size > text_asize) {
62                 new_size += START_STRSIZE - 1;
63                 new_size &= -START_STRSIZE;
64                 text = xrealloc(text, new_size);
65                 text_asize = new_size;
66         }
67         memcpy(text + text_size, str, size);
68         text_size += size;
69         text[text_size] = 0;
70 }
71
72 static void alloc_string(const char *str, int size)
73 {
74         text = xmalloc(size + 1);
75         memcpy(text, str, size);
76         text[size] = 0;
77 }
78
79 static void warn_ignored_character(char chr)
80 {
81         fprintf(stderr,
82                 "%s:%d:warning: ignoring unsupported character '%c'\n",
83                 current_file->name, yylineno, chr);
84 }
85 %}
86
87 n       [A-Za-z0-9_-]
88
89 %%
90         char open_quote = 0;
91
92 #.*                     /* ignore comment */
93 [ \t]*                  /* whitespaces */
94 \\\n                    /* escaped new line */
95 \n                      return T_EOL;
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 "depends"               return T_DEPENDS;
104 "endchoice"             return T_ENDCHOICE;
105 "endif"                 return T_ENDIF;
106 "endmenu"               return T_ENDMENU;
107 "help"                  return T_HELP;
108 "hex"                   return T_HEX;
109 "if"                    return T_IF;
110 "imply"                 return T_IMPLY;
111 "int"                   return T_INT;
112 "mainmenu"              return T_MAINMENU;
113 "menu"                  return T_MENU;
114 "menuconfig"            return T_MENUCONFIG;
115 "modules"               return T_MODULES;
116 "on"                    return T_ON;
117 "optional"              return T_OPTIONAL;
118 "prompt"                return T_PROMPT;
119 "range"                 return T_RANGE;
120 "select"                return T_SELECT;
121 "source"                return T_SOURCE;
122 "string"                return T_STRING;
123 "tristate"              return T_TRISTATE;
124 "visible"               return T_VISIBLE;
125 "||"                    return T_OR;
126 "&&"                    return T_AND;
127 "="                     return T_EQUAL;
128 "!="                    return T_UNEQUAL;
129 "<"                     return T_LESS;
130 "<="                    return T_LESS_EQUAL;
131 ">"                     return T_GREATER;
132 ">="                    return T_GREATER_EQUAL;
133 "!"                     return T_NOT;
134 "("                     return T_OPEN_PAREN;
135 ")"                     return T_CLOSE_PAREN;
136 ":="                    return T_COLON_EQUAL;
137 "+="                    return T_PLUS_EQUAL;
138 \"|\'                   {
139                                 open_quote = yytext[0];
140                                 new_string();
141                                 BEGIN(STRING);
142                         }
143 {n}+                    {
144                                 alloc_string(yytext, yyleng);
145                                 yylval.string = text;
146                                 return T_WORD;
147                         }
148 ({n}|$)+                {
149                                 /* this token includes at least one '$' */
150                                 yylval.string = expand_token(yytext, yyleng);
151                                 if (strlen(yylval.string))
152                                         return T_WORD;
153                                 free(yylval.string);
154                         }
155 .                       warn_ignored_character(*yytext);
156
157 <ASSIGN_VAL>{
158         [^[:blank:]\n]+.*       {
159                 alloc_string(yytext, yyleng);
160                 yylval.string = text;
161                 return T_ASSIGN_VAL;
162         }
163         \n      { BEGIN(INITIAL); return T_EOL; }
164         .
165 }
166
167 <STRING>{
168         "$".*   append_expanded_string(yytext);
169         [^$'"\\\n]+     {
170                 append_string(yytext, yyleng);
171         }
172         \\.?    {
173                 append_string(yytext + 1, yyleng - 1);
174         }
175         \'|\"   {
176                 if (open_quote == yytext[0]) {
177                         BEGIN(INITIAL);
178                         yylval.string = text;
179                         return T_WORD_QUOTE;
180                 } else
181                         append_string(yytext, 1);
182         }
183         \n      {
184                 fprintf(stderr,
185                         "%s:%d:warning: multi-line strings not supported\n",
186                         zconf_curname(), zconf_lineno());
187                 unput('\n');
188                 BEGIN(INITIAL);
189                 yylval.string = text;
190                 return T_WORD_QUOTE;
191         }
192         <<EOF>> {
193                 BEGIN(INITIAL);
194                 yylval.string = text;
195                 return T_WORD_QUOTE;
196         }
197 }
198
199 <HELP>{
200         [ \t]+  {
201                 int ts, i;
202
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_file = file_lookup(name);
401         yylineno = 1;
402 }
403
404 void zconf_nextfile(const char *name)
405 {
406         struct file *iter;
407         struct file *file = file_lookup(name);
408         struct buffer *buf = xmalloc(sizeof(*buf));
409
410         buf->state = YY_CURRENT_BUFFER;
411         buf->yylineno = yylineno;
412         buf->parent = current_buf;
413         current_buf = buf;
414         yyin = zconf_fopen(file->name);
415         if (!yyin) {
416                 fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
417                         zconf_curname(), zconf_lineno(), file->name);
418                 exit(1);
419         }
420         yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
421
422         current_file->lineno = zconf_lineno();
423         file->parent = current_file;
424
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);
436                         } while (strcmp(iter->name, file->name));
437                         exit(1);
438                 }
439         }
440
441         yylineno = 1;
442         current_file = file;
443 }
444
445 static void zconf_endfile(void)
446 {
447         struct buffer *tmp;
448
449         current_file = current_file->parent;
450
451         if (!current_buf)
452                 return;
453
454         fclose(yyin);
455         yy_delete_buffer(YY_CURRENT_BUFFER);
456         yy_switch_to_buffer(current_buf->state);
457         yylineno = current_buf->yylineno;
458         tmp = current_buf;
459         current_buf = current_buf->parent;
460         free(tmp);
461 }
462
463 int zconf_lineno(void)
464 {
465         return current_pos.lineno;
466 }
467
468 const char *zconf_curname(void)
469 {
470         return current_pos.file ? current_pos.file->name : "<none>";
471 }