]> git.ozlabs.org Git - petitboot/blob - discover/grub2/parser.y
discover/grub2: Implement 'else' blocks
[petitboot] / discover / grub2 / parser.y
1
2 %pure-parser
3 %lex-param { yyscan_t scanner }
4 %parse-param { struct grub2_parser *parser }
5
6 %{
7 #include <talloc/talloc.h>
8
9 #include "grub2.h"
10 #include "parser.h"
11 #include "lexer.h"
12
13 #define YYLEX_PARAM parser->scanner
14
15 static void yyerror(struct grub2_parser *, char const *s);
16 %}
17
18 %union {
19         struct grub2_word       *word;
20         struct grub2_argv       *argv;
21         struct grub2_statement  *statement;
22         struct grub2_statements *statements;
23 }
24
25 /* reserved words */
26 %token  TOKEN_LDSQBRACKET       "[["
27 %token  TOKEN_RDSQBRACKET       "]]"
28 %token  TOKEN_CASE              "case"
29 %token  TOKEN_DO                "do"
30 %token  TOKEN_DONE              "done"
31 %token  TOKEN_ELIF              "elif"
32 %token  TOKEN_ELSE              "else"
33 %token  TOKEN_ESAC              "esac"
34 %token  TOKEN_FI                "fi"
35 %token  TOKEN_FOR               "for"
36 %token  TOKEN_FUNCTION          "function"
37 %token  TOKEN_IF                "if"
38 %token  TOKEN_IN                "in"
39 %token  TOKEN_MENUENTRY         "menuentry"
40 %token  TOKEN_SELECT            "select"
41 %token  TOKEN_THEN              "then"
42 %token  TOKEN_TIME              "time"
43 %token  TOKEN_UTIL              "until"
44 %token  TOKEN_WHILE             "while"
45
46 %type <statement>       statement
47 %type <statements>      statements
48 %type <argv>            words
49 %type <word>            word
50
51 /* syntax */
52 %token  TOKEN_EOL
53 %token  TOKEN_DELIM
54 %token  <word> TOKEN_WORD
55
56 %start  script
57 %debug
58
59 %%
60
61 script: statements {
62                 parser->script->statements = $1;
63         }
64
65 statements: statement {
66                 $$ = create_statements(parser);
67                 statement_append($$, $1);
68         }
69         | statements statement {
70                 statement_append($1, $2);
71                 $$ = $1;
72         }
73
74 statement: TOKEN_EOL {
75                 $$ = NULL;
76         }
77         | words TOKEN_EOL {
78                    $$ = create_statement_simple(parser, $1);
79         }
80         | '{' statements '}' {
81                 $$ = create_statement_block(parser, $2);
82         }
83         | "if" TOKEN_DELIM statement
84                 "then" TOKEN_EOL
85                 statements
86                 "fi" TOKEN_EOL {
87                 $$ = create_statement_if(parser, $3, $6, NULL);
88         }
89         | "if" TOKEN_DELIM statement
90                 "then" TOKEN_EOL
91                 statements
92                 "else" TOKEN_EOL
93                 statements
94                 "fi" TOKEN_EOL {
95                 $$ = create_statement_if(parser, $3, $6, $9);
96         }
97         | "menuentry" TOKEN_DELIM words TOKEN_DELIM
98                 '{' statements '}'
99                 TOKEN_EOL {
100                 $$ = create_statement_menuentry(parser, $3, $6);
101         }
102
103 words:  word {
104                 $$ = create_argv(parser);
105                 argv_append($$, $1);
106         }
107         | words TOKEN_DELIM word {
108                 argv_append($1, $3);
109                 $$ = $1;
110         }
111
112 word:   TOKEN_WORD
113         | word TOKEN_WORD {
114                 word_append($1, $2);
115                 $$ = $1;
116         }
117
118 %%
119 void yyerror(struct grub2_parser *parser, char const *s)
120 {
121         fprintf(stderr, "%d: error: %s '%s'\n",
122                         yyget_lineno(parser->scanner),
123                         s, yyget_text(parser->scanner));
124 }
125
126 struct grub2_statements *create_statements(struct grub2_parser *parser)
127 {
128         struct grub2_statements *stmts = talloc(parser,
129                         struct grub2_statements);
130         list_init(&stmts->list);
131         return stmts;
132 }
133
134 struct grub2_statement *create_statement_simple(struct grub2_parser *parser,
135                 struct grub2_argv *argv)
136 {
137         struct grub2_statement_simple *stmt =
138                 talloc(parser, struct grub2_statement_simple);
139         stmt->st.type = STMT_TYPE_SIMPLE;
140         stmt->st.exec = statement_simple_execute;
141         stmt->argv = argv;
142         return &stmt->st;
143 }
144
145 struct grub2_statement *create_statement_menuentry(struct grub2_parser *parser,
146                 struct grub2_argv *argv, struct grub2_statements *stmts)
147 {
148         struct grub2_statement_menuentry *stmt =
149                 talloc(parser, struct grub2_statement_menuentry);
150         stmt->st.type = STMT_TYPE_MENUENTRY;
151         stmt->st.exec = statement_menuentry_execute;
152         stmt->argv = argv;
153         stmt->statements = stmts;
154         return &stmt->st;
155 }
156
157 struct grub2_statement *create_statement_if(struct grub2_parser *parser,
158                 struct grub2_statement *condition,
159                 struct grub2_statements *true_case,
160                 struct grub2_statements *false_case)
161 {
162         struct grub2_statement_if *stmt =
163                 talloc(parser, struct grub2_statement_if);
164         stmt->st.type = STMT_TYPE_IF;
165         stmt->st.exec = statement_if_execute;
166         stmt->condition = condition;
167         stmt->true_case = true_case;
168         stmt->false_case = false_case;
169         return &stmt->st;
170 }
171
172 struct grub2_statement *create_statement_block(struct grub2_parser *parser,
173                 struct grub2_statements *stmts)
174 {
175         struct grub2_statement_block *stmt =
176                 talloc(parser, struct grub2_statement_block);
177         stmt->st.type = STMT_TYPE_BLOCK;
178         stmt->st.exec = NULL;
179         stmt->statements = stmts;
180         return &stmt->st;
181 }
182
183 void statement_append(struct grub2_statements *stmts,
184                 struct grub2_statement *stmt)
185 {
186         if (!stmt)
187                 return;
188         list_add_tail(&stmts->list, &stmt->list);
189 }
190
191 struct grub2_word *create_word_text(struct grub2_parser *parser,
192                 const char *text)
193 {
194         struct grub2_word *word = talloc(parser, struct grub2_word);
195         word->type = GRUB2_WORD_TEXT;
196         word->split = false;
197         word->text = talloc_strdup(word, text);
198         word->next = NULL;
199         word->last = word;
200         return word;
201 }
202
203 struct grub2_word *create_word_var(struct grub2_parser *parser,
204                 const char *name, bool split)
205 {
206         struct grub2_word *word = talloc(parser, struct grub2_word);
207         word->type = GRUB2_WORD_VAR;
208         word->name = talloc_strdup(word, name);
209         word->split = split;
210         word->next = NULL;
211         word->last = word;
212         return word;
213 }
214
215 struct grub2_argv *create_argv(struct grub2_parser *parser)
216 {
217         struct grub2_argv *argv = talloc(parser, struct grub2_argv);
218         list_init(&argv->words);
219         return argv;
220 }
221
222 void argv_append(struct grub2_argv *argv, struct grub2_word *word)
223 {
224         list_add_tail(&argv->words, &word->argv_list);
225 }
226
227 void word_append(struct grub2_word *w1, struct grub2_word *w2)
228 {
229         w1->last->next = w2;
230         w1->last = w2;
231 }
232
233 struct grub2_parser *grub2_parser_create(struct discover_context *ctx)
234 {
235         struct grub2_parser *parser;
236
237         parser = talloc(ctx, struct grub2_parser);
238         yylex_init_extra(parser, &parser->scanner);
239         parser->script = create_script(parser, ctx);
240
241         return parser;
242 }
243
244 void grub2_parser_parse(struct grub2_parser *parser, char *buf, int len)
245 {
246         YY_BUFFER_STATE bufstate;
247
248         bufstate = yy_scan_bytes(buf, len - 1, parser->scanner);
249
250         yyparse(parser);
251
252         yy_delete_buffer(bufstate, parser->scanner);
253
254         script_execute(parser->script);
255 }
256