2 /* yylex.l The scripting lexer. */
4 * GRUB -- GRand Unified Bootloader
5 * Copyright (C) 2009,2010 Free Software Foundation, Inc.
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.
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.
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/>.
21 #include <grub/parser.h>
22 #include <grub/misc.h>
24 #include <grub/script_sh.h>
25 #include "grub_script.tab.h"
27 #define yyfree grub_lexer_yyfree
28 #define yyalloc grub_lexer_yyalloc
29 #define yyrealloc grub_lexer_yyrealloc
32 * As we don't have access to yyscanner, we cannot do much except to
33 * print the fatal error.
35 #define YY_FATAL_ERROR(msg) \
37 grub_printf ("fatal error: %s\n", msg); \
40 #define COPY(str, hint) \
42 copy_string (yyextra, str, hint); \
48 grub_script_lexer_record (yyextra, yytext); \
53 yyextra->lexerstate->type = t; \
54 return GRUB_PARSER_TOKEN_WORD; \
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)
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);
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 *,
76 #include <sys/types.h>
78 typedef size_t yy_size_t;
79 #define YY_TYPEDEF_YY_SIZE_T 1
82 * Some flex hacks for -nostdinc; XXX We need to fix these when libc
83 * support becomes availble in GRUB.
90 #define fprintf(...) 0
104 %option never-interactive
106 %option noyyfree noyyalloc noyyrealloc
107 %option nounistd nostdinit nodefault noyylineno
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
117 %option extra-type="struct grub_parser_param*"
122 CHAR [^{}|&$;<> \t\n\'\"\\]
124 NAME [[:alpha:]_][[:alnum:]_]*
132 VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\}
133 WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+
135 MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)|(\\\n))
146 {COMMENT} { RECORD; }
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; }
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; }
182 if (grub_lexer_unput (yytext, yyscanner))
183 return GRUB_PARSER_TOKEN_BAD;
186 {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
189 yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
190 if (grub_lexer_resplit (yytext, yyscanner))
192 yypop_buffer_state (yyscanner);
193 return GRUB_PARSER_TOKEN_WORD;
195 yyextra->lexerstate->resplit = 1;
198 grub_script_yyerror (yyextra, yytext);
199 return GRUB_PARSER_TOKEN_BAD;
202 /* Split word into multiple args */
205 \\. { COPY (yytext + 1, yyleng - 1); }
206 \\\n { /* ignore */ }
208 yy_push_state (DQUOTE, yyscanner);
209 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
212 yy_push_state (SQUOTE, yyscanner);
213 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
216 yy_push_state (VAR, yyscanner);
217 ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
220 [^\"\'\$\\]+ { COPY (yytext, yyleng); }
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);
234 COPY (yytext, yyleng);
235 yy_pop_state (yyscanner);
236 if (YY_START == SPLIT)
237 ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
239 ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
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);
250 ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
252 .|\n { return GRUB_PARSER_TOKEN_BAD; }
257 yy_pop_state (yyscanner);
258 ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
260 [^\']+ { COPY (yytext, yyleng); }
264 \\\$ { COPY ("$", 1); }
265 \\\\ { COPY ("\\", 1); }
266 \\\" { COPY ("\"", 1); }
267 \\\n { /* ignore */ }
268 [^\"\$\\\n]+ { COPY (yytext, yyleng); }
270 yy_pop_state (yyscanner);
271 ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
274 yy_push_state (VAR, yyscanner);
275 ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
277 (.|\n) { COPY (yytext, yyleng); }
281 yypop_buffer_state (yyscanner);
282 yyextra->lexerstate->eof = 1;
283 return GRUB_PARSER_TOKEN_EOF;
288 yywrap (yyscan_t yyscanner)
290 if (yyget_extra (yyscanner)->lexerstate->resplit)
293 return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
297 grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused)))
303 grub_lexer_yyalloc (yy_size_t size, yyscan_t yyscanner __attribute__ ((unused)))
305 return grub_malloc (size);
309 grub_lexer_yyrealloc (void *ptr, yy_size_t size,
310 yyscan_t yyscanner __attribute__ ((unused)))
312 return grub_realloc (ptr, size);
315 static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
321 len = hint ? hint : grub_strlen (str);
322 if (parser->lexerstate->used + len >= parser->lexerstate->size)
324 size = grub_max (len, parser->lexerstate->size) * 2;
325 ptr = grub_realloc (parser->lexerstate->text, size);
328 grub_script_yyerror (parser, 0);
332 parser->lexerstate->text = ptr;
333 parser->lexerstate->size = size;
335 grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
336 parser->lexerstate->used += len;
340 grub_lexer_resplit (const char *text, yyscan_t yyscanner)
343 if (yy_scan_string (text, yyscanner))
345 yyget_extra (yyscanner)->lexerstate->merge_start = 1;
346 yy_push_state (SPLIT, yyscanner);
349 grub_script_yyerror (yyget_extra (yyscanner), 0);
354 grub_lexer_unput (const char *text, yyscan_t yyscanner)
356 struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;
358 if (lexerstate->prefix)
359 grub_free (lexerstate->prefix);
361 lexerstate->prefix = grub_strdup (text);
362 if (! lexerstate->prefix)
364 grub_script_yyerror (yyget_extra (yyscanner), "out of memory");