]> git.proxmox.com Git - grub2.git/blob - grub-core/script/yylex.l
* grub-core/lib/LzFind.c: Add missing include.
[grub2.git] / grub-core / script / yylex.l
1 %{
2 /* yylex.l The scripting lexer. */
3 /*
4 * GRUB -- GRand Unified Bootloader
5 * Copyright (C) 2009,2010 Free Software Foundation, Inc.
6 *
7 * GRUB is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * GRUB is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <grub/parser.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24 #include <grub/script_sh.h>
25 #include "grub_script.tab.h"
26
27 #define yyfree grub_lexer_yyfree
28 #define yyalloc grub_lexer_yyalloc
29 #define yyrealloc grub_lexer_yyrealloc
30
31 /*
32 * As we don't have access to yyscanner, we cannot do much except to
33 * print the fatal error.
34 */
35 #define YY_FATAL_ERROR(msg) \
36 do { \
37 grub_printf ("fatal error: %s\n", msg); \
38 } while (0)
39
40 #define COPY(str, hint) \
41 do { \
42 copy_string (yyextra, str, hint); \
43 } while (0)
44
45
46 #define RECORD \
47 do { \
48 grub_script_lexer_record (yyextra, yytext); \
49 } while (0)
50
51 #define ARG(t) \
52 do { \
53 yyextra->lexerstate->type = t; \
54 return GRUB_PARSER_TOKEN_WORD; \
55 } while (0)
56
57 /* We don't need YY_INPUT, as we rely on yy_scan_strings */
58 #define YY_INPUT(buf,res,max) do { res = 0; } while (0)
59
60 /* forward declarations */
61 static int grub_lexer_unput (const char *input, yyscan_t yyscanner);
62 static int grub_lexer_resplit (const char *input, yyscan_t yyscanner);
63
64 static void grub_lexer_yyfree (void *, yyscan_t yyscanner);
65 static void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner);
66 static void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner);
67 static void copy_string (struct grub_parser_param *, const char *,
68 unsigned hint);
69
70 %}
71
72 %top{
73
74 #include <config.h>
75
76 #include <sys/types.h>
77
78 typedef size_t yy_size_t;
79 #define YY_TYPEDEF_YY_SIZE_T 1
80
81 /*
82 * Some flex hacks for -nostdinc; XXX We need to fix these when libc
83 * support becomes availble in GRUB.
84 */
85
86 #ifndef GRUB_UTIL
87 #define stdin 0
88 #define stdout 0
89
90 #define fprintf(...) 0
91 #define exit(...)
92 #endif
93
94 }
95
96 %option ecs
97 %option meta-ecs
98
99 %option warn
100 %option array
101 %option stack
102 %option reentrant
103 %option bison-bridge
104 %option never-interactive
105
106 %option noyyfree noyyalloc noyyrealloc
107 %option nounistd nostdinit nodefault noyylineno
108
109 /* Reduce lexer size, by not defining these. */
110 %option noyy_top_state
111 %option noinput nounput
112 %option noyyget_in noyyset_in
113 %option noyyget_out noyyset_out
114 %option noyyget_debug noyyset_debug
115 %option noyyget_lineno noyyset_lineno
116
117 %option extra-type="struct grub_parser_param*"
118
119 BLANK [ \t]
120 COMMENT #.*$
121
122 CHAR [^{}|&$;<> \t\n\'\"\\]
123 DIGITS [[:digit:]]+
124 NAME [[:alpha:]_][[:alnum:]_]*
125
126 ESC \\(.|\n)
127 SQCHR [^\']
128 DQCHR {ESC}|[^\\\"]
129 DQSTR \"{DQCHR}*\"
130 SQSTR \'{SQCHR}*\'
131 SPECIAL \?|\#|\*|\@
132 VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\}
133 WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+
134
135 MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)|(\\\n))
136
137 %x SPLIT
138 %x DQUOTE
139 %x SQUOTE
140 %x VAR
141
142 %%
143
144 /* White spaces */
145 {BLANK}+ { RECORD; }
146 {COMMENT} { RECORD; }
147
148 /* Special symbols */
149 "\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; }
150 "||" { RECORD; return GRUB_PARSER_TOKEN_OR; }
151 "&&" { RECORD; return GRUB_PARSER_TOKEN_AND; }
152 ";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; }
153 "|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; }
154 "&" { RECORD; return GRUB_PARSER_TOKEN_AMP; }
155 ";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; }
156 "<" { RECORD; return GRUB_PARSER_TOKEN_LT; }
157 ">" { RECORD; return GRUB_PARSER_TOKEN_GT; }
158
159 /* Reserved words */
160 "{" { RECORD; return GRUB_PARSER_TOKEN_LBR; }
161 "}" { RECORD; return GRUB_PARSER_TOKEN_RBR; }
162 "[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; }
163 "]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; }
164 "time" { RECORD; return GRUB_PARSER_TOKEN_TIME; }
165 "case" { RECORD; return GRUB_PARSER_TOKEN_CASE; }
166 "do" { RECORD; return GRUB_PARSER_TOKEN_DO; }
167 "done" { RECORD; return GRUB_PARSER_TOKEN_DONE; }
168 "elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; }
169 "else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; }
170 "esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; }
171 "fi" { RECORD; return GRUB_PARSER_TOKEN_FI; }
172 "for" { RECORD; return GRUB_PARSER_TOKEN_FOR; }
173 "if" { RECORD; return GRUB_PARSER_TOKEN_IF; }
174 "in" { RECORD; return GRUB_PARSER_TOKEN_IN; }
175 "select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; }
176 "then" { RECORD; return GRUB_PARSER_TOKEN_THEN; }
177 "until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; }
178 "while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; }
179 "function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; }
180
181 {MULTILINE} {
182 if (grub_lexer_unput (yytext, yyscanner))
183 return GRUB_PARSER_TOKEN_BAD;
184 }
185
186 {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
187 {WORD} {
188 RECORD;
189 yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
190 if (grub_lexer_resplit (yytext, yyscanner))
191 {
192 yypop_buffer_state (yyscanner);
193 return GRUB_PARSER_TOKEN_WORD;
194 }
195 yyextra->lexerstate->resplit = 1;
196 }
197 . {
198 grub_script_yyerror (yyextra, yytext);
199 return GRUB_PARSER_TOKEN_BAD;
200 }
201
202 /* Split word into multiple args */
203
204 <SPLIT>{
205 \\. { COPY (yytext + 1, yyleng - 1); }
206 \\\n { /* ignore */ }
207 \" {
208 yy_push_state (DQUOTE, yyscanner);
209 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
210 }
211 \' {
212 yy_push_state (SQUOTE, yyscanner);
213 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
214 }
215 \$ {
216 yy_push_state (VAR, yyscanner);
217 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
218 }
219 \\ |
220 [^\"\'\$\\]+ { COPY (yytext, yyleng); }
221 <<EOF>> {
222 yy_pop_state (yyscanner);
223 yypop_buffer_state (yyscanner);
224 yyextra->lexerstate->resplit = 0;
225 yyextra->lexerstate->merge_end = 1;
226 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
227 }
228 }
229
230 <VAR>{
231 {SPECIAL} |
232 {DIGITS} |
233 {NAME} {
234 COPY (yytext, yyleng);
235 yy_pop_state (yyscanner);
236 if (YY_START == SPLIT)
237 ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
238 else
239 ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
240 }
241 \{{SPECIAL}\} |
242 \{{DIGITS}\} |
243 \{{NAME}\} {
244 yytext[yyleng - 1] = '\0';
245 COPY (yytext + 1, yyleng - 2);
246 yy_pop_state (yyscanner);
247 if (YY_START == SPLIT)
248 ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
249 else
250 ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
251 }
252 .|\n { return GRUB_PARSER_TOKEN_BAD; }
253 }
254
255 <SQUOTE>{
256 \' {
257 yy_pop_state (yyscanner);
258 ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
259 }
260 [^\']+ { COPY (yytext, yyleng); }
261 }
262
263 <DQUOTE>{
264 \\\$ { COPY ("$", 1); }
265 \\\\ { COPY ("\\", 1); }
266 \\\" { COPY ("\"", 1); }
267 \\\n { /* ignore */ }
268 [^\"\$\\\n]+ { COPY (yytext, yyleng); }
269 \" {
270 yy_pop_state (yyscanner);
271 ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
272 }
273 \$ {
274 yy_push_state (VAR, yyscanner);
275 ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
276 }
277 (.|\n) { COPY (yytext, yyleng); }
278 }
279
280 <<EOF>> {
281 yypop_buffer_state (yyscanner);
282 yyextra->lexerstate->eof = 1;
283 return GRUB_PARSER_TOKEN_EOF;
284 }
285 %%
286
287 int
288 yywrap (yyscan_t yyscanner)
289 {
290 if (yyget_extra (yyscanner)->lexerstate->resplit)
291 return 1;
292
293 return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
294 }
295
296 static void
297 grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused)))
298 {
299 grub_free(ptr);
300 }
301
302 static void*
303 grub_lexer_yyalloc (yy_size_t size, yyscan_t yyscanner __attribute__ ((unused)))
304 {
305 return grub_malloc (size);
306 }
307
308 static void*
309 grub_lexer_yyrealloc (void *ptr, yy_size_t size,
310 yyscan_t yyscanner __attribute__ ((unused)))
311 {
312 return grub_realloc (ptr, size);
313 }
314
315 static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
316 {
317 int size;
318 char *ptr;
319 unsigned len;
320
321 len = hint ? hint : grub_strlen (str);
322 if (parser->lexerstate->used + len >= parser->lexerstate->size)
323 {
324 size = grub_max (len, parser->lexerstate->size) * 2;
325 ptr = grub_realloc (parser->lexerstate->text, size);
326 if (!ptr)
327 {
328 grub_script_yyerror (parser, 0);
329 return;
330 }
331
332 parser->lexerstate->text = ptr;
333 parser->lexerstate->size = size;
334 }
335 grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
336 parser->lexerstate->used += len;
337 }
338
339 static int
340 grub_lexer_resplit (const char *text, yyscan_t yyscanner)
341 {
342 /* resplit text */
343 if (yy_scan_string (text, yyscanner))
344 {
345 yyget_extra (yyscanner)->lexerstate->merge_start = 1;
346 yy_push_state (SPLIT, yyscanner);
347 return 0;
348 }
349 grub_script_yyerror (yyget_extra (yyscanner), 0);
350 return 1;
351 }
352
353 static int
354 grub_lexer_unput (const char *text, yyscan_t yyscanner)
355 {
356 struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;
357
358 if (lexerstate->prefix)
359 grub_free (lexerstate->prefix);
360
361 lexerstate->prefix = grub_strdup (text);
362 if (! lexerstate->prefix)
363 {
364 grub_script_yyerror (yyget_extra (yyscanner), "out of memory");
365 return 1;
366 }
367 return 0;
368 }