Root/b2/lang.y

1%{
2/*
3 * lang.y - BOOM grammar
4 *
5 * Copyright 2012 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdlib.h>
15#include <assert.h>
16
17#include "util.h"
18#include "relop.h"
19#include "param.h"
20#include "chr.h"
21#include "db.h"
22#include "subst.h"
23#include "lang.h"
24
25#include "y.tab.h"
26
27
28const char *dollar;
29
30struct action hierarchy;
31struct subst *substitutions = NULL;
32
33static struct currency *curr;
34
35
36static struct field_stack {
37    const struct field *field;
38    struct field_stack *next;
39} *field_stack = NULL;
40
41
42static void push_field(const struct field *field)
43{
44    struct field_stack *entry;
45
46    entry = alloc_type(struct field_stack);
47    entry->field = field;
48    entry->next = field_stack;
49    field_stack = entry;
50}
51
52
53static void pop_fields(const struct field *last)
54{
55    struct field_stack *entry;
56    const struct field *popped;
57
58    do {
59        assert(field_stack);
60        entry = field_stack;
61        popped = entry->field;
62        field_stack = entry->next;
63        free(entry);
64    } while (popped != last);
65}
66
67
68static const struct field *top_field(void)
69{
70    return field_stack ? field_stack->field : NULL;
71}
72
73
74static struct subst *parse_jump(const char *keyword, const char *target)
75{
76    if (!strcmp(keyword, "break"))
77        return subst_break(target);
78    if (!strcmp(keyword, "continue"))
79        return subst_continue(target);
80    if (!strcmp(keyword, "end") || !strcmp(keyword, "ignore"))
81        yyerror("unreachable code");
82    yyerrorf("unknown keyword \"%s\"", keyword);
83}
84
85%}
86
87
88%union {
89    const char *s;
90    int num;
91    double fnum;
92    struct equiv *equiv;
93    struct names *names;
94    struct format *format;
95    enum relop relop;
96    struct field *field;
97    struct selector *sel;
98    struct condition *cond;
99    struct action act;
100    struct part *part;
101    struct param *param;
102    struct price *price;
103    struct stock *stock;
104    struct provider *prov;
105    struct subst *subst;
106};
107
108
109%token START_HIERARCHY START_CHAR START_INVENTORY
110%token START_EXCHANGE START_PROVIDERS START_SUBST START_BOM
111%token START_SYMBOLS
112%token BOM_EESCHEMA
113%token TOK_LE TOK_GE TOK_NL
114%token <s> WORD PATTERN
115
116%type <num> int
117%type <fnum> float
118%type <equiv> nameqs
119%type <names> names nameq
120%type <format> format
121%type <relop> relop opt_relop
122%type <field> /*rules*/ opt_rule rule opt_fields fields field
123%type <sel> selectors
124%type <cond> conditions condition
125%type <act> hierarchy opt_wildcard action
126%type <part> part inventory_item
127%type <param> param params
128%type <price> prices price
129%type <stock> stock
130%type <prov> providers provider
131%type <subst> substitutions block opt_block
132%type <s> word_or_dollar
133
134%%
135
136all:
137    START_HIERARCHY hierarchy
138        {
139            hierarchy = $2;
140        }
141    | START_CHAR characteristics
142    | START_INVENTORY inventory
143    | START_EXCHANGE exchange
144    | START_PROVIDERS providers
145    | START_SUBST substitutions
146        {
147            substitutions = $2;
148        }
149    | START_BOM bom
150    | START_SYMBOLS symbols
151    ;
152
153
154/* ----- Characteristics hierarchy ----------------------------------------- */
155
156
157hierarchy:
158    nameset hierarchy
159        {
160            $$ = $2;
161        }
162    | action
163        {
164            $$ = $1;
165        }
166    ;
167
168nameset:
169    '<' WORD '>' '=' names ';'
170        {
171            register_nameset($2, $5);
172        }
173    ;
174
175names:
176    nameq
177        {
178            $$ = $1;
179        }
180    | nameq '<' names
181        {
182            $$ = $1;
183            $$->next = $3;
184        }
185    ;
186
187nameq:
188    nameqs
189        {
190            $$ = alloc_type(struct names);
191            $$->equiv = $1;
192            $$->next = NULL;
193        }
194    ;
195
196nameqs:
197    WORD
198        {
199            $$ = alloc_type(struct equiv);
200            $$->name = $1;
201            $$->next = NULL;
202        }
203    | WORD '=' nameqs
204        {
205            $$ = alloc_type(struct equiv);
206            $$->name = $1;
207            $$->next = $3;
208        }
209    ;
210
211/*
212 * @@@ for now, we can't select on a collective of fields. maybe later, with
213 * a syntax change.
214 *
215rules:
216        {
217            $$ = NULL;
218        }
219    | rule rules
220        {
221            $$ = $1;
222            $$->next = $2;
223        }
224    ;
225*/
226
227opt_rule:
228        {
229            $$ = NULL;
230        }
231    | rule
232        {
233            $$ = $1;
234        }
235    ;
236
237rule:
238    field
239        {
240            $1->prev = top_field();
241            push_field($1);
242        }
243        '{' selectors opt_wildcard '}'
244        {
245            $$ = $1;
246            $$->sel = $4;
247            $$->any = $5;
248            $$->next = NULL;
249            field_finalize($$);
250            pop_fields($$);
251        }
252    ;
253
254selectors:
255        {
256            $$ = NULL;
257        }
258    | conditions ':' action selectors
259        {
260            $$ = new_selector();
261            $$->cond = $1;
262            $$->act = $3;
263            $$->next = $4;
264        }
265    ;
266
267conditions:
268    condition
269        {
270            $$ = $1;
271        }
272    | condition '|' conditions
273        {
274            $$ = $1;
275            $$->next = $3;
276        }
277    ;
278
279condition:
280    opt_relop WORD
281        {
282            $$ = new_condition($1, $2);
283        }
284    ;
285
286opt_wildcard:
287        {
288            $$.fields = NULL;
289            $$.rules = NULL;
290        }
291    | '*' ':' action
292        {
293            $$ = $3;
294        }
295    ;
296
297action:
298        {
299            $<field>$ = (struct field *) top_field();
300            push_field(top_field());
301        }
302    opt_fields opt_rule ';'
303        {
304            $$.fields = $2;
305            $$.rules = $3;
306            pop_fields($<field>1);
307        }
308    ;
309
310opt_relop:
311        {
312            $$ = rel_eq;
313        }
314    | relop
315        {
316            $$ = $1;
317        }
318    ;
319
320relop:
321    '='
322        {
323            $$ = rel_eq;
324        }
325    | '<'
326        {
327            $$ = rel_lt;
328        }
329    | '>'
330        {
331            $$ = rel_gt;
332        }
333    | TOK_LE
334        {
335            $$ = rel_le;
336        }
337    | TOK_GE
338        {
339            $$ = rel_ge;
340        }
341    ;
342
343opt_fields:
344        {
345            $$ = NULL;
346        }
347    | '{' fields '}'
348        {
349            $$ = $2;
350        }
351    ;
352
353fields:
354        {
355            $$ = NULL;
356        }
357    | field
358        {
359            $1->prev = top_field();
360            push_field($1);
361        }
362        fields
363        {
364            $$ = $1;
365            $$->next = $3;
366            if ($3)
367                $3->prev = $1;
368        }
369    ;
370
371field:
372    WORD '=' format
373        {
374            $$ = new_field($1, $3, top_field());
375        }
376    ;
377
378format:
379    '*'
380        {
381            $$ = alloc_type(struct format);
382            $$->ops = &param_ops_name;
383        }
384    | '<' WORD '>'
385        {
386            $$ = alloc_type(struct format);
387            $$->ops = &param_ops_set;
388            $$->u.set = find_nameset($2);
389            if (!$$->u.set)
390                yyerrorf("unknown name set \"%s\"", $2);
391        }
392    | '#' WORD
393        {
394            $$ = alloc_type(struct format);
395            $$->ops = &param_ops_abs;
396            $$->u.abs = $2;
397        }
398    | '#' '#'
399        {
400            $$ = alloc_type(struct format);
401            $$->ops = &param_ops_abs;
402            $$->u.abs = NULL;
403        }
404    | '%' WORD
405        {
406            $$ = alloc_type(struct format);
407            $$->ops = &param_ops_rel;
408            $$->u.rel = field_find($2, top_field());
409            if (!$$->u.rel)
410                yyerrorf("unknown field \"%s\"", $2);
411        }
412    ;
413
414
415/* ----- Part characteristics --------------------------------------------- */
416
417
418characteristics:
419    | TOK_NL
420    | part characteristics
421        {
422            part_finalize($1, &hierarchy);
423        }
424    ;
425
426part:
427    WORD WORD params TOK_NL
428        {
429            $$ = part_add($1, $2);
430            if ($$->param)
431                yyerrorf("%s %s parameters already defined",
432                    $1, $2);
433            $$->param = $3;
434        }
435    ;
436
437params:
438        {
439            $$ = NULL;
440        }
441    | param params
442        {
443            $$ = $1;
444            $$->next = $2;
445        }
446    ;
447
448param:
449    WORD '=' WORD
450        {
451            $$ = alloc_type(struct param);
452            $$->u.name = $1;
453            $$->op = rel_eq;
454            $$->value.u.s = $3;
455        }
456    ;
457
458
459/* ----- Part inventory ---------------------------------------------------- */
460
461
462inventory:
463    | TOK_NL
464    | inventory_item inventory
465        {
466            part_dump(stderr, $1);
467        }
468    ;
469
470inventory_item:
471    WORD WORD stock TOK_NL
472        {
473            $$ = part_add($1, $2);
474            $3->provider = provider_add($1);
475            part_add_stock($$, $3);
476        }
477    ;
478
479stock:
480    WORD int int WORD float prices
481        {
482            $$ = alloc_type(struct stock);
483            $$->provider = NULL;
484            $$->cat = $1;
485            $$->avail = $2;
486            $$->package = $3;
487            $$->curr = currency_lookup($4);
488            if (!$$->curr)
489                yyerrorf("unknown currency %s", $4);
490            $$->add = $5;
491            $$->price = $6;
492        }
493    ;
494
495prices:
496    price
497        {
498            $$ = $1;
499        }
500    | price prices
501        {
502            $$ = $1;
503            $$->next = $2;
504        }
505    ;
506
507price:
508    int float
509        {
510            $$ = alloc_type(struct price);
511            $$->qty = $1;
512            $$->value = $2;
513            $$->next = NULL;
514        }
515    ;
516
517int:
518    WORD
519        {
520            char *end;
521
522            $$ = strtol($1, &end, 10);
523            if (*end)
524                yyerrorf("\"%s\" is not an integer", $1);
525        }
526    ;
527
528float:
529    WORD
530        {
531            char *end;
532
533            $$ = strtod($1, &end);
534            if (*end)
535                yyerrorf("\"%s\" is not a number", $1);
536        }
537    ;
538
539
540/* ----- Currency exchange ------------------------------------------------- */
541
542
543exchange:
544    | TOK_NL
545    | currency exchange
546    ;
547
548currency:
549    WORD
550        {
551            curr = currency_add($1);
552        }
553        rates TOK_NL
554    ;
555
556rates:
557    | rate rates
558    ;
559
560rate:
561    WORD float
562        {
563            const struct currency *to;
564
565            /* add and not lookup, since we just introduce the
566               currency here */
567            to = currency_add($1);
568            currency_exchange(curr, to, $2);
569        }
570    ;
571
572
573/* ----- Providers --------------------------------------------------------- */
574
575
576providers:
577        {
578            $$ = NULL;
579        }
580    | TOK_NL
581        {
582            $$ = NULL;
583        }
584    | provider providers
585        {
586            $$ = $1;
587            $$->next = $2;
588        }
589    ;
590
591provider:
592    WORD WORD float float TOK_NL
593        {
594            $$ = provider_add($1);
595            if ($$->curr)
596                yyerrorf("provider %s is already defined", $1);
597            $$->curr = currency_add($2);
598            $$->shipping = $3;
599            $$->minimum = $4;
600        }
601    ;
602
603
604/* ----- Substitutions ----------------------------------------------------- */
605
606
607substitutions:
608    block
609        {
610            $$ = $1;
611            subst_finalize($$);
612        }
613    ;
614
615block:
616        {
617            $$ = NULL;
618        }
619    | word_or_dollar relop PATTERN opt_block block
620        {
621            if ($4) {
622                if ($2 != rel_eq)
623                    yyerror("only = allow for matching");
624                $$ = subst_match($1, $3, NULL);
625                $$->u.match.block = $4;
626            } else {
627                $$ = subst_assign($1, $2, $3);
628            }
629            free((void *) $3);
630            $$->next = $5;
631        }
632    | WORD WORD block
633        {
634            if (!strcmp($1, "print")) {
635                $$ = subst_print($2);
636                $$->next = $3;
637            } else {
638                $$ = parse_jump($1, $2);
639                if ($3)
640                    yyerror("unreachable code");
641            }
642        }
643    | WORD '$'
644        {
645            $$ = parse_jump($1, NULL);
646        }
647    | WORD
648        {
649            if (!strcmp($1, "end"))
650                $$ = subst_end();
651            else if (!strcmp($1, "ignore"))
652                $$ = subst_ignore();
653            else
654                $$ = parse_jump($1, NULL);
655        }
656    | WORD PATTERN
657        {
658        }
659    ;
660
661word_or_dollar:
662    '$'
663        {
664            $$ = dollar;
665        }
666    | WORD
667        {
668            $$ = $1;
669        }
670    ;
671
672opt_block:
673        {
674            $$ = NULL;
675        }
676    | '{' block '}'
677        {
678            $$ = $2;
679        }
680    ;
681
682
683/* ----- KiCad BOM (from eeschema) ----------------------------------------- */
684
685
686bom:
687    BOM_EESCHEMA
688        /*
689         * The KiCad BOM syntax is quite alien, so we just check the
690         * overall structure here, leave extracting the lines with
691         * actual content to the lexer, and do all the detail work in
692         * bom.c
693         */
694    ;
695
696
697/* ----- Symbols (BOM supplement) ------------------------------------------ */
698
699
700symbols:
701    | TOK_NL
702    | symbol symbols
703    ;
704
705symbol:
706    WORD WORD TOK_NL
707        {
708            bom_set_sym($1, $2);
709        }
710    ;
711

Archive Download this file

Branches:
master



interactive