25 // int yylex (YYSTYPE *yylval_param, yyscan_t yyscanner);
26 void yyerror (struct parser *,char *);
27 #define YYLEX_PARAM &yylval, prs->lexer
31 %token NEWLINE INDENT COMMENT
32 %token GEN_FROM DRIVE_TO
33 %token OPEN CLOSE BRA KET
34 %token STAR PLUS COMMA COLON AT
35 %token CMP_EQ CMP_NE CMP_LT CMP_LE CMP_GT CMP_GE
36 %token LOG_NOT LOG_AND LOG_OR
37 %token ATTRTYPE ATTRNAME ATTROPT VARIABLE SILENCER DRIVERNAME PARAMETER
38 %token STRING BLOB INTEGER FLOAT
40 %type<varnum> INTEGER FLOAT STRING BLOB DRIVERNAME
41 %type<varnum> VARIABLE PARAMETER optvalue value const varnm dnvar bindrdnpart
46 /* The parser is made re-entrant, with parameters for the various tables
47 * that will store the semantics for later analysis.
48 * Kludge: Bison seems to extract the last identifier for lex-param only,
49 * so we've defined one to take that place
52 %lex-param { YYSTYPE *yylval_param, yyscan_t prs_arrow_scanner }
53 //HUH?// %define api.puri
54 %parse-param { struct parser *prs }
57 #define prs_arrow_scanner prs->lexer
60 /* Define a switching start symbol, and hav yylex() prefix the input stream
61 * with a suitable start condition switch; this makes for flexibility in the
62 * syntax scanned with bison. The global bison_switch directs yylex() to
63 * deliver these special starting tags. The syntax below requires it, but
64 * will only accept it at the beginning of the parsing process.
67 %token START_SCRIPT START_LINE START_GENERATOR START_CONDITION START_DRIVEROUT
73 // The following code implements a stack, together with a virtual production
74 // rule _pushV that does the opposite of _popV.
76 // This may not be the best option; we might also return bitsets of variables
77 // from the various non-terminals in the grammar, set their %type and use $i.
78 // The vital matter in that case is allocation and reuse of the variable sets.
80 // _tosV is the top of the variable stack
81 bitset_t *_tosV (struct parser *prs) {
82 if (prs->varstack_sp < 0) {
83 fatal_error ("Cannot share top of empty stack");
85 return prs->varstack [prs->varstack_sp];
88 void _pushV (struct parser *prs) {
90 if (prs->varstack_sp >= PARSER_VARIABLE_STACK_ENTRIES) {
91 fatal_error ("Parser ran out of variable stack levels");
93 bitset_empty (prs->varstack [prs->varstack_sp]);
96 // _popV retrieves the top element of the variable stack
97 bitset_t *_popV (struct parser *prs) {
98 if (prs->varstack_sp <= 0) {
99 fatal_error ("Attempt to pop top element of variable stack");
101 return prs->varstack [prs->varstack_sp--];
104 // _clrV wipes the variable stack
105 void _clrV (struct parser *prs) {
106 prs->varstack_sp = 0;
107 bitset_empty (prs->varstack [0]);
114 /* The definition of a (fake) construct that pushes that variable stack.
115 * This is used to separate contexts of variables within a line. The new
116 * top-of-stack accumulates new variables, and starts empty after _pushV().
118 _pushV: { _pushV (prs); }
120 /* When initiated by the pulley_parser_XXX() functions, they will be setup
121 * to parse either a single line, possibly even of a particular type, or a
122 * sequence of lines informally known as a script. The switch implements
123 * this behaviour, in unison with a bit of startup code in the lexer that
124 * inserts the special START_xxx symbols at the head of the lexeme stream.
126 switch: START_SCRIPT script
127 switch: START_LINE line
128 switch: START_GENERATOR line_generator
129 switch: START_CONDITION line_condition
130 switch: START_DRIVEROUT line_driverout
133 script: script line NEWLINE
134 script: script error NEWLINE
136 line: line_generator | line_condition | line_driverout | line_empty
138 /* Empty lines constitute acceptable grammar withing scripts, or if the line
139 * type has not been specified. It does not make any semantical modifications.
143 /* Generator lines contain variables that are bound to the environment, they
144 * extract information from a DN-type variable and they have annotations that
145 * can define guard variables and a line weight.
147 line_generator: error GEN_FROM dnvar annotations { _clrV (prs); }
148 line_generator: binding GEN_FROM _pushV dnvar annotations {
149 bitset_t *guards = _popV (prs);
151 bitset_t *bindvars = _tosV (prs);
152 gennum_t gennew = gen_new (prs->gentab, dnvar);
155 printf ("FOUND %d bound variables in generator line\n", bitset_count (bindvars));
156 bitset_iterator_init (&lvi, bindvars);
157 while (bitset_iterator_next_one (&lvi, NULL)) {
158 varnum_t varnum = bitset_iterator_bitnum (&lvi);
159 var_used_in_generator (prs->vartab, varnum, gennew);
160 gen_add_variable (prs->gentab, gennew, varnum);
162 if (! bitset_isempty (guards)) {
163 //TODO// Process guards (but first discover what they mean!)
164 fprintf (stderr, "WARNING: Ignoring explicit guards to generator, unsure about semantics...\n");
166 gen_set_weight (prs->gentab, gennew, prs->weight_set? prs->weight: 250.0);
167 hash_curline (&prs->scanhashbuf, &linehash);
168 gen_set_hash (prs->gentab, gennew, linehash);
172 /* Condition lines simply mention a filter and annotations. As part of their
173 * most valuable impact on semantics, they cause variable partitions; but
174 * this is not currently worked out. Instead, sets of variables used in
175 * conditions are setup for later processing with cndtab_drive_partitions().
176 * Annotations may set a weight and could introduce more variables as guards
177 * that will also be taken into account during partitioning.
179 line_condition: filter annotations {
180 bitset_t *filtervars = _tosV (prs); // Includes explicit guards!
182 bitset_iterator_init (&fvi, filtervars);
184 while (bitset_iterator_next_one (&fvi, NULL)) {
185 varnum_t varnum = bitset_iterator_bitnum (&fvi);
186 var_used_in_condition (prs->vartab, varnum, prs->newcnd);
187 cnd_needvar (prs->cndtab, prs->newcnd, varnum);
189 cnd_set_weight (prs->cndtab, prs->newcnd, prs->weight_set? prs->weight: 0.02);
190 hash_curline (&prs->scanhashbuf, &linehash);
191 cnd_set_hash (prs->cndtab, prs->newcnd, linehash);
193 prs->newcnd = CNDNUM_BAD;
196 /* Driver output lines specify a number of variables that will be sent out,
197 * they name an output driver module as well as constant settings for named
198 * parameters that this driver module may expect. The constant settings are
199 * provided while configuring the driver module; the variables will be supplied
200 * when actually transmitting data through the driver module.
201 * Processing of the line's information is done as soon as it is recognised,
202 * to save internal structures beyond the sets that we wish to maintain.
203 * Although a weight could be defined, it hardly has an impact on ordering;
204 * although guards could be specified, it barely seems interesting to do so.
206 //USELESS???// line_driveout: error DRIVE_TO DRIVERNAME OPEN parmlist CLOSE annotations { _clrV (); }
207 //USELESS???// line_driveout: error CLOSE annotations { _clrV (); }
208 line_driverout: drvout_vallist_s DRIVE_TO {
209 bitset_t *varout = _tosV (prs);
211 bitset_iterator_init (&voi, varout);
212 while (bitset_iterator_next_one (&voi, NULL)) {
213 varnum_t varnum = bitset_iterator_bitnum (&voi);
217 char *module = var_get_name (prs->vartab, $4);
218 drv_set_module (prs->drvtab, prs->newdrv, module);
219 bitset_t *driver = _tosV (prs);
221 } OPEN parmlist CLOSE {
222 bitset_t *params = _tosV (prs);
225 bitset_t *guards = _tosV (prs);
227 bitset_iterator_init (&gvi, guards);
228 while (bitset_iterator_next_one (&gvi, NULL)) {
229 varnum_t varnum = bitset_iterator_bitnum (&gvi);
230 var_used_in_driverout (prs->vartab, varnum, prs->newdrv);
231 drv_add_guardvar (prs->drvtab, prs->newdrv, varnum);
233 drv_set_weight (prs->drvtab, prs->newdrv, prs->weight_set? prs->weight: 3.0);
235 hash_curline (&prs->scanhashbuf, &linehash);
236 drv_set_hash (prs->drvtab, prs->newdrv, linehash);
238 prs->newdrv = DRVNUM_BAD;
241 annotations: annotation1 annotation2
242 annotation1: /* %empty */
243 annotation1: BRA varlist KET
244 annotation2: /* %empty */ { prs->weight_set = false; }
245 annotation2: STAR FLOAT { prs->weight_set = true; prs->weight = /*TODO*/ 0.1; }
248 binding: bindatr COMMA bindsteps
251 bindsteps: bindsteps COMMA bindstep
253 bitset_set (_tosV (prs), $2);
257 bindrdn: bindrdn PLUS bindrdnpart
258 bindrdnpart: ATTRTYPE CMP_EQ optvalue {
259 // The optvalue may be a SILENCER
260 if ($3 != VARNUM_BAD) {
261 bitset_set (_tosV (prs), $3);
265 bindatr: bindatr PLUS atmatch
266 atmatch: ATTRTYPE COLON optvalue {
267 // The optvalue may be a SILENCER
268 if ($3 != VARNUM_BAD) {
269 bitset_set (_tosV (prs), $3);
274 if (prs->newcnd == CNDNUM_BAD) {
275 prs->newcnd = cnd_new (prs->cndtab);
278 filter: OPEN error CLOSE
280 filtbody: LOG_NOT filter {
281 cnd_pushop (prs->cndtab, prs->newcnd, CND_NOT);
284 cnd_pushop (prs->cndtab, prs->newcnd, CND_SEQ_START);
286 cnd_pushop (prs->cndtab, prs->newcnd, CND_AND);
289 cnd_pushop (prs->cndtab, prs->newcnd, CND_SEQ_START);
291 cnd_pushop (prs->cndtab, prs->newcnd, CND_OR);
293 filters: /* %empty */
294 filters: filters filter
295 filtcmp: CMP_EQ { $$ = CND_EQ; }
296 | CMP_NE { $$ = CND_NE; }
297 | CMP_LT { $$ = CND_LT; }
298 | CMP_LE { $$ = CND_LE; }
299 | CMP_GT { $$ = CND_GT; }
300 | CMP_GE { $$ = CND_GE; }
301 filtbase: varnm filtcmp value {
302 var_used_in_condition (prs->vartab, $1, prs->newcnd);
303 var_used_in_condition (prs->vartab, $3, prs->newcnd);
304 cnd_needvar (prs->cndtab, prs->newcnd, $1);
305 cnd_needvar (prs->cndtab, prs->newcnd, $3);
306 /* TODO: Type checking? Operator applicability checking? */
307 cnd_pushvar (prs->cndtab, prs->newcnd, $1);
308 cnd_pushvar (prs->cndtab, prs->newcnd, $3);
309 cnd_pushop (prs->cndtab, prs->newcnd, $2);
313 // value_s: BRA valuelist KET
315 // valuelist: valuelist COMMA value
316 optvalue: value { $$ = $1; }
317 optvalue: SILENCER { $$ = VARNUM_BAD; }
320 drvout_vallist_s: drvout_vallist_s COMMA drvout_vallist_s
321 drvout_vallist_s: value {
322 if (prs->newdrv == DRVNUM_BAD) {
323 prs->newdrv = drv_new (prs->drvtab);
325 drv_output_variable (prs->drvtab, prs->newdrv, $1);
326 var_used_in_driverout (prs->vartab, $1, prs->newdrv);
328 drvout_vallist_s: BRA {
329 drv_output_list_begin (prs->drvtab, prs->newdrv);
330 } drvout_vallist KET {
331 drv_output_list_end (prs->drvtab, prs->newdrv);
333 drvout_vallist: drvout_vallist COMMA drvout_vallist
334 drvout_vallist: value {
335 if (prs->newdrv == DRVNUM_BAD) {
336 prs->newdrv = drv_new (prs->drvtab);
338 drv_output_variable (prs->drvtab, prs->newdrv, $1);
339 var_used_in_driverout (prs->vartab, $1, prs->newdrv);
342 varlist: varlist COMMA varnm
344 const: STRING | INTEGER | FLOAT | BLOB
345 parmlist: parmlist COMMA parm
347 parm: PARAMETER CMP_EQ const {
348 char *paramname = var_get_name (prs->vartab, $1);
349 drv_setup_param (prs->drvtab, prs->newdrv, paramname, $3);