]>
Commit | Line | Data |
---|---|---|
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 */ | |
68 | static int grub_lexer_unput (const char *input, yyscan_t yyscanner); | |
69 | static int grub_lexer_resplit (const char *input, yyscan_t yyscanner); | |
70 | ||
71 | static 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 | ||
82 | typedef 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 | ||
123 | BLANK [ \t] | |
124 | COMMENT #.*$ | |
125 | ||
126 | CHAR [^{}|&$;<> \t\n\'\"\\] | |
127 | DIGITS [[:digit:]]+ | |
128 | NAME [[:alpha:]_][[:alnum:]_]* | |
129 | ||
130 | ESC \\(.|\n) | |
131 | SQCHR [^\'] | |
132 | DQCHR {ESC}|[^\\\"] | |
133 | DQSTR \"{DQCHR}*\" | |
134 | I18NSTR \$\"{DQCHR}*\" | |
135 | SQSTR \'{SQCHR}*\' | |
136 | SPECIAL \?|\#|\*|\@ | |
137 | VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\} | |
138 | WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE}|{I18NSTR})+ | |
139 | ||
140 | MULTILINE {WORD}?((\"{DQCHR}*)|(\$\"{DQCHR}*)|(\'{SQCHR}*)) | |
141 | POS_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 | ||
330 | int | |
331 | yywrap (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 | ||
339 | static 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 | ||
365 | static int | |
366 | grub_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 | ||
379 | static int | |
380 | grub_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 | } |