~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/script/parser.y

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* parser.y - The scripting parser.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2005,2006,2007,2008,2009,2010  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB is free software: you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
%{
 
21
#include <grub/script_sh.h>
 
22
#include <grub/mm.h>
 
23
#include <grub/misc.h>
 
24
 
 
25
#define YYFREE          grub_free
 
26
#define YYMALLOC        grub_malloc
 
27
#define YYLTYPE_IS_TRIVIAL      0
 
28
#define YYENABLE_NLS    0
 
29
 
 
30
#include "grub_script.tab.h"
 
31
%}
 
32
 
 
33
%union {
 
34
  struct grub_script_cmd *cmd;
 
35
  struct grub_script_arglist *arglist;
 
36
  struct grub_script_arg *arg;
 
37
  char *string;
 
38
  struct {
 
39
    unsigned offset;
 
40
    struct grub_script_mem *memory;
 
41
    struct grub_script *scripts;
 
42
  };
 
43
}
 
44
 
 
45
%token GRUB_PARSER_TOKEN_BAD
 
46
%token GRUB_PARSER_TOKEN_EOF 0 "end-of-input"
 
47
 
 
48
%token GRUB_PARSER_TOKEN_NEWLINE "\n"
 
49
%token GRUB_PARSER_TOKEN_AND     "&&"
 
50
%token GRUB_PARSER_TOKEN_OR      "||"
 
51
%token GRUB_PARSER_TOKEN_SEMI2   ";;"
 
52
%token GRUB_PARSER_TOKEN_PIPE    "|"
 
53
%token GRUB_PARSER_TOKEN_AMP     "&"
 
54
%token GRUB_PARSER_TOKEN_SEMI    ";"
 
55
%token GRUB_PARSER_TOKEN_LBR     "{"
 
56
%token GRUB_PARSER_TOKEN_RBR     "}"
 
57
%token GRUB_PARSER_TOKEN_NOT     "!"
 
58
%token GRUB_PARSER_TOKEN_LSQBR2  "["
 
59
%token GRUB_PARSER_TOKEN_RSQBR2  "]"
 
60
%token GRUB_PARSER_TOKEN_LT      "<"
 
61
%token GRUB_PARSER_TOKEN_GT      ">"
 
62
 
 
63
%token <arg> GRUB_PARSER_TOKEN_CASE      "case"
 
64
%token <arg> GRUB_PARSER_TOKEN_DO        "do"
 
65
%token <arg> GRUB_PARSER_TOKEN_DONE      "done"
 
66
%token <arg> GRUB_PARSER_TOKEN_ELIF      "elif"
 
67
%token <arg> GRUB_PARSER_TOKEN_ELSE      "else"
 
68
%token <arg> GRUB_PARSER_TOKEN_ESAC      "esac"
 
69
%token <arg> GRUB_PARSER_TOKEN_FI        "fi"
 
70
%token <arg> GRUB_PARSER_TOKEN_FOR       "for"
 
71
%token <arg> GRUB_PARSER_TOKEN_IF        "if"
 
72
%token <arg> GRUB_PARSER_TOKEN_IN        "in"
 
73
%token <arg> GRUB_PARSER_TOKEN_SELECT    "select"
 
74
%token <arg> GRUB_PARSER_TOKEN_THEN      "then"
 
75
%token <arg> GRUB_PARSER_TOKEN_UNTIL     "until"
 
76
%token <arg> GRUB_PARSER_TOKEN_WHILE     "while"
 
77
%token <arg> GRUB_PARSER_TOKEN_TIME      "time"
 
78
%token <arg> GRUB_PARSER_TOKEN_FUNCTION  "function"
 
79
%token <arg> GRUB_PARSER_TOKEN_NAME      "name"
 
80
%token <arg> GRUB_PARSER_TOKEN_WORD      "word"
 
81
 
 
82
%type <arg> block block0
 
83
%type <arglist> word argument arguments0 arguments1
 
84
 
 
85
%type <cmd> script_init script
 
86
%type <cmd> grubcmd ifclause ifcmd forcmd whilecmd untilcmd
 
87
%type <cmd> command commands1 statement
 
88
 
 
89
%pure-parser
 
90
%lex-param   { struct grub_parser_param *state };
 
91
%parse-param { struct grub_parser_param *state };
 
92
 
 
93
%start script_init
 
94
 
 
95
%%
 
96
/* It should be possible to do this in a clean way...  */
 
97
script_init: { state->err = 0; } script { state->parsed = $2; state->err = 0; }
 
98
;
 
99
 
 
100
script: newlines0
 
101
        {
 
102
          $$ = 0;
 
103
        }
 
104
      | script statement delimiter newlines0
 
105
        {
 
106
          $$ = grub_script_append_cmd (state, $1, $2);
 
107
        }
 
108
      | error
 
109
        {
 
110
          $$ = 0;
 
111
          yyerror (state, "Incorrect command");
 
112
          yyerrok;
 
113
        }
 
114
;
 
115
 
 
116
newlines0: /* Empty */ | newlines1 ;
 
