gram.y revision 1.2 1 %{
2 /* $NetBSD: gram.y,v 1.2 2005/09/10 15:38:46 martin Exp $ */
3
4 /*
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This software was developed by the Computer Systems Engineering group
9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10 * contributed to Berkeley.
11 *
12 * All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by the University of
15 * California, Lawrence Berkeley Laboratories.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 * from: @(#)gram.y 8.1 (Berkeley) 6/6/93
42 */
43
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <ctype.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <errno.h>
51 #include "defs.h"
52 #include "sem.h"
53
54 #define FORMAT(n) (((n).fmt == 8 && (n).val != 0) ? "0%llo" : \
55 ((n).fmt == 16) ? "0x%llx" : "%lld")
56
57 #define stop(s) error(s), exit(1)
58
59 static struct config conf; /* at most one active at a time */
60
61 /* the following is used to recover nvlist space after errors */
62 static struct nvlist *alloc[1000];
63 static int adepth;
64 #define new0(n,s,p,i,x) (alloc[adepth++] = newnv(n, s, p, i, x))
65 #define new_n(n) new0(n, NULL, NULL, 0, NULL)
66 #define new_nx(n, x) new0(n, NULL, NULL, 0, x)
67 #define new_ns(n, s) new0(n, s, NULL, 0, NULL)
68 #define new_si(s, i) new0(NULL, s, NULL, i, NULL)
69 #define new_nsi(n,s,i) new0(n, s, NULL, i, NULL)
70 #define new_np(n, p) new0(n, NULL, p, 0, NULL)
71 #define new_s(s) new0(NULL, s, NULL, 0, NULL)
72 #define new_p(p) new0(NULL, NULL, p, 0, NULL)
73 #define new_px(p, x) new0(NULL, NULL, p, 0, x)
74 #define new_sx(s, x) new0(NULL, s, NULL, 0, x)
75
76 #define fx_atom(s) new0(s, NULL, NULL, FX_ATOM, NULL)
77 #define fx_not(e) new0(NULL, NULL, NULL, FX_NOT, e)
78 #define fx_and(e1, e2) new0(NULL, NULL, e1, FX_AND, e2)
79 #define fx_or(e1, e2) new0(NULL, NULL, e1, FX_OR, e2)
80
81 static void cleanup(void);
82 static void setmachine(const char *, const char *, struct nvlist *);
83 static void check_maxpart(void);
84
85 static void app(struct nvlist *, struct nvlist *);
86
87 static struct nvlist *mk_nsis(const char *, int, struct nvlist *, int);
88 static struct nvlist *mk_ns(const char *, struct nvlist *);
89
90 %}
91
92 %union {
93 struct attr *attr;
94 struct devbase *devb;
95 struct deva *deva;
96 struct nvlist *list;
97 const char *str;
98 struct numconst num;
99 int64_t val;
100 }
101
102 %token AND AT ATTACH
103 %token BLOCK BUILD
104 %token CHAR COMPILE_WITH CONFIG
105 %token DEFFS DEFINE DEFOPT DEFPARAM DEFFLAG DEFPSEUDO DEVICE DEVCLASS DUMPS
106 %token DEVICE_MAJOR
107 %token ENDFILE
108 %token XFILE FILE_SYSTEM FLAGS
109 %token IDENT
110 %token XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR
111 %token NEEDS_COUNT NEEDS_FLAG NO
112 %token XOBJECT ON OPTIONS
113 %token PACKAGE PLUSEQ PREFIX PSEUDO_DEVICE
114 %token ROOT
115 %token SOURCE
116 %token TYPE
117 %token WITH
118 %token <num> NUMBER
119 %token <str> PATHNAME QSTRING WORD EMPTY
120 %token ENDDEFS
121
122 %left '|'
123 %left '&'
124
125 %type <list> fopts fexpr fatom
126 %type <str> fs_spec
127 %type <val> fflgs fflag oflgs oflag
128 %type <str> rule
129 %type <attr> attr
130 %type <devb> devbase
131 %type <deva> devattach_opt
132 %type <list> atlist interface_opt
133 %type <str> atname
134 %type <list> loclist_opt loclist locdef
135 %type <str> locdefault
136 %type <list> values locdefaults
137 %type <list> attrs_opt attrs
138 %type <list> locators locator
139 %type <list> dev_spec
140 %type <str> device_instance
141 %type <str> attachment
142 %type <str> value
143 %type <val> major_minor npseudo
144 %type <num> signed_number
145 %type <val> flags_opt
146 %type <str> deffs
147 %type <list> deffses
148 %type <str> fsoptfile_opt
149 %type <str> defopt
150 %type <list> defopts
151 %type <str> optdep
152 %type <list> optdeps
153 %type <list> defoptdeps
154 %type <str> optfile_opt
155 %type <list> subarches_opt subarches
156 %type <str> filename stringvalue locname mkvarname
157 %type <val> device_major_block device_major_char
158
159 %%
160
161 /*
162 * A configuration consists of a machine type, followed by the machine
163 * definition files (via the include() mechanism), followed by the
164 * configuration specification(s) proper. In effect, this is two
165 * separate grammars, with some shared terminals and nonterminals.
166 * Note that we do not have sufficient keywords to enforce any order
167 * between elements of "topthings" without introducing shift/reduce
168 * conflicts. Instead, check order requirements in the C code.
169 */
170 Configuration:
171 topthings /* dirspecs, include "std.arch" */
172 machine_spec /* "machine foo" from machine descr. */
173 dev_defs ENDDEFS /* all machine definition files */
174 { check_maxpart(); }
175 specs; /* rest of machine description */
176
177 topthings:
178 topthings topthing |
179 /* empty */;
180
181 topthing:
182 SOURCE filename '\n' { if (!srcdir) srcdir = $2; } |
183 BUILD filename '\n' { if (!builddir) builddir = $2; } |
184 '\n';
185
186 machine_spec:
187 XMACHINE WORD '\n' { setmachine($2,NULL,NULL); } |
188 XMACHINE WORD WORD subarches_opt '\n' { setmachine($2,$3,$4); } |
189 error { stop("cannot proceed without machine specifier"); };
190
191 subarches_opt:
192 subarches |
193 /* empty */ { $$ = NULL; };
194
195 subarches:
196 subarches WORD { $$ = new_nx($2, $1); } |
197 WORD { $$ = new_n($1); };
198
199 /*
200 * Various nonterminals shared between the grammars.
201 */
202 file:
203 XFILE filename fopts fflgs rule { addfile($2, $3, $4, $5); };
204
205 object:
206 XOBJECT filename fopts oflgs { addobject($2, $3, $4); };
207
208 device_major:
209 DEVICE_MAJOR WORD device_major_char device_major_block fopts
210 { adddevm($2, $3, $4, $5); };
211
212 device_major_block:
213 BLOCK NUMBER { $$ = $2.val; } |
214 /* empty */ { $$ = -1; };
215
216 device_major_char:
217 CHAR NUMBER { $$ = $2.val; } |
218 /* empty */ { $$ = -1; };
219
220 /* order of options is important, must use right recursion */
221 fopts:
222 fexpr { $$ = $1; } |
223 /* empty */ { $$ = NULL; };
224
225 fexpr:
226 fatom { $$ = $1; } |
227 '!' fatom { $$ = fx_not($2); } |
228 fexpr '&' fexpr { $$ = fx_and($1, $3); } |
229 fexpr '|' fexpr { $$ = fx_or($1, $3); } |
230 '(' fexpr ')' { $$ = $2; };
231
232 fatom:
233 WORD { $$ = fx_atom($1); };
234
235 fflgs:
236 fflgs fflag { $$ = $1 | $2; } |
237 /* empty */ { $$ = 0; };
238
239 fflag:
240 NEEDS_COUNT { $$ = FI_NEEDSCOUNT; } |
241 NEEDS_FLAG { $$ = FI_NEEDSFLAG; };
242
243 oflgs:
244 oflgs oflag { $$ = $1 | $2; } |
245 /* empty */ { $$ = 0; };
246
247 oflag:
248 NEEDS_FLAG { $$ = OI_NEEDSFLAG; };
249
250 rule:
251 COMPILE_WITH stringvalue { $$ = $2; } |
252 /* empty */ { $$ = NULL; };
253
254 prefix:
255 PREFIX filename { prefix_push($2); } |
256 PREFIX { prefix_pop(); };
257
258 /*
259 * The machine definitions grammar.
260 */
261 dev_defs:
262 dev_defs dev_def |
263 dev_defs ENDFILE { enddefs(); checkfiles(); } |
264 /* empty */;
265
266 dev_def:
267 one_def '\n' { adepth = 0; } |
268 '\n' |
269 error '\n' { cleanup(); };
270
271 one_def:
272 file |
273 object |
274 device_major { do_devsw = 1; } |
275 prefix |
276 DEVCLASS WORD { (void)defattr($2, NULL, NULL, 1); } |
277 DEFFS fsoptfile_opt deffses { deffilesystem($2, $3); } |
278 DEFINE WORD interface_opt attrs_opt
279 { (void)defattr($2, $3, $4, 0); } |
280 DEFOPT optfile_opt defopts defoptdeps
281 { defoption($2, $3, $4); } |
282 DEFFLAG optfile_opt defopts defoptdeps
283 { defflag($2, $3, $4); } |
284 DEFPARAM optfile_opt defopts defoptdeps
285 { defparam($2, $3, $4); } |
286 DEVICE devbase interface_opt attrs_opt
287 { defdev($2, $3, $4, 0); } |
288 ATTACH devbase AT atlist devattach_opt attrs_opt
289 { defdevattach($5, $2, $4, $6); } |
290 MAXPARTITIONS NUMBER { maxpartitions = $2.val; } |
291 MAXUSERS NUMBER NUMBER NUMBER { setdefmaxusers($2.val, $3.val, $4.val); } |
292 MAKEOPTIONS condmkopt_list |
293 DEFPSEUDO devbase interface_opt attrs_opt
294 { defdev($2, $3, $4, 1); } |
295 MAJOR '{' majorlist '}';
296
297 atlist:
298 atlist ',' atname { $$ = new_nx($3, $1); } |
299 atname { $$ = new_n($1); };
300
301 atname:
302 WORD { $$ = $1; } |
303 ROOT { $$ = NULL; };
304
305 deffses:
306 deffses deffs { $$ = new_nx($2, $1); } |
307 deffs { $$ = new_n($1); };
308
309 deffs:
310 WORD { $$ = $1; };
311
312 defoptdeps:
313 ':' optdeps { $$ = $2; } |
314 /* empty */ { $$ = NULL; };
315
316 optdeps:
317 optdeps ',' optdep { $$ = new_nx($3, $1); } |
318 optdep { $$ = new_n($1); };
319
320 optdep:
321 WORD { $$ = $1; };
322
323 defopts:
324 defopts defopt { $$ = new_nx($2, $1); } |
325 defopt { $$ = new_n($1); };
326
327 defopt:
328 WORD { $$ = $1; };
329
330 devbase:
331 WORD { $$ = getdevbase($1); };
332
333 devattach_opt:
334 WITH WORD { $$ = getdevattach($2); } |
335 /* empty */ { $$ = NULL; };
336
337 interface_opt:
338 '{' loclist_opt '}' { $$ = new_nx("", $2); } |
339 /* empty */ { $$ = NULL; };
340
341 loclist_opt:
342 loclist { $$ = $1; } |
343 /* empty */ { $$ = NULL; };
344
345 /* loclist order matters, must use right recursion */
346 loclist:
347 locdef ',' loclist { $$ = $1; app($1, $3); } |
348 locdef { $$ = $1; };
349
350 /* "[ WORD locdefault ]" syntax may be unnecessary... */
351 locdef:
352 locname locdefault { $$ = new_nsi($1, $2, 0); } |
353 locname { $$ = new_nsi($1, NULL, 0); } |
354 '[' locname locdefault ']' { $$ = new_nsi($2, $3, 1); } |
355 locname '[' NUMBER ']' { $$ = mk_nsis($1, $3.val, NULL, 0); } |
356 locname '[' NUMBER ']' locdefaults
357 { $$ = mk_nsis($1, $3.val, $5, 0); } |
358 '[' locname '[' NUMBER ']' locdefaults ']'
359 { $$ = mk_nsis($2, $4.val, $6, 1); };
360
361 locname:
362 WORD { $$ = $1; } |
363 QSTRING { $$ = $1; };
364
365 locdefault:
366 '=' value { $$ = $2; };
367
368 locdefaults:
369 '=' '{' values '}' { $$ = $3; };
370
371 fsoptfile_opt:
372 filename { $$ = $1; } |
373 /* empty */ { $$ = NULL; };
374
375 optfile_opt:
376 filename { $$ = $1; } |
377 /* empty */ { $$ = NULL; };
378
379 filename:
380 QSTRING { $$ = $1; } |
381 PATHNAME { $$ = $1; };
382
383 value:
384 QSTRING { $$ = $1; } |
385 WORD { $$ = $1; } |
386 EMPTY { $$ = $1; } |
387 signed_number { char bf[40];
388 (void)snprintf(bf, sizeof(bf),
389 FORMAT($1), (long long)$1.val);
390 $$ = intern(bf); };
391
392 stringvalue:
393 QSTRING { $$ = $1; } |
394 WORD { $$ = $1; };
395
396 values:
397 value ',' values { $$ = new_sx($1, $3); } |
398 value { $$ = new_s($1); };
399
400 signed_number:
401 NUMBER { $$ = $1; } |
402 '-' NUMBER { $$.fmt = $2.fmt; $$.val = -$2.val; };
403
404 attrs_opt:
405 ':' attrs { $$ = $2; } |
406 /* empty */ { $$ = NULL; };
407
408 attrs:
409 attrs ',' attr { $$ = new_px($3, $1); } |
410 attr { $$ = new_p($1); };
411
412 attr:
413 WORD { $$ = getattr($1); };
414
415 majorlist:
416 majorlist ',' majordef |
417 majordef;
418
419 majordef:
420 devbase '=' NUMBER { setmajor($1, $3.val); };
421
422
423 /*
424 * The configuration grammar.
425 */
426 specs:
427 specs spec |
428 /* empty */;
429
430 spec:
431 config_spec '\n' { adepth = 0; } |
432 '\n' |
433 error '\n' { cleanup(); };
434
435 config_spec:
436 one_def |
437 NO FILE_SYSTEM no_fs_list |
438 FILE_SYSTEM fs_list |
439 NO MAKEOPTIONS no_mkopt_list |
440 MAKEOPTIONS mkopt_list |
441 NO OPTIONS no_opt_list |
442 OPTIONS opt_list |
443 MAXUSERS NUMBER { setmaxusers($2.val); } |
444 IDENT stringvalue { setident($2); } |
445 CONFIG conf root_spec sysparam_list
446 { addconf(&conf); } |
447 NO PSEUDO_DEVICE WORD { delpseudo($3); } |
448 PSEUDO_DEVICE WORD npseudo { addpseudo($2, $3); } |
449 NO device_instance AT attachment
450 { deldev($2, $4); } |
451 device_instance AT attachment locators flags_opt
452 { adddev($1, $3, $4, $5); };
453
454 fs_list:
455 fs_list ',' fsoption |
456 fsoption;
457
458 fsoption:
459 WORD { addfsoption($1); };
460
461 no_fs_list:
462 no_fs_list ',' no_fsoption |
463 no_fsoption;
464
465 no_fsoption:
466 WORD { delfsoption($1); };
467
468 mkopt_list:
469 mkopt_list ',' mkoption |
470 mkoption;
471
472 mkvarname:
473 QSTRING { $$ = $1; } |
474 WORD { $$ = $1; };
475
476 mkoption:
477 mkvarname '=' value { addmkoption($1, $3); } |
478 mkvarname PLUSEQ value { appendmkoption($1, $3); };
479
480 condmkopt_list:
481 condmkopt_list ',' condmkoption |
482 condmkoption;
483
484 condmkoption:
485 WORD mkvarname PLUSEQ value { appendcondmkoption($1, $2, $4); };
486
487 no_mkopt_list:
488 no_mkopt_list ',' no_mkoption |
489 no_mkoption;
490
491 no_mkoption:
492 WORD { delmkoption($1); }
493
494 opt_list:
495 opt_list ',' option |
496 option;
497
498 option:
499 WORD { addoption($1, NULL); } |
500 WORD '=' value { addoption($1, $3); };
501
502 no_opt_list:
503 no_opt_list ',' no_option |
504 no_option;
505
506 no_option:
507 WORD { deloption($1); };
508
509 conf:
510 WORD { conf.cf_name = $1;
511 conf.cf_lineno = currentline();
512 conf.cf_fstype = NULL;
513 conf.cf_root = NULL;
514 conf.cf_dump = NULL; };
515
516 root_spec:
517 ROOT on_opt dev_spec fs_spec_opt
518 { setconf(&conf.cf_root, "root", $3); };
519
520 fs_spec_opt:
521 TYPE fs_spec { setfstype(&conf.cf_fstype, $2); } |
522 /* empty */;
523
524 fs_spec:
525 '?' { $$ = intern("?"); } |
526 WORD { $$ = $1; };
527
528 sysparam_list:
529 sysparam_list sysparam |
530 /* empty */;
531
532 sysparam:
533 DUMPS on_opt dev_spec { setconf(&conf.cf_dump, "dumps", $3); };
534
535 dev_spec:
536 '?' { $$ = new_si(intern("?"), NODEV); } |
537 WORD { $$ = new_si($1, NODEV); } |
538 major_minor { $$ = new_si(NULL, $1); };
539
540 major_minor:
541 MAJOR NUMBER MINOR NUMBER { $$ = makedev($2.val, $4.val); };
542
543 on_opt:
544 ON | /* empty */;
545
546 npseudo:
547 NUMBER { $$ = $1.val; } |
548 /* empty */ { $$ = 1; };
549
550 device_instance:
551 WORD '*' { $$ = starref($1); } |
552 WORD { $$ = $1; };
553
554 attachment:
555 ROOT { $$ = NULL; } |
556 WORD '?' { $$ = wildref($1); } |
557 WORD { $$ = $1; };
558
559 locators:
560 locators locator { $$ = $2; app($2, $1); } |
561 /* empty */ { $$ = NULL; };
562
563 locator:
564 WORD values { $$ = mk_ns($1, $2); } |
565 WORD '?' { $$ = new_ns($1, NULL); };
566
567 flags_opt:
568 FLAGS NUMBER { $$ = $2.val; } |
569 /* empty */ { $$ = 0; };
570
571 %%
572
573 void
574 yyerror(const char *s)
575 {
576
577 error("%s", s);
578 }
579
580 /*
581 * Cleanup procedure after syntax error: release any nvlists
582 * allocated during parsing the current line.
583 */
584 static void
585 cleanup(void)
586 {
587 struct nvlist **np;
588 int i;
589
590 for (np = alloc, i = adepth; --i >= 0; np++)
591 nvfree(*np);
592 adepth = 0;
593 }
594
595 static void
596 setmachine(const char *mch, const char *mcharch, struct nvlist *mchsubarches)
597 {
598 char buf[MAXPATHLEN];
599 struct nvlist *nv;
600
601 machine = mch;
602 machinearch = mcharch;
603 machinesubarches = mchsubarches;
604
605 /*
606 * Set up the file inclusion stack. This empty include tells
607 * the parser there are no more device definitions coming.
608 */
609 strlcpy(buf, _PATH_DEVNULL, sizeof(buf));
610 if (include(buf, ENDDEFS, 0, 0) != 0)
611 exit(1);
612
613 /* Include arch/${MACHINE}/conf/files.${MACHINE} */
614 (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
615 machine, machine);
616 if (include(buf, ENDFILE, 0, 0) != 0)
617 exit(1);
618
619 /* Include any arch/${MACHINE_SUBARCH}/conf/files.${MACHINE_SUBARCH} */
620 for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
621 (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
622 nv->nv_name, nv->nv_name);
623 if (include(buf, ENDFILE, 0, 0) != 0)
624 exit(1);
625 }
626
627 /* Include any arch/${MACHINE_ARCH}/conf/files.${MACHINE_ARCH} */
628 if (machinearch != NULL)
629 (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
630 machinearch, machinearch);
631 else
632 strlcpy(buf, _PATH_DEVNULL, sizeof(buf));
633 if (include(buf, ENDFILE, 0, 0) != 0)
634 exit(1);
635
636 /*
637 * Include the global conf/files. As the last thing
638 * pushed on the stack, it will be processed first.
639 */
640 if (include("conf/files", ENDFILE, 0, 0) != 0)
641 exit(1);
642
643 oktopackage = 1;
644 }
645
646 static void
647 check_maxpart(void)
648 {
649
650 if (maxpartitions <= 0) {
651 stop("cannot proceed without maxpartitions specifier");
652 }
653 }
654
655 static void
656 app(struct nvlist *p, struct nvlist *q)
657 {
658 while (p->nv_next)
659 p = p->nv_next;
660 p->nv_next = q;
661 }
662
663 static struct nvlist *
664 mk_nsis(const char *name, int count, struct nvlist *adefs, int opt)
665 {
666 struct nvlist *defs = adefs;
667 struct nvlist **p;
668 char buf[200];
669 int i;
670
671 if (count <= 0) {
672 fprintf(stderr, "config: array with <= 0 size: %s\n", name);
673 exit(1);
674 }
675 p = &defs;
676 for(i = 0; i < count; i++) {
677 if (*p == NULL)
678 *p = new_s("0");
679 snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
680 (*p)->nv_name = i == 0 ? name : intern(buf);
681 (*p)->nv_int = i > 0 || opt;
682 p = &(*p)->nv_next;
683 }
684 *p = 0;
685 return defs;
686 }
687
688
689 static struct nvlist *
690 mk_ns(const char *name, struct nvlist *vals)
691 {
692 struct nvlist *p;
693 char buf[200];
694 int i;
695
696 for(i = 0, p = vals; p; i++, p = p->nv_next) {
697 snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
698 p->nv_name = i == 0 ? name : intern(buf);
699 }
700 return vals;
701 }
702
703