Commit | Line | Data |
---|---|---|
90b8dad5 CT |
1 | %{ |
2 | ||
3 | /* | |
62a2aae7 KB |
4 | * Copyright (c) 1992, 1993 |
5 | * The Regents of the University of California. All rights reserved. | |
90b8dad5 CT |
6 | * |
7 | * This software was developed by the Computer Systems Engineering group | |
8 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | |
9 | * contributed to Berkeley. | |
10 | * | |
11 | * All advertising materials mentioning features or use of this software | |
12 | * must display the following acknowledgement: | |
13 | * This product includes software developed by the University of | |
14 | * California, Lawrence Berkeley Laboratories. | |
15 | * | |
16 | * %sccs.include.redist.c% | |
17 | * | |
62a2aae7 | 18 | * @(#)gram.y 8.1 (Berkeley) %G% |
90b8dad5 CT |
19 | */ |
20 | ||
21 | #include <sys/param.h> | |
22 | #include <ctype.h> | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include "config.h" | |
26 | #include "sem.h" | |
27 | ||
28 | #define FORMAT(n) ((n) > -10 && (n) < 10 ? "%d" : "0x%x") | |
29 | ||
30 | #define stop(s) error(s), exit(1) | |
31 | ||
32 | int include __P((const char *, int)); | |
33 | void yyerror __P((const char *)); | |
34 | int yylex __P((void)); | |
35 | extern const char *lastfile; | |
36 | ||
37 | static struct config conf; /* at most one active at a time */ | |
38 | ||
39 | /* the following is used to recover nvlist space after errors */ | |
40 | static struct nvlist *alloc[1000]; | |
41 | static int adepth; | |
42 | #define new0(n,s,p,i) (alloc[adepth++] = newnv(n, s, p, i)) | |
43 | #define new_n(n) new0(n, NULL, NULL, 0) | |
44 | #define new_ns(n, s) new0(n, s, NULL, 0) | |
45 | #define new_si(s, i) new0(NULL, s, NULL, i) | |
46 | #define new_nsi(n,s,i) new0(n, s, NULL, i) | |
47 | #define new_np(n, p) new0(n, NULL, p, 0) | |
48 | #define new_s(s) new0(NULL, s, NULL, 0) | |
49 | #define new_p(p) new0(NULL, NULL, p, 0) | |
50 | ||
51 | static void cleanup __P((void)); | |
52 | static void setmachine __P((const char *)); | |
53 | ||
54 | %} | |
55 | ||
56 | %union { | |
57 | struct attr *attr; | |
58 | struct devbase *devb; | |
59 | struct nvlist *list; | |
60 | const char *str; | |
61 | int val; | |
62 | } | |
63 | ||
64 | %token AND AT COMPILE_WITH CONFIG DEFINE DEVICE DUMPS ENDFILE | |
65 | %token XFILE FLAGS INCLUDE XMACHINE MAJOR MAKEOPTIONS MAXUSERS MINOR | |
66 | %token ON OPTIONS PSEUDO_DEVICE ROOT SWAP VECTOR | |
67 | %token <val> FFLAG NUMBER | |
68 | %token <str> PATHNAME WORD | |
69 | ||
70 | %type <list> fopts | |
71 | %type <val> fflgs | |
72 | %type <str> rule | |
73 | %type <attr> attr | |
74 | %type <devb> devbase | |
75 | %type <list> atlist interface_opt | |
76 | %type <str> atname | |
77 | %type <list> loclist_opt loclist locdef | |
78 | %type <str> locdefault | |
79 | %type <list> veclist_opt veclist | |
80 | %type <list> attrs_opt attrs | |
81 | %type <list> locators locator | |
82 | %type <list> swapdev_list dev_spec | |
83 | %type <str> device_instance | |
84 | %type <str> attachment | |
85 | %type <str> value | |
86 | %type <val> major_minor signed_number npseudo | |
87 | %type <val> flags_opt | |
88 | ||
89 | %% | |
90 | ||
91 | /* | |
92 | * A configuration consists of a machine type, followed by the machine | |
93 | * definition files (via the include() mechanism), followed by the | |
94 | * configuration specification(s) proper. In effect, this is two | |
95 | * separate grammars, with some shared terminals and nonterminals. | |
96 | */ | |
97 | Configuration: | |
98 | hdrs machine_spec /* "machine foo" from machine descr. */ | |
99 | dev_defs dev_eof /* ../../conf/devices */ | |
100 | dev_defs dev_eof /* devices.foo */ | |
101 | specs; /* rest of machine description */ | |
102 | ||
103 | hdrs: | |
104 | hdrs hdr | | |
105 | /* empty */; | |
106 | ||
107 | hdr: | |
108 | include | | |
109 | '\n'; | |
110 | ||
111 | machine_spec: | |
112 | XMACHINE WORD = { setmachine($2); } | | |
113 | error = { stop("cannot proceed without machine specifier"); }; | |
114 | ||
115 | dev_eof: | |
116 | ENDFILE = { enddefs(lastfile); checkfiles(); }; | |
117 | ||
118 | ||
119 | ||
120 | /* | |
121 | * Various nonterminals shared between the grammars. | |
122 | */ | |
123 | file: | |
124 | XFILE PATHNAME fopts fflgs rule = { addfile($2, $3, $4, $5); }; | |
125 | ||
126 | /* order of options is important, must use right recursion */ | |
127 | fopts: | |
128 | WORD fopts = { ($$ = new_n($1))->nv_next = $2; } | | |
129 | /* empty */ = { $$ = NULL; }; | |
130 | ||
131 | fflgs: | |
132 | fflgs FFLAG = { $$ = $1 | $2; } | | |
133 | /* empty */ = { $$ = 0; }; | |
134 | ||
135 | rule: | |
136 | COMPILE_WITH WORD = { $$ = $2; } | | |
137 | /* empty */ = { $$ = NULL; }; | |
138 | ||
139 | include: | |
140 | INCLUDE WORD = { (void)include($2, '\n'); }; | |
141 | ||
142 | /* | |
143 | * The machine definitions grammar. | |
144 | */ | |
145 | dev_defs: | |
146 | dev_defs dev_def | | |
147 | /* empty */; | |
148 | ||
149 | dev_def: | |
150 | one_def '\n' = { adepth = 0; } | | |
151 | '\n' | | |
152 | error '\n' = { cleanup(); }; | |
153 | ||
154 | one_def: | |
155 | file | | |
156 | /* include | */ | |
157 | DEFINE WORD interface_opt = { (void)defattr($2, $3); } | | |
158 | DEVICE devbase AT atlist veclist_opt interface_opt attrs_opt | |
159 | = { defdev($2, 0, $4, $5, $6, $7); } | | |
160 | MAXUSERS NUMBER NUMBER NUMBER = { setdefmaxusers($2, $3, $4); } | | |
161 | PSEUDO_DEVICE devbase attrs_opt = { defdev($2,1,NULL,NULL,NULL,$3); } | | |
162 | MAJOR '{' majorlist '}'; | |
163 | ||
164 | atlist: | |
165 | atlist ',' atname = { ($$ = new_n($3))->nv_next = $1; } | | |
166 | atname = { $$ = new_n($1); }; | |
167 | ||
168 | atname: | |
169 | WORD = { $$ = $1; } | | |
170 | ROOT = { $$ = NULL; }; | |
171 | ||
172 | veclist_opt: | |
173 | VECTOR veclist = { $$ = $2; } | | |
174 | /* empty */ = { $$ = NULL; }; | |
175 | ||
176 | /* veclist order matters, must use right recursion */ | |
177 | veclist: | |
178 | WORD veclist = { ($$ = new_n($1))->nv_next = $2; } | | |
179 | WORD = { $$ = new_n($1); }; | |
180 | ||
181 | devbase: | |
182 | WORD = { $$ = getdevbase($1); }; | |
183 | ||
184 | interface_opt: | |
185 | '{' loclist_opt '}' = { ($$ = new_n(""))->nv_next = $2; } | | |
186 | /* empty */ = { $$ = NULL; }; | |
187 | ||
188 | loclist_opt: | |
189 | loclist = { $$ = $1; } | | |
190 | /* empty */ = { $$ = NULL; }; | |
191 | ||
192 | /* loclist order matters, must use right recursion */ | |
193 | loclist: | |
194 | locdef ',' loclist = { ($$ = $1)->nv_next = $3; } | | |
195 | locdef = { $$ = $1; }; | |
196 | ||
197 | /* "[ WORD locdefault ]" syntax may be unnecessary... */ | |
198 | locdef: | |
199 | WORD locdefault = { $$ = new_nsi($1, $2, 0); } | | |
200 | WORD = { $$ = new_nsi($1, NULL, 0); } | | |
201 | '[' WORD locdefault ']' = { $$ = new_nsi($2, $3, 1); }; | |
202 | ||
203 | locdefault: | |
204 | '=' value = { $$ = $2; }; | |
205 | ||
206 | value: | |
207 | WORD = { $$ = $1; } | | |
208 | signed_number = { char bf[40]; | |
209 | (void)sprintf(bf, FORMAT($1), $1); | |
210 | $$ = intern(bf); }; | |
211 | ||
212 | signed_number: | |
213 | NUMBER = { $$ = $1; } | | |
214 | '-' NUMBER = { $$ = -$2; }; | |
215 | ||
216 | attrs_opt: | |
217 | ':' attrs = { $$ = $2; } | | |
218 | /* empty */ = { $$ = NULL; }; | |
219 | ||
220 | attrs: | |
221 | attrs ',' attr = { ($$ = new_p($3))->nv_next = $1; } | | |
222 | attr = { $$ = new_p($1); }; | |
223 | ||
224 | attr: | |
225 | WORD = { $$ = getattr($1); }; | |
226 | ||
227 | majorlist: | |
228 | majorlist ',' majordef | | |
229 | majordef; | |
230 | ||
231 | majordef: | |
232 | devbase '=' NUMBER = { setmajor($1, $3); }; | |
233 | ||
234 | ||
235 | ||
236 | /* | |
237 | * The configuration grammar. | |
238 | */ | |
239 | specs: | |
240 | specs spec | | |
241 | /* empty */; | |
242 | ||
243 | spec: | |
244 | config_spec '\n' = { adepth = 0; } | | |
245 | '\n' | | |
246 | error '\n' = { cleanup(); }; | |
247 | ||
248 | config_spec: | |
249 | file | | |
250 | include | | |
251 | OPTIONS opt_list | | |
252 | MAKEOPTIONS mkopt_list | | |
253 | MAXUSERS NUMBER = { setmaxusers($2); } | | |
254 | CONFIG conf sysparam_list = { addconf(&conf); } | | |
255 | PSEUDO_DEVICE WORD npseudo = { addpseudo($2, $3); } | | |
256 | device_instance AT attachment locators flags_opt | |
257 | = { adddev($1, $3, $4, $5); }; | |
258 | ||
259 | mkopt_list: | |
260 | mkopt_list ',' mkoption | | |
261 | mkoption; | |
262 | ||
263 | mkoption: | |
264 | WORD '=' value = { addmkoption($1, $3); } | |
265 | ||
266 | opt_list: | |
267 | opt_list ',' option | | |
268 | option; | |
269 | ||
270 | option: | |
271 | WORD = { addoption($1, NULL); } | | |
272 | WORD '=' value = { addoption($1, $3); }; | |
273 | ||
274 | conf: | |
275 | WORD = { conf.cf_name = $1; | |
276 | conf.cf_lineno = currentline(); | |
277 | conf.cf_root = NULL; | |
278 | conf.cf_swap = NULL; | |
279 | conf.cf_dump = NULL; }; | |
280 | ||
281 | sysparam_list: | |
282 | sysparam_list sysparam | | |
283 | sysparam; | |
284 | ||
285 | sysparam: | |
286 | ROOT on_opt dev_spec = { setconf(&conf.cf_root, "root", $3); } | | |
287 | SWAP on_opt swapdev_list = { setconf(&conf.cf_swap, "swap", $3); } | | |
288 | DUMPS on_opt dev_spec = { setconf(&conf.cf_dump, "dumps", $3); }; | |
289 | ||
290 | swapdev_list: | |
291 | dev_spec AND swapdev_list = { ($$ = $1)->nv_next = $3; } | | |
292 | dev_spec = { $$ = $1; }; | |
293 | ||
294 | dev_spec: | |
295 | WORD = { $$ = new_si($1, NODEV); } | | |
296 | major_minor = { $$ = new_si(NULL, $1); }; | |
297 | ||
298 | major_minor: | |
299 | MAJOR NUMBER MINOR NUMBER = { $$ = makedev($2, $4); }; | |
300 | ||
301 | on_opt: | |
302 | ON | /* empty */; | |
303 | ||
304 | npseudo: | |
305 | NUMBER = { $$ = $1; } | | |
306 | /* empty */ = { $$ = 1; }; | |
307 | ||
308 | device_instance: | |
309 | WORD '*' = { $$ = starref($1); } | | |
310 | WORD = { $$ = $1; }; | |
311 | ||
312 | attachment: | |
313 | ROOT = { $$ = NULL; } | | |
314 | WORD '?' = { $$ = wildref($1); } | | |
315 | WORD '*' = { $$ = starref($1); } | | |
316 | WORD = { $$ = $1; }; | |
317 | ||
318 | locators: | |
319 | locators locator = { ($$ = $2)->nv_next = $1; } | | |
320 | /* empty */ = { $$ = NULL; }; | |
321 | ||
322 | locator: | |
323 | WORD value = { $$ = new_ns($1, $2); } | | |
324 | WORD '?' = { $$ = new_ns($1, NULL); }; | |
325 | ||
326 | flags_opt: | |
327 | FLAGS NUMBER = { $$ = $2; } | | |
328 | /* empty */ = { $$ = 0; }; | |
329 | ||
330 | %% | |
331 | ||
332 | void | |
333 | yyerror(s) | |
334 | const char *s; | |
335 | { | |
336 | ||
337 | error("%s", s); | |
338 | } | |
339 | ||
340 | /* | |
341 | * Cleanup procedure after syntax error: release any nvlists | |
342 | * allocated during parsing the current line. | |
343 | */ | |
344 | static void | |
345 | cleanup() | |
346 | { | |
347 | register struct nvlist **np; | |
348 | register int i; | |
349 | ||
350 | for (np = alloc, i = adepth; --i >= 0; np++) | |
351 | nvfree(*np); | |
352 | adepth = 0; | |
353 | } | |
354 | ||
355 | static void | |
356 | setmachine(mch) | |
357 | const char *mch; | |
358 | { | |
359 | char buf[MAXPATHLEN]; | |
360 | ||
361 | machine = mch; | |
362 | (void)sprintf(buf, "files.%s", mch); | |
43fbfd6c CT |
363 | if (include(buf, ENDFILE) || |
364 | include("../../conf/files.newconf", ENDFILE)) | |
90b8dad5 CT |
365 | exit(1); |
366 | } |