117
newlines1: newlines0 "\n" ;
 
118
 
 
119
delimiter: ";"
 
120
         | "\n"
 
121
;
 
122
delimiters0: /* Empty */ | delimiters1 ;
 
123
delimiters1: delimiter
 
124
          | delimiters1 "\n"
 
125
;
 
126
 
 
127
word: GRUB_PARSER_TOKEN_NAME { $$ = grub_script_add_arglist (state, 0, $1); }
 
128
    | GRUB_PARSER_TOKEN_WORD { $$ = grub_script_add_arglist (state, 0, $1); }
 
129
;
 
130
 
 
131
statement: command   { $$ = $1; }
 
132
         | function  { $$ = 0;  }
 
133
;
 
134
 
 
135
argument : "case"      { $$ = grub_script_add_arglist (state, 0, $1); }
 
136
         | "do"        { $$ = grub_script_add_arglist (state, 0, $1); }
 
137
         | "done"      { $$ = grub_script_add_arglist (state, 0, $1); }
 
138
         | "elif"      { $$ = grub_script_add_arglist (state, 0, $1); }
 
139
         | "else"      { $$ = grub_script_add_arglist (state, 0, $1); }
 
140
         | "esac"      { $$ = grub_script_add_arglist (state, 0, $1); }
 
141
         | "fi"        { $$ = grub_script_add_arglist (state, 0, $1); }
 
142
         | "for"       { $$ = grub_script_add_arglist (state, 0, $1); }
 
143
         | "if"        { $$ = grub_script_add_arglist (state, 0, $1); }
 
144
         | "in"        { $$ = grub_script_add_arglist (state, 0, $1); }
 
145
         | "select"    { $$ = grub_script_add_arglist (state, 0, $1); }
 
146
         | "then"      { $$ = grub_script_add_arglist (state, 0, $1); }
 
147
         | "until"     { $$ = grub_script_add_arglist (state, 0, $1); }
 
148
         | "while"     { $$ = grub_script_add_arglist (state, 0, $1); }
 
149
         | "function"  { $$ = grub_script_add_arglist (state, 0, $1); }
 
150
         | word { $$ = $1; }
 
151
;
 
152
 
 
153
/*
 
154
  Block parameter is passed to commands in two forms: as unparsed
 
155
  string and as pre-parsed grub_script object.  Passing as grub_script
 
156
  object makes memory management difficult, because:
 
157
 
 
158
  (1) Command may want to keep a reference to grub_script objects for
 
159
      later use, so script framework may not free the grub_script
 
160
      object after command completes.
 
161
 
 
162
  (2) Command may get called multiple times with same grub_script
 
163
      object under loops, so we should not let command implementation
 
164
      to free the grub_script object.
 
165
 
 
166
  To solve above problems, we rely on reference counting for
 
167
  grub_script objects.  Commands that want to keep the grub_script
 
168
  object must take a reference to it.
 
169
 
 
170
  Other complexity comes with arbitrary nesting of grub_script
 
171
  objects: a grub_script object may have commands with several block
 
172
  parameters, and each block parameter may further contain multiple
 
173
  block parameters nested.  We use temporary variable, state->scripts
 
174
  to collect nested child scripts (that are linked by siblings and
 
175
  children members), and will build grub_scripts tree from bottom.
 
176
 */
 
177
block: "{"
 
178
       {
 
179
         grub_script_lexer_ref (state->lexerstate);
 
180
         $<offset>$ = grub_script_lexer_record_start (state);
 
181
         $<memory>$ = grub_script_mem_record (state);
 
182
 
 
183
         /* save currently known scripts.  */
 
184
         $<scripts>$ = state->scripts;
 
185
         state->scripts = 0;
 
186
       }
 
187
       commands1 delimiters0 "}"
 
188
       {
 
189
         char *p;
 
190
         struct grub_script_mem *memory;
 
191
         struct grub_script *s = $<scripts>2;
 
192
 
 
193
         memory = grub_script_mem_record_stop (state, $<memory>2);
 
194
         if ((p = grub_script_lexer_record_stop (state, $<offset>2)))
 
195
           *grub_strrchr (p, '}') = '\0';
 
196
 
 
197
         $$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p);
 
198
         if (! $$ || ! ($$->script = grub_script_create ($3, memory)))
 
199
           grub_script_mem_free (memory);
 
200
 
 
201
         else {
 
202
           /* attach nested scripts to $$->script as children */
 
203
           $$->script->children = state->scripts;
 
204
 
 
205
           /* restore old scripts; append $$->script to siblings. */
 
206
           state->scripts = $<scripts>2 ?: $$->script;
 
207
           if (s) {
 
208
             while (s->next_siblings)
 
209
               s = s->next_siblings;
 
210
             s->next_siblings = $$->script;
 
211
           }
 
212
         }
 
213
 
 
214
         grub_script_lexer_deref (state->lexerstate);
 
215
       }
 
216
;
 
217
block0: /* Empty */ { $$ = 0; }
 
218
      | block { $$ = $1; }
 
