diff options
-rw-r--r-- | ChangeLog | 42 | ||||
-rw-r--r-- | array.c | 69 | ||||
-rw-r--r-- | awk.h | 53 | ||||
-rw-r--r-- | awkgram.c | 10 | ||||
-rw-r--r-- | awkgram.y | 10 | ||||
-rw-r--r-- | builtin.c | 18 | ||||
-rw-r--r-- | cint_array.c | 52 | ||||
-rw-r--r-- | debug.c | 18 | ||||
-rw-r--r-- | eval.c | 1 | ||||
-rw-r--r-- | field.c | 4 | ||||
-rw-r--r-- | int_array.c | 16 | ||||
-rw-r--r-- | interpret.h | 50 | ||||
-rw-r--r-- | profile.c | 1 | ||||
-rw-r--r-- | str_array.c | 16 | ||||
-rw-r--r-- | symbol.c | 2 |
15 files changed, 261 insertions, 101 deletions
@@ -1,3 +1,45 @@ +2012-04-19 John Haque <j.eh@mchsi.com> + + Enhanced array interface to support transparent implementation + using external storage and ... + + * awk.h (astore): Optional post-assignment store routine for + array subscripts. + (Op_subscript_assign): New opcode to support the store routine. + (alength): New array interface routine for array length. + (assoc_length): New macro. + (assoc_empty): Renamed from array_empty. + * awkgram.y (snode): Append Op_subscript_assign opcode if + (g)sub variable is an array element. + (mk_getline): Same for getline variable. + (mk_assignment): Same if assigning to an array element. + * field.c (set_element): Call store routine if needed. + * builtin.c (do_match): Ditto. + (do_length): Use length routine for array size. + * symbol.c (print_vars): Ditto. + * array.c (null_length): Default function for array length interface. + (asort_actual): Call store routine if defined. + (asort_actual, assoc_list): Use length routine for array size. + (null_array_func): Add length and store routine entries. + * str_array.c (str_array_func): Same. + * cint_array.c (cint_array_func): Same. + * int_array.c (int_array_func): Same. + * eval.c (optypetab): Add Op_subscript_assign. + * profile.c (pprint): Add case Op_subscript_assign. + * interpret.h (set_array, set_idx): New variables to keep track + of an array element with store routine. + (Op_sub_array, Op_subscript_lhs, Op_store_sub, Op_subscript_assign): + Add code to handle array store routine. + * debug.c (print_symbol, print_array, cmp_val, watchpoint_triggered, + initialize_watch_item): Use length routine for array size. + + * awk.h (assoc_kind_t): New typedef for enum assoc_list_flags. + (sort_context_t): Renamed from SORT_CONTEXT. + * array.c (asort_actual, assoc_sort): Adjust. + * cint_array.c (cint_list, tree_list, leaf_list): Adjust. + * int_array.c (int_list): Adjust. + * str_array.c (str_list): Adjust. + 2012-04-18 John Haque <j.eh@mchsi.com> * awk.h (atypeof, AFUNC): New macros. @@ -37,6 +37,7 @@ static NODE **null_dump(NODE *symbol, NODE *subs); static afunc_t null_array_func[] = { (afunc_t) 0, (afunc_t) 0, + null_length, null_lookup, null_afunc, null_afunc, @@ -44,6 +45,7 @@ static afunc_t null_array_func[] = { null_afunc, null_afunc, null_dump, + (afunc_t) 0, }; #define MAX_ATYPE 10 @@ -140,6 +142,15 @@ null_lookup(NODE *symbol, NODE *subs) return symbol->alookup(symbol, subs); } +/* null_length --- default function for array length interface */ + +NODE ** +null_length(NODE *symbol, NODE *subs ATTRIBUTE_UNUSED) +{ + static NODE *tmp; + tmp = symbol; + return & tmp; +} /* null_afunc --- default function for array interface */ @@ -630,14 +641,13 @@ void do_delete_loop(NODE *symbol, NODE **lhs) { NODE **list; - NODE fl; + NODE akind; - if (array_empty(symbol)) - return; + akind.flags = AINDEX|ADELETE; /* need a single index */ + list = symbol->alist(symbol, & akind); - fl.flags = AINDEX|ADELETE; /* need a single index */ - list = symbol->alist(symbol, & fl); - assert(list != NULL); + if (assoc_empty(symbol)) + return; unref(*lhs); *lhs = list[0]; @@ -785,7 +795,7 @@ do_adump(int nargs) /* asort_actual --- do the actual work to sort the input array */ static NODE * -asort_actual(int nargs, SORT_CTXT ctxt) +asort_actual(int nargs, sort_context_t ctxt) { NODE *array, *dest = NULL, *result; NODE *r, *subs, *s; @@ -838,11 +848,11 @@ asort_actual(int nargs, SORT_CTXT ctxt) } } - num_elems = array->table_size; - if (num_elems > 0) /* sorting happens inside assoc_list */ - list = assoc_list(array, sort_str, ctxt); + /* sorting happens inside assoc_list */ + list = assoc_list(array, sort_str, ctxt); DEREF(s); + num_elems = assoc_length(array); if (num_elems == 0 || list == NULL) { /* source array is empty */ if (dest != NULL && dest != array) @@ -874,6 +884,8 @@ asort_actual(int nargs, SORT_CTXT ctxt) lhs = assoc_lookup(result, subs); unref(*lhs); *lhs = *ptr; + if (result->astore != NULL) + (*result->astore)(result, subs); unref(subs); } } else { @@ -905,6 +917,8 @@ asort_actual(int nargs, SORT_CTXT ctxt) unref(*lhs); *lhs = assoc_copy(r, arr); } + if (result->astore != NULL) + (*result->astore)(result, subs); unref(subs); } } @@ -1237,14 +1251,14 @@ sort_user_func(const void *p1, const void *p2) /* assoc_list -- construct, and optionally sort, a list of array elements */ NODE ** -assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt) +assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt) { typedef int (*qsort_compfunc)(const void *, const void *); static const struct qsort_funcs { const char *name; qsort_compfunc comp_func; - enum assoc_list_flags flags; + assoc_kind_t kind; } sort_funcs[] = { { "@ind_str_asc", sort_up_index_string, AINDEX|AISTR|AASC }, { "@ind_num_asc", sort_up_index_number, AINDEX|AINUM|AASC }, @@ -1265,20 +1279,16 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt) */ NODE **list; - NODE fl; + NODE akind; unsigned long num_elems, j; int elem_size, qi; qsort_compfunc cmp_func = 0; INSTRUCTION *code = NULL; extern int currule; int save_rule = 0; + assoc_kind_t assoc_kind = 0; - num_elems = symbol->table_size; - if (num_elems == 0) - return NULL; - elem_size = 1; - fl.flags = 0; for (qi = 0, j = sizeof(sort_funcs)/sizeof(sort_funcs[0]); qi < j; qi++) { if (strcmp(sort_funcs[qi].name, sort_str) == 0) @@ -1287,15 +1297,15 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt) if (qi < j) { cmp_func = sort_funcs[qi].comp_func; - fl.flags = sort_funcs[qi].flags; + assoc_kind = sort_funcs[qi].kind; if (symbol->array_funcs != cint_array_func) - fl.flags &= ~(AASC|ADESC); + assoc_kind &= ~(AASC|ADESC); - if (sort_ctxt != SORTED_IN || (fl.flags & AVALUE) != 0) { + if (sort_ctxt != SORTED_IN || (assoc_kind & AVALUE) != 0) { /* need index and value pair in the list */ - fl.flags |= (AINDEX|AVALUE); + assoc_kind |= (AINDEX|AVALUE); elem_size = 2; } @@ -1303,8 +1313,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt) NODE *f; const char *sp; - for (sp = sort_str; *sp != '\0' - && ! isspace((unsigned char) *sp); sp++) + for (sp = sort_str; *sp != '\0' && ! isspace((unsigned char) *sp); sp++) continue; /* empty string or string with space(s) not valid as function name */ @@ -1318,7 +1327,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt) cmp_func = sort_user_func; /* need index and value pair in the list */ - fl.flags |= (AVALUE|AINDEX); + assoc_kind |= (AVALUE|AINDEX); elem_size = 2; /* make function call instructions */ @@ -1340,11 +1349,15 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt) PUSH_CODE(code); } - list = symbol->alist(symbol, & fl); + akind.flags = (unsigned int) assoc_kind; /* kludge */ + list = symbol->alist(symbol, & akind); + assoc_kind = (assoc_kind_t) akind.flags; /* symbol->alist can modify it */ - if (list == NULL || ! cmp_func || (fl.flags & (AASC|ADESC)) != 0) + if (list == NULL || ! cmp_func || (assoc_kind & (AASC|ADESC)) != 0) return list; /* empty list or unsorted, or list already sorted */ + num_elems = assoc_length(symbol); + qsort(list, num_elems, elem_size * sizeof(NODE *), cmp_func); /* shazzam! */ if (cmp_func == sort_user_func) { @@ -1354,7 +1367,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt) bcfree(code); /* Op_func_call */ } - if (sort_ctxt == SORTED_IN && (fl.flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) { + if (sort_ctxt == SORTED_IN && (assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) { /* relocate all index nodes to the first half of the list. */ for (j = 1; j < num_elems; j++) list[j] = list[2 * j]; @@ -361,6 +361,7 @@ typedef struct exp_node { Regexp *preg; struct exp_node **av; BUCKET **bv; + void *aq; void (*uptr)(void); struct exp_instruction *iptr; } r; @@ -497,6 +498,7 @@ typedef struct exp_node { /* Node_var_array: */ #define buckets sub.nodep.r.bv #define nodes sub.nodep.r.av +#define a_opaque sub.nodep.r.aq #define array_funcs sub.nodep.l.lp #define array_base sub.nodep.l.ll #define table_size sub.nodep.reflags @@ -507,14 +509,16 @@ typedef struct exp_node { #define ainit array_funcs[0] #define atypeof array_funcs[1] -#define alookup array_funcs[2] -#define aexists array_funcs[3] -#define aclear array_funcs[4] -#define aremove array_funcs[5] -#define alist array_funcs[6] -#define acopy array_funcs[7] -#define adump array_funcs[8] -#define NUM_AFUNCS 9 /* # of entries in array_funcs */ +#define alength array_funcs[2] +#define alookup array_funcs[3] +#define aexists array_funcs[4] +#define aclear array_funcs[5] +#define aremove array_funcs[6] +#define alist array_funcs[7] +#define acopy array_funcs[8] +#define adump array_funcs[9] +#define astore array_funcs[10] +#define NUM_AFUNCS 11 /* # of entries in array_funcs */ /* array func to index mapping */ #define AFUNC(F) (& ((NODE *) 0)->F - ((NODE *) 0)->array_funcs) @@ -654,6 +658,7 @@ typedef enum opcodeval { Op_var_update, /* update value of NR, NF or FNR */ Op_var_assign, Op_field_assign, + Op_subscript_assign, Op_after_beginfile, Op_after_endfile, @@ -1337,7 +1342,8 @@ if (val++) \ if (--val) \ memcpy((char *) tag, (const char *) (stack), sizeof(jmp_buf)) -#define array_empty(a) ((a)->table_size == 0) +#define assoc_length(a) (*((a)->alength(a, NULL)))->table_size +#define assoc_empty(a) (assoc_length(a) == 0) #define assoc_lookup(a, s) (a)->alookup(a, s) /* assoc_clear --- flush all the values in symbol[] */ @@ -1348,7 +1354,7 @@ if (--val) \ #if __GNUC__ >= 2 -#define in_array(a, s) ({ NODE **_l; _l = (a)->aexists(a, s); _l ? *_l : NULL; }) +#define in_array(a, s) ({ NODE **_l = (a)->aexists(a, s); _l ? *_l : NULL; }) #else /* not __GNUC__ */ #define in_array(a, s) r_in_array(a, s) #endif /* __GNUC__ */ @@ -1356,18 +1362,18 @@ if (--val) \ /* ------------- Function prototypes or defs (as appropriate) ------------- */ /* array.c */ -typedef enum sort_context { SORTED_IN = 1, ASORT, ASORTI } SORT_CTXT; -enum assoc_list_flags { -AINDEX = 0x01, /* list of indices */ -AVALUE = 0x02, /* list of values */ -AINUM = 0x04, /* numeric index */ -AISTR = 0x08, /* string index */ -AVNUM = 0x10, /* numeric scalar value */ -AVSTR = 0x20, /* string scalar value */ -AASC = 0x40, /* ascending order */ -ADESC = 0x80, /* descending order */ -ADELETE = 0x100, /* need a single index; for use in do_delete_loop */ -}; +typedef enum { SORTED_IN = 1, ASORT, ASORTI } sort_context_t; +typedef enum { + AINDEX = 0x01, /* list of indices */ + AVALUE = 0x02, /* list of values */ + AINUM = 0x04, /* numeric index */ + AISTR = 0x08, /* string index */ + AVNUM = 0x10, /* numeric scalar value */ + AVSTR = 0x20, /* string scalar value */ + AASC = 0x40, /* ascending order */ + ADESC = 0x80, /* descending order */ + ADELETE = 0x100, /* need a single index; for use in do_delete_loop */ +} assoc_kind_t; extern NODE *make_array(void); extern void null_array(NODE *symbol); @@ -1376,13 +1382,14 @@ extern const char *make_aname(const NODE *symbol); extern const char *array_vname(const NODE *symbol); extern void array_init(void); extern int register_array_func(afunc_t *afunc); +extern NODE **null_length(NODE *symbol, NODE *subs); extern NODE **null_afunc(NODE *symbol, NODE *subs); extern void set_SUBSEP(void); extern NODE *concat_exp(int nargs, int do_subsep); extern NODE *r_in_array(NODE *symbol, NODE *subs); extern NODE *assoc_copy(NODE *symbol, NODE *newsymb); extern void assoc_dump(NODE *symbol, NODE *p); -extern NODE **assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT sort_ctxt); +extern NODE **assoc_list(NODE *symbol, const char *sort_str, sort_context_t sort_ctxt); extern void assoc_info(NODE *subs, NODE *val, NODE *p, const char *aname); extern void do_delete(NODE *symbol, int nsubs); extern void do_delete_loop(NODE *symbol, NODE **lhs); @@ -6387,7 +6387,11 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) subn->lasti->assign_ctxt = Op_sub_builtin; subn->lasti->field_assign = (Func_ptr) 0; ip->target_assign = subn->lasti; + } else if (ip->opcode == Op_subscript_lhs) { + (void) list_append(subn, instruction(Op_subscript_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; } + return subn; } else { @@ -7553,6 +7557,8 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op) (void) list_append(ip, instruction(Op_field_assign)); ip->lasti->field_assign = (Func_ptr) 0; tp->target_assign = ip->lasti; + } else if (tp->opcode == Op_subscript_lhs) { + (void) list_append(ip, instruction(Op_subscript_assign)); } return ip; @@ -7762,7 +7768,11 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype) asgn->assign_ctxt = op->opcode; asgn->field_assign = (Func_ptr) 0; /* determined at run time */ tp->target_assign = asgn; + } else if (tp->opcode == Op_subscript_lhs) { + asgn = instruction(Op_subscript_assign); + asgn->assign_ctxt = op->opcode; } + if (redir != NULL) { ip = list_merge(redir, var); (void) list_append(ip, op); @@ -3690,7 +3690,11 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) subn->lasti->assign_ctxt = Op_sub_builtin; subn->lasti->field_assign = (Func_ptr) 0; ip->target_assign = subn->lasti; + } else if (ip->opcode == Op_subscript_lhs) { + (void) list_append(subn, instruction(Op_subscript_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; } + return subn; } else { @@ -4856,6 +4860,8 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op) (void) list_append(ip, instruction(Op_field_assign)); ip->lasti->field_assign = (Func_ptr) 0; tp->target_assign = ip->lasti; + } else if (tp->opcode == Op_subscript_lhs) { + (void) list_append(ip, instruction(Op_subscript_assign)); } return ip; @@ -5065,7 +5071,11 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype) asgn->assign_ctxt = op->opcode; asgn->field_assign = (Func_ptr) 0; /* determined at run time */ tp->target_assign = asgn; + } else if (tp->opcode == Op_subscript_lhs) { + asgn = instruction(Op_subscript_assign); + asgn->assign_ctxt = op->opcode; } + if (redir != NULL) { ip = list_merge(redir, var); (void) list_append(ip, op); @@ -492,6 +492,7 @@ do_length(int nargs) tmp = POP(); if (tmp->type == Node_var_array) { static short warned = FALSE; + unsigned long size; if (do_posix) fatal(_("length: received array argument")); @@ -499,7 +500,15 @@ do_length(int nargs) warned = TRUE; lintwarn(_("`length(array)' is a gawk extension")); } - return make_number((AWKNUM) tmp->table_size); + + /* + * Support for deferred loading of array elements requires that + * we use the array length interface even though it isn't + * necessary for the built-in array types. + */ + + size = assoc_length(tmp); + return make_number(size); } assert(tmp->type == Node_val); @@ -2450,6 +2459,9 @@ do_match(int nargs) lhs = assoc_lookup(dest, sub); unref(*lhs); *lhs = it; + /* execute post-assignment routine if any */ + if (dest->astore != NULL) + (*dest->astore)(dest, sub); unref(sub); sprintf(buff, "%d", ii); @@ -2473,6 +2485,8 @@ do_match(int nargs) lhs = assoc_lookup(dest, sub); unref(*lhs); *lhs = it; + if (dest->astore != NULL) + (*dest->astore)(dest, sub); unref(sub); memcpy(buf, buff, ilen); @@ -2486,6 +2500,8 @@ do_match(int nargs) lhs = assoc_lookup(dest, sub); unref(*lhs); *lhs = it; + if (dest->astore != NULL) + (*dest->astore)(dest, sub); unref(sub); } } diff --git a/cint_array.c b/cint_array.c index 136f9ad4..9bf4987b 100644 --- a/cint_array.c +++ b/cint_array.c @@ -59,6 +59,7 @@ static void cint_print(NODE *symbol); afunc_t cint_array_func[] = { cint_array_init, is_uinteger, + null_length, cint_lookup, cint_exists, cint_clear, @@ -66,6 +67,7 @@ afunc_t cint_array_func[] = { cint_list, cint_copy, cint_dump, + (afunc_t) 0, }; static inline int cint_hash(long k); @@ -78,7 +80,7 @@ static NODE **tree_exists(NODE *tree, long k); static void tree_clear(NODE *tree); static int tree_remove(NODE *symbol, NODE *tree, long k); static void tree_copy(NODE *newsymb, NODE *tree, NODE *newtree); -static long tree_list(NODE *tree, NODE **list, unsigned int flags); +static long tree_list(NODE *tree, NODE **list, assoc_kind_t assoc_kind); static inline NODE **tree_find(NODE *tree, long k, int i); static void tree_info(NODE *tree, NODE *ndump, const char *aname); static size_t tree_kilobytes(NODE *tree); @@ -91,7 +93,7 @@ static inline NODE **leaf_exists(NODE *array, long k); static void leaf_clear(NODE *array); static int leaf_remove(NODE *symbol, NODE *array, long k); static void leaf_copy(NODE *newsymb, NODE *array, NODE *newarray); -static long leaf_list(NODE *array, NODE **list, unsigned int flags); +static long leaf_list(NODE *array, NODE **list, assoc_kind_t assoc_kind); static void leaf_info(NODE *array, NODE *ndump, const char *aname); #ifdef ARRAYDEBUG static void leaf_print(NODE *array, size_t bi, int indent_level); @@ -418,15 +420,16 @@ cint_list(NODE *symbol, NODE *t) unsigned long k = 0, num_elems, list_size; size_t j, ja, jd; int elem_size = 1; + assoc_kind_t assoc_kind; num_elems = symbol->table_size; if (num_elems == 0) return NULL; - - if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE)) + assoc_kind = (assoc_kind_t) t->flags; + if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE)) num_elems = 1; - if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) + if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) elem_size = 2; list_size = num_elems * elem_size; @@ -434,7 +437,8 @@ cint_list(NODE *symbol, NODE *t) xn = symbol->xarray; list = xn->alist(xn, t); assert(list != NULL); - t->flags &= ~(AASC|ADESC); + assoc_kind &= ~(AASC|ADESC); + t->flags = (unsigned int) assoc_kind; if (num_elems == 1 || num_elems == xn->table_size) return list; erealloc(list, NODE **, list_size * sizeof(NODE *), "cint_list"); @@ -442,18 +446,20 @@ cint_list(NODE *symbol, NODE *t) } else emalloc(list, NODE **, list_size * sizeof(NODE *), "cint_list"); - - if ((t->flags & AINUM) == 0) /* not sorting by "index num" */ - t->flags &= ~(AASC|ADESC); + if ((assoc_kind & AINUM) == 0) { + /* not sorting by "index num" */ + assoc_kind &= ~(AASC|ADESC); + t->flags = (unsigned int) assoc_kind; + } /* populate it with index in ascending or descending order */ for (ja = NHAT, jd = INT32_BIT - 1; ja < INT32_BIT && jd >= NHAT; ) { - j = (t->flags & ADESC) ? jd-- : ja++; + j = (assoc_kind & ADESC) ? jd-- : ja++; tn = symbol->nodes[j]; if (tn == NULL) continue; - k += tree_list(tn, list + k, t->flags); + k += tree_list(tn, list + k, assoc_kind); if (k >= list_size) return list; } @@ -875,7 +881,7 @@ tree_find(NODE *tree, long k, int i) /* tree_list --- return a list of items in the HAT */ static long -tree_list(NODE *tree, NODE **list, unsigned int flags) +tree_list(NODE *tree, NODE **list, assoc_kind_t assoc_kind) { NODE *tn; size_t j, cj, hsize; @@ -888,15 +894,15 @@ tree_list(NODE *tree, NODE **list, unsigned int flags) hsize /= 2; for (j = 0; j < hsize; j++) { - cj = (flags & ADESC) ? (hsize - 1 - j) : j; + cj = (assoc_kind & ADESC) ? (hsize - 1 - j) : j; tn = tree->nodes[cj]; if (tn == NULL) continue; if (tn->type == Node_array_tree) - k += tree_list(tn, list + k, flags); + k += tree_list(tn, list + k, assoc_kind); else - k += leaf_list(tn, list + k, flags); - if ((flags & ADELETE) != 0 && k >= 1) + k += leaf_list(tn, list + k, assoc_kind); + if ((assoc_kind & ADELETE) != 0 && k >= 1) return k; } return k; @@ -1141,7 +1147,7 @@ leaf_copy(NODE *newsymb, NODE *array, NODE *newarray) /* leaf_list --- return a list of items */ static long -leaf_list(NODE *array, NODE **list, unsigned int flags) +leaf_list(NODE *array, NODE **list, assoc_kind_t assoc_kind) { NODE *r, *subs; long num, i, ci, k = 0; @@ -1149,14 +1155,14 @@ leaf_list(NODE *array, NODE **list, unsigned int flags) static char buf[100]; for (i = 0; i < size; i++) { - ci = (flags & ADESC) ? (size - 1 - i) : i; + ci = (assoc_kind & ADESC) ? (size - 1 - i) : i; r = array->nodes[ci]; if (r == NULL) continue; /* index */ num = array->array_base + ci; - if (flags & AISTR) { + if (assoc_kind & AISTR) { sprintf(buf, "%ld", num); subs = make_string(buf, strlen(buf)); subs->numbr = num; @@ -1168,16 +1174,16 @@ leaf_list(NODE *array, NODE **list, unsigned int flags) list[k++] = subs; /* value */ - if (flags & AVALUE) { + if (assoc_kind & AVALUE) { if (r->type == Node_val) { - if ((flags & AVNUM) != 0) + if ((assoc_kind & AVNUM) != 0) (void) force_number(r); - else if ((flags & AVSTR) != 0) + else if ((assoc_kind & AVSTR) != 0) r = force_string(r); } list[k++] = r; } - if ((flags & ADELETE) != 0 && k >= 1) + if ((assoc_kind & ADELETE) != 0 && k >= 1) return k; } @@ -943,7 +943,7 @@ print_symbol(NODE *r, int isparam) valinfo(r->var_value, fprintf, out_fp); break; case Node_var_array: - fprintf(out_fp, "array, %ld elements\n", r->table_size); + fprintf(out_fp, "array, %ld elements\n", assoc_length(r)); break; case Node_func: fprintf(out_fp, "`function'\n"); @@ -1064,12 +1064,12 @@ print_array(volatile NODE *arr, char *arr_name) volatile int ret = 0; volatile jmp_buf pager_quit_tag_stack; - if (array_empty(arr)) { + if (assoc_empty((NODE *) arr)) { gprintf(out_fp, _("array `%s' is empty\n"), arr_name); return 0; } - num_elems = arr->table_size; + num_elems = assoc_length((NODE *) arr); /* sort indices, sub_arrays are also sorted! */ list = assoc_list((NODE *) arr, "@ind_str_asc", SORTED_IN); @@ -1646,7 +1646,7 @@ cmp_val(struct list_item *w, NODE *old, NODE *new) if (new->type == Node_val) /* 7 */ return TRUE; /* new->type == Node_var_array */ /* 8 */ - size = new->table_size; + size = assoc_length(new); if (w->cur_size == size) return FALSE; return TRUE; @@ -1720,7 +1720,7 @@ watchpoint_triggered(struct list_item *w) w->flags &= ~CUR_IS_ARRAY; w->cur_value = dupnode(t2); } else - w->cur_size = (t2->type == Node_var_array) ? t2->table_size : 0; + w->cur_size = (t2->type == Node_var_array) ? assoc_length(t2) : 0; } else if (! t1) { /* 1, 2 */ w->old_value = 0; /* new != NULL */ @@ -1728,7 +1728,7 @@ watchpoint_triggered(struct list_item *w) w->cur_value = dupnode(t2); else { w->flags |= CUR_IS_ARRAY; - w->cur_size = (t2->type == Node_var_array) ? t2->table_size : 0; + w->cur_size = (t2->type == Node_var_array) ? assoc_length(t2) : 0; } } else /* if (t1->type == Node_val) */ { /* 4, 5, 6 */ w->old_value = w->cur_value; @@ -1736,7 +1736,7 @@ watchpoint_triggered(struct list_item *w) w->cur_value = 0; else if (t2->type == Node_var_array) { w->flags |= CUR_IS_ARRAY; - w->cur_size = t2->table_size; + w->cur_size = assoc_length(t2); } else w->cur_value = dupnode(t2); } @@ -1762,7 +1762,7 @@ initialize_watch_item(struct list_item *w) w->cur_value = (NODE *) 0; else if (r->type == Node_var_array) { /* it's a sub-array */ w->flags |= CUR_IS_ARRAY; - w->cur_size = r->table_size; + w->cur_size = assoc_length(r); } else w->cur_value = dupnode(r); } else if (IS_FIELD(w)) { @@ -1779,7 +1779,7 @@ initialize_watch_item(struct list_item *w) w->cur_value = dupnode(r); } else if (symbol->type == Node_var_array) { w->flags |= CUR_IS_ARRAY; - w->cur_size = symbol->table_size; + w->cur_size = assoc_length(symbol); } /* else can't happen */ } @@ -358,6 +358,7 @@ static struct optypetab { { "Op_var_update", NULL }, { "Op_var_assign", NULL }, { "Op_field_assign", NULL }, + { "Op_subscript_assign", NULL }, { "Op_after_beginfile", NULL }, { "Op_after_endfile", NULL }, { "Op_func", NULL }, @@ -939,9 +939,11 @@ set_element(long num, char *s, long len, NODE *n) it->flags |= MAYBE_NUM; sub = make_number((AWKNUM) (num)); lhs = assoc_lookup(n, sub); - unref(sub); unref(*lhs); *lhs = it; + if (n->astore != NULL) + (*n->astore)(n, sub); + unref(sub); } /* do_split --- implement split(), semantics are same as for field splitting */ diff --git a/int_array.c b/int_array.c index bc413c57..7b8b261a 100644 --- a/int_array.c +++ b/int_array.c @@ -48,6 +48,7 @@ static void grow_int_table(NODE *symbol); afunc_t int_array_func[] = { int_array_init, is_integer, + null_length, int_lookup, int_exists, int_clear, @@ -55,6 +56,7 @@ afunc_t int_array_func[] = { int_list, int_copy, int_dump, + (afunc_t) 0, }; @@ -458,15 +460,17 @@ int_list(NODE *symbol, NODE *t) int j, elem_size = 1; long num; static char buf[100]; + assoc_kind_t assoc_kind; if (symbol->table_size == 0) return NULL; + assoc_kind = (assoc_kind_t) t->flags; num_elems = symbol->table_size; - if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE)) + if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE)) num_elems = 1; - if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) + if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) elem_size = 2; list_size = elem_size * num_elems; @@ -488,7 +492,7 @@ int_list(NODE *symbol, NODE *t) for (j = 0; j < b->aicount; j++) { /* index */ num = b->ainum[j]; - if (t->flags & AISTR) { + if (assoc_kind & AISTR) { sprintf(buf, "%ld", num); subs = make_string(buf, strlen(buf)); subs->numbr = num; @@ -500,12 +504,12 @@ int_list(NODE *symbol, NODE *t) list[k++] = subs; /* value */ - if (t->flags & AVALUE) { + if (assoc_kind & AVALUE) { r = b->aivalue[j]; if (r->type == Node_val) { - if ((t->flags & AVNUM) != 0) + if ((assoc_kind & AVNUM) != 0) (void) force_number(r); - else if ((t->flags & AVSTR) != 0) + else if ((assoc_kind & AVSTR) != 0) r = force_string(r); } list[k++] = r; diff --git a/interpret.h b/interpret.h index acb8d219..0b830010 100644 --- a/interpret.h +++ b/interpret.h @@ -37,6 +37,9 @@ r_interpret(INSTRUCTION *code) AWKNUM x, x2; int di; Regexp *rp; + NODE *set_array = NULL; /* array with a post-assignment routine */ + NODE *set_idx = NULL; /* the index of the array element */ + /* array subscript */ #define mk_sub(n) (n == 1 ? POP_SCALAR() : concat_exp(n, TRUE)) @@ -229,6 +232,10 @@ top: *lhs = r; t2 = force_string(t2); r->vname = estrdup(t2->stptr, t2->stlen); /* the subscript in parent array */ + + /* execute post-assignment routine if any */ + if (t1->astore != NULL) + (*t1->astore)(t1, t2); } else if (r->type != Node_var_array) { t2 = force_string(t2); fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"), @@ -258,7 +265,15 @@ top: array_vname(t1), (int) t2->stlen, t2->stptr); } - DEREF(t2); + assert(set_idx == NULL); + + if (t1->astore) { + /* array has post-assignment routine */ + set_array = t1; + set_idx = t2; + } else + DEREF(t2); + PUSH_ADDRESS(lhs); break; @@ -533,9 +548,14 @@ mod: fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"), array_vname(t1), (int) t2->stlen, t2->stptr); } - DEREF(t2); unref(*lhs); *lhs = POP_SCALAR(); + + /* execute post-assignment routine if any */ + if (t1->astore != NULL) + (*t1->astore)(t1, t2); + + DEREF(t2); break; case Op_store_var: @@ -616,6 +636,30 @@ mod: REPLACE(r); break; + case Op_subscript_assign: + /* conditionally execute post-assignment routine for an array element */ + + if (set_idx != NULL) { + di = TRUE; + if (pc->assign_ctxt == Op_sub_builtin + && (r = TOP()) + && get_number_si(r) == 0 /* no substitution performed */ + ) + di = FALSE; + else if ((pc->assign_ctxt == Op_K_getline + || pc->assign_ctxt == Op_K_getline_redir) + && (r = TOP()) + && get_number_si(r) <= 0 /* EOF or error */ + ) + di = FALSE; + + if (di) + (*set_array->astore)(set_array, set_idx); + unref(set_idx); + set_idx = NULL; + } + break; + /* numeric assignments */ case Op_assign_plus: case Op_assign_minus: @@ -720,7 +764,7 @@ mod: array = POP_ARRAY(); /* sanity: check if empty */ - if (array_empty(array)) + if (assoc_empty(array)) goto arrayfor; num_elems = array->table_size; @@ -477,6 +477,7 @@ cleanup: case Op_var_update: case Op_var_assign: case Op_field_assign: + case Op_subscript_assign: case Op_arrayfor_init: case Op_arrayfor_incr: case Op_arrayfor_final: diff --git a/str_array.c b/str_array.c index a452dac6..c6b33c6d 100644 --- a/str_array.c +++ b/str_array.c @@ -58,6 +58,7 @@ static NODE **str_dump(NODE *symbol, NODE *ndump); afunc_t str_array_func[] = { str_array_init, (afunc_t) 0, + null_length, str_lookup, str_exists, str_clear, @@ -65,6 +66,7 @@ afunc_t str_array_func[] = { str_list, str_copy, str_dump, + (afunc_t) 0, }; static inline NODE **str_find(NODE *symbol, NODE *s1, size_t code1, unsigned long hash1); @@ -352,16 +354,18 @@ str_list(NODE *symbol, NODE *t) BUCKET *b; unsigned long num_elems, list_size, i, k = 0; int elem_size = 1; + assoc_kind_t assoc_kind; if (symbol->table_size == 0) return NULL; - if ((t->flags & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) + assoc_kind = (assoc_kind_t) t->flags; + if ((assoc_kind & (AINDEX|AVALUE)) == (AINDEX|AVALUE)) elem_size = 2; /* allocate space for array */ num_elems = symbol->table_size; - if ((t->flags & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE)) + if ((assoc_kind & (AINDEX|AVALUE|ADELETE)) == (AINDEX|ADELETE)) num_elems = 1; list_size = elem_size * num_elems; @@ -373,17 +377,17 @@ str_list(NODE *symbol, NODE *t) for (b = symbol->buckets[i]; b != NULL; b = b->ahnext) { /* index */ subs = b->ahname; - if (t->flags & AINUM) + if (assoc_kind & AINUM) (void) force_number(subs); list[k++] = dupnode(subs); /* value */ - if (t->flags & AVALUE) { + if (assoc_kind & AVALUE) { val = b->ahvalue; if (val->type == Node_val) { - if ((t->flags & AVNUM) != 0) + if ((assoc_kind & AVNUM) != 0) (void) force_number(val); - else if ((t->flags & AVSTR) != 0) + else if ((assoc_kind & AVSTR) != 0) val = force_string(val); } list[k++] = val; @@ -386,7 +386,7 @@ print_vars(NODE **table, int (*print_func)(FILE *, const char *, ...), FILE *fp) continue; print_func(fp, "%s: ", r->vname); if (r->type == Node_var_array) - print_func(fp, "array, %ld elements\n", r->table_size); + print_func(fp, "array, %ld elements\n", assoc_length(r)); else if (r->type == Node_var_new) print_func(fp, "untyped variable\n"); else if (r->type == Node_var) |