]> git.proxmox.com Git - grub2.git/blame - grub-core/script/yylex.l
Import grub2_2.02+dfsg1.orig.tar.xz
[grub2.git] / grub-core / script / yylex.l
CommitLineData
4d8d554a
CW
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/i18n.h>
26#include "grub_script.tab.h"
27
28#pragma GCC diagnostic ignored "-Wunused-parameter"
29#pragma GCC diagnostic ignored "-Wmissing-prototypes"
30#pragma GCC diagnostic ignored "-Wmissing-declarations"
31#pragma GCC diagnostic ignored "-Wunused-function"
32#pragma GCC diagnostic ignored "-Wsign-compare"
33
34#define yyalloc(size, scanner) (grub_malloc((size)))
35#define yyfree(ptr, scanner) (grub_free((ptr)))
36#define yyrealloc(ptr, size, scanner) (grub_realloc((ptr), (size)))
37
38/*
39 * As we don't have access to yyscanner, we cannot do much except to
40 * print the fatal error.
41 */
42#define YY_FATAL_ERROR(msg) \
43 do { \
44 grub_printf (_("fatal error: %s\n"), _(msg)); \
45 } while (0)
46
47#define COPY(str, hint) \
48 do { \
49 copy_string (yyextra, str, hint); \
50 } while (0)
51
52
53#define RECORD \
54 do { \
55 grub_script_lexer_record (yyextra, yytext); \
56 } while (0)
57
58#define ARG(t) \
59 do { \
60 yyextra->lexerstate->type = t; \
61 return GRUB_PARSER_TOKEN_WORD; \
62 } while (0)
63
64/* We don't need YY_INPUT, as we rely on yy_scan_strings */
65#define YY_INPUT(buf,res,max) do { res = 0; } while (0)
66
67/* forward declarations */
68static int grub_lexer_unput (const char *input, yyscan_t yyscanner);
69static int grub_lexer_resplit (const char *input, yyscan_t yyscanner);
70
71static void copy_string (struct grub_parser_param *, const char *,
72 unsigned hint);
73
74%}
75
76%top{
77
78#include <config.h>
79
80#include <sys/types.h>
81
82typedef size_t yy_size_t;
83#define YY_TYPEDEF_YY_SIZE_T 1
84
85/*
86 * Some flex hacks for -nostdinc; XXX We need to fix these when libc
87 * support becomes availble in GRUB.
88 */
89
90#ifndef GRUB_UTIL
91#define stdin 0
92#define stdout 0
93
94#define fprintf(...) 0
95#define exit(...) grub_fatal("fatal error in lexer")
96#endif
97
98}
99
100%option ecs
101%option meta-ecs
102
103%option warn
104%option array
105%option stack
106%option reentrant
107%option bison-bridge
108%option never-interactive
109
110%option noyyfree noyyalloc noyyrealloc
111%option nounistd nostdinit nodefault noyylineno
112
113/* Reduce lexer size, by not defining these. */
114%option noyy_top_state
115%option noinput nounput
116%option noyyget_in noyyset_in
117%option noyyget_out noyyset_out
118%option noyyget_debug noyyset_debug
119%option noyyget_lineno noyyset_lineno
120
121%option extra-type="struct grub_parser_param*"
122
123BLANK [ \t]
124COMMENT #.*$
125
126CHAR [^{}|&$;<> \t\n\'\"\\]
127DIGITS [[:digit:]]+
128NAME [[:alpha:]_][[:alnum:]_]*
129
130ESC \\(.|\n)
131SQCHR [^\']
132DQCHR {ESC}|[^\\\"]
133DQSTR \"{DQCHR}*\"
134I18NSTR \$\"{DQCHR}*\"
135SQSTR \'{SQCHR}*\'
136SPECIAL \?|\#|\*|\@
137VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\}
138WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE}|{I18NSTR})+
139
140MULTILINE {WORD}?((\"{DQCHR}*)|(\$\"{DQCHR}*)|(\'{SQCHR}*))
141POS_MULTILINE {WORD}?\\\n
142
143%x SPLIT
144%x DQUOTE
145%x I18NQUOTE
146%x SQUOTE
147%x VAR
148
149%%
150
151 /* White spaces */
152{BLANK}+ { RECORD; }
153{COMMENT} { RECORD; }
154
155 /* Special symbols */
156"\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; }
157"||" { RECORD; return GRUB_PARSER_TOKEN_OR; }
158"&&" { RECORD; return GRUB_PARSER_TOKEN_AND; }
159";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; }
160"|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; }
161"&" { RECORD; return GRUB_PARSER_TOKEN_AMP; }
162";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; }
163"<" { RECORD; return GRUB_PARSER_TOKEN_LT; }
164">" { RECORD; return GRUB_PARSER_TOKEN_GT; }
165
166 /* Reserved words */
167"{" { RECORD; return GRUB_PARSER_TOKEN_LBR; }
168"}" { RECORD; return GRUB_PARSER_TOKEN_RBR; }
169"[[" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; }
170"]]" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; }
171"case" { RECORD; return GRUB_PARSER_TOKEN_CASE; }
172"do" { RECORD; return GRUB_PARSER_TOKEN_DO; }
173"done" { RECORD; return GRUB_PARSER_TOKEN_DONE; }
174"elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; }
175"else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; }
176"esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; }
177"fi" { RECORD; return GRUB_PARSER_TOKEN_FI; }
178"for" { RECORD; return GRUB_PARSER_TOKEN_FOR; }
179"if" { RECORD; return GRUB_PARSER_TOKEN_IF; }
180"in" { RECORD; return GRUB_PARSER_TOKEN_IN; }
181"select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; }
182"then" { RECORD; return GRUB_PARSER_TOKEN_THEN; }
183"until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; }
184"while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; }
185"function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; }
186
187{MULTILINE} {
188 if (grub_lexer_unput (yytext, yyscanner))
189 return GRUB_PARSER_TOKEN_BAD;
190 }
191
192{POS_MULTILINE} {
193 if (yyg->yy_c_buf_p + 1 == &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
194 {
195 if (grub_lexer_unput (yytext, yyscanner))
196 return GRUB_PARSER_TOKEN_BAD;
197 }
198 else
199 {
200 RECORD;
201 yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
202 if (grub_lexer_resplit (yytext, yyscanner))
203 {
204 yypop_buffer_state (yyscanner);
205 return GRUB_PARSER_TOKEN_WORD;
206 }
207 yyextra->lexerstate->resplit = 1;
208 }
209 }
210
211
212{NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
213{WORD} {
214 RECORD;
215 yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
216 if (grub_lexer_resplit (yytext, yyscanner))
217 {
218 yypop_buffer_state (yyscanner);
219 return GRUB_PARSER_TOKEN_WORD;
220 }
221 yyextra->lexerstate->resplit = 1;
222 }
223. {
224 grub_script_yyerror (yyextra, yytext);
225 return GRUB_PARSER_TOKEN_BAD;
226 }
227
228 /* Split word into multiple args */
229
230<SPLIT>{
231 \\. { COPY (yytext, yyleng); }
232 \\\n { /* ignore */ }
233 \" {
234 yy_push_state (DQUOTE, yyscanner);
235 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
236 }
237 \' {
238 yy_push_state (SQUOTE, yyscanner);
239 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
240 }
241 "\$\"" {
242 yy_push_state (I18NQUOTE, yyscanner);
243 ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
244 }
245 \$ {
246 yy_push_state (VAR, yyscanner);
247 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
248 }
249 \\ |
250 [^\"\'\$\\]+ { COPY (yytext, yyleng); }
251 <<EOF>> {
252 yy_pop_state (yyscanner);
253 yypop_buffer_state (yyscanner);
254 yyextra->lexerstate->resplit = 0;
255 yyextra->lexerstate->merge_end = 1;
256 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
257 }
258}
259
260<VAR>{
261 {SPECIAL} |
262 {DIGITS} |
263 {NAME} {
264 COPY (yytext, yyleng);
265 yy_pop_state (yyscanner);
266 if (YY_START == SPLIT)
267 ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
268 else
269 ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
270 }
271 \{{SPECIAL}\} |
272 \{{DIGITS}\} |
273 \{{NAME}\} {
274 yytext[yyleng - 1] = '\0';
275 COPY (yytext + 1, yyleng - 2);
276 yy_pop_state (yyscanner);
277 if (YY_START == SPLIT)
278 ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
279 else
280 ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
281 }
282 .|\n { return GRUB_PARSER_TOKEN_BAD; }
283}
284
285<SQUOTE>{
286 \' {
287 yy_pop_state (yyscanner);
288 ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
289 }
290 [^\']+ { COPY (yytext, yyleng); }
291}
292
293<DQUOTE>{
294 \\\$ { COPY ("$", 1); }
295 \\\\ { COPY ("\\", 1); }
296 \\\" { COPY ("\"", 1); }
297 \\\n { /* ignore */ }
298 [^\"\$\\\n]+ { COPY (yytext, yyleng); }
299 \" {
300 yy_pop_state (yyscanner);
301 ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
302 }
303 \$ {
304 yy_push_state (VAR, yyscanner);
305 ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
306 }
307 (.|\n) { COPY (yytext, yyleng); }
308}
309
310<I18NQUOTE>{
311 \\\\ { COPY ("\\\\", 2); }
312 \\\" { COPY ("\"", 1); }
313 \\\n { /* ignore */ }
314 [^\"\\\n]+ { COPY (yytext, yyleng); }
315 \" {
316 yy_pop_state (yyscanner);
317 ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
318 }
319 \\ { COPY ("\\", 1); }
320 (.|\n) { COPY (yytext, yyleng); }
321}
322
323<<EOF>> {
324 yypop_buffer_state (yyscanner);
325 yyextra->lexerstate->eof = 1;
326 return GRUB_PARSER_TOKEN_EOF;
327 }
328%%
329
330int
331yywrap (yyscan_t yyscanner)
332{
333 if (yyget_extra (yyscanner)->lexerstate->resplit)
334 return 1;
335
336 return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
337}
338
339static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
340{
341 grub_size_t size;
342 char *ptr;
343 unsigned len;
344
345 len = hint ? hint : grub_strlen (str);
346 if (parser->lexerstate->used + len >= parser->lexerstate->size)
347 {
348 size = len * 2;
349 if (size < parser->lexerstate->size * 2)
350 size = parser->lexerstate->size * 2;
351 ptr = grub_realloc (parser->lexerstate->text, size);
352 if (!ptr)
353 {
354 grub_script_yyerror (parser, 0);
355 return;
356 }
357
358 parser->lexerstate->text = ptr;
359 parser->lexerstate->size = size;
360 }
361 grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
362 parser->lexerstate->used += len;
363}
364
365static int
366grub_lexer_resplit (const char *text, yyscan_t yyscanner)
367{
368 /* resplit text */
369 if (yy_scan_string (text, yyscanner))
370 {
371 yyget_extra (yyscanner)->lexerstate->merge_start = 1;
372 yy_push_state (SPLIT, yyscanner);
373 return 0;
374 }
375 grub_script_yyerror (yyget_extra (yyscanner), 0);
376 return 1;
377}
378
379static int
380grub_lexer_unput (const char *text, yyscan_t yyscanner)
381{
382 struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;
383
384 grub_free (lexerstate->prefix);
385
386 lexerstate->prefix = grub_strdup (text);
387 if (! lexerstate->prefix)
388 {
389 grub_script_yyerror (yyget_extra (yyscanner), N_("out of memory"));
390 return 1;
391 }
392 return 0;
393}