1 #include <stdlib.h>
2 #include "lib/mlr_globals.h"
3 #include "lib/mlrutil.h"
4 #include "mlr_dsl_cst.h"
5 #include "context_flags.h"
6
7 // ================================================================
8 // The Lemon parser in parsing/mlr_dsl_parse.y builds up an abstract syntax tree
9 // specifically for the CST builder here.
10 //
11 // For clearer visuals on what the ASTs look like:
12 // * See parsing/mlr_dsl_parse.y
13 // * See reg_test/run's filter -v and put -v outputs, e.g. in reg_test/expected/out
14 // * Do "mlr -n put -v 'your expression goes here'"
15 // ================================================================
16
17 // ================================================================
cst_statement_block_alloc(int subframe_var_count)18 cst_statement_block_t* cst_statement_block_alloc(int subframe_var_count) {
19 cst_statement_block_t* pblock = mlr_malloc_or_die(sizeof(cst_statement_block_t));
20
21 pblock->subframe_var_count = subframe_var_count;
22 pblock->pstatements = sllv_alloc();
23
24 return pblock;
25 }
26
27 // ----------------------------------------------------------------
cst_statement_block_free(cst_statement_block_t * pblock,context_t * pctx)28 void cst_statement_block_free(cst_statement_block_t* pblock, context_t* pctx) {
29 if (pblock == NULL)
30 return;
31 for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
32 mlr_dsl_cst_statement_free(pe->pvvalue, pctx);
33 }
34 sllv_free(pblock->pstatements);
35 free(pblock);
36 }
37
38 // ================================================================
39 // ALLOCATORS
40 // ================================================================
cst_top_level_statement_block_alloc(int max_var_depth,int subframe_var_count)41 cst_top_level_statement_block_t* cst_top_level_statement_block_alloc(int max_var_depth, int subframe_var_count) {
42 cst_top_level_statement_block_t* ptop_level_block = mlr_malloc_or_die(sizeof(cst_top_level_statement_block_t));
43
44 ptop_level_block->max_var_depth = max_var_depth;
45 ptop_level_block->pframe = local_stack_frame_alloc(max_var_depth);
46 ptop_level_block->pblock = cst_statement_block_alloc(subframe_var_count);
47
48 return ptop_level_block;
49 }
50
51 // ----------------------------------------------------------------
cst_top_level_statement_block_free(cst_top_level_statement_block_t * ptop_level_block,context_t * pctx)52 void cst_top_level_statement_block_free(cst_top_level_statement_block_t* ptop_level_block, context_t* pctx) {
53 if (ptop_level_block == NULL)
54 return;
55 local_stack_frame_free(ptop_level_block->pframe);
56 cst_statement_block_free(ptop_level_block->pblock, pctx);
57 free(ptop_level_block);
58 }
59
60 // ================================================================
61 // The parser accepts many things that are invalid, e.g.
62 // * begin{end{}} -- begin/end not at top level
63 // * begin{$x=1} -- references to stream records at begin/end
64 // * break/continue outside of for/while/do-while
65 // * $x=x -- boundvars outside of for-loop variable bindings
66 //
67 // All of the above are enforced here by the CST builder, which takes the parser's output AST as
68 // input. This is done (a) to keep the parser from being overly complex, and (b) so we can get much
69 // more informative error messages in C than in Lemon ('syntax error').
70 //
71 // In this file we set up left-hand sides for assignments, as well as right-hand sides for emit and
72 // unset. Most right-hand sides are set up in rval_expr_evaluators.c so the context_flags are
73 // passed through to there as well.
74
mlr_dsl_cst_alloc_statement(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int type_inferencing,int context_flags)75 mlr_dsl_cst_statement_t* mlr_dsl_cst_alloc_statement(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
76 int type_inferencing, int context_flags)
77 {
78 switch(pnode->type) {
79
80 case MD_AST_NODE_TYPE_FUNC_DEF:
81 fprintf(stderr, "%s: func statements are only valid at top level.\n", MLR_GLOBALS.bargv0);
82 exit(1);
83 break;
84
85 case MD_AST_NODE_TYPE_SUBR_DEF:
86 fprintf(stderr, "%s: subr statements are only valid at top level.\n", MLR_GLOBALS.bargv0);
87 exit(1);
88 break;
89
90 case MD_AST_NODE_TYPE_BEGIN:
91 fprintf(stderr, "%s: begin statements are only valid at top level.\n", MLR_GLOBALS.bargv0);
92 exit(1);
93 break;
94
95 case MD_AST_NODE_TYPE_END:
96 fprintf(stderr, "%s: end statements are only valid at top level.\n", MLR_GLOBALS.bargv0);
97 exit(1);
98 break;
99
100 case MD_AST_NODE_TYPE_RETURN_VALUE:
101 if (!(context_flags & IN_FUNC_DEF)) {
102 fprintf(stderr, "%s: return-value statements are only valid within func blocks.\n",
103 MLR_GLOBALS.bargv0);
104 exit(1);
105 }
106 return alloc_return_value(pcst, pnode, type_inferencing, context_flags);
107 break;
108
109 case MD_AST_NODE_TYPE_RETURN_VOID:
110 if (!(context_flags & IN_SUBR_DEF)) {
111 fprintf(stderr, "%s: return-void statements are only valid within subr blocks.\n",
112 MLR_GLOBALS.bargv0);
113 exit(1);
114 }
115 return alloc_return_void(pcst, pnode, type_inferencing, context_flags);
116 break;
117
118 case MD_AST_NODE_TYPE_SUBR_CALLSITE:
119 if (context_flags & IN_FUNC_DEF) {
120 fprintf(stderr, "%s: subroutine calls are not valid within func blocks.\n",
121 MLR_GLOBALS.bargv0);
122 exit(1);
123 }
124 return alloc_subr_callsite_statement(pcst, pnode, type_inferencing, context_flags);
125 break;
126
127 case MD_AST_NODE_TYPE_CONDITIONAL_BLOCK:
128 return alloc_conditional_block(pcst, pnode, type_inferencing, context_flags);
129 break;
130 case MD_AST_NODE_TYPE_IF_HEAD:
131 return alloc_if_head(pcst, pnode, type_inferencing, context_flags);
132 break;
133
134 case MD_AST_NODE_TYPE_WHILE:
135 return alloc_while(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
136 break;
137 case MD_AST_NODE_TYPE_DO_WHILE:
138 return alloc_do_while(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
139 break;
140
141 case MD_AST_NODE_TYPE_FOR_SREC:
142 if (context_flags & IN_BEGIN_OR_END) {
143 fprintf(stderr, "%s: statements involving $-variables are not valid within begin or end blocks.\n",
144 MLR_GLOBALS.bargv0);
145 exit(1);
146 }
147 return alloc_for_srec(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
148 break;
149
150 case MD_AST_NODE_TYPE_FOR_SREC_KEY_ONLY:
151 if (context_flags & IN_BEGIN_OR_END) {
152 fprintf(stderr, "%s: statements involving $-variables are not valid within begin or end blocks.\n",
153 MLR_GLOBALS.bargv0);
154 exit(1);
155 }
156 return alloc_for_srec_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
157 break;
158
159 case MD_AST_NODE_TYPE_FOR_OOSVAR:
160 return alloc_for_map(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
161 break;
162 case MD_AST_NODE_TYPE_FOR_OOSVAR_KEY_ONLY:
163 return alloc_for_map_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
164 break;
165
166 case MD_AST_NODE_TYPE_FOR_LOCAL_MAP:
167 return alloc_for_map(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
168 break;
169 case MD_AST_NODE_TYPE_FOR_LOCAL_MAP_KEY_ONLY:
170 return alloc_for_map_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
171 break;
172
173 case MD_AST_NODE_TYPE_FOR_MAP_LITERAL:
174 return alloc_for_map(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
175 break;
176 case MD_AST_NODE_TYPE_FOR_MAP_LITERAL_KEY_ONLY:
177 return alloc_for_map_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
178 break;
179
180 case MD_AST_NODE_TYPE_FOR_FUNC_RETVAL:
181 return alloc_for_map(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
182 break;
183 case MD_AST_NODE_TYPE_FOR_FUNC_RETVAL_KEY_ONLY:
184 return alloc_for_map_key_only(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
185 break;
186
187 case MD_AST_NODE_TYPE_TRIPLE_FOR:
188 return alloc_triple_for(pcst, pnode, type_inferencing, context_flags | IN_BREAKABLE);
189 break;
190
191 case MD_AST_NODE_TYPE_BREAK:
192 if (!(context_flags & IN_BREAKABLE)) {
193 fprintf(stderr, "%s: break statements are only valid within for, while, or do-while.\n",
194 MLR_GLOBALS.bargv0);
195 exit(1);
196 }
197 return alloc_break(pcst, pnode, type_inferencing, context_flags);
198 break;
199 case MD_AST_NODE_TYPE_CONTINUE:
200 if (!(context_flags & IN_BREAKABLE)) {
201 fprintf(stderr, "%s: break statements are only valid within for, while, or do-while.\n",
202 MLR_GLOBALS.bargv0);
203 exit(1);
204 }
205 return alloc_continue(pcst, pnode, type_inferencing, context_flags);
206 break;
207
208 case MD_AST_NODE_TYPE_UNTYPED_LOCAL_DEFINITION:
209 return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_ANY);
210
211 case MD_AST_NODE_TYPE_NUMERIC_LOCAL_DEFINITION:
212 return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_NUMERIC);
213 break;
214
215 case MD_AST_NODE_TYPE_INT_LOCAL_DEFINITION:
216 return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_INT);
217 break;
218
219 case MD_AST_NODE_TYPE_FLOAT_LOCAL_DEFINITION:
220 return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_FLOAT);
221 break;
222
223 case MD_AST_NODE_TYPE_BOOLEAN_LOCAL_DEFINITION:
224 return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_BOOLEAN);
225 break;
226
227 case MD_AST_NODE_TYPE_STRING_LOCAL_DEFINITION:
228 return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_STRING);
229 break;
230
231 case MD_AST_NODE_TYPE_MAP_LOCAL_DEFINITION:
232 return alloc_local_variable_definition(pcst, pnode, type_inferencing, context_flags, TYPE_MASK_MAP);
233 break;
234
235 case MD_AST_NODE_TYPE_NONINDEXED_LOCAL_ASSIGNMENT:
236 return alloc_nonindexed_local_variable_assignment(pcst, pnode, type_inferencing, context_flags);
237 break;
238
239 case MD_AST_NODE_TYPE_INDEXED_LOCAL_ASSIGNMENT:
240 return alloc_indexed_local_variable_assignment(pcst, pnode, type_inferencing, context_flags);
241 break;
242
243 case MD_AST_NODE_TYPE_SREC_ASSIGNMENT:
244 if (context_flags & IN_BEGIN_OR_END) {
245 fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n",
246 MLR_GLOBALS.bargv0);
247 exit(1);
248 }
249 if (context_flags & IN_FUNC_DEF) {
250 fprintf(stderr, "%s: assignments to $-variables are not valid within func blocks.\n",
251 MLR_GLOBALS.bargv0);
252 exit(1);
253 }
254 return alloc_srec_assignment(pcst, pnode, type_inferencing, context_flags);
255 break;
256
257 case MD_AST_NODE_TYPE_INDIRECT_SREC_ASSIGNMENT:
258 if (context_flags & IN_BEGIN_OR_END) {
259 fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n",
260 MLR_GLOBALS.bargv0);
261 exit(1);
262 }
263 if (context_flags & IN_FUNC_DEF) {
264 fprintf(stderr, "%s: assignments to $-variables are not valid within func blocks.\n",
265 MLR_GLOBALS.bargv0);
266 exit(1);
267 }
268 return alloc_indirect_srec_assignment(pcst, pnode, type_inferencing, context_flags);
269 break;
270
271 case MD_AST_NODE_TYPE_POSITIONAL_SREC_NAME_ASSIGNMENT:
272 if (context_flags & IN_BEGIN_OR_END) {
273 fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n",
274 MLR_GLOBALS.bargv0);
275 exit(1);
276 }
277 if (context_flags & IN_FUNC_DEF) {
278 fprintf(stderr, "%s: assignments to $-variables are not valid within func blocks.\n",
279 MLR_GLOBALS.bargv0);
280 exit(1);
281 }
282 return alloc_positional_srec_name_assignment(pcst, pnode, type_inferencing, context_flags);
283 break;
284
285 case MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT:
286 return alloc_oosvar_assignment(pcst, pnode, type_inferencing, context_flags);
287 break;
288
289 case MD_AST_NODE_TYPE_OOSVAR_FROM_FULL_SREC_ASSIGNMENT:
290 if (context_flags & IN_BEGIN_OR_END) {
291 fprintf(stderr, "%s: assignments from $-variables are not valid within begin or end blocks.\n",
292 MLR_GLOBALS.bargv0);
293 exit(1);
294 }
295 return alloc_oosvar_assignment(pcst, pnode, type_inferencing, context_flags);
296 break;
297
298 case MD_AST_NODE_TYPE_FULL_OOSVAR_ASSIGNMENT:
299 return alloc_full_oosvar_assignment(pcst, pnode, type_inferencing, context_flags);
300 break;
301
302 case MD_AST_NODE_TYPE_FULL_OOSVAR_FROM_FULL_SREC_ASSIGNMENT:
303 if (context_flags & IN_BEGIN_OR_END) {
304 fprintf(stderr, "%s: assignments from $-variables are not valid within begin or end blocks.\n",
305 MLR_GLOBALS.bargv0);
306 exit(1);
307 }
308 return alloc_full_oosvar_assignment(pcst, pnode, type_inferencing, context_flags);
309 break;
310
311 case MD_AST_NODE_TYPE_FULL_SREC_ASSIGNMENT:
312 if (context_flags & IN_BEGIN_OR_END) {
313 fprintf(stderr, "%s: assignments to $-variables are not valid within begin or end blocks.\n",
314 MLR_GLOBALS.bargv0);
315 exit(1);
316 }
317 if (context_flags & IN_FUNC_DEF) {
318 fprintf(stderr, "%s: assignments to $-variables are not valid within func blocks.\n",
319 MLR_GLOBALS.bargv0);
320 exit(1);
321 }
322 return alloc_full_srec_assignment(pcst, pnode, type_inferencing, context_flags);
323 break;
324
325 case MD_AST_NODE_TYPE_ENV_ASSIGNMENT:
326 return alloc_env_assignment(pcst, pnode, type_inferencing, context_flags);
327 break;
328
329 case MD_AST_NODE_TYPE_UNSET:
330 return alloc_unset(pcst, pnode, type_inferencing, context_flags);
331 break;
332
333 case MD_AST_NODE_TYPE_TEE:
334 if (context_flags & IN_FUNC_DEF) {
335 fprintf(stderr, "%s: tee statements are not valid within func blocks.\n",
336 MLR_GLOBALS.bargv0);
337 exit(1);
338 }
339 return alloc_tee(pcst, pnode, type_inferencing, context_flags);
340 break;
341
342 case MD_AST_NODE_TYPE_EMITF:
343 if (context_flags & IN_FUNC_DEF) {
344 fprintf(stderr, "%s: emitf statements are not valid within func blocks.\n",
345 MLR_GLOBALS.bargv0);
346 exit(1);
347 }
348 return alloc_emitf(pcst, pnode, type_inferencing, context_flags);
349 break;
350 case MD_AST_NODE_TYPE_EMITP:
351 if (context_flags & IN_FUNC_DEF) {
352 fprintf(stderr, "%s: emitp statements are not valid within func blocks.\n",
353 MLR_GLOBALS.bargv0);
354 exit(1);
355 }
356 return alloc_emit(pcst, pnode, type_inferencing, context_flags, TRUE);
357 break;
358 case MD_AST_NODE_TYPE_EMIT:
359 if (context_flags & IN_FUNC_DEF) {
360 fprintf(stderr, "%s: emit statements are not valid within func blocks.\n",
361 MLR_GLOBALS.bargv0);
362 exit(1);
363 }
364 return alloc_emit(pcst, pnode, type_inferencing, context_flags, FALSE);
365 break;
366
367 case MD_AST_NODE_TYPE_EMITP_LASHED:
368 if (context_flags & IN_FUNC_DEF) {
369 fprintf(stderr, "%s: emitp statements are not valid within func blocks.\n",
370 MLR_GLOBALS.bargv0);
371 exit(1);
372 }
373 return alloc_emit_lashed(pcst, pnode, type_inferencing, context_flags, TRUE);
374 break;
375 case MD_AST_NODE_TYPE_EMIT_LASHED:
376 if (context_flags & IN_FUNC_DEF) {
377 fprintf(stderr, "%s: emit statements are not valid within func blocks.\n",
378 MLR_GLOBALS.bargv0);
379 exit(1);
380 }
381 return alloc_emit_lashed(pcst, pnode, type_inferencing, context_flags, FALSE);
382 break;
383
384 case MD_AST_NODE_TYPE_FILTER:
385 if (context_flags & IN_FUNC_DEF) {
386 fprintf(stderr, "%s: filter statements are not valid within func blocks.\n",
387 MLR_GLOBALS.bargv0);
388 exit(1);
389 }
390 if (context_flags & IN_MLR_FILTER) {
391 fprintf(stderr, "%s filter: expressions must not also contain the \"filter\" keyword.\n",
392 MLR_GLOBALS.bargv0);
393 exit(1);
394 }
395 return alloc_filter(pcst, pnode, type_inferencing, context_flags);
396 break;
397
398 case MD_AST_NODE_TYPE_DUMP:
399 return alloc_dump(pcst, pnode, type_inferencing, context_flags);
400 break;
401
402 case MD_AST_NODE_TYPE_PRINT:
403 return alloc_print(pcst, pnode, type_inferencing, context_flags, "\n");
404 break;
405
406 case MD_AST_NODE_TYPE_PRINTN:
407 return alloc_print(pcst, pnode, type_inferencing, context_flags, "");
408 break;
409
410 default:
411 return alloc_bare_boolean(pcst, pnode, type_inferencing, context_flags);
412 break;
413 }
414 }
415
416 // ----------------------------------------------------------------
417 // mlr put and mlr filter are almost entirely the same code. The key difference is that the final
418 // statement for the latter must be a bare boolean expression.
419
mlr_dsl_cst_alloc_final_filter_statement(mlr_dsl_cst_t * pcst,mlr_dsl_ast_node_t * pnode,int negate_final_filter,int type_inferencing,int context_flags)420 mlr_dsl_cst_statement_t* mlr_dsl_cst_alloc_final_filter_statement(mlr_dsl_cst_t* pcst, mlr_dsl_ast_node_t* pnode,
421 int negate_final_filter, int type_inferencing, int context_flags)
422 {
423 switch(pnode->type) {
424
425 case MD_AST_NODE_TYPE_FILTER:
426 fprintf(stderr, "%s filter: expressions must not also contain the \"filter\" keyword.\n",
427 MLR_GLOBALS.bargv0);
428 exit(1);
429 break;
430
431 case MD_AST_NODE_TYPE_FUNC_DEF:
432 case MD_AST_NODE_TYPE_SUBR_DEF:
433 case MD_AST_NODE_TYPE_BEGIN:
434 case MD_AST_NODE_TYPE_END:
435 case MD_AST_NODE_TYPE_RETURN_VALUE:
436 case MD_AST_NODE_TYPE_RETURN_VOID:
437 case MD_AST_NODE_TYPE_SUBR_CALLSITE:
438 case MD_AST_NODE_TYPE_CONDITIONAL_BLOCK:
439 case MD_AST_NODE_TYPE_IF_HEAD:
440 case MD_AST_NODE_TYPE_WHILE:
441 case MD_AST_NODE_TYPE_DO_WHILE:
442 case MD_AST_NODE_TYPE_FOR_SREC:
443 case MD_AST_NODE_TYPE_FOR_SREC_KEY_ONLY:
444 case MD_AST_NODE_TYPE_FOR_OOSVAR:
445 case MD_AST_NODE_TYPE_TRIPLE_FOR:
446 case MD_AST_NODE_TYPE_BREAK:
447 case MD_AST_NODE_TYPE_CONTINUE:
448 case MD_AST_NODE_TYPE_UNTYPED_LOCAL_DEFINITION:
449 case MD_AST_NODE_TYPE_NUMERIC_LOCAL_DEFINITION:
450 case MD_AST_NODE_TYPE_INT_LOCAL_DEFINITION:
451 case MD_AST_NODE_TYPE_FLOAT_LOCAL_DEFINITION:
452 case MD_AST_NODE_TYPE_BOOLEAN_LOCAL_DEFINITION:
453 case MD_AST_NODE_TYPE_STRING_LOCAL_DEFINITION:
454 case MD_AST_NODE_TYPE_NONINDEXED_LOCAL_ASSIGNMENT:
455 case MD_AST_NODE_TYPE_SREC_ASSIGNMENT:
456 case MD_AST_NODE_TYPE_INDIRECT_SREC_ASSIGNMENT:
457 case MD_AST_NODE_TYPE_POSITIONAL_SREC_NAME_ASSIGNMENT:
458 case MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT:
459 case MD_AST_NODE_TYPE_OOSVAR_FROM_FULL_SREC_ASSIGNMENT:
460 case MD_AST_NODE_TYPE_FULL_OOSVAR_ASSIGNMENT:
461 case MD_AST_NODE_TYPE_FULL_OOSVAR_FROM_FULL_SREC_ASSIGNMENT:
462 case MD_AST_NODE_TYPE_FULL_SREC_ASSIGNMENT:
463 case MD_AST_NODE_TYPE_UNSET:
464 case MD_AST_NODE_TYPE_TEE:
465 case MD_AST_NODE_TYPE_EMITF:
466 case MD_AST_NODE_TYPE_EMITP:
467 case MD_AST_NODE_TYPE_EMIT:
468 case MD_AST_NODE_TYPE_EMITP_LASHED:
469 case MD_AST_NODE_TYPE_EMIT_LASHED:
470 case MD_AST_NODE_TYPE_DUMP:
471 case MD_AST_NODE_TYPE_PRINT:
472 case MD_AST_NODE_TYPE_PRINTN:
473 fprintf(stderr, "%s: filter expressions must end in a final boolean statement.\n", MLR_GLOBALS.bargv0);
474 exit(1);
475 break;
476
477 default:
478 return alloc_final_filter(pcst, pnode, negate_final_filter, type_inferencing, context_flags);
479 break;
480 }
481 }
482
483 // ----------------------------------------------------------------
484 // For used by constructors of subclasses of mlr_dsl_cst_statement_t.
485
mlr_dsl_cst_statement_valloc(mlr_dsl_ast_node_t * past_node,mlr_dsl_cst_statement_handler_t * pstatement_handler,mlr_dsl_cst_statement_freer_t * pstatement_freer,void * pvstate)486 mlr_dsl_cst_statement_t* mlr_dsl_cst_statement_valloc(
487 mlr_dsl_ast_node_t* past_node,
488 mlr_dsl_cst_statement_handler_t* pstatement_handler,
489 mlr_dsl_cst_statement_freer_t* pstatement_freer,
490 void* pvstate)
491 {
492 mlr_dsl_cst_statement_t* pstatement = mlr_malloc_or_die(sizeof(mlr_dsl_cst_statement_t));
493 pstatement->past_node = past_node;
494 pstatement->pstatement_handler = pstatement_handler;
495 pstatement->pblock = NULL;
496 pstatement->pblock_handler = NULL;
497 pstatement->pstatement_freer = pstatement_freer;
498 pstatement->pvstate = pvstate;
499 return pstatement;
500 }
501
mlr_dsl_cst_statement_valloc_with_block(mlr_dsl_ast_node_t * past_node,mlr_dsl_cst_statement_handler_t * pstatement_handler,cst_statement_block_t * pblock,mlr_dsl_cst_block_handler_t * pblock_handler,mlr_dsl_cst_statement_freer_t * pstatement_freer,void * pvstate)502 mlr_dsl_cst_statement_t* mlr_dsl_cst_statement_valloc_with_block(
503 mlr_dsl_ast_node_t* past_node,
504 mlr_dsl_cst_statement_handler_t* pstatement_handler,
505 cst_statement_block_t* pblock,
506 mlr_dsl_cst_block_handler_t* pblock_handler,
507 mlr_dsl_cst_statement_freer_t* pstatement_freer,
508 void* pvstate)
509 {
510 mlr_dsl_cst_statement_t* pstatement = mlr_malloc_or_die(sizeof(mlr_dsl_cst_statement_t));
511 pstatement->past_node = past_node;
512 pstatement->pstatement_handler = pstatement_handler;
513 pstatement->pblock = pblock;
514 pstatement->pblock_handler = pblock_handler;
515 pstatement->pstatement_freer = pstatement_freer;
516 pstatement->pvstate = pvstate;
517 return pstatement;
518 }
519
520 // ----------------------------------------------------------------
mlr_dsl_cst_statement_free(mlr_dsl_cst_statement_t * pstatement,context_t * pctx)521 void mlr_dsl_cst_statement_free(mlr_dsl_cst_statement_t* pstatement, context_t* pctx) {
522
523 if (pstatement->pstatement_freer != NULL) {
524 pstatement->pstatement_freer(pstatement, pctx);
525 }
526
527 cst_statement_block_free(pstatement->pblock, pctx);
528
529 free(pstatement);
530 }
531
532 // ================================================================
533 // Top-level entry point for statement-handling, e.g. from mapper_put.
534
mlr_dsl_cst_handle_top_level_statement_blocks(sllv_t * ptop_level_blocks,variables_t * pvars,cst_outputs_t * pcst_outputs)535 void mlr_dsl_cst_handle_top_level_statement_blocks(
536 sllv_t* ptop_level_blocks, // block bodies for begins, main, ends
537 variables_t* pvars,
538 cst_outputs_t* pcst_outputs)
539 {
540 for (sllve_t* pe = ptop_level_blocks->phead; pe != NULL; pe = pe->pnext) {
541 mlr_dsl_cst_handle_top_level_statement_block(pe->pvvalue, pvars, pcst_outputs);
542 }
543 }
544
mlr_dsl_cst_handle_top_level_statement_block(cst_top_level_statement_block_t * ptop_level_block,variables_t * pvars,cst_outputs_t * pcst_outputs)545 void mlr_dsl_cst_handle_top_level_statement_block(
546 cst_top_level_statement_block_t* ptop_level_block,
547 variables_t* pvars,
548 cst_outputs_t* pcst_outputs)
549 {
550 local_stack_push(pvars->plocal_stack, local_stack_frame_enter(ptop_level_block->pframe));
551 local_stack_frame_t* pframe = local_stack_get_top_frame(pvars->plocal_stack);
552 local_stack_subframe_enter(pframe, ptop_level_block->pblock->subframe_var_count);
553
554 mlr_dsl_cst_handle_statement_block(ptop_level_block->pblock, pvars, pcst_outputs);
555
556 local_stack_subframe_exit(pframe, ptop_level_block->pblock->subframe_var_count);
557 local_stack_frame_exit(local_stack_pop(pvars->plocal_stack));
558 }
559
560 // ================================================================
561 // HANDLERS
562 // ================================================================
563 // This is for statement lists not recursively contained within a loop body -- including the
564 // main/begin/end statements. Since there is no containing loop body, there is no need to check
565 // for break or continue flags after each statement.
mlr_dsl_cst_handle_statement_block(cst_statement_block_t * pblock,variables_t * pvars,cst_outputs_t * pcst_outputs)566 void mlr_dsl_cst_handle_statement_block(
567 cst_statement_block_t* pblock,
568 variables_t* pvars,
569 cst_outputs_t* pcst_outputs)
570 {
571 if (pvars->trace_execution) {
572 for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
573 mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
574 fprintf(stdout, "TRACE ");
575 mlr_dsl_ast_node_pretty_fprint(pstatement->past_node, stdout);
576 pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
577 // The UDF/subroutine executor will clear the flag, and consume the retval if there is one.
578 if (pvars->return_state.returned) {
579 break;
580 }
581 }
582 } else {
583 for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
584 mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
585 pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
586 // The UDF/subroutine executor will clear the flag, and consume the retval if there is one.
587 if (pvars->return_state.returned) {
588 break;
589 }
590 }
591 }
592 }
593
594 // This is for statement lists recursively contained within a loop body.
595 // It checks for break or continue flags after each statement.
mlr_dsl_cst_handle_statement_block_with_break_continue(cst_statement_block_t * pblock,variables_t * pvars,cst_outputs_t * pcst_outputs)596 void mlr_dsl_cst_handle_statement_block_with_break_continue(
597 cst_statement_block_t* pblock,
598 variables_t* pvars,
599 cst_outputs_t* pcst_outputs)
600 {
601 if (pvars->trace_execution) {
602 for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
603 mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
604 fprintf(stdout, "TRACE ");
605 mlr_dsl_ast_node_pretty_fprint(pstatement->past_node, stdout);
606 pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
607 if (loop_stack_get(pvars->ploop_stack) != 0) {
608 break;
609 }
610 // The UDF/subroutine executor will clear the flag, and consume the retval if there is one.
611 if (pvars->return_state.returned) {
612 break;
613 }
614 }
615 } else {
616 for (sllve_t* pe = pblock->pstatements->phead; pe != NULL; pe = pe->pnext) {
617 mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
618 pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
619 if (loop_stack_get(pvars->ploop_stack) != 0) {
620 break;
621 }
622 // The UDF/subroutine executor will clear the flag, and consume the retval if there is one.
623 if (pvars->return_state.returned) {
624 break;
625 }
626 }
627 }
628 }
629
630 // Triple-for start/continuation/update statement lists
mlr_dsl_cst_handle_statement_list(sllv_t * pstatements,variables_t * pvars,cst_outputs_t * pcst_outputs)631 void mlr_dsl_cst_handle_statement_list(
632 sllv_t* pstatements,
633 variables_t* pvars,
634 cst_outputs_t* pcst_outputs)
635 {
636 if (pvars->trace_execution) {
637 for (sllve_t* pe = pstatements->phead; pe != NULL; pe = pe->pnext) {
638 mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
639 fprintf(stdout, "TRACE ");
640 mlr_dsl_ast_node_pretty_fprint(pstatement->past_node, stdout);
641 pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
642 }
643 } else {
644 for (sllve_t* pe = pstatements->phead; pe != NULL; pe = pe->pnext) {
645 mlr_dsl_cst_statement_t* pstatement = pe->pvvalue;
646 pstatement->pstatement_handler(pstatement, pvars, pcst_outputs);
647 }
648 }
649 }
650