From: Ben Pfaff Date: Sat, 11 Dec 2021 05:02:57 +0000 (-0800) Subject: better X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d8c45134836523c1a547a29a5738e642f5462c8f;p=pspp better --- diff --git a/src/data/transformations.c b/src/data/transformations.c index 999638c527..f1cfaf47c9 100644 --- a/src/data/transformations.c +++ b/src/data/transformations.c @@ -90,7 +90,6 @@ trns_chain_execute (const struct trns_chain *chain, for (size_t i = 0; i < chain->n; i++) { const struct transformation *trns = &chain->xforms[i]; - printf ("%s\n", trns->class->name); int retval = trns->class->execute (trns->aux, c, case_nr); if (retval != TRNS_CONTINUE) return retval; diff --git a/src/language/command.c b/src/language/command.c index 15b7651967..09c951cae2 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -86,13 +86,15 @@ cmd_result_is_failure (enum cmd_result result) /* Command processing states. */ enum states { - S_INITIAL = 1 << 0, /* Allowed before active dataset defined. */ - S_DATA = 1 << 1, /* Allowed after active dataset defined. */ - S_INPUT_PROGRAM = 1 << 2, /* Allowed in INPUT PROGRAM. */ - S_FILE_TYPE = 1 << 3, /* Allowed in FILE TYPE. */ - S_NESTED = 1 << 4, /* Allowed in LOOP and DO IF. */ - - S_ANY = S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE | S_NESTED, + S_INITIAL = 1 << CMD_STATE_INITIAL, + S_DATA = 1 << CMD_STATE_DATA, + S_INPUT_PROGRAM = 1 << CMD_STATE_INPUT_PROGRAM, + S_FILE_TYPE = 1 << CMD_STATE_FILE_TYPE, + S_NESTED_DATA = 1 << CMD_STATE_NESTED_DATA, + S_NESTED_INPUT_PROGRAM = 1 << CMD_STATE_NESTED_INPUT_PROGRAM, + + S_NESTED_ANY = S_NESTED_DATA | S_NESTED_INPUT_PROGRAM, + S_ANY = S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE | S_NESTED_ANY, }; /* Other command requirements. */ @@ -359,26 +361,7 @@ parse_command_name (struct lexer *lexer, int *n_tokens) static bool in_correct_state (const struct command *command, enum cmd_state state) { - switch (state) - { - case CMD_STATE_INITIAL: - return command->states & S_INITIAL; - - case CMD_STATE_DATA: - return command->states & S_DATA; - - case CMD_STATE_INPUT_PROGRAM: - return command->states & S_INPUT_PROGRAM; - - case CMD_STATE_FILE_TYPE: - return command->states & S_FILE_TYPE; - - case CMD_STATE_NESTED: - return command->states & S_NESTED; - - default: - NOT_REACHED (); - } + return command->states & (1 << state); } /* Emits an appropriate error message for trying to invoke @@ -469,8 +452,22 @@ report_state_mismatch (const struct command *command, enum cmd_state state) msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE"); break; - case CMD_STATE_NESTED: - msg (SE, _("%s is not allowed inside DO IF or LOOP."), command->name); + case CMD_STATE_NESTED_DATA: + case CMD_STATE_NESTED_INPUT_PROGRAM: + switch ((int) command->states & S_NESTED_ANY) + { + case 0: + msg (SE, _("%s is not allowed inside DO IF or LOOP."), command->name); + break; + + case S_NESTED_DATA: + msg (SE, _("In INPUT PROGRAM, " + "%s is not allowed inside DO IF or LOOP."), command->name); + break; + + default: + NOT_REACHED (); + } break; } } diff --git a/src/language/command.def b/src/language/command.def index 53a23a2c90..b588552244 100644 --- a/src/language/command.def +++ b/src/language/command.def @@ -65,46 +65,48 @@ DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET NAME", cmd_dataset_name) DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET DISPLAY", cmd_dataset_display) /* Utilities that may appear after active file definition or within INPUT PROGRAM. */ -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "ADD VALUE LABELS", cmd_add_value_labels) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "ADD DOCUMENT", cmd_add_documents) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "APPLY DICTIONARY", cmd_apply_dictionary) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DATAFILE ATTRIBUTE", cmd_datafile_attribute) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DISPLAY", cmd_display) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DOCUMENT", cmd_document) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DROP DOCUMENTS", cmd_drop_documents) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "FORMATS", cmd_formats) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "LEAVE", cmd_leave) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "MISSING VALUES", cmd_missing_values) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "MRSETS", cmd_mrsets) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "PRINT FORMATS", cmd_print_formats) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "SPLIT FILE", cmd_split_file) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VALUE LABELS", cmd_value_labels) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE ALIGNMENT", cmd_variable_alignment) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE ATTRIBUTE", cmd_variable_attribute) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE LABELS", cmd_variable_labels) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE LEVEL", cmd_variable_level) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE ROLE", cmd_variable_role) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VARIABLE WIDTH", cmd_variable_width) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "VECTOR", cmd_vector) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "WEIGHT", cmd_weight) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "WRITE FORMATS", cmd_write_formats) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "ADD VALUE LABELS", cmd_add_value_labels) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "ADD DOCUMENT", cmd_add_documents) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "APPLY DICTIONARY", cmd_apply_dictionary) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "DATAFILE ATTRIBUTE", cmd_datafile_attribute) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "DISPLAY", cmd_display) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "DOCUMENT", cmd_document) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "DROP DOCUMENTS", cmd_drop_documents) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "FORMATS", cmd_formats) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "LEAVE", cmd_leave) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "MISSING VALUES", cmd_missing_values) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "MRSETS", cmd_mrsets) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "PRINT FORMATS", cmd_print_formats) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "SPLIT FILE", cmd_split_file) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "VALUE LABELS", cmd_value_labels) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "VARIABLE ALIGNMENT", cmd_variable_alignment) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "VARIABLE ATTRIBUTE", cmd_variable_attribute) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "VARIABLE LABELS", cmd_variable_labels) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "VARIABLE LEVEL", cmd_variable_level) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "VARIABLE ROLE", cmd_variable_role) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "VARIABLE WIDTH", cmd_variable_width) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "VECTOR", cmd_vector) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "WEIGHT", cmd_weight) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "WRITE FORMATS", cmd_write_formats) /* Transformations. */ -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "BREAK", cmd_break) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "COMPUTE", cmd_compute) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "DO IF", cmd_do_if) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "IF", cmd_if) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "LOOP", cmd_loop) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "NUMERIC", cmd_numeric) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "PRINT EJECT", cmd_print_eject) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "PRINT SPACE", cmd_print_space) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "PRINT", cmd_print) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "RECODE", cmd_recode) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "SELECT IF", cmd_select_if) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "STRING", cmd_string) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "WRITE", cmd_write) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, F_ENHANCED, "XEXPORT", cmd_xexport) -DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "XSAVE", cmd_xsave) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "BREAK", cmd_break) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "COMPUTE", cmd_compute) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "DO IF", cmd_do_if) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "IF", cmd_if) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "LOOP", cmd_loop) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "NUMERIC", cmd_numeric) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "PRINT EJECT", cmd_print_eject) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "PRINT SPACE", cmd_print_space) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "PRINT", cmd_print) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "RECODE", cmd_recode) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "STRING", cmd_string) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "WRITE", cmd_write) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, F_ENHANCED, "XEXPORT", cmd_xexport) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED_ANY, 0, "XSAVE", cmd_xsave) + +/* Restricted transformations. */ +DEF_CMD (S_DATA | S_NESTED_DATA, 0, "SELECT IF", cmd_select_if) /* Commands that may appear after active dataset definition. */ DEF_CMD (S_DATA, 0, "AGGREGATE", cmd_aggregate) @@ -148,9 +150,9 @@ DEF_CMD (S_DATA, 0, "TEMPORARY", cmd_temporary) DEF_CMD (S_DATA, 0, "USE", cmd_use) /* Commands valid only with INPUT PROGRAM. */ -DEF_CMD (S_INPUT_PROGRAM | S_NESTED, 0, "END CASE", cmd_end_case) -DEF_CMD (S_INPUT_PROGRAM | S_NESTED, 0, "END FILE", cmd_end_file) -DEF_CMD (S_INPUT_PROGRAM | S_NESTED, 0, "REREAD", cmd_reread) +DEF_CMD (S_INPUT_PROGRAM | S_NESTED_INPUT_PROGRAM, 0, "END CASE", cmd_end_case) +DEF_CMD (S_INPUT_PROGRAM | S_NESTED_INPUT_PROGRAM, 0, "END FILE", cmd_end_file) +DEF_CMD (S_INPUT_PROGRAM | S_NESTED_INPUT_PROGRAM, 0, "REREAD", cmd_reread) /* Commands for testing PSPP. */ DEF_CMD (S_ANY, F_TESTING, "DEBUG EXPAND", cmd_debug_expand) diff --git a/src/language/command.h b/src/language/command.h index f38ed5cdb9..ecd2a75265 100644 --- a/src/language/command.h +++ b/src/language/command.h @@ -43,7 +43,10 @@ enum cmd_state CMD_STATE_DATA, /* Active dataset has been defined. */ CMD_STATE_INPUT_PROGRAM, /* Inside INPUT PROGRAM. */ CMD_STATE_FILE_TYPE, /* Inside FILE TYPE. */ - CMD_STATE_NESTED, /* Inside LOOP or DO IF. */ + + /* Inside LOOP or DO IF... */ + CMD_STATE_NESTED_DATA, /* ...in CMD_STATE_DATA. */ + CMD_STATE_NESTED_INPUT_PROGRAM, /* ...in CMD_STATE_INPUT_PROGRAM. */ }; struct dataset; diff --git a/src/language/control/do-if.c b/src/language/control/do-if.c index efe4667753..f4fab4734c 100644 --- a/src/language/control/do-if.c +++ b/src/language/control/do-if.c @@ -21,6 +21,7 @@ #include "data/dataset.h" #include "data/transformations.h" #include "language/command.h" +#include "language/data-io/inpt-pgm.h" #include "language/expressions/public.h" #include "language/lexer/lexer.h" #include "libpspp/compiler.h" @@ -45,6 +46,9 @@ struct do_if_trns { struct clause *clauses; /* Clauses. */ size_t n_clauses; /* Number of clauses. */ + + const struct trns_chain *resume; + size_t ofs; }; static const struct trns_class do_if_trns_class; @@ -127,7 +131,10 @@ cmd_do_if (struct lexer *lexer, struct dataset *ds) start_clause (lexer, ds, false, do_if, &allocated_clauses, &ok); } else - cmd_parse_in_state (lexer, ds, CMD_STATE_NESTED); + cmd_parse_in_state (lexer, ds, + (in_input_program () + ? CMD_STATE_NESTED_INPUT_PROGRAM + : CMD_STATE_NESTED_DATA)); } finish_clause (ds, do_if); @@ -136,32 +143,69 @@ cmd_do_if (struct lexer *lexer, struct dataset *ds) return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE; } -/* DO IF transformation procedure. - Checks each clause and jumps to the appropriate - transformation. */ +static const struct trns_chain * +do_if_find_clause (const struct do_if_trns *do_if, + struct ccase *c, casenumber case_num) +{ + for (size_t i = 0; i < do_if->n_clauses; i++) + { + const struct clause *clause = &do_if->clauses[i]; + if (!clause->condition) + return &clause->xforms; + + double boolean = expr_evaluate_num (clause->condition, c, case_num); + if (boolean != 0.0) + return boolean == SYSMIS ? NULL : &clause->xforms; + } + return NULL; +} + static enum trns_result do_if_trns_proc (void *do_if_, struct ccase **c, casenumber case_num) { struct do_if_trns *do_if = do_if_; - for (size_t i = 0; i < do_if->n_clauses; i++) + const struct trns_chain *chain; + size_t start; + if (do_if->resume) { - const struct clause *clause = &do_if->clauses[i]; - if (clause->condition != NULL) + chain = do_if->resume; + start = do_if->ofs; + do_if->resume = NULL; + do_if->ofs = 0; + } + else + { + chain = do_if_find_clause (do_if, *c, case_num); + if (!chain) + return TRNS_CONTINUE; + start = 0; + } + + for (size_t i = start; i < chain->n; i++) + { + const struct transformation *trns = &chain->xforms[i]; + enum trns_result r = trns->class->execute (trns->aux, c, case_num); + switch (r) { - double boolean = expr_evaluate_num (clause->condition, *c, case_num); - if (boolean == 0.0) - continue; - else if (boolean == SYSMIS) - return TRNS_CONTINUE; - } + case TRNS_CONTINUE: + break; - return trns_chain_execute (&clause->xforms, case_num, c); + case TRNS_BREAK: + case TRNS_DROP_CASE: + case TRNS_ERROR: + case TRNS_END_FILE: + return r; + + case TRNS_END_CASE: + do_if->resume = chain; + do_if->ofs = i; + return r; + } } return TRNS_CONTINUE; } -/* Frees a DO IF transformation. */ static bool do_if_trns_free (void *do_if_) { diff --git a/src/language/control/loop.c b/src/language/control/loop.c index f081c761c7..22c73519de 100644 --- a/src/language/control/loop.c +++ b/src/language/control/loop.c @@ -25,8 +25,10 @@ #include "data/transformations.h" #include "data/variable.h" #include "language/command.h" +#include "language/data-io/inpt-pgm.h" #include "language/expressions/public.h" #include "language/lexer/lexer.h" +#include "libpspp/assertion.h" #include "libpspp/compiler.h" #include "libpspp/message.h" #include "libpspp/misc.h" @@ -41,10 +43,10 @@ struct loop_trns { /* a=a TO b [BY c]. */ - struct variable *index_var; /* Index variable. */ - struct expression *first; /* Starting index. */ - struct expression *by; /* Index increment (or NULL). */ - struct expression *last; /* Terminal index. */ + struct variable *index_var; /* Index variable. */ + struct expression *first_expr; /* Starting index. */ + struct expression *by_expr; /* Index increment (or NULL). */ + struct expression *last_expr; /* Terminal index. */ /* IF condition for LOOP or END LOOP. */ struct expression *loop_condition; @@ -52,6 +54,11 @@ struct loop_trns /* Inner transformations. */ struct trns_chain xforms; + + /* State. */ + double cur, by, last; /* Index data. */ + int iteration; /* For MXLOOPS. */ + size_t resume_idx; /* For resuming after END CASE. */ }; static struct trns_class loop_trns_class; @@ -70,7 +77,7 @@ int cmd_loop (struct lexer *lexer, struct dataset *ds) { struct loop_trns *loop = xmalloc (sizeof *loop); - *loop = (struct loop_trns) { .index_var = NULL }; + *loop = (struct loop_trns) { .resume_idx = SIZE_MAX }; bool ok = true; while (lex_token (lexer) != T_ENDCMD && ok) @@ -99,11 +106,13 @@ cmd_loop (struct lexer *lexer, struct dataset *ds) break; } else - cmd_parse_in_state (lexer, ds, CMD_STATE_NESTED); + cmd_parse_in_state (lexer, ds, + (in_input_program () + ? CMD_STATE_NESTED_INPUT_PROGRAM + : CMD_STATE_NESTED_DATA)); } in_loop--; proc_pop_transformations (ds, &loop->xforms); - printf ("%zu loop transvformations\n", loop->xforms.n); add_transformation (ds, &loop_trns_class, loop); @@ -180,30 +189,30 @@ parse_index_clause (struct dataset *ds, struct lexer *lexer, if (!lex_force_match (lexer, T_EQUALS)) return false; - loop->first = expr_parse (lexer, ds, VAL_NUMERIC); - if (loop->first == NULL) + loop->first_expr = expr_parse (lexer, ds, VAL_NUMERIC); + if (loop->first_expr == NULL) return false; for (;;) { struct expression **e; if (lex_match (lexer, T_TO)) - e = &loop->last; + e = &loop->last_expr; else if (lex_match (lexer, T_BY)) - e = &loop->by; + e = &loop->by_expr; else break; if (*e != NULL) { - lex_sbc_only_once (e == &loop->last ? "TO" : "BY"); + lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY"); return false; } *e = expr_parse (lexer, ds, VAL_NUMERIC); if (*e == NULL) return false; } - if (loop->last == NULL) + if (loop->last_expr == NULL) { lex_sbc_missing ("TO"); return false; @@ -218,39 +227,69 @@ loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num) { struct loop_trns *loop = loop_; - double cur, by, last; + size_t start_idx = loop->resume_idx; + loop->resume_idx = SIZE_MAX; + if (start_idx != SIZE_MAX) + goto resume; + if (loop->index_var) { /* Evaluate loop index expressions. */ - cur = expr_evaluate_num (loop->first, *c, case_num); - by = loop->by ? expr_evaluate_num (loop->by, *c, case_num) : 1.0; - last = expr_evaluate_num (loop->last, *c, case_num); + loop->cur = expr_evaluate_num (loop->first_expr, *c, case_num); + loop->by = (loop->by_expr + ? expr_evaluate_num (loop->by_expr, *c, case_num) + : 1.0); + loop->last = expr_evaluate_num (loop->last_expr, *c, case_num); /* Even if the loop is never entered, set the index variable to the initial value. */ *c = case_unshare (*c); - *case_num_rw (*c, loop->index_var) = cur; + *case_num_rw (*c, loop->index_var) = loop->cur; /* Throw out pathological cases. */ - if (!isfinite (cur) || !isfinite (by) || !isfinite (last) - || by == 0.0 - || (by > 0.0 && cur > last) - || (by < 0.0 && cur < last)) + if (!isfinite (loop->cur) + || !isfinite (loop->by) + || !isfinite (loop->last) + || loop->by == 0.0 + || (loop->by > 0.0 && loop->cur > loop->last) + || (loop->by < 0.0 && loop->cur < loop->last)) return TRNS_CONTINUE; } - else - cur = by = last = 0.0; - for (int i = 0; loop->index_var || i < settings_get_mxloops (); i++) + for (loop->iteration = 0; + loop->index_var || loop->iteration < settings_get_mxloops (); + loop->iteration++) { - printf ("loop %g %g %g\n", cur, by, last); if (loop->loop_condition && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0) break; - enum trns_result r = trns_chain_execute (&loop->xforms, case_num, c); - if (r != TRNS_CONTINUE) - return r == TRNS_BREAK ? TRNS_CONTINUE : r; + start_idx = 0; + resume: + for (size_t i = start_idx; i < loop->xforms.n; i++) + { + const struct transformation *trns = &loop->xforms.xforms[i]; + enum trns_result r = trns->class->execute (trns->aux, c, case_num); + switch (r) + { + case TRNS_CONTINUE: + break; + + case TRNS_BREAK: + return TRNS_CONTINUE; + + case TRNS_END_CASE: + loop->resume_idx = i; + return TRNS_END_CASE; + + case TRNS_ERROR: + case TRNS_END_FILE: + return r; + + case TRNS_DROP_CASE: + NOT_REACHED (); + } + } if (loop->end_loop_condition != NULL && expr_evaluate_num (loop->end_loop_condition, *c, case_num) != 0.0) @@ -258,12 +297,12 @@ loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num) if (loop->index_var) { - cur += by; - if (by > 0.0 ? cur > last : cur < last) + loop->cur += loop->by; + if (loop->by > 0.0 ? loop->cur > loop->last : loop->cur < loop->last) break; *c = case_unshare (*c); - *case_num_rw (*c, loop->index_var) = cur; + *case_num_rw (*c, loop->index_var) = loop->cur; } } return TRNS_CONTINUE; @@ -275,9 +314,9 @@ loop_trns_free (void *loop_) { struct loop_trns *loop = loop_; - expr_free (loop->first); - expr_free (loop->by); - expr_free (loop->last); + expr_free (loop->first_expr); + expr_free (loop->by_expr); + expr_free (loop->last_expr); expr_free (loop->loop_condition); expr_free (loop->end_loop_condition); diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index 55b19cbf5e..03345003b7 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -84,7 +84,7 @@ in_input_program (void) static void emit_END_CASE (struct dataset *ds) { - add_transformation (ds, &end_case_trns_class, NULL); + add_transformation (ds, &end_case_trns_class, xzalloc (sizeof (bool))); } int @@ -165,10 +165,8 @@ input_program_casereader_read (struct casereader *reader UNUSED, void *inp_) struct ccase *c = case_create (inp->proto); caseinit_init_vars (inp->init, c); - printf ("%s:%d\n", __FILE__, __LINE__); for (size_t i = inp->idx < inp->xforms.n ? inp->idx : 0; ; i++) { - printf ("%s:%d %zu\n", __FILE__, __LINE__, i); if (i >= inp->xforms.n) { i = 0; @@ -181,23 +179,19 @@ input_program_casereader_read (struct casereader *reader UNUSED, void *inp_) switch (trns->class->execute (trns->aux, &c, inp->case_nr)) { case TRNS_END_CASE: - printf ("END CASE\n"); inp->case_nr++; - inp->idx = i + 1; + inp->idx = i; return c; case TRNS_ERROR: - printf ("ERROR\n"); casereader_force_error (reader); /* Fall through. */ case TRNS_END_FILE: - printf ("END FILE\n"); inp->eof = true; case_unref (c); return NULL; case TRNS_CONTINUE: - printf ("CONTINUE\n"); break; default: @@ -246,16 +240,26 @@ cmd_end_case (struct lexer *lexer UNUSED, struct dataset *ds) /* Outputs the current case */ static enum trns_result -end_case_trns_proc (void *aux UNUSED, struct ccase **c UNUSED, +end_case_trns_proc (void *resume_, struct ccase **c UNUSED, casenumber case_nr UNUSED) { - printf ("%s:%d\n", __FILE__, __LINE__); - return TRNS_END_CASE; + bool *resume = resume_; + enum trns_result retval = *resume ? TRNS_CONTINUE : TRNS_END_CASE; + *resume = !*resume; + return retval; +} + +static bool +end_case_trns_free (void *resume) +{ + free (resume); + return true; } static const struct trns_class end_case_trns_class = { .name = "END CASE", .execute = end_case_trns_proc, + .destroy = end_case_trns_free, }; /* REREAD transformation. */