discover: Reimplement native-parser as a Bison parser
[petitboot] / discover / native / native-parser.y
1
2 %pure-parser
3 %lex-param { nscan_t scanner }
4 %parse-param { struct native_parser *parser }
5 %parse-param { void *scanner }
6 %error-verbose
7
8 %define api.prefix {n}
9 %{
10 #include <talloc/talloc.h>
11 #include <log/log.h>
12 #include "discover/resource.h"
13 #include "discover/parser-utils.h"
14
15 #include "native.h"
16
17 void yyerror(struct native_parser *parser, void *scanner, const char *fmt, ...);
18 %}
19
20 %union {
21         char    *word;
22         int     num;
23 }
24
25 %token  <word>  TOKEN_WORD
26 %token  <num>   TOKEN_NUMBER
27 %token  <num>   TOKEN_DELIM
28
29 %token TOKEN_DEFAULT
30 %token TOKEN_DEV_DESCRIPTION
31
32 %token TOKEN_NAME
33 %token TOKEN_IMAGE
34 %token TOKEN_INITRD
35 %token TOKEN_ARGS
36 %token TOKEN_DTB
37 %token TOKEN_DESCRIPTION
38 %token TOKEN_NEWLINE
39
40 %{
41 #include "native-lexer.h"
42 %}
43
44 %%
45
46 native:
47       globals boot_options { native_parser_finish(parser); }
48       | boot_options { native_parser_finish(parser); }
49       ;
50
51 globals: globals global
52        | global
53        ;
54
55 global: TOKEN_DEFAULT delims TOKEN_WORD {
56                 if (parser->default_name)
57                         pb_log_fn("Duplicate default option, ignoring\n");
58                 else
59                         parser->default_name = talloc_strdup(parser, $3);
60         }
61         | TOKEN_DEV_DESCRIPTION delims TOKEN_WORD {
62                 native_append_string(parser,
63                         &parser->ctx->device->device->description, $3);
64         }
65         ;
66
67 boot_options:
68             boot_options option
69             | option
70             ;
71
72 option: name params
73      ;
74
75 name: TOKEN_NAME delims TOKEN_WORD {
76                 native_parser_create_option(parser, $3);
77         }
78         ;
79
80 params: params param
81       | param
82       ;
83
84 param: TOKEN_IMAGE delims TOKEN_WORD {
85                 native_set_resource(parser, &parser->opt->boot_image, $3);
86         }
87         | TOKEN_INITRD delims TOKEN_WORD {
88                 native_set_resource(parser, &parser->opt->initrd, $3);
89         }
90         | TOKEN_DTB delims TOKEN_WORD  {
91                 native_set_resource(parser, &parser->opt->dtb, $3);
92         }
93         | TOKEN_ARGS delims TOKEN_WORD {
94                 native_append_string(parser, &parser->opt->option->boot_args, $3);
95         }
96         | TOKEN_DESCRIPTION delims TOKEN_WORD  {
97                 native_append_string(parser, &parser->opt->option->description, $3);
98         }
99         ;
100
101 delims: delims TOKEN_DELIM
102       | TOKEN_DELIM
103       ;
104
105 %%
106
107 void yyerror(struct native_parser *parser, void *scanner, const char *fmt, ...)
108 {
109         const char *str;
110         va_list ap;
111
112         va_start(ap, fmt);
113         str = talloc_vasprintf(parser, fmt, ap);
114         va_end(ap);
115
116         pb_log("parse error: %d('%s'): %s\n", nget_lineno(scanner),
117                                         nget_text(scanner), str);
118 }
119
120 void native_parser_finish(struct native_parser *parser)
121 {
122         if (parser->opt) {
123                 discover_context_add_boot_option(parser->ctx, parser->opt);
124                 parser->opt = NULL;
125         }
126 }
127
128 void native_set_resource(struct native_parser *parser,
129                 struct resource ** resource, const char *path)
130 {
131         if (*resource) {
132                 pb_log_fn("Duplicate resource at line %d: %s\n",
133                         nget_lineno(parser->scanner), path);
134                 return;
135         }
136
137         *resource = create_devpath_resource(parser->opt, parser->opt->device,
138                                         path);
139 }
140
141 void native_append_string(struct native_parser *parser,
142                 char **str, const char *append)
143 {
144         if (*str)
145                 *str = talloc_asprintf_append(*str, "%s", append);
146         else
147                 *str = talloc_strdup(parser->opt, append);
148 }
149
150 void native_parser_create_option(struct native_parser *parser, const char *name)
151 {
152         struct discover_boot_option *opt = parser->opt;
153
154         if (opt)
155                 native_parser_finish(parser);
156
157         opt = discover_boot_option_create(parser->ctx, parser->ctx->device);
158         opt->option->name = talloc_strdup(opt, name);
159         opt->option->id = talloc_asprintf(opt, "%s@%p",
160                         parser->ctx->device->device->id, opt);
161         opt->option->type = DISCOVER_BOOT_OPTION;
162         opt->option->is_default = parser->default_name &&
163                                 streq(parser->default_name, name);
164         parser->opt = opt;
165         return;
166 }
167
168 struct native_parser *native_parser_create(struct discover_context *ctx)
169 {
170         struct native_parser *parser;
171
172         parser = talloc_zero(ctx, struct native_parser);
173         parser->ctx = ctx;
174         nlex_init_extra(parser, &parser->scanner);
175
176         return parser;
177 }
178
179 void native_parser_parse(struct native_parser *parser, const char *filename,
180         char *buf, int len)
181 {
182         YY_BUFFER_STATE bufstate;
183         int rc;
184
185         if (!len)
186                 return;
187
188         parser->filename = filename;
189
190         bufstate = n_scan_bytes(buf, len - 1, parser->scanner);
191         nset_lineno(1, parser->scanner);
192
193         rc = nparse(parser, parser->scanner);
194
195         if (rc)
196                 pb_log("Failed to parse %s\n", filename);
197
198         n_delete_buffer(bufstate, parser->scanner);
199 }
200