219
;
 
220
 
 
221
arguments0: /* Empty */ { $$ = 0; }
 
222
          | arguments1  { $$ = $1; }
 
223
;
 
224
arguments1: argument arguments0
 
225
            {
 
226
              if ($1 && $2)
 
227
                {
 
228
                  $1->next = $2;
 
229
                  $1->argcount += $2->argcount;
 
230
                  $2->argcount = 0;
 
231
                }
 
232
              $$ = $1;
 
233
            }
 
234
;
 
235
 
 
236
grubcmd: word arguments0 block0
 
237
         {
 
238
           struct grub_script_arglist *x = $2;
 
239
 
 
240
           if ($3)
 
241
             x = grub_script_add_arglist (state, $2, $3);
 
242
 
 
243
           if ($1 && x) {
 
244
             $1->next = x;
 
245
             $1->argcount += x->argcount;
 
246
             x->argcount = 0;
 
247
           }
 
248
           $$ = grub_script_create_cmdline (state, $1);
 
249
         }
 
250
;
 
251
 
 
252
/* A single command.  */
 
253
command: grubcmd  { $$ = $1; }
 
254
       | ifcmd    { $$ = $1; }
 
255
       | forcmd   { $$ = $1; }
 
256
       | whilecmd { $$ = $1; }
 
257
       | untilcmd { $$ = $1; }
 
258
;
 
259
 
 
260
/* A list of commands. */
 
261
commands1: newlines0 command
 
262
           {
 
263
             $$ = grub_script_append_cmd (state, 0, $2);
 
264
           }
 
265
         | commands1 delimiters1 command
 
266
           {
 
267
             $$ = grub_script_append_cmd (state, $1, $3);
 
268
           }
 
269
;
 
270
 
 
271
function: "function" "name"
 
272
          {
 
273
            grub_script_lexer_ref (state->lexerstate);
 
274
            state->func_mem = grub_script_mem_record (state);
 
275
 
 
276
            $<scripts>$ = state->scripts;
 
277
            state->scripts = 0;
 
278
          }
 
279
          delimiters0 "{" commands1 delimiters1 "}"
 
280
          {
 
281
            struct grub_script *script;
 
282
            state->func_mem = grub_script_mem_record_stop (state,
 
283
                                                           state->func_mem);
 
284
            script = grub_script_create ($6, state->func_mem);
 
285
            if (! script)
 
286
              grub_script_mem_free (state->func_mem);
 
287
            else {
 
288
              script->children = state->scripts;
 
289
              grub_script_function_create ($2, script);
 
290
            }
 
291
 
 
292
            state->scripts = $<scripts>3;
 
293
            grub_script_lexer_deref (state->lexerstate);
 
294
          }
 
295
;
 
296
 
 
297
ifcmd: "if"
 
298
        {
 
299
          grub_script_lexer_ref (state->lexerstate);
 
300
        }
 
301
        ifclause "fi"
 
302
        {
 
303
          $$ = $3;
 
304
          grub_script_lexer_deref (state->lexerstate);
 
305
        }
 
306
;
 
307
ifclause: commands1 delimiters1 "then" commands1 delimiters1
 
308
          {
 
309
            $$ = grub_script_create_cmdif (state, $1, $4, 0);
 
310
          }
 
311
        | commands1 delimiters1 "then" commands1 delimiters1 "else" commands1 delimiters1
 
312
          {
 
313
            $$ = grub_script_create_cmdif (state, $1, $4, $7);
 
314
          }
 
315
        | commands1 delimiters1 "then" commands1 delimiters1 "elif" ifclause
 
316
          {
 
317
            $$ = grub_script_create_cmdif (state, $1, $4, $7);
 
318
          }
 
319
;
 
320
 
 
321
forcmd: "for" "name"
 
322
        {
 
323
          grub_script_lexer_ref (state->lexerstate);
 
324
        }
 
325
        "in" arguments0 delimiters1 "do" commands1 delimiters1 "done"
 
326
        {
 
327
          $$ = grub_script_create_cmdfor (state, $2, $5, $8);
 
328
          grub_script_lexer_deref (state->lexerstate);
 
329
        }
 
330
;
 
331
 
 
332
whilecmd: "while"
 
333
          {
 
334
            grub_script_lexer_ref (state->lexerstate);
 
335
          }
 
336
          commands1 delimiters1 "do" commands1 delimiters1 "done"
 
337
          {
 
338
            $$ = grub_script_create_cmdwhile (state, $3, $6, 0);
 
339
            grub_script_lexer_deref (state->lexerstate);
 
340
          }
 
341
;
 
342
 
 
343
untilcmd: "until"
 
344
          {
 
345
            grub_script_lexer_ref (state->lexerstate);
 
346
          }
 
347
          commands1 delimiters1 "do" commands1 delimiters1 "done"
 
348
          {
 
349
            $$ = grub_script_create_cmdwhile (state, $3, $6, 1);
 
350
            grub_script_lexer_deref (state->lexerstate);
 
351
          }
 
352
;