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