diff --git a/c/containers/local_stack.c b/c/containers/local_stack.c index 8f814af7b..c963d6b02 100644 --- a/c/containers/local_stack.c +++ b/c/containers/local_stack.c @@ -3,192 +3,183 @@ #include "lib/mlr_globals.h" #include "containers/local_stack.h" -#define INITIAL_SIZE 32 - // ---------------------------------------------------------------- -// Private to .c file -struct _local_stack_frame_t { - lhmsmv_t* pbindings; - char fenced; - char ephemeral; - char in_use; -}; - -// ---------------------------------------------------------------- -local_stack_t* local_stack_alloc() { +local_stack_t* local_stack_alloc(int size) { local_stack_t* pstack = mlr_malloc_or_die(sizeof(local_stack_t)); - pstack->num_used = 0; - pstack->num_allocated = INITIAL_SIZE; - - pstack->ppframes = mlr_malloc_or_die(pstack->num_allocated * sizeof(local_stack_frame_t*)); - memset(pstack->ppframes, 0, pstack->num_allocated * sizeof(local_stack_frame_t*)); - - pstack->pbase_frame = local_stack_frame_alloc_unfenced(); - local_stack_push(pstack, pstack->pbase_frame); + pstack->in_use = FALSE; + pstack->size = size; + pstack->pvars = mlr_malloc_or_die(size * sizeof(mv_t)); + for (int i = 0; i < size; i++) { + pstack->pvars[i] = mv_absent(); + } return pstack; } // ---------------------------------------------------------------- void local_stack_free(local_stack_t* pstack) { - if (pstack == NULL) - return; - - local_stack_frame_free(pstack->pbase_frame); - free(pstack->ppframes); - free(pstack); } -// ---------------------------------------------------------------- -static inline local_stack_frame_t* local_stack_frame_alloc(int fenced, int ephemeral) { - local_stack_frame_t* pframe = mlr_malloc_or_die(sizeof(local_stack_frame_t)); - pframe->pbindings = lhmsmv_alloc(); - pframe->fenced = fenced; - pframe->ephemeral = ephemeral; - pframe->in_use = FALSE; - return pframe; -} - -local_stack_frame_t* local_stack_frame_alloc_unfenced() { - return local_stack_frame_alloc(FALSE, FALSE); -} - -local_stack_frame_t* local_stack_frame_alloc_fenced() { - return local_stack_frame_alloc(TRUE, FALSE); -} - -// ---------------------------------------------------------------- -void local_stack_frame_free(local_stack_frame_t* pframe) { - lhmsmv_free(pframe->pbindings); - free(pframe); -} - -// ---------------------------------------------------------------- -// xxx cmt -local_stack_frame_t* local_stack_frame_enter(local_stack_frame_t* pframe) { - if (pframe->in_use) { - local_stack_frame_t* pephemeral = local_stack_frame_alloc(pframe->fenced, TRUE); - pephemeral->in_use = TRUE; - return pephemeral; - } else { - pframe->in_use = TRUE; - return pframe; - } -} - -void local_stack_frame_exit(local_stack_frame_t* pframe) { - if (pframe->ephemeral) { - local_stack_frame_free(pframe); - } else { - lhmsmv_clear(pframe->pbindings); - pframe->in_use = FALSE; - } -} - -// ---------------------------------------------------------------- -void local_stack_push(local_stack_t* pstack, local_stack_frame_t* pframe) { - if (pstack->num_used >= pstack->num_allocated) { - pstack->num_allocated += INITIAL_SIZE; - pstack->ppframes = mlr_realloc_or_die(pstack->ppframes, - pstack->num_allocated * sizeof(local_stack_frame_t*)); - } - pstack->ppframes[pstack->num_used] = pframe; - pstack->num_used++; -} - -// ---------------------------------------------------------------- -local_stack_frame_t* local_stack_pop(local_stack_t* pstack) { - if (pstack->num_used <= 0) { - fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n", - MLR_GLOBALS.bargv0, __FILE__, __LINE__); - exit(1); - } - - local_stack_frame_t* pframe = pstack->ppframes[pstack->num_used-1]; - pstack->num_used--; - return pframe; -} - -// ---------------------------------------------------------------- -// xxx cmt -mv_t* local_stack_resolve(local_stack_t* pstack, char* name) { - for (int i = pstack->num_used - 1; i >= 0; i--) { - mv_t* pval = lhmsmv_get(pstack->ppframes[i]->pbindings, name); - if (pval != NULL) { - return pval; - } - if (pstack->ppframes[i]->fenced) { - break; - } - } - return NULL; -} - -// ---------------------------------------------------------------- -// xxx +//// ---------------------------------------------------------------- +//void local_stack_free(local_stack_t* pstack) { +// if (pstack == NULL) +// return; // -// run_mlr --opprint --from $indir/abixy put ' -// func f(x) { -// local a = 1; -// if (NR > 5) { -// a = 2; -// } -// return a; -// } +// local_stack_frame_free(pstack->pbase_frame); +// free(pstack->ppframes); +// free(pstack); +//} + +//// ---------------------------------------------------------------- +//static inline local_stack_frame_t* local_stack_frame_alloc(int fenced, int ephemeral) { +// local_stack_frame_t* pframe = mlr_malloc_or_die(sizeof(local_stack_frame_t)); +// pframe->pbindings = lhmsmv_alloc(); +// pframe->fenced = fenced; +// pframe->ephemeral = ephemeral; +// pframe->in_use = FALSE; +// return pframe; +//} +// +//local_stack_frame_t* local_stack_frame_alloc_unfenced() { +// return local_stack_frame_alloc(FALSE, FALSE); +//} +// +//local_stack_frame_t* local_stack_frame_alloc_fenced() { +// return local_stack_frame_alloc(TRUE, FALSE); +//} +// +//// ---------------------------------------------------------------- +//void local_stack_frame_free(local_stack_frame_t* pframe) { +// lhmsmv_free(pframe->pbindings); +// free(pframe); +//} +// +//// ---------------------------------------------------------------- +//// xxx cmt +//local_stack_frame_t* local_stack_frame_enter(local_stack_frame_t* pframe) { +// if (pframe->in_use) { +// local_stack_frame_t* pephemeral = local_stack_frame_alloc(pframe->fenced, TRUE); +// pephemeral->in_use = TRUE; +// return pephemeral; +// } else { +// pframe->in_use = TRUE; +// return pframe; +// } +//} +// +//void local_stack_frame_exit(local_stack_frame_t* pframe) { +// if (pframe->ephemeral) { +// local_stack_frame_free(pframe); +// } else { +// lhmsmv_clear(pframe->pbindings); +// pframe->in_use = FALSE; +// } +//} +// +//// ---------------------------------------------------------------- +//void local_stack_push(local_stack_t* pstack, local_stack_frame_t* pframe) { +// if (pstack->num_used >= pstack->num_allocated) { +// pstack->num_allocated += INITIAL_SIZE; +// pstack->ppframes = mlr_realloc_or_die(pstack->ppframes, +// pstack->num_allocated * sizeof(local_stack_frame_t*)); +// } +// pstack->ppframes[pstack->num_used] = pframe; +// pstack->num_used++; +//} +// +//// ---------------------------------------------------------------- +//local_stack_frame_t* local_stack_pop(local_stack_t* pstack) { +// if (pstack->num_used <= 0) { +// fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n", +// MLR_GLOBALS.bargv0, __FILE__, __LINE__); +// exit(1); +// } +// +// local_stack_frame_t* pframe = pstack->ppframes[pstack->num_used-1]; +// pstack->num_used--; +// return pframe; +//} +// +//// ---------------------------------------------------------------- +//// xxx cmt +//mv_t* local_stack_resolve(local_stack_t* pstack, char* name) { +// for (int i = pstack->num_used - 1; i >= 0; i--) { +// mv_t* pval = lhmsmv_get(pstack->ppframes[i]->pbindings, name); +// if (pval != NULL) { +// return pval; +// } +// if (pstack->ppframes[i]->fenced) { +// break; +// } +// } +// return NULL; +//} +// +//// ---------------------------------------------------------------- +//// xxx +//// +//// run_mlr --opprint --from $indir/abixy put ' +//// func f(x) { +//// local a = 1; +//// if (NR > 5) { +//// a = 2; +//// } +//// return a; +//// } +//// +//// func g(x) { +//// local b = 1; +//// if (NR > 5) { +//// local b = 2; +//// } +//// return b; +//// } +//// $of = f(NR); +//// $og = g(NR); +//// ' +// +//void local_stack_define(local_stack_t* pstack, char* name, mv_t* pmv, char free_flags) { +// local_stack_frame_t* ptop_frame = pstack->ppframes[pstack->num_used - 1]; +// lhmsmv_put(ptop_frame->pbindings, name, pmv, free_flags); +//} +// +//void local_stack_set(local_stack_t* pstack, char* name, mv_t* pmv, char free_flags) { +// +// // xxx comment +// // xxx test thoroughly +// for (int i = pstack->num_used - 1; i >= 0; i--) { +// local_stack_frame_t* pframe = pstack->ppframes[i]; +// if (lhmsmv_get(pframe->pbindings, name)) { +// lhmsmv_put(pframe->pbindings, name, pmv, free_flags); +// return; +// } +// if (pstack->ppframes[i]->fenced) { +// break; +// } +// } +// +// local_stack_frame_t* ptop_frame = pstack->ppframes[pstack->num_used - 1]; +// lhmsmv_put(ptop_frame->pbindings, name, pmv, free_flags); +//} +// +//// ---------------------------------------------------------------- +//void local_stack_clear(local_stack_t* pstack) { +// if (pstack->num_used <= 0) { +// fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n", +// MLR_GLOBALS.bargv0, __FILE__, __LINE__); +// exit(1); +// } +// lhmsmv_clear(pstack->ppframes[pstack->num_used-1]->pbindings); +//} +// +//// ---------------------------------------------------------------- +//void local_stack_print(local_stack_t* pstack) { +// printf("BIND STACK BEGIN (#frames %d):\n", pstack->num_used); +// for (int i = pstack->num_used - 1; i >= 0; i--) { +// printf("-- FRAME %d (fenced:%d):\n", i, pstack->ppframes[i]->fenced); +// lhmsmv_dump(pstack->ppframes[i]->pbindings); +// } +// printf("BIND STACK END\n"); +//} // -// func g(x) { -// local b = 1; -// if (NR > 5) { -// local b = 2; -// } -// return b; -// } -// $of = f(NR); -// $og = g(NR); -// ' - -void local_stack_define(local_stack_t* pstack, char* name, mv_t* pmv, char free_flags) { - local_stack_frame_t* ptop_frame = pstack->ppframes[pstack->num_used - 1]; - lhmsmv_put(ptop_frame->pbindings, name, pmv, free_flags); -} - -void local_stack_set(local_stack_t* pstack, char* name, mv_t* pmv, char free_flags) { - - // xxx comment - // xxx test thoroughly - for (int i = pstack->num_used - 1; i >= 0; i--) { - local_stack_frame_t* pframe = pstack->ppframes[i]; - if (lhmsmv_get(pframe->pbindings, name)) { - lhmsmv_put(pframe->pbindings, name, pmv, free_flags); - return; - } - if (pstack->ppframes[i]->fenced) { - break; - } - } - - local_stack_frame_t* ptop_frame = pstack->ppframes[pstack->num_used - 1]; - lhmsmv_put(ptop_frame->pbindings, name, pmv, free_flags); -} - -// ---------------------------------------------------------------- -void local_stack_clear(local_stack_t* pstack) { - if (pstack->num_used <= 0) { - fprintf(stderr, "%s: internal coding error detected in file %s at line %d.\n", - MLR_GLOBALS.bargv0, __FILE__, __LINE__); - exit(1); - } - lhmsmv_clear(pstack->ppframes[pstack->num_used-1]->pbindings); -} - -// ---------------------------------------------------------------- -void local_stack_print(local_stack_t* pstack) { - printf("BIND STACK BEGIN (#frames %d):\n", pstack->num_used); - for (int i = pstack->num_used - 1; i >= 0; i--) { - printf("-- FRAME %d (fenced:%d):\n", i, pstack->ppframes[i]->fenced); - lhmsmv_dump(pstack->ppframes[i]->pbindings); - } - printf("BIND STACK END\n"); -} - diff --git a/c/containers/local_stack.h b/c/containers/local_stack.h index ea0029c85..b501c1579 100644 --- a/c/containers/local_stack.h +++ b/c/containers/local_stack.h @@ -2,80 +2,67 @@ #define LOCAL_STACK_H #include "containers/mlrval.h" -#include "containers/lhmsmv.h" // Bound & scoped variables for use in for-loops, function bodies, and -// subroutine bodies. A frame is 'fenced' if it's at entry to a -// function/subroutine body. Example: +// subroutine bodies. Indices of local variables, and max-depth for top-level +// statement blocks, are compted by the stack-allocator which marks up the AST +// before the CST is built from it. // -// mlr ... put -f ' -// func f(x) { -// return k; -// } -// for (k,v in $*) { -// $[k] = f(v) -// } -// ' -// -// There is a bind-stack created on entering the put. A frame is pushed in the -// for-loop. A second frame is pushed in the call to f(x). The former should -// have access to k; the latter should not. +// A convention shared between the stack-allocator and this data structure is +// that slot 0 is an absent-null which is used for reads of undefined (or +// as-yet-undefined) local variables. // ---------------------------------------------------------------- -// Data private to .c file -typedef struct _local_stack_frame_t local_stack_frame_t; - typedef struct _local_stack_t { - int num_used; - int num_allocated; - local_stack_frame_t** ppframes; - local_stack_frame_t* pbase_frame; + int in_use; + int size; + mv_t* pvars; } local_stack_t; // ---------------------------------------------------------------- // Constructors/destructors -local_stack_t* local_stack_alloc(); +local_stack_t* local_stack_alloc(int size); void local_stack_free(local_stack_t* pstack); -local_stack_frame_t* local_stack_frame_alloc_unfenced(); -local_stack_frame_t* local_stack_frame_alloc_fenced(); -void local_stack_frame_free(local_stack_frame_t* pframe); - -// xxx comment -local_stack_frame_t* local_stack_frame_enter(local_stack_frame_t* pframe); -void local_stack_frame_exit(local_stack_frame_t* pframe); - -// ---------------------------------------------------------------- -// Scope entry/exit - -// To be called on entry to scoped block -void local_stack_push(local_stack_t* pstack, local_stack_frame_t* pframe); - -// To be called on exit from scoped block. -local_stack_frame_t* local_stack_pop(local_stack_t* pstack); - -// ---------------------------------------------------------------- -// Access within scope - -// Use of local variables on expression right-hand sides -mv_t* local_stack_resolve(local_stack_t* pstack, char* key); - -// Use of local variables on expression left-hand sides -// The pmv is not copied. You may wish to mv_copy the argument you pass in. -// The pmv will be freed. - -// xxx cmt -void local_stack_define(local_stack_t* pstack, char* name, mv_t* pmv, char free_flags); -void local_stack_set(local_stack_t* pstack, char* name, mv_t* pmv, char free_flags); - -// Clears the binding from the top frame without popping it. Useful -// for clearing the baseframe which is never popped. -void local_stack_clear(local_stack_t* pstack); - -// ---------------------------------------------------------------- -// Test/debug - -void local_stack_print(local_stack_t* pstack); +//local_stack_frame_t* local_stack_frame_alloc_unfenced(); +//local_stack_frame_t* local_stack_frame_alloc_fenced(); +//void local_stack_frame_free(local_stack_frame_t* pframe); +// +//// xxx comment +//local_stack_frame_t* local_stack_frame_enter(local_stack_frame_t* pframe); +//void local_stack_frame_exit(local_stack_frame_t* pframe); +// +//// ---------------------------------------------------------------- +//// Scope entry/exit +// +//// To be called on entry to scoped block +//void local_stack_push(local_stack_t* pstack, local_stack_frame_t* pframe); +// +//// To be called on exit from scoped block. +//local_stack_frame_t* local_stack_pop(local_stack_t* pstack); +// +//// ---------------------------------------------------------------- +//// Access within scope +// +//// Use of local variables on expression right-hand sides +//mv_t* local_stack_resolve(local_stack_t* pstack, char* key); +// +//// Use of local variables on expression left-hand sides +//// The pmv is not copied. You may wish to mv_copy the argument you pass in. +//// The pmv will be freed. +// +//// xxx cmt +//void local_stack_define(local_stack_t* pstack, char* name, mv_t* pmv, char free_flags); +//void local_stack_set(local_stack_t* pstack, char* name, mv_t* pmv, char free_flags); +// +//// Clears the binding from the top frame without popping it. Useful +//// for clearing the baseframe which is never popped. +//void local_stack_clear(local_stack_t* pstack); +// +//// ---------------------------------------------------------------- +//// Test/debug +// +//void local_stack_print(local_stack_t* pstack); #endif // LOCAL_STACK_H