/* Look for an iterate-over-plot construct, of the form * {s}plot for [<var> = <start> : <end> { : <increment>}] ... */ void check_for_iteration() { char *errormsg = "Expecting iterator \tfor [<var> = <start> : <end>]\n\t\t\tor\tfor [<var> in \"string of words\"]"; iteration_udv = NULL; free(iteration_string); iteration_string = NULL; iteration_increment = 1; iteration = 0; if (!equals(c_token, "for")) return; c_token++; if (!equals(c_token++, "[") || !isletter(c_token)) int_error(c_token-1, errormsg); iteration_udv = add_udv(c_token++); if (equals(c_token, "=")) { c_token++; iteration_start = int_expression(); if (!equals(c_token++, ":")) int_error(c_token-1, errormsg); iteration_end = int_expression(); if (equals(c_token,":")) { c_token++; iteration_increment = int_expression(); } if (!equals(c_token++, "]")) int_error(c_token-1, errormsg); if (iteration_udv->udv_undef == FALSE) gpfree_string(&iteration_udv->udv_value); Ginteger(&(iteration_udv->udv_value), iteration_start); iteration_udv->udv_undef = FALSE; } else if (equals(c_token++, "in")) { iteration_string = try_to_get_string(); if (!iteration_string) int_error(c_token-1, errormsg); if (!equals(c_token++, "]")) int_error(c_token-1, errormsg); iteration_start = 1; iteration_end = gp_words(iteration_string); if (iteration_udv->udv_undef == FALSE) gpfree_string(&iteration_udv->udv_value); Gstring(&(iteration_udv->udv_value), gp_word(iteration_string, 1)); iteration_udv->udv_undef = FALSE; } else /* Neither [i=B:E] or [s in "foo"] */ int_error(c_token-1, errormsg); iteration_current = iteration_start; }
/* Set up next iteration. * Return TRUE if there is one, FALSE if we're done */ TBOOLEAN next_iteration() { if (!iteration_udv) { iteration = 0; return FALSE; } iteration++; iteration_current += iteration_increment; if (iteration_string) { free(iteration_udv->udv_value.v.string_val); iteration_udv->udv_value.v.string_val = gp_word(iteration_string,iteration_current); } else iteration_udv->udv_value.v.int_val = iteration_current; return iteration_increment && /* no infinite loops! */ ((iteration_end - iteration_current)*iteration_increment >= 0); }
/* Set up next iteration. * Return TRUE if there is one, FALSE if we're done */ TBOOLEAN next_iteration(t_iterator *iter) { t_iterator *this_iter; TBOOLEAN condition = FALSE; if (!iter || iter->empty_iteration) return FALSE; /* Support for nested iteration: * we start with the innermost loop. */ this_iter = iter->prev; /* linked to the last element of the list */ if (!this_iter) return FALSE; while (!iter->really_done && this_iter != iter && this_iter->done) { this_iter->iteration_current = this_iter->iteration_start; this_iter->done = FALSE; if (this_iter->iteration_string) { gpfree_string(&(this_iter->iteration_udv->udv_value)); Gstring(&(this_iter->iteration_udv->udv_value), gp_word(this_iter->iteration_string, this_iter->iteration_current)); } else this_iter->iteration_udv->udv_value.v.int_val = this_iter->iteration_current; this_iter = this_iter->prev; } if (!this_iter->iteration_udv) { this_iter->iteration = 0; return FALSE; } iter->iteration++; /* don't increment if we're at the last iteration */ if (!iter->really_done) this_iter->iteration_current += this_iter->iteration_increment; if (this_iter->iteration_string) { gpfree_string(&(this_iter->iteration_udv->udv_value)); Gstring(&(this_iter->iteration_udv->udv_value), gp_word(this_iter->iteration_string, this_iter->iteration_current)); } else this_iter->iteration_udv->udv_value.v.int_val = this_iter->iteration_current; /* Mar 2014 revised to avoid integer overflow */ if (this_iter->iteration_increment > 0 && this_iter->iteration_end - this_iter->iteration_current < this_iter->iteration_increment) this_iter->done = TRUE; else if (this_iter->iteration_increment < 0 && this_iter->iteration_end - this_iter->iteration_current > this_iter->iteration_increment) this_iter->done = TRUE; else this_iter->done = FALSE; /* We return false only if we're, um, really done */ this_iter = iter; while (this_iter) { condition = condition || (!this_iter->done); this_iter = this_iter->next; } if (!condition) { if (!iter->really_done) { iter->really_done = TRUE; condition = TRUE; } else condition = FALSE; } return condition; }
/* Look for iterate-over-plot constructs, of the form * for [<var> = <start> : <end> { : <increment>}] ... * If one (or more) is found, an iterator structure is allocated and filled * and a pointer to that structure is returned. * The pointer is NULL if no "for" statements are found. */ t_iterator * check_for_iteration() { char *errormsg = "Expecting iterator \tfor [<var> = <start> : <end> {: <incr>}]\n\t\t\tor\tfor [<var> in \"string of words\"]"; int nesting_depth = 0; t_iterator *iter = NULL; t_iterator *this_iter = NULL; /* Now checking for iteration parameters */ /* Nested "for" statements are supported, each one corresponds to a node of the linked list */ while (equals(c_token, "for")) { struct udvt_entry *iteration_udv = NULL; char *iteration_string = NULL; int iteration_start; int iteration_end; int iteration_increment = 1; int iteration_current; int iteration = 0; TBOOLEAN empty_iteration; TBOOLEAN just_once = FALSE; c_token++; if (!equals(c_token++, "[") || !isletter(c_token)) int_error(c_token-1, errormsg); iteration_udv = add_udv(c_token++); if (equals(c_token, "=")) { c_token++; iteration_start = int_expression(); if (!equals(c_token++, ":")) int_error(c_token-1, errormsg); iteration_end = int_expression(); if (equals(c_token,":")) { c_token++; iteration_increment = int_expression(); if (iteration_increment == 0) int_error(c_token-1, errormsg); } if (!equals(c_token++, "]")) int_error(c_token-1, errormsg); if (iteration_udv->udv_undef == FALSE) gpfree_string(&(iteration_udv->udv_value)); Ginteger(&(iteration_udv->udv_value), iteration_start); iteration_udv->udv_undef = FALSE; } else if (equals(c_token++, "in")) { iteration_string = try_to_get_string(); if (!iteration_string) int_error(c_token-1, errormsg); if (!equals(c_token++, "]")) int_error(c_token-1, errormsg); iteration_start = 1; iteration_end = gp_words(iteration_string); if (iteration_udv->udv_undef == FALSE) gpfree_string(&(iteration_udv->udv_value)); Gstring(&(iteration_udv->udv_value), gp_word(iteration_string, 1)); iteration_udv->udv_undef = FALSE; } else /* Neither [i=B:E] or [s in "foo"] */ int_error(c_token-1, errormsg); iteration_current = iteration_start; empty_iteration = FALSE; if ( (iteration_udv != NULL) && ((iteration_end > iteration_start && iteration_increment < 0) || (iteration_end < iteration_start && iteration_increment > 0))) { empty_iteration = TRUE; FPRINTF((stderr,"Empty iteration\n")); } /* Allocating a node of the linked list nested iterations. */ /* Iterating just once is the same as not iterating at all */ /* so we skip building the node in that case. */ if (iteration_start == iteration_end) just_once = TRUE; if (iteration_start < iteration_end && iteration_end < iteration_start + iteration_increment) just_once = TRUE; if (iteration_start > iteration_end && iteration_end > iteration_start + iteration_increment) just_once = TRUE; if (!just_once) { this_iter = gp_alloc(sizeof(t_iterator), "iteration linked list"); this_iter->iteration_udv = iteration_udv; this_iter->iteration_string = iteration_string; this_iter->iteration_start = iteration_start; this_iter->iteration_end = iteration_end; this_iter->iteration_increment = iteration_increment; this_iter->iteration_current = iteration_current; this_iter->iteration = iteration; this_iter->done = FALSE; this_iter->really_done = FALSE; this_iter->empty_iteration = empty_iteration; this_iter->next = NULL; this_iter->prev = NULL; if (nesting_depth == 0) { /* first "for" statement: this will be the listhead */ iter = this_iter; } else { /* not the first "for" statement: attach the newly created node to the end of the list */ iter->prev->next = this_iter; /* iter->prev points to the last node of the list */ this_iter->prev = iter->prev; } iter->prev = this_iter; /* a shortcut: making the list circular */ /* if one iteration in the chain is empty, the subchain of nested iterations is too */ if (!iter->empty_iteration) iter->empty_iteration = empty_iteration; nesting_depth++; } } return iter; }
/* Set up next iteration. * Return TRUE if there is one, FALSE if we're done */ TBOOLEAN next_iteration(t_iterator *iter) { t_iterator *this_iter; TBOOLEAN condition = FALSE; if (!iter || iter->empty_iteration) return FALSE; /* Support for nested iteration: * we start with the innermost loop. */ this_iter = iter->prev; /* linked to the last element of the list */ if (!this_iter) return FALSE; while (!iter->really_done && this_iter != iter && this_iter->done) { this_iter->iteration_current = this_iter->iteration_start; this_iter->done = FALSE; if (this_iter->iteration_string) { free(this_iter->iteration_udv->udv_value.v.string_val); this_iter->iteration_udv->udv_value.v.string_val = gp_word(this_iter->iteration_string, this_iter->iteration_current); } else this_iter->iteration_udv->udv_value.v.int_val = this_iter->iteration_current; this_iter = this_iter->prev; } if (!this_iter->iteration_udv) { this_iter->iteration = 0; return FALSE; } iter->iteration++; /* don't increment if we're at the last iteration */ if (!iter->really_done) this_iter->iteration_current += this_iter->iteration_increment; if (this_iter->iteration_string) { free(this_iter->iteration_udv->udv_value.v.string_val); this_iter->iteration_udv->udv_value.v.string_val = gp_word(this_iter->iteration_string, this_iter->iteration_current); } else this_iter->iteration_udv->udv_value.v.int_val = this_iter->iteration_current; /* no need to check for increment <> 0 here, * because that case was already caught in check_for_iteration */ this_iter->done = !((this_iter->iteration_end - this_iter->iteration_current - this_iter->iteration_increment) * this_iter->iteration_increment >= 0); /* We return false only if we're, erm, really done */ this_iter = iter; while (this_iter) { condition = condition || (!this_iter->done); this_iter = this_iter->next; } if (!condition) { if (!iter->really_done) { iter->really_done = TRUE; condition = TRUE; } else condition = FALSE; } return condition; }