mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-23 07:59:37 +00:00
938 lines
39 KiB
C
938 lines
39 KiB
C
#include <stdlib.h>
|
|
#include "lib/mlr_globals.h"
|
|
#include "lib/mlrutil.h"
|
|
#include "containers/free_flags.h"
|
|
#include "containers/lhmsi.h"
|
|
#include "mapping/mlr_dsl_blocked_ast.h"
|
|
#include "mapping/context_flags.h"
|
|
|
|
// ================================================================
|
|
// This is a two-pass stack allocator for the Miller DSL.
|
|
//
|
|
// ----------------------------------------------------------------
|
|
// CONTEXT:
|
|
//
|
|
// In the initial Miller implementation of local variables (e.g. for-loop
|
|
// indices or frame-local variables), I used a hashmap from string name to
|
|
// mlrval at each level. This was very easy to code and it worked, but it had
|
|
// the property that every local-variable read or write involved a hashmap
|
|
// lookup to locate each local variable on the stack. For compute-intensive
|
|
// work this resulted in 80% or more of the compute time being used for the
|
|
// hashmap accesses. It doesn't make sense to always be asking "where is
|
|
// variable 'a'"? at runtime (maybe ten million times doing hash-map lookups)
|
|
// since this can be figured out ahead of time.
|
|
//
|
|
// The Miller DSL allows for recursive functions and subroutines, but within
|
|
// those, stack layout is knowable at parse time.
|
|
//
|
|
// ----------------------------------------------------------------
|
|
// TERMINOLOGY
|
|
//
|
|
// * A top-level statement block starts with 'begin', 'end', 'func', 'subr',
|
|
// or is the remaining collection of statements outside of any of those which
|
|
// is called the 'main' statement block.
|
|
//
|
|
// * A stack frame is all the locals for a top-level statement block including
|
|
// anything local to a scoped block within the top-level block. For example,
|
|
// locals may be defined within if/while/do-while blocks. Also, variables can
|
|
// be local to a triple-for, e.g. 'for (var i = 0; i < 10; i += 1) { ... }'.
|
|
// As well, locals are bound to variables in for-loops over stream records
|
|
// or out-of-stream variables: 'for (k, v in $*) { ... }' or
|
|
// 'for ((k1, k2), v in @*) { ... }'. Lastly, function arguments are local
|
|
// to the function/subroutine definition site.
|
|
//
|
|
// * A subframe is the locals defined within any of the above: locals
|
|
// defined within an if/while/for/etc. block. Or, the locals defined
|
|
// in the top-level block have their own subframe.
|
|
//
|
|
// ----------------------------------------------------------------
|
|
// CONVENTION: Local variables are bound to indices within the stack frame, but,
|
|
// local variable may be read before they are defined. Slot 0 of each frame is
|
|
// an absent-null which is reserved for this purpose.
|
|
//
|
|
// ----------------------------------------------------------------
|
|
// EXAMPLE:
|
|
//
|
|
// # ---- FUNC TOP-LEVEL SUBFRAME 0: defcount 7 {absent-RHS,a,b,c,i,j,y}
|
|
// # Absent-null-RHS is at slot 0 of top level.
|
|
// func f(a, b, c) { # Args define locals 1,2,3 at current level.
|
|
// var i = 24; # Explicitly define local 4 at current level.
|
|
// j = 25; # Implicitly define local 5 at current level.
|
|
// #
|
|
// # ---- IF-STATEMENT SUBFRAME 1: defcount 1 {k}
|
|
// if (a == 26) { # Read of local 1, found at top level (subframe 0).
|
|
// var k = 27; # Explicitly define local 0 at this level.
|
|
// j = 28; # LHS is local 5, found at top level.
|
|
// #
|
|
// # Note that the 'if' and the 'else' are both at subframe
|
|
// # depth 1, while each defines a different number of locals.
|
|
// # For this function the max variable depth is 9:
|
|
// # 7 at top level plus 1 = 8 if the if is taken,
|
|
// # 7 at top level plus 2 = 9 if the else is taken,
|
|
// #
|
|
// } else { # ---- ELSE-STATEMENT SUBFRAME 1: defcount 2 {n, u}
|
|
// n = b; # Implicitly define local 0 at this level.
|
|
// var u = 4; # Implicitly define local 1 at this level.
|
|
// } #
|
|
// #
|
|
// y = 7; # LHS is local 6 at current level.
|
|
// i = z; # LHS is local 4 at current level;
|
|
// # RHS is unresolved -> slot 0 at current level.
|
|
// } #
|
|
//
|
|
// Notes:
|
|
//
|
|
// * Pass 1 computes frame-relative indices and subframe-level counts,
|
|
// as in the example, for each local variable.
|
|
//
|
|
// * Pass 2 computes absolute indices for each local variable. These
|
|
// aren't computable in pass 1 due to the example 'y = 7' assignment
|
|
// above: the number of local variables in an upper level can change
|
|
// after the invocation of a child level, so the total frame size is not
|
|
// known until all AST nodes in the top-level block have been visited.
|
|
//
|
|
// * Pass 2 also computes the max depth, counting number of variables, so
|
|
// that for each top-level block we can allocate an array of mlrvals which
|
|
// will be reused on every invocation. (For recursive function calls an entire
|
|
// frame be dynamically allocated.)
|
|
//
|
|
// * Slot 0 of the top level is reserved for an absent-null for unresolved
|
|
// names on reads.
|
|
//
|
|
// * The tree-traversal order is done correctly so that if a variable is read
|
|
// before it is defined, then read again after it is defined, then the first
|
|
// read gets absent-null and the second gets the defined value.
|
|
// ================================================================
|
|
|
|
// ================================================================
|
|
// Pass-1 stack-frame container: simply a hashmap from name to position on the
|
|
// frame relative to the curly-braced statement block (top-level, for-loop,
|
|
// if-statement, else-statement, etc.).
|
|
|
|
typedef struct _stkalc_subframe_t {
|
|
int var_count;
|
|
lhmsi_t* pnames_to_indices;
|
|
} stkalc_subframe_t;
|
|
|
|
// ----------------------------------------------------------------
|
|
// Pass-1 stack-frame methods
|
|
|
|
static stkalc_subframe_t* stkalc_subframe_alloc();
|
|
|
|
static void stkalc_subframe_free(stkalc_subframe_t* pframe);
|
|
|
|
static int stkalc_subframe_test_and_get(stkalc_subframe_t* pframe, char* name, int* pvalue);
|
|
|
|
static int stkalc_subframe_get(stkalc_subframe_t* pframe, char* name);
|
|
|
|
static int stkalc_subframe_add(stkalc_subframe_t* pframe, char* name);
|
|
|
|
// ================================================================
|
|
// Pass-1 frame-group container: a linked list with current frame at the head
|
|
// and top-level frame at the tail. Within a given top-level block there is a
|
|
// tree of curly-braced statement blocks, e.g. a function-definition might have
|
|
// an if-statement, else-if, else-if, else, each with its own frame. But during
|
|
// pass 1 we only maintain a list from the current frame being analyzed up to
|
|
// its parents; sibling branches are not simultaneously stored in this data
|
|
// structure.
|
|
|
|
typedef struct _stkalc_subframe_group_t {
|
|
sllv_t* plist;
|
|
} stkalc_subframe_group_t;
|
|
|
|
// ----------------------------------------------------------------
|
|
// Pass-1 stack-frame-group methods
|
|
|
|
static stkalc_subframe_group_t* stkalc_subframe_group_alloc(stkalc_subframe_t* pframe, int trace);
|
|
|
|
static void stkalc_subframe_group_free(stkalc_subframe_group_t* pframe_group);
|
|
|
|
static void stkalc_subframe_group_push(stkalc_subframe_group_t* pframe_group, stkalc_subframe_t* pframe);
|
|
|
|
static stkalc_subframe_t* stkalc_subframe_group_pop(stkalc_subframe_group_t* pframe_group);
|
|
|
|
// Pass-1 stack-frame-group node-mutator methods: given an AST node containing a
|
|
// local-variable usage they assign a subframe-relative index and a subframe-depth
|
|
// counter (how many frames deep into the top-level statement block the node
|
|
// is).
|
|
|
|
static void stkalc_subframe_group_mutate_node_for_define(stkalc_subframe_group_t* pframe_group,
|
|
mlr_dsl_ast_node_t* pnode, char* desc, int trace);
|
|
|
|
static void stkalc_subframe_group_mutate_node_for_write(stkalc_subframe_group_t* pframe_group,
|
|
mlr_dsl_ast_node_t* pnode, char* desc, int trace);
|
|
|
|
static void stkalc_subframe_group_mutate_node_for_read(stkalc_subframe_group_t* pframe_group,
|
|
mlr_dsl_ast_node_t* pnode, char* desc, int trace);
|
|
|
|
// ================================================================
|
|
// Pass-1 helper methods for the main entry point to this file.
|
|
|
|
static void pass_1_for_func_subr_block(mlr_dsl_ast_node_t* pnode, int trace);
|
|
|
|
static void pass_1_for_begin_end_block(mlr_dsl_ast_node_t* pnode, int trace);
|
|
|
|
static void pass_1_for_main_block(mlr_dsl_ast_node_t* pnode, int trace);
|
|
|
|
static void pass_1_for_statement_block(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_statement_list(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_node(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
|
|
static void pass_1_for_local_definition(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_local_assignment(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_local_read(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_srec_for_loop(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_map_key_only_for_loop(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_map_for_loop(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_triple_for_loop(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
static void pass_1_for_non_terminal_node(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace);
|
|
|
|
// Pass-2 helper methods for the main entry point to this file.
|
|
static void pass_2_for_top_level_block(mlr_dsl_ast_node_t* pnode, int trace);
|
|
|
|
static void pass_2_for_node(mlr_dsl_ast_node_t* pnode,
|
|
int subframe_depth, int var_count_below_subframe, int var_count_at_subframe, int* pmax_var_depth,
|
|
int* subframe_var_count_belows, int max_subframe_depth,
|
|
int trace);
|
|
|
|
// ================================================================
|
|
// Utility methods
|
|
static void leader_print(int depth);
|
|
|
|
// ================================================================
|
|
// Main entry point for the bind-stack allocator
|
|
|
|
void blocked_ast_allocate_locals(blocked_ast_t* paast, int trace) {
|
|
|
|
// Pass 1
|
|
for (sllve_t* pe = paast->pfunc_defs->phead; pe != NULL; pe = pe->pnext) {
|
|
pass_1_for_func_subr_block(pe->pvvalue, trace);
|
|
}
|
|
for (sllve_t* pe = paast->psubr_defs->phead; pe != NULL; pe = pe->pnext) {
|
|
pass_1_for_func_subr_block(pe->pvvalue, trace);
|
|
}
|
|
for (sllve_t* pe = paast->pbegin_blocks->phead; pe != NULL; pe = pe->pnext) {
|
|
pass_1_for_begin_end_block(pe->pvvalue, trace);
|
|
}
|
|
{
|
|
pass_1_for_main_block(paast->pmain_block, trace);
|
|
}
|
|
for (sllve_t* pe = paast->pend_blocks->phead; pe != NULL; pe = pe->pnext) {
|
|
pass_1_for_begin_end_block(pe->pvvalue, trace);
|
|
}
|
|
|
|
// Pass 2
|
|
for (sllve_t* pe = paast->pfunc_defs->phead; pe != NULL; pe = pe->pnext) {
|
|
pass_2_for_top_level_block(pe->pvvalue, trace);
|
|
}
|
|
for (sllve_t* pe = paast->psubr_defs->phead; pe != NULL; pe = pe->pnext) {
|
|
pass_2_for_top_level_block(pe->pvvalue, trace);
|
|
}
|
|
for (sllve_t* pe = paast->pbegin_blocks->phead; pe != NULL; pe = pe->pnext) {
|
|
pass_2_for_top_level_block(pe->pvvalue, trace);
|
|
}
|
|
{
|
|
pass_2_for_top_level_block(paast->pmain_block, trace);
|
|
}
|
|
for (sllve_t* pe = paast->pend_blocks->phead; pe != NULL; pe = pe->pnext) {
|
|
pass_2_for_top_level_block(pe->pvvalue, trace);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_func_subr_block(mlr_dsl_ast_node_t* pnode, int trace) {
|
|
if (trace) {
|
|
printf("\n");
|
|
printf("ALLOCATING RELATIVE (PASS-1) LOCALS FOR DEFINITION BLOCK [%s]\n", pnode->text);
|
|
}
|
|
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->type != MD_AST_NODE_TYPE_SUBR_DEF && pnode->type != MD_AST_NODE_TYPE_FUNC_DEF);
|
|
|
|
stkalc_subframe_t* pframe = stkalc_subframe_alloc();
|
|
stkalc_subframe_group_t* pframe_group = stkalc_subframe_group_alloc(pframe, trace);
|
|
int max_subframe_depth = 1;
|
|
|
|
mlr_dsl_ast_node_t* pdef_name_node = pnode->pchildren->phead->pvvalue;
|
|
mlr_dsl_ast_node_t* plist_node = pnode->pchildren->phead->pnext->pvvalue;
|
|
for (sllve_t* pe = pdef_name_node->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pparameter_node = pe->pvvalue;
|
|
stkalc_subframe_group_mutate_node_for_define(pframe_group, pparameter_node, "PARAMETER", trace);
|
|
}
|
|
pass_1_for_statement_block(plist_node, pframe_group, &max_subframe_depth, trace);
|
|
pnode->subframe_var_count = pframe->var_count;
|
|
pnode->max_subframe_depth = max_subframe_depth;
|
|
if (trace) {
|
|
printf("BLOCK %s subframe_var_count=%d max_subframe_depth=%d\n",
|
|
pnode->text, pnode->subframe_var_count, pnode->max_subframe_depth);
|
|
}
|
|
|
|
stkalc_subframe_free(stkalc_subframe_group_pop(pframe_group));
|
|
stkalc_subframe_group_free(pframe_group);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_begin_end_block(mlr_dsl_ast_node_t* pnode, int trace) {
|
|
if (trace) {
|
|
printf("\n");
|
|
printf("ALLOCATING RELATIVE (PASS-1) LOCALS FOR %s BLOCK\n", pnode->text);
|
|
}
|
|
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->type != MD_AST_NODE_TYPE_BEGIN && pnode->type != MD_AST_NODE_TYPE_END);
|
|
|
|
stkalc_subframe_t* pframe = stkalc_subframe_alloc();
|
|
stkalc_subframe_group_t* pframe_group = stkalc_subframe_group_alloc(pframe, trace);
|
|
int max_subframe_depth = 1;
|
|
|
|
pass_1_for_statement_block(pnode->pchildren->phead->pvvalue, pframe_group, &max_subframe_depth, trace);
|
|
pnode->subframe_var_count = pframe->var_count;
|
|
pnode->max_subframe_depth = max_subframe_depth;
|
|
if (trace) {
|
|
printf("BLOCK %s subframe_var_count=%d max_subframe_depth=%d\n",
|
|
pnode->text, pnode->subframe_var_count, pnode->max_subframe_depth);
|
|
}
|
|
|
|
stkalc_subframe_free(stkalc_subframe_group_pop(pframe_group));
|
|
stkalc_subframe_group_free(pframe_group);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_main_block(mlr_dsl_ast_node_t* pnode, int trace) {
|
|
if (trace) {
|
|
printf("\n");
|
|
printf("ALLOCATING RELATIVE (PASS-1) LOCALS FOR MAIN BLOCK\n");
|
|
}
|
|
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->type != MD_AST_NODE_TYPE_STATEMENT_BLOCK);
|
|
|
|
stkalc_subframe_t* pframe = stkalc_subframe_alloc();
|
|
stkalc_subframe_group_t* pframe_group = stkalc_subframe_group_alloc(pframe, trace);
|
|
int max_subframe_depth = 1;
|
|
|
|
pass_1_for_statement_block(pnode, pframe_group, &max_subframe_depth, trace);
|
|
pnode->subframe_var_count = pframe->var_count;
|
|
pnode->max_subframe_depth = max_subframe_depth;
|
|
if (trace) {
|
|
printf("BLOCK %s subframe_var_count=%d max_subframe_depth=%d\n",
|
|
pnode->text, pnode->subframe_var_count, pnode->max_subframe_depth);
|
|
}
|
|
|
|
stkalc_subframe_free(stkalc_subframe_group_pop(pframe_group));
|
|
stkalc_subframe_group_free(pframe_group);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Curly-braced bodies of if/while/for/etc.
|
|
|
|
static void pass_1_for_statement_block(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->type != MD_AST_NODE_TYPE_STATEMENT_BLOCK);
|
|
for (sllve_t* pe = pnode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pchild = pe->pvvalue;
|
|
pass_1_for_node(pchild, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
}
|
|
|
|
// Non-curly-braced triple-for starts/continuations/updates statement lists.
|
|
static void pass_1_for_statement_list(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->type != MD_AST_NODE_TYPE_STATEMENT_LIST);
|
|
for (sllve_t* pe = pnode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pchild = pe->pvvalue;
|
|
pass_1_for_node(pchild, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_node(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
if (pnode->type == MD_AST_NODE_TYPE_UNTYPED_LOCAL_DEFINITION) { // LHS
|
|
pass_1_for_local_definition(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_NUMERIC_LOCAL_DEFINITION) { // LHS
|
|
pass_1_for_local_definition(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_INT_LOCAL_DEFINITION) { // LHS
|
|
pass_1_for_local_definition(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FLOAT_LOCAL_DEFINITION) { // LHS
|
|
pass_1_for_local_definition(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_BOOLEAN_LOCAL_DEFINITION) { // LHS
|
|
pass_1_for_local_definition(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_STRING_LOCAL_DEFINITION) { // LHS
|
|
pass_1_for_local_definition(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_MAP_LOCAL_DEFINITION) { // LHS
|
|
pass_1_for_local_definition(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_NONINDEXED_LOCAL_ASSIGNMENT) { // LHS
|
|
pass_1_for_local_assignment(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_INDEXED_LOCAL_ASSIGNMENT) { // LHS
|
|
pass_1_for_local_assignment(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_NONINDEXED_LOCAL_VARIABLE) { // RHS
|
|
pass_1_for_local_read(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_INDEXED_LOCAL_VARIABLE) { // RHS
|
|
pass_1_for_local_read(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_SREC) {
|
|
pass_1_for_srec_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_OOSVAR_KEY_ONLY) {
|
|
pass_1_for_map_key_only_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_OOSVAR) {
|
|
pass_1_for_map_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_LOCAL_MAP_KEY_ONLY) {
|
|
pass_1_for_map_key_only_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_LOCAL_MAP) {
|
|
pass_1_for_map_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_MAP_LITERAL_KEY_ONLY) {
|
|
pass_1_for_map_key_only_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_MAP_LITERAL) {
|
|
pass_1_for_map_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_LOCAL_MAP_KEY_ONLY) {
|
|
pass_1_for_map_key_only_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_FOR_LOCAL_MAP) {
|
|
pass_1_for_map_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->type == MD_AST_NODE_TYPE_TRIPLE_FOR) {
|
|
pass_1_for_triple_for_loop(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
} else if (pnode->pchildren != NULL) {
|
|
pass_1_for_non_terminal_node(pnode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_local_definition(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
mlr_dsl_ast_node_t* pnamenode = pnode->pchildren->phead->pvvalue;
|
|
|
|
// RHS must exist for non-map types ('int x = 3', not 'int x') but must not for map types
|
|
// ('map x', not 'map x = {}').
|
|
if (pnode->pchildren->phead->pnext) {
|
|
mlr_dsl_ast_node_t* pvaluenode = pnode->pchildren->phead->pnext->pvvalue;
|
|
pass_1_for_node(pvaluenode, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
// Do the LHS after the RHS, in case 'var nonesuch = nonesuch'
|
|
stkalc_subframe_group_mutate_node_for_define(pframe_group, pnamenode, "DEFINE", trace);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_local_assignment(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
mlr_dsl_ast_node_t* pnamenode = pnode->pchildren->phead->pvvalue;
|
|
mlr_dsl_ast_node_t* pvaluenode = pnode->pchildren->phead->pnext->pvvalue;
|
|
pass_1_for_node(pvaluenode, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
// Do the LHS after the RHS, in case 'var nonesuch = nonesuch'
|
|
stkalc_subframe_group_mutate_node_for_write(pframe_group, pnamenode, "WRITE", trace);
|
|
|
|
if (pnamenode->pchildren != NULL) {
|
|
// E.g. a[i][j]: variable is being written to; i and j are being read from.
|
|
for (sllve_t* pe = pnamenode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pchild = pe->pvvalue;
|
|
pass_1_for_node(pchild, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_local_read(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
stkalc_subframe_group_mutate_node_for_read(pframe_group, pnode, "READ", trace);
|
|
|
|
if (pnode->pchildren != NULL) {
|
|
// E.g. a[i][j]: variable is being written to; i and j are being read from.
|
|
for (sllve_t* pe = pnode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pchild = pe->pvvalue;
|
|
pass_1_for_node(pchild, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// for (k,v in $*) { ... }: the k and v are scoped to the curly-brace block.
|
|
static void pass_1_for_srec_for_loop(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("PUSH SUBFRAME %s\n", pnode->text);
|
|
}
|
|
stkalc_subframe_t* pnext_subframe = stkalc_subframe_alloc();
|
|
stkalc_subframe_group_push(pframe_group, pnext_subframe);
|
|
if (*pmax_subframe_depth < pframe_group->plist->length)
|
|
*pmax_subframe_depth = pframe_group->plist->length;
|
|
|
|
mlr_dsl_ast_node_t* pvarsnode = pnode->pchildren->phead->pvvalue;
|
|
mlr_dsl_ast_node_t* pblocknode = pnode->pchildren->phead->pnext->pvvalue;
|
|
|
|
mlr_dsl_ast_node_t* pknode = pvarsnode->pchildren->phead->pvvalue;
|
|
mlr_dsl_ast_node_t* pvnode = pvarsnode->pchildren->phead->pnext->pvvalue;
|
|
stkalc_subframe_group_mutate_node_for_define(pframe_group, pknode, "FOR-BIND", trace);
|
|
stkalc_subframe_group_mutate_node_for_define(pframe_group, pvnode, "FOR-BIND", trace);
|
|
|
|
pass_1_for_statement_block(pblocknode, pframe_group, pmax_subframe_depth, trace);
|
|
pnode->subframe_var_count = pnext_subframe->var_count;
|
|
|
|
stkalc_subframe_free(stkalc_subframe_group_pop(pframe_group));
|
|
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("POP SUBFRAME %s subframe_var_count=%d\n", pnode->text, pnode->subframe_var_count);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_map_key_only_for_loop(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
mlr_dsl_ast_node_t* pkeynode = pnode->pchildren->phead->pvvalue;
|
|
mlr_dsl_ast_node_t* pkeylistnode = pnode->pchildren->phead->pnext->pvvalue;
|
|
mlr_dsl_ast_node_t* pblocknode = pnode->pchildren->phead->pnext->pnext->pvvalue;
|
|
|
|
// The keylistnode is outside the block binding. In particular if there
|
|
// are any localvar reads in there, they shouldn't read from forloop
|
|
// boundvars.
|
|
//
|
|
// Example: 'for(a in @b[c][d]) { var e = a}': the c and d
|
|
// should be obtained from the enclosing scope.
|
|
|
|
if (pkeylistnode->type == MD_AST_NODE_TYPE_NONINDEXED_LOCAL_VARIABLE) {
|
|
// For-local-map: e.g. 'for(a in b[c][d])'.
|
|
pass_1_for_node(pkeylistnode, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
if (pkeylistnode->pchildren != NULL) {
|
|
for (sllve_t* pe = pkeylistnode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pchild = pe->pvvalue;
|
|
pass_1_for_node(pchild, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
}
|
|
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("PUSH SUBFRAME %s\n", pnode->text);
|
|
}
|
|
stkalc_subframe_t* pnext_subframe = stkalc_subframe_alloc();
|
|
stkalc_subframe_group_push(pframe_group, pnext_subframe);
|
|
if (*pmax_subframe_depth < pframe_group->plist->length)
|
|
*pmax_subframe_depth = pframe_group->plist->length;
|
|
|
|
stkalc_subframe_group_mutate_node_for_define(pframe_group, pkeynode, "FOR-BIND", trace);
|
|
pass_1_for_statement_block(pblocknode, pframe_group, pmax_subframe_depth, trace);
|
|
pnode->subframe_var_count = pnext_subframe->var_count;
|
|
|
|
stkalc_subframe_free(stkalc_subframe_group_pop(pframe_group));
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("POP SUBFRAME %s subframe_var_count=%d\n", pnode->text, pnode->subframe_var_count);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_map_for_loop(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
mlr_dsl_ast_node_t* pvarsnode = pnode->pchildren->phead->pvvalue;
|
|
mlr_dsl_ast_node_t* pkeylistnode = pnode->pchildren->phead->pnext->pvvalue;
|
|
mlr_dsl_ast_node_t* pblocknode = pnode->pchildren->phead->pnext->pnext->pvvalue;
|
|
|
|
mlr_dsl_ast_node_t* pkeysnode = pvarsnode->pchildren->phead->pvvalue;
|
|
mlr_dsl_ast_node_t* pvalnode = pvarsnode->pchildren->phead->pnext->pvvalue;
|
|
|
|
// The keylistnode is outside the block binding. In particular if there
|
|
// are any localvar reads in there, they shouldn't read from forloop
|
|
// boundvars.
|
|
//
|
|
// Example: 'for(k, v in @a[b][c]) { var d = k; var e = v }': the b and c
|
|
// should be obtained from the enclosing scope.
|
|
if (pkeylistnode->type == MD_AST_NODE_TYPE_NONINDEXED_LOCAL_VARIABLE) {
|
|
// For-local-map: e.g. 'for(a,b in c[d][e])'.
|
|
pass_1_for_node(pkeylistnode, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
if (pkeylistnode->pchildren == NULL) {
|
|
pass_1_for_node(pkeylistnode, pframe_group, pmax_subframe_depth, trace);
|
|
} else {
|
|
for (sllve_t* pe = pkeylistnode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pchild = pe->pvvalue;
|
|
pass_1_for_node(pchild, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
}
|
|
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("PUSH SUBFRAME %s\n", pnode->text);
|
|
}
|
|
stkalc_subframe_t* pnext_subframe = stkalc_subframe_alloc();
|
|
stkalc_subframe_group_push(pframe_group, pnext_subframe);
|
|
if (*pmax_subframe_depth < pframe_group->plist->length)
|
|
*pmax_subframe_depth = pframe_group->plist->length;
|
|
|
|
for (sllve_t* pe = pkeysnode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pkeynode = pe->pvvalue;
|
|
stkalc_subframe_group_mutate_node_for_define(pframe_group, pkeynode, "FOR-BIND", trace);
|
|
}
|
|
stkalc_subframe_group_mutate_node_for_define(pframe_group, pvalnode, "FOR-BIND", trace);
|
|
pass_1_for_statement_block(pblocknode, pframe_group, pmax_subframe_depth, trace);
|
|
pnode->subframe_var_count = pnext_subframe->var_count;
|
|
|
|
stkalc_subframe_free(stkalc_subframe_group_pop(pframe_group));
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("POP SUBFRAME %s subframe_var_count=%d\n", pnode->text, pnode->subframe_var_count);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_triple_for_loop(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
mlr_dsl_ast_node_t* pstarts_node = pnode->pchildren->phead->pvvalue;
|
|
mlr_dsl_ast_node_t* pcontinuations_node = pnode->pchildren->phead->pnext->pvvalue;
|
|
mlr_dsl_ast_node_t* pupdates_node = pnode->pchildren->phead->pnext->pnext->pvvalue;
|
|
mlr_dsl_ast_node_t* pblock_node = pnode->pchildren->phead->pnext->pnext->pnext->pvvalue;
|
|
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("PUSH SUBFRAME %s\n", pnode->text);
|
|
}
|
|
stkalc_subframe_t* pnext_subframe = stkalc_subframe_alloc();
|
|
stkalc_subframe_group_push(pframe_group, pnext_subframe);
|
|
if (*pmax_subframe_depth < pframe_group->plist->length)
|
|
*pmax_subframe_depth = pframe_group->plist->length;
|
|
|
|
pass_1_for_statement_list(pstarts_node, pframe_group, pmax_subframe_depth, trace);
|
|
pass_1_for_statement_list(pcontinuations_node, pframe_group, pmax_subframe_depth, trace);
|
|
pass_1_for_statement_list(pupdates_node, pframe_group, pmax_subframe_depth, trace);
|
|
pass_1_for_statement_block(pblock_node, pframe_group, pmax_subframe_depth, trace);
|
|
|
|
pnode->subframe_var_count = pnext_subframe->var_count;
|
|
|
|
stkalc_subframe_free(stkalc_subframe_group_pop(pframe_group));
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("POP SUBFRAME %s subframe_var_count=%d\n", pnode->text, pnode->subframe_var_count);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_1_for_non_terminal_node(mlr_dsl_ast_node_t* pnode, stkalc_subframe_group_t* pframe_group,
|
|
int* pmax_subframe_depth, int trace)
|
|
{
|
|
for (sllve_t* pe = pnode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pchild = pe->pvvalue;
|
|
|
|
if (pchild->type == MD_AST_NODE_TYPE_STATEMENT_BLOCK) {
|
|
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("PUSH SUBFRAME %s\n", pchild->text);
|
|
}
|
|
|
|
stkalc_subframe_t* pnext_subframe = stkalc_subframe_alloc();
|
|
stkalc_subframe_group_push(pframe_group, pnext_subframe);
|
|
if (*pmax_subframe_depth < pframe_group->plist->length)
|
|
*pmax_subframe_depth = pframe_group->plist->length;
|
|
|
|
pass_1_for_statement_block(pchild, pframe_group, pmax_subframe_depth, trace);
|
|
pchild->subframe_var_count = pnext_subframe->var_count;
|
|
|
|
stkalc_subframe_free(stkalc_subframe_group_pop(pframe_group));
|
|
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("POP SUBFRAME %s subframe_var_count=%d\n", pnode->text, pchild->subframe_var_count);
|
|
}
|
|
|
|
} else {
|
|
pass_1_for_node(pchild, pframe_group, pmax_subframe_depth, trace);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ================================================================
|
|
static stkalc_subframe_t* stkalc_subframe_alloc() {
|
|
stkalc_subframe_t* pframe = mlr_malloc_or_die(sizeof(stkalc_subframe_t));
|
|
pframe->var_count = 0;
|
|
pframe->pnames_to_indices = lhmsi_alloc();
|
|
return pframe;
|
|
}
|
|
|
|
static void stkalc_subframe_free(stkalc_subframe_t* pframe) {
|
|
if (pframe == NULL)
|
|
return;
|
|
lhmsi_free(pframe->pnames_to_indices);
|
|
free(pframe);
|
|
}
|
|
|
|
static int stkalc_subframe_test_and_get(stkalc_subframe_t* pframe, char* name, int* pvalue) {
|
|
return lhmsi_test_and_get(pframe->pnames_to_indices, name, pvalue);
|
|
}
|
|
|
|
static int stkalc_subframe_get(stkalc_subframe_t* pframe, char* name) {
|
|
return lhmsi_get(pframe->pnames_to_indices, name);
|
|
}
|
|
|
|
static int stkalc_subframe_add(stkalc_subframe_t* pframe, char* name) {
|
|
int rv = pframe->var_count;
|
|
lhmsi_put(pframe->pnames_to_indices, name, pframe->var_count, NO_FREE);
|
|
pframe->var_count++;
|
|
return rv;
|
|
}
|
|
|
|
// ================================================================
|
|
static stkalc_subframe_group_t* stkalc_subframe_group_alloc(stkalc_subframe_t* pframe, int trace) {
|
|
stkalc_subframe_group_t* pframe_group = mlr_malloc_or_die(sizeof(stkalc_subframe_group_t));
|
|
pframe_group->plist = sllv_alloc();
|
|
sllv_push(pframe_group->plist, pframe);
|
|
stkalc_subframe_add(pframe, "");
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("ADD FOR ABSENT s @ %du%d\n", 0, 0);
|
|
}
|
|
return pframe_group;
|
|
}
|
|
|
|
static void stkalc_subframe_group_free(stkalc_subframe_group_t* pframe_group) {
|
|
if (pframe_group == NULL)
|
|
return;
|
|
while (pframe_group->plist->phead != NULL) {
|
|
stkalc_subframe_free(sllv_pop(pframe_group->plist));
|
|
}
|
|
sllv_free(pframe_group->plist);
|
|
free(pframe_group);
|
|
}
|
|
|
|
static void stkalc_subframe_group_push(stkalc_subframe_group_t* pframe_group, stkalc_subframe_t* pframe) {
|
|
sllv_push(pframe_group->plist, pframe);
|
|
}
|
|
|
|
static stkalc_subframe_t* stkalc_subframe_group_pop(stkalc_subframe_group_t* pframe_group) {
|
|
return sllv_pop(pframe_group->plist);
|
|
}
|
|
|
|
// 'var x = 1' always applies to the current subframe.
|
|
static void stkalc_subframe_group_mutate_node_for_define(stkalc_subframe_group_t* pframe_group,
|
|
mlr_dsl_ast_node_t* pnode, char* desc, int trace)
|
|
{
|
|
stkalc_subframe_t* pframe = pframe_group->plist->phead->pvvalue;
|
|
pnode->vardef_subframe_index = pframe_group->plist->length - 1;
|
|
if (stkalc_subframe_test_and_get(pframe, pnode->text, &pnode->vardef_subframe_relative_index)) {
|
|
fprintf(stderr, "%s: redefinition of variable %s in the same scope.\n",
|
|
MLR_GLOBALS.bargv0, pnode->text);
|
|
exit(1);
|
|
} else {
|
|
pnode->vardef_subframe_relative_index = stkalc_subframe_add(pframe, pnode->text);
|
|
}
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("ADD %s %s @ %ds%d\n", desc, pnode->text,
|
|
pnode->vardef_subframe_relative_index, pnode->vardef_subframe_index);
|
|
}
|
|
}
|
|
|
|
// 'x = 1' is one of two things: (1) already defined in a higher subframe and
|
|
// referenced in the current subframe; (2) not defined in a higher subframe, in
|
|
// which case it is hereby defined in the current subframe.
|
|
static void stkalc_subframe_group_mutate_node_for_write(stkalc_subframe_group_t* pframe_group,
|
|
mlr_dsl_ast_node_t* pnode, char* desc, int trace)
|
|
{
|
|
char* op = "REUSE";
|
|
int found = FALSE;
|
|
|
|
// Search for definitions in current & higher subframes.
|
|
pnode->vardef_subframe_index = pframe_group->plist->length - 1;
|
|
for (sllve_t* pe = pframe_group->plist->phead; pe != NULL; pe = pe->pnext, pnode->vardef_subframe_index--) {
|
|
stkalc_subframe_t* pframe = pe->pvvalue;
|
|
if (stkalc_subframe_test_and_get(pframe, pnode->text, &pnode->vardef_subframe_relative_index)) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If not found, define locally.
|
|
if (!found) {
|
|
pnode->vardef_subframe_index = pframe_group->plist->length - 1;
|
|
stkalc_subframe_t* pframe = pframe_group->plist->phead->pvvalue;
|
|
pnode->vardef_subframe_relative_index = stkalc_subframe_add(pframe, pnode->text);
|
|
op = "ADD";
|
|
}
|
|
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("%s %s %s @ %ds%d\n", op, desc, pnode->text,
|
|
pnode->vardef_subframe_relative_index, pnode->vardef_subframe_index);
|
|
}
|
|
}
|
|
|
|
// The right-hand side of '$a = b' is one of two things: (1) already defined in a higher
|
|
// subframe and referenced in the current subframe; (2) not defined in a higher subframe,
|
|
// in which case the RHS evaluates to absent-null. An absent-null is always kept at index
|
|
// 0 in the frame. This is an important assumption to be tracked across modules, including
|
|
// here as well as the CST-node handlers. It's tested in the test-dsl-stack-allocation.mlr
|
|
// regtest case.
|
|
static void stkalc_subframe_group_mutate_node_for_read(stkalc_subframe_group_t* pframe_group, mlr_dsl_ast_node_t* pnode,
|
|
char* desc, int trace)
|
|
{
|
|
char* op = "PRESENT";
|
|
int found = FALSE;
|
|
|
|
// Search for definitions in current & higher subframes.
|
|
pnode->vardef_subframe_index = pframe_group->plist->length - 1;
|
|
for (sllve_t* pe = pframe_group->plist->phead; pe != NULL; pe = pe->pnext, pnode->vardef_subframe_index--) {
|
|
stkalc_subframe_t* pframe = pe->pvvalue;
|
|
if (stkalc_subframe_test_and_get(pframe, pnode->text, &pnode->vardef_subframe_relative_index)) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Absent-null is indexed in this stack allocator by the "" variable name.
|
|
if (!found) {
|
|
stkalc_subframe_t* plast = pframe_group->plist->ptail->pvvalue;
|
|
pnode->vardef_subframe_relative_index = stkalc_subframe_get(plast, "");
|
|
pnode->vardef_subframe_index = 0;
|
|
op = "ABSENT";
|
|
}
|
|
|
|
if (trace) {
|
|
leader_print(pframe_group->plist->length);
|
|
printf("%s %s %s @ %ds%d\n", desc, pnode->text, op,
|
|
pnode->vardef_subframe_relative_index, pnode->vardef_subframe_index);
|
|
}
|
|
}
|
|
|
|
// ================================================================
|
|
static void pass_2_for_top_level_block(mlr_dsl_ast_node_t* pnode, int trace) {
|
|
int subframe_depth = 0;
|
|
int var_count_below_subframe = 0;
|
|
int var_count_at_subframe = 0;
|
|
int max_var_depth = 0;
|
|
|
|
int max_subframe_depth = pnode->max_subframe_depth;
|
|
MLR_INTERNAL_CODING_ERROR_IF(max_subframe_depth == MD_UNUSED_INDEX);
|
|
int* subframe_var_count_belows = mlr_malloc_or_die(max_subframe_depth * sizeof(int));
|
|
for (int i = 0; i < pnode->max_subframe_depth; i++)
|
|
subframe_var_count_belows[i] = MD_UNUSED_INDEX;
|
|
|
|
|
|
if (trace) {
|
|
printf("\n");
|
|
printf("ALLOCATING ABSOLUTE (PASS-2) LOCALS FOR DEFINITION BLOCK [%s]\n", pnode->text);
|
|
}
|
|
pass_2_for_node(pnode, subframe_depth, var_count_below_subframe, var_count_at_subframe, &max_var_depth,
|
|
subframe_var_count_belows, max_subframe_depth, trace);
|
|
pnode->max_var_depth = max_var_depth;
|
|
free(subframe_var_count_belows);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void pass_2_for_node(mlr_dsl_ast_node_t* pnode,
|
|
int subframe_depth, int var_count_below_subframe, int var_count_at_subframe, int* pmax_var_depth,
|
|
int* subframe_var_count_belows, int max_subframe_depth,
|
|
int trace)
|
|
{
|
|
if (pnode->subframe_var_count != MD_UNUSED_INDEX) {
|
|
var_count_below_subframe += var_count_at_subframe;
|
|
var_count_at_subframe = pnode->subframe_var_count;
|
|
int depth = var_count_below_subframe + var_count_at_subframe;
|
|
if (depth > *pmax_var_depth) {
|
|
*pmax_var_depth = depth;
|
|
}
|
|
subframe_var_count_belows[subframe_depth] = var_count_below_subframe;
|
|
if (trace) {
|
|
leader_print(subframe_depth);
|
|
printf("SUBFRAME [%s] var_count_below=%d var_count_at=%d max_var_depth_so_far=%d subframe_depth=%d\n",
|
|
pnode->text, var_count_below_subframe, var_count_at_subframe, *pmax_var_depth, subframe_depth);
|
|
}
|
|
subframe_depth++;
|
|
}
|
|
|
|
if (pnode->vardef_subframe_relative_index != MD_UNUSED_INDEX) {
|
|
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->vardef_subframe_index < 0);
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->vardef_subframe_index >= max_subframe_depth);
|
|
pnode->vardef_frame_relative_index = subframe_var_count_belows[pnode->vardef_subframe_index]
|
|
+ pnode->vardef_subframe_relative_index;
|
|
|
|
if (trace) {
|
|
leader_print(subframe_depth);
|
|
|
|
printf("NODE %s %ds%d (",
|
|
pnode->text,
|
|
pnode->vardef_subframe_relative_index,
|
|
pnode->vardef_subframe_index);
|
|
|
|
for (int i = 0; i < subframe_depth; i++) {
|
|
if (i > 0)
|
|
printf(",");
|
|
printf("%d:%d", i, subframe_var_count_belows[i]);
|
|
}
|
|
printf(") -> %d\n",
|
|
pnode->vardef_frame_relative_index);
|
|
|
|
}
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->vardef_frame_relative_index < 0);
|
|
MLR_INTERNAL_CODING_ERROR_IF(pnode->vardef_frame_relative_index > *pmax_var_depth);
|
|
}
|
|
|
|
if (pnode->pchildren != NULL) {
|
|
for (sllve_t* pe = pnode->pchildren->phead; pe != NULL; pe = pe->pnext) {
|
|
mlr_dsl_ast_node_t* pchild = pe->pvvalue;
|
|
pass_2_for_node(pchild, subframe_depth,
|
|
var_count_below_subframe, var_count_at_subframe, pmax_var_depth,
|
|
subframe_var_count_belows, max_subframe_depth,
|
|
trace);
|
|
}
|
|
}
|
|
if (pnode->subframe_var_count != MD_UNUSED_INDEX) {
|
|
subframe_depth--;
|
|
subframe_var_count_belows[subframe_depth] = MD_UNUSED_INDEX;
|
|
}
|
|
}
|
|
|
|
// ================================================================
|
|
const char* STKALC_TRACE_LEADER = " ";
|
|
static void leader_print(int depth) {
|
|
for (int i = 0; i < depth; i++)
|
|
printf("%s", STKALC_TRACE_LEADER);
|
|
}
|