local-stack iterate

This commit is contained in:
John Kerl 2016-10-13 08:51:26 -04:00
parent 75dce976bc
commit d0c48eb02b
2 changed files with 216 additions and 238 deletions

View file

@ -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");
}

View file

@ -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