From: Ben Pfaff Date: Fri, 10 Dec 2021 06:23:59 +0000 (-0800) Subject: Work toward getting rid of finalizers and control stacks and jumping around among... X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0aae014cd74bc4ff005f87d7bac7901ccd2d8224;p=pspp Work toward getting rid of finalizers and control stacks and jumping around among transformations --- diff --git a/src/data/dataset.c b/src/data/dataset.c index 8b3332ec0d..2ffc4eb423 100644 --- a/src/data/dataset.c +++ b/src/data/dataset.c @@ -425,7 +425,6 @@ proc_open_filtering (struct dataset *ds, bool filter) add_case_limit_trns (ds); if (filter) add_filter_trns (ds); - trns_chain_finalize (ds->cur_trns_chain); /* Make permanent_dict refer to the dictionary right before data reaches the sink. */ @@ -694,30 +693,6 @@ add_transformation (struct dataset *ds, trns_proc_func *proc, trns_free_func *fr dataset_transformations_changed__ (ds, true); } -/* Adds a transformation that processes a case with PROC and - frees itself with FREE to the current set of transformations. - When parsing of the block of transformations is complete, - FINALIZE will be called. - The functions are passed AUX as auxiliary data. */ -void -add_transformation_with_finalizer (struct dataset *ds, - trns_finalize_func *finalize, - trns_proc_func *proc, - trns_free_func *free, void *aux) -{ - trns_chain_append (ds->cur_trns_chain, finalize, proc, free, aux); - dataset_transformations_changed__ (ds, true); -} - -/* Returns the index of the next transformation. - This value can be returned by a transformation procedure - function to indicate a "jump" to that transformation. */ -size_t -next_transformation (const struct dataset *ds) -{ - return trns_chain_next (ds->cur_trns_chain); -} - /* Returns true if the next call to add_transformation() will add a temporary transformation, false if it will add a permanent transformation. */ @@ -739,7 +714,6 @@ proc_start_temporary_transformations (struct dataset *ds) ds->permanent_dict = dict_clone (ds->dict); - trns_chain_finalize (ds->permanent_trns_chain); ds->temporary_trns_chain = ds->cur_trns_chain = trns_chain_create (); dataset_transformations_changed__ (ds, true); } @@ -758,7 +732,6 @@ proc_make_temporary_transformations_permanent (struct dataset *ds) { if (proc_in_temporary_transformations (ds)) { - trns_chain_finalize (ds->temporary_trns_chain); trns_chain_splice (ds->permanent_trns_chain, ds->temporary_trns_chain); ds->temporary_trns_chain = NULL; @@ -811,7 +784,7 @@ proc_cancel_all_transformations (struct dataset *ds) return ok; } -static int +static enum trns_result store_case_num (void *var_, struct ccase **cc, casenumber case_num) { struct variable *var = var_; @@ -836,7 +809,6 @@ add_permanent_ordering_transformation (struct dataset *ds) perm_var = dict_clone_var_in_place_assert (ds->permanent_dict, temp_var); trns_chain_append (ds->permanent_trns_chain, NULL, store_case_num, NULL, perm_var); - trns_chain_finalize (ds->permanent_trns_chain); } else add_transformation (ds, store_case_num, NULL, temp_var); @@ -897,7 +869,7 @@ add_case_limit_trns (struct dataset *ds) /* Limits the maximum number of cases processed to *CASES_REMAINING. */ -static int +static enum trns_result case_limit_trns_proc (void *cases_remaining_, struct ccase **c UNUSED, casenumber case_nr UNUSED) { @@ -936,7 +908,7 @@ add_filter_trns (struct dataset *ds) } /* FILTER transformation. */ -static int +static enum trns_result filter_trns_proc (void *filter_var_, struct ccase **c, casenumber case_nr UNUSED) diff --git a/src/data/dataset.h b/src/data/dataset.h index ce8b980d2e..fec342ef62 100644 --- a/src/data/dataset.h +++ b/src/data/dataset.h @@ -26,6 +26,7 @@ struct casereader; struct dataset; struct dictionary; struct session; +struct transformation; struct dataset *dataset_create (struct session *, const char *); struct dataset *dataset_clone (struct dataset *, const char *); @@ -80,14 +81,12 @@ void dataset_set_display (struct dataset *, enum dataset_display); void add_transformation (struct dataset *ds, trns_proc_func *, trns_free_func *, void *); -void add_transformation_with_finalizer (struct dataset *ds, - trns_finalize_func *, - trns_proc_func *, - trns_free_func *, void *); -size_t next_transformation (const struct dataset *ds); bool proc_cancel_all_transformations (struct dataset *ds); struct trns_chain *proc_capture_transformations (struct dataset *ds); +void proc_push_transformations (struct dataset *); +void proc_pop_transformations (struct dataset *, struct transformation **, + size_t *n); void proc_start_temporary_transformations (struct dataset *ds); bool proc_in_temporary_transformations (const struct dataset *ds); diff --git a/src/data/transformations.c b/src/data/transformations.c index cd5c6a188c..4501b90f0b 100644 --- a/src/data/transformations.c +++ b/src/data/transformations.c @@ -32,7 +32,6 @@ struct transformation transformation index. Normally 0 but set to the starting index of a spliced chain after splicing. */ int idx_ofs; - trns_finalize_func *finalize; /* Finalize proc. */ trns_proc_func *execute; /* Executes the transformation. */ trns_free_func *free; /* Garbage collector proc. */ void *aux; /* Auxiliary data. */ @@ -44,7 +43,6 @@ struct trns_chain struct transformation *trns; /* Array of transformations. */ size_t n_trns; /* Number of transformations. */ size_t allocated_trns; /* Allocated capacity. */ - bool finalized; /* Finalize functions called? */ }; /* Allocates and returns a new transformation chain. */ @@ -55,56 +53,24 @@ trns_chain_create (void) chain->trns = NULL; chain->n_trns = 0; chain->allocated_trns = 0; - chain->finalized = false; return chain; } -/* Finalizes all the un-finalized transformations in CHAIN. - Any given transformation is only finalized once. */ -void -trns_chain_finalize (struct trns_chain *chain) -{ - while (!chain->finalized) - { - size_t i; - - chain->finalized = true; - for (i = 0; i < chain->n_trns; i++) - { - struct transformation *trns = &chain->trns[i]; - trns_finalize_func *finalize = trns->finalize; - - trns->finalize = NULL; - if (finalize != NULL) - finalize (trns->aux); - } - } -} - -/* Destroys CHAIN, finalizing it in the process if it has not - already been finalized. */ +/* Destroys CHAIN. */ bool trns_chain_destroy (struct trns_chain *chain) { - bool ok = true; + if (!chain) + return true; - if (chain != NULL) + for (size_t i = 0; i < chain->n_trns; i++) { - size_t i; - - /* Needed to ensure that the control stack gets cleared. */ - trns_chain_finalize (chain); - - for (i = 0; i < chain->n_trns; i++) - { - struct transformation *trns = &chain->trns[i]; - if (trns->free != NULL) - ok = trns->free (trns->aux) && ok; - } - free (chain->trns); - free (chain); + struct transformation *trns = &chain->trns[i]; + if (trns->free) + ok = trns->free (trns->aux) && ok; } - + free (chain->trns); + free (chain); return ok; } @@ -116,48 +82,36 @@ trns_chain_is_empty (const struct trns_chain *chain) return chain->n_trns == 0; } -/* Adds a transformation to CHAIN with finalize function - FINALIZE, execute function EXECUTE, free function FREE, and - auxiliary data AUX. */ +/* Adds a transformation to CHAIN with execute function EXECUTE, free function + FREE, and auxiliary data AUX. */ void -trns_chain_append (struct trns_chain *chain, trns_finalize_func *finalize, - trns_proc_func *execute, trns_free_func *free, - void *aux) +trns_chain_append (struct trns_chain *chain, trns_proc_func *execute, + trns_free_func *free, void *aux) { struct transformation *trns; - chain->finalized = false; - if (chain->n_trns == chain->allocated_trns) chain->trns = x2nrealloc (chain->trns, &chain->allocated_trns, sizeof *chain->trns); trns = &chain->trns[chain->n_trns++]; trns->idx_ofs = 0; - trns->finalize = finalize; trns->execute = execute; trns->free = free; trns->aux = aux; } -/* Appends the transformations in SRC to those in DST, - and destroys SRC. - Both DST and SRC must already be finalized. */ +/* Appends the transformations in SRC to those in DST, and destroys SRC. */ void trns_chain_splice (struct trns_chain *dst, struct trns_chain *src) { - size_t i; - - assert (dst->finalized); - assert (src->finalized); - if (dst->n_trns + src->n_trns > dst->allocated_trns) { dst->allocated_trns = dst->n_trns + src->n_trns; dst->trns = xnrealloc (dst->trns, dst->allocated_trns, sizeof *dst->trns); } - for (i = 0; i < src->n_trns; i++) + for (size_t i = 0; i < src->n_trns; i++) { struct transformation *d = &dst->trns[i + dst->n_trns]; const struct transformation *s = &src->trns[i]; @@ -190,7 +144,6 @@ trns_chain_execute (const struct trns_chain *chain, enum trns_result start, { size_t i; - assert (chain->finalized); for (i = start < 0 ? 0 : start; i < chain->n_trns;) { struct transformation *trns = &chain->trns[i]; diff --git a/src/data/transformations.h b/src/data/transformations.h index 013bcaa731..2091499782 100644 --- a/src/data/transformations.h +++ b/src/data/transformations.h @@ -24,28 +24,43 @@ /* trns_proc_func return values. */ enum trns_result { - TRNS_CONTINUE = -1, /* Continue to next transformation. */ - TRNS_DROP_CASE = -2, /* Drop this case. */ - TRNS_ERROR = -3, /* A serious error, so stop the procedure. */ - TRNS_END_CASE = -4, /* Skip to next case. INPUT PROGRAM only. */ - TRNS_END_FILE = -5 /* End of input. INPUT PROGRAM only. */ + TRNS_CONTINUE, /* Continue to next transformation. */ + TRNS_BREAK, /* Break out of LOOP. */ + TRNS_DROP_CASE, /* Drop this case. */ + TRNS_ERROR, /* A serious error, so stop the procedure. */ + TRNS_END_CASE, /* Skip to next case. INPUT PROGRAM only. */ + TRNS_END_FILE /* End of input. INPUT PROGRAM only. */ }; struct ccase; -typedef void trns_finalize_func (void *); -typedef int trns_proc_func (void *, struct ccase **, casenumber); + +typedef enum trns_result trns_proc_func (void *, struct ccase **, casenumber); typedef bool trns_free_func (void *); +struct trns_class + { + int (*execute) (void *aux, struct ccase **, casenumber); + bool (*destroy) (void *aux); + }; /* Transformation chains. */ -struct trns_chain *trns_chain_create (void); -void trns_chain_finalize (struct trns_chain *); -bool trns_chain_destroy (struct trns_chain *); +struct transformation + { + const struct trns_class *class; + void *aux; + }; +enum trns_result transformations_execute (const struct transformation *, + size_t n, + struct ccase **, casenumber case_num); +void transformations_destroy (struct transformation *, size_t n); + +struct trns_builder *trns_builder_create (void); +void trns_builder_append (struct trns_builder *, trns_proc_func *, trns_free_func *, void *); +struct trns_chain *trns_builder_finish (struct trns_builder *); +void trns_builder_destroy (struct trns_chain *); bool trns_chain_is_empty (const struct trns_chain *); -void trns_chain_append (struct trns_chain *, trns_finalize_func *, - trns_proc_func *, trns_free_func *, void *); size_t trns_chain_next (struct trns_chain *); enum trns_result trns_chain_execute (const struct trns_chain *, enum trns_result, struct ccase **, diff --git a/src/language/command.c b/src/language/command.c index 924b221b22..522d53eaa2 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -89,19 +89,21 @@ cmd_result_is_failure (enum cmd_result result) /* Command processing states. */ enum states { - S_INITIAL = 0x01, /* Allowed before active dataset defined. */ - S_DATA = 0x02, /* Allowed after active dataset defined. */ - S_INPUT_PROGRAM = 0x04, /* Allowed in INPUT PROGRAM. */ - S_FILE_TYPE = 0x08, /* Allowed in FILE TYPE. */ - S_ANY = 0x0f /* Allowed anywhere. */ + 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, }; /* Other command requirements. */ enum flags { - F_ENHANCED = 0x10, /* Allowed only in enhanced syntax mode. */ - F_TESTING = 0x20, /* Allowed only in testing mode. */ - F_ABBREV = 0x80 /* Not a candidate for name completion. */ + F_ENHANCED = 1 << 0, /* Allowed only in enhanced syntax mode. */ + F_TESTING = 1 << 1, /* Allowed only in testing mode. */ + F_ABBREV = 1 << 2 /* Not a candidate for name completion. */ }; /* A single command. */ @@ -126,7 +128,7 @@ static const struct command commands[] = static const size_t n_commands = sizeof commands / sizeof *commands; static bool in_correct_state (const struct command *, enum cmd_state); -static bool report_state_mismatch (const struct command *, enum cmd_state); +static void report_state_mismatch (const struct command *, enum cmd_state); static void set_completion_state (enum cmd_state); /* Command parser. */ @@ -360,21 +362,39 @@ parse_command_name (struct lexer *lexer, int *n_tokens) static bool in_correct_state (const struct command *command, enum cmd_state state) { - return ((state == CMD_STATE_INITIAL && command->states & S_INITIAL) - || (state == CMD_STATE_DATA && command->states & S_DATA) - || (state == CMD_STATE_INPUT_PROGRAM - && command->states & S_INPUT_PROGRAM) - || (state == CMD_STATE_FILE_TYPE && command->states & S_FILE_TYPE)); + 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 (); + } } /* Emits an appropriate error message for trying to invoke COMMAND in STATE. */ -static bool +static void report_state_mismatch (const struct command *command, enum cmd_state state) { assert (!in_correct_state (command, state)); - if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA) + + switch (state) { + case CMD_STATE_INITIAL: + case CMD_STATE_DATA: switch ((int) command->states) { /* One allowed state. */ @@ -441,14 +461,21 @@ report_state_mismatch (const struct command *command, enum cmd_state state) default: NOT_REACHED (); } - } - else if (state == CMD_STATE_INPUT_PROGRAM) - msg (SE, _("%s is not allowed inside %s."), - command->name, "INPUT PROGRAM"); - else if (state == CMD_STATE_FILE_TYPE) - msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE"); + break; + + case CMD_STATE_INPUT_PROGRAM: + msg (SE, _("%s is not allowed inside %s."), + command->name, "INPUT PROGRAM"); + break; - return false; + case CMD_STATE_FILE_TYPE: + 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); + break; + } } /* Command name completion. */ diff --git a/src/language/command.def b/src/language/command.def index 88cbaf5cbe..253885857e 100644 --- a/src/language/command.def +++ b/src/language/command.def @@ -49,7 +49,7 @@ DEF_CMD (S_ANY, 0, "TITLE", cmd_title) /* Commands that define (or replace) the active dataset. */ DEF_CMD (S_INITIAL | S_DATA, 0, "ADD FILES", cmd_add_files) -DEF_CMD (S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE, 0, "DATA LIST", cmd_data_list) +DEF_CMD (S_ANY, 0, "DATA LIST", cmd_data_list) DEF_CMD (S_INITIAL | S_DATA, 0, "GET", cmd_get) DEF_CMD (S_INITIAL | S_DATA, 0, "GET DATA", cmd_get_data) DEF_CMD (S_INITIAL | S_DATA, 0, "IMPORT", cmd_import) @@ -64,50 +64,51 @@ DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET COPY", cmd_dataset_copy) DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET NAME", cmd_dataset_name) DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET DISPLAY", cmd_dataset_display) -/* Transformations and utilities that may appear after active - file definition or within INPUT PROGRAM. */ -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ADD VALUE LABELS", cmd_add_value_labels) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ADD DOCUMENT", cmd_add_documents) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "APPLY DICTIONARY", cmd_apply_dictionary) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "BREAK", cmd_break) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "COMPUTE", cmd_compute) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DATAFILE ATTRIBUTE", cmd_datafile_attribute) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DISPLAY", cmd_display) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DOCUMENT", cmd_document) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DO IF", cmd_do_if) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DROP DOCUMENTS", cmd_drop_documents) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ELSE IF", cmd_else_if) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ELSE", cmd_else) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "END IF", cmd_end_if) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "END LOOP", cmd_end_loop) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "FORMATS", cmd_formats) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "IF", cmd_if) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "LEAVE", cmd_leave) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "LOOP", cmd_loop) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "MISSING VALUES", cmd_missing_values) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "MRSETS", cmd_mrsets) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "NUMERIC", cmd_numeric) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "PRINT EJECT", cmd_print_eject) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "PRINT FORMATS", cmd_print_formats) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "PRINT SPACE", cmd_print_space) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "PRINT", cmd_print) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "RECODE", cmd_recode) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "SELECT IF", cmd_select_if) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "SPLIT FILE", cmd_split_file) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "STRING", cmd_string) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VALUE LABELS", cmd_value_labels) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ALIGNMENT", cmd_variable_alignment) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ATTRIBUTE", cmd_variable_attribute) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE LABELS", cmd_variable_labels) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE LEVEL", cmd_variable_level) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ROLE", cmd_variable_role) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE WIDTH", cmd_variable_width) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VECTOR", cmd_vector) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WEIGHT", cmd_weight) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WRITE FORMATS", cmd_write_formats) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WRITE", cmd_write) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, F_ENHANCED, "XEXPORT", cmd_xexport) -DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "XSAVE", cmd_xsave) +/* 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) + +/* 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, "ELSE IF", cmd_else_if) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "ELSE", cmd_else) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "END IF", cmd_end_if) +DEF_CMD (S_DATA | S_INPUT_PROGRAM | S_NESTED, 0, "END LOOP", cmd_end_loop) +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) /* Commands that may appear after active dataset definition. */ DEF_CMD (S_DATA, 0, "AGGREGATE", cmd_aggregate) @@ -151,10 +152,10 @@ 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, 0, "END CASE", cmd_end_case) -DEF_CMD (S_INPUT_PROGRAM, 0, "END FILE", cmd_end_file) -DEF_CMD (S_INPUT_PROGRAM, 0, "END INPUT PROGRAM", cmd_end_input_program) -DEF_CMD (S_INPUT_PROGRAM, 0, "REREAD", cmd_reread) +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, "END INPUT PROGRAM", cmd_end_input_program) +DEF_CMD (S_INPUT_PROGRAM | S_NESTED, 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 ab133c25e7..766a637b0b 100644 --- a/src/language/command.h +++ b/src/language/command.h @@ -48,7 +48,8 @@ enum cmd_state CMD_STATE_INITIAL, /* No active dataset yet defined. */ CMD_STATE_DATA, /* Active dataset has been defined. */ CMD_STATE_INPUT_PROGRAM, /* Inside INPUT PROGRAM. */ - CMD_STATE_FILE_TYPE /* Inside FILE TYPE. */ + CMD_STATE_FILE_TYPE, /* Inside FILE TYPE. */ + CMD_STATE_NESTED, /* Inside LOOP or DO IF. */ }; struct dataset; diff --git a/src/language/control/automake.mk b/src/language/control/automake.mk index 9d09687c81..38ecf68364 100644 --- a/src/language/control/automake.mk +++ b/src/language/control/automake.mk @@ -18,8 +18,6 @@ language_control_sources = \ - src/language/control/control-stack.c \ - src/language/control/control-stack.h \ src/language/control/define.c \ src/language/control/do-if.c \ src/language/control/loop.c \ diff --git a/src/language/control/control-stack.c b/src/language/control/control-stack.c deleted file mode 100644 index 8d0962be63..0000000000 --- a/src/language/control/control-stack.c +++ /dev/null @@ -1,116 +0,0 @@ -/* -PSPP - a program for statistical analysis. -Copyright (C) 2017 Free Software Foundation, Inc. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include - -#include "language/control/control-stack.h" - -#include -#include - -#include "libpspp/compiler.h" -#include "libpspp/message.h" - -#include "gl/xalloc.h" - -#include "gettext.h" -#define _(msgid) gettext (msgid) - -struct ctl_struct - { - const struct ctl_class *class; /* Class of control structure. */ - struct ctl_struct *down; /* Points toward the bottom of ctl_stack. */ - void *private; /* Private data. */ - }; - -static struct ctl_struct *ctl_stack; - -void -ctl_stack_clear (void) -{ - while (ctl_stack != NULL) - { - struct ctl_struct *top = ctl_stack; - msg (SE, _("%s without %s."), - top->class->start_name, top->class->end_name); - ctl_stack_pop (top->private); - } -} - -void -ctl_stack_push (const struct ctl_class *class, void *private) -{ - struct ctl_struct *ctl; - - assert (private != NULL); - ctl = xmalloc (sizeof *ctl); - ctl->class = class; - ctl->down = ctl_stack; - ctl->private = private; - ctl_stack = ctl; -} - -void * -ctl_stack_top (const struct ctl_class *class) -{ - struct ctl_struct *top = ctl_stack; - if (top != NULL && top->class == class) - return top->private; - else - { - if (ctl_stack_search (class) != NULL) - msg (SE, _("This command must appear inside %s...%s, " - "without intermediate %s...%s."), - class->start_name, class->end_name, - top->class->start_name, top->class->end_name); - return NULL; - } -} - -void * -ctl_stack_search (const struct ctl_class *class) -{ - struct ctl_struct *ctl; - - for (ctl = ctl_stack; ctl != NULL; ctl = ctl->down) - if (ctl->class == class) - return ctl->private; - - msg (SE, _("This command cannot appear outside %s...%s."), - class->start_name, class->end_name); - return NULL; -} - -void -ctl_stack_pop (void *private) -{ - struct ctl_struct *top = ctl_stack; - - assert (top != NULL); - assert (top->private == private); - - top->class->close (top->private); - ctl_stack = top->down; - free (top); -} - -bool -ctl_stack_is_empty (void) -{ - return ctl_stack == NULL; -} diff --git a/src/language/control/control-stack.h b/src/language/control/control-stack.h deleted file mode 100644 index 9c6824b5f6..0000000000 --- a/src/language/control/control-stack.h +++ /dev/null @@ -1,43 +0,0 @@ -/* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#ifndef CTL_STACK_H -#define CTL_STACK_H 1 - -#include - -/* The following #include avoids a potential problem when Gnulib substitutes - * for close() by putting "#define close rpl_close" into , by - * ensuring that every source file that includes this one sees the #define.. - * (It would probably be better to rename the 'close' member of struct - * ctl_class.) */ -#include - -struct ctl_class - { - const char *start_name; /* e.g. LOOP. */ - const char *end_name; /* e.g. END LOOP. */ - void (*close) (void *); /* Closes the control structure. */ - }; - -void ctl_stack_clear (void); -void ctl_stack_push (const struct ctl_class *, void *private); -void *ctl_stack_top (const struct ctl_class *); -void *ctl_stack_search (const struct ctl_class *); -void ctl_stack_pop (void *); -bool ctl_stack_is_empty (void); - -#endif /* ctl_stack.h */ diff --git a/src/language/control/do-if.c b/src/language/control/do-if.c index b361fba920..b45694804a 100644 --- a/src/language/control/do-if.c +++ b/src/language/control/do-if.c @@ -18,12 +18,9 @@ #include -#include "data/case.h" #include "data/dataset.h" #include "data/transformations.h" -#include "data/value.h" #include "language/command.h" -#include "language/control/control-stack.h" #include "language/expressions/public.h" #include "language/lexer/lexer.h" #include "libpspp/compiler.h" @@ -35,234 +32,136 @@ #include "gettext.h" #define _(msgid) gettext (msgid) -/* DO IF, ELSE IF, and ELSE are translated as a single - transformation that evaluates each condition and jumps to the - start of the appropriate block of transformations. Each block - of transformations (except for the last) ends with a - transformation that jumps past the remaining blocks. - - So, the following code: - - DO IF a. - ...block 1... - ELSE IF b. - ...block 2... - ELSE. - ...block 3... - END IF. - - is effectively translated like this: - - IF a GOTO 1, IF b GOTO 2, ELSE GOTO 3. - 1: ...block 1... - GOTO 4 - 2: ...block 2... - GOTO 4 - 3: ...block 3... - 4: - -*/ - /* A conditional clause. */ struct clause { + struct msg_location *location; struct expression *condition; /* Test expression; NULL for ELSE clause. */ - int target_index; /* Transformation to jump to if true. */ + struct transformation *xforms; + size_t n_xforms; }; /* DO IF transformation. */ struct do_if_trns { - struct dataset *ds; /* The dataset */ struct clause *clauses; /* Clauses. */ size_t n_clauses; /* Number of clauses. */ - int past_END_IF_index; /* Transformation just past last clause. */ }; -static const struct ctl_class do_if_class; - -static int parse_clause (struct lexer *, struct do_if_trns *, struct dataset *ds); -static void add_clause (struct do_if_trns *, struct expression *condition); -static void add_else (struct do_if_trns *); - -static bool has_else (struct do_if_trns *); -static bool must_not_have_else (struct do_if_trns *); -static void close_do_if (void *do_if); - -static trns_finalize_func do_if_finalize_func; -static trns_proc_func do_if_trns_proc, break_trns_proc; +static trns_proc_func do_if_trns_proc; static trns_free_func do_if_trns_free; -/* Parse DO IF. */ -int -cmd_do_if (struct lexer *lexer, struct dataset *ds) -{ - struct do_if_trns *do_if = xmalloc (sizeof *do_if); - do_if->clauses = NULL; - do_if->n_clauses = 0; - do_if->ds = ds; - - ctl_stack_push (&do_if_class, do_if); - add_transformation_with_finalizer (ds, do_if_finalize_func, - do_if_trns_proc, do_if_trns_free, do_if); - - return parse_clause (lexer, do_if, ds); -} - -/* Parse ELSE IF. */ -int -cmd_else_if (struct lexer *lexer, struct dataset *ds) -{ - struct do_if_trns *do_if = ctl_stack_top (&do_if_class); - if (do_if == NULL || !must_not_have_else (do_if)) - return CMD_CASCADING_FAILURE; - return parse_clause (lexer, do_if, ds); -} - -/* Parse ELSE. */ -int -cmd_else (struct lexer *lexer UNUSED, struct dataset *ds) +static void +start_clause (struct lexer *lexer, struct dataset *ds, + bool condition, struct do_if_trns *do_if, + size_t *allocated_clauses, bool *ok) { - struct do_if_trns *do_if = ctl_stack_top (&do_if_class); - - if (do_if == NULL || !must_not_have_else (do_if)) - return CMD_CASCADING_FAILURE; + if (*ok && do_if->n_clauses > 0 + && !do_if->clauses[do_if->n_clauses - 1].condition) + { + if (condition) + msg (SE, _("ELSE IF is not allowed following ELSE " + "within DO IF...END IF.")); + else + msg (SE, _("Only one ELSE is allowed within DO IF...END IF.")); - assert (ds == do_if->ds); + msg_at (SN, do_if->clauses[do_if->n_clauses - 1].location, + _("This is the location of the previous ELSE clause.")); - add_else (do_if); - return CMD_SUCCESS; -} + msg_at (SN, do_if->clauses[0].location, + _("This is the location of the DO IF command.")); + } -/* Parse END IF. */ -int -cmd_end_if (struct lexer *lexer UNUSED, struct dataset *ds) -{ - struct do_if_trns *do_if = ctl_stack_top (&do_if_class); + if (do_if->n_clauses >= *allocated_clauses) + do_if->clauses = x2nrealloc (do_if->clauses, allocated_clauses, + sizeof *do_if->clauses); + struct clause *clause = &do_if->clauses[do_if->n_clauses++]; - if (do_if == NULL) - return CMD_CASCADING_FAILURE; + *clause = (struct clause) { .n_xforms = 0 }; + if (condition) + { + clause->condition = expr_parse_bool (lexer, ds); + if (!clause->condition) + lex_discard_rest_of_command (lexer); + } + clause->location = lex_ofs_location (lexer, 0, lex_ofs (lexer)); - assert (ds == do_if->ds); - ctl_stack_pop (do_if); + lex_end_of_command (lexer); + lex_get (lexer); - return CMD_SUCCESS; + proc_push_transformations (ds); } -/* Closes out DO_IF, by adding a sentinel ELSE clause if - necessary and setting past_END_IF_index. */ static void -close_do_if (void *do_if_) +finish_clause (struct dataset *ds, struct do_if_trns *do_if) { - struct do_if_trns *do_if = do_if_; - - if (!has_else (do_if)) - add_else (do_if); - do_if->past_END_IF_index = next_transformation (do_if->ds); + struct clause *clause = &do_if->clauses[do_if->n_clauses - 1]; + proc_pop_transformations (ds, &clause->xforms, &clause->n_xforms); } -/* Adds an ELSE clause to DO_IF pointing to the next - transformation. */ -static void -add_else (struct do_if_trns *do_if) +/* Parse DO IF. */ +int +cmd_do_if (struct lexer *lexer, struct dataset *ds) { - assert (!has_else (do_if)); - add_clause (do_if, NULL); -} + struct do_if_trns *do_if = xmalloc (sizeof *do_if); + *do_if = (struct do_if_trns) { .n_clauses = 0 }; -/* Returns true if DO_IF does not yet have an ELSE clause. - Reports an error and returns false if it does already. */ -static bool -must_not_have_else (struct do_if_trns *do_if) -{ - if (has_else (do_if)) + size_t allocated_clauses = 0; + bool ok = true; + + start_clause (lexer, ds, true, do_if, &allocated_clauses, &ok); + while (!lex_match_phrase (lexer, "END IF")) { - msg (SE, _("This command may not follow %s in %s ... %s."), "ELSE", "DO IF", "END IF"); - return false; + if (lex_token (lexer) == T_STOP) + { + lex_error (lexer, NULL); + ok = false; + break; + } + else if (lex_match_phrase (lexer, "ELSE IF")) + { + finish_clause (ds, do_if); + start_clause (lexer, ds, true, do_if, &allocated_clauses, &ok); + } + else if (lex_match_id (lexer, "ELSE")) + { + finish_clause (ds, do_if); + start_clause (lexer, ds, false, do_if, &allocated_clauses, &ok); + } + else + cmd_parse_in_state (lexer, ds, CMD_STATE_NESTED); } - else - return true; -} - -/* Returns true if DO_IF already has an ELSE clause, - false otherwise. */ -static bool -has_else (struct do_if_trns *do_if) -{ - return (do_if->n_clauses != 0 - && do_if->clauses[do_if->n_clauses - 1].condition == NULL); -} - -/* Parses a DO IF or ELSE IF expression and appends the - corresponding clause to DO_IF. Checks for end of command and - returns a command return code. */ -static int -parse_clause (struct lexer *lexer, struct do_if_trns *do_if, struct dataset *ds) -{ - struct expression *condition; - - condition = expr_parse_bool (lexer, NULL, ds); - if (condition == NULL) - return CMD_CASCADING_FAILURE; - - add_clause (do_if, condition); - - return CMD_SUCCESS; -} + finish_clause (ds, do_if); -/* Adds a clause to DO_IF that tests for the given CONDITION and, - if true, jumps to the set of transformations produced by - following commands. */ -static void -add_clause (struct do_if_trns *do_if, struct expression *condition) -{ - struct clause *clause; - - if (do_if->n_clauses > 0) - add_transformation (do_if->ds, break_trns_proc, NULL, do_if); + add_transformation (ds, do_if_trns_proc, do_if_trns_free, do_if); - do_if->clauses = xnrealloc (do_if->clauses, - do_if->n_clauses + 1, sizeof *do_if->clauses); - clause = &do_if->clauses[do_if->n_clauses++]; - clause->condition = condition; - clause->target_index = next_transformation (do_if->ds); -} - -/* Finalizes DO IF by clearing the control stack, thus ensuring - that all open DO IFs are closed. */ -static void -do_if_finalize_func (void *do_if_ UNUSED) -{ - /* This will be called multiple times if multiple DO IFs were - executed, which is slightly unclean, but at least it's - idempotent. */ - ctl_stack_clear (); + return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE; } /* DO IF transformation procedure. Checks each clause and jumps to the appropriate transformation. */ -static int -do_if_trns_proc (void *do_if_, struct ccase **c, casenumber case_num UNUSED) +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_; - struct clause *clause; - for (clause = do_if->clauses; clause < do_if->clauses + do_if->n_clauses; - clause++) + for (size_t i = 0; i < do_if->n_clauses; i++) { + const struct clause *clause = &do_if->clauses[i]; if (clause->condition != NULL) { double boolean = expr_evaluate_num (clause->condition, *c, case_num); - if (boolean == 1.0) - return clause->target_index; + if (boolean == 0.0) + continue; else if (boolean == SYSMIS) - return do_if->past_END_IF_index; + return TRNS_CONTINUE; } - else - return clause->target_index; + + return transformations_execute (clause->xforms, clause->n_xforms, + c, case_num); } - return do_if->past_END_IF_index; + return TRNS_CONTINUE; } /* Frees a DO IF transformation. */ @@ -270,30 +169,17 @@ static bool do_if_trns_free (void *do_if_) { struct do_if_trns *do_if = do_if_; - struct clause *clause; - for (clause = do_if->clauses; clause < do_if->clauses + do_if->n_clauses; - clause++) - expr_free (clause->condition); + for (size_t i = 0; i < do_if->n_clauses; i++) + { + struct clause *clause = &do_if->clauses[i]; + + msg_location_destroy (clause->location); + expr_free (clause->condition); + + transformations_destroy (clause->xforms, clause->n_xforms); + } free (do_if->clauses); free (do_if); return true; } - -/* Breaks out of a DO IF construct. */ -static int -break_trns_proc (void *do_if_, struct ccase **c UNUSED, - casenumber case_num UNUSED) -{ - struct do_if_trns *do_if = do_if_; - - return do_if->past_END_IF_index; -} - -/* DO IF control structure class definition. */ -static const struct ctl_class do_if_class = - { - "DO IF", - "END IF", - close_do_if, - }; diff --git a/src/language/control/loop.c b/src/language/control/loop.c index 156e647ea0..604af45569 100644 --- a/src/language/control/loop.c +++ b/src/language/control/loop.c @@ -16,7 +16,7 @@ #include -#include "language/control/control-stack.h" +#include #include "data/case.h" #include "data/dataset.h" @@ -38,59 +38,30 @@ #include "gettext.h" #define _(msgid) gettext (msgid) -/* LOOP outputs a transformation that is executed only on the - first pass through the loop. On this trip, it initializes for - the first pass by resetting the pass number, setting up the - indexing clause, and testing the LOOP IF clause. If the loop - is not to be entered at all, it jumps forward just past the - END LOOP transformation; otherwise, it continues to the - transformation following LOOP. - - END LOOP outputs a transformation that executes at the end of - each trip through the loop. It checks the END LOOP IF clause, - then updates the pass number, increments the indexing clause, - and tests the LOOP IF clause. If another pass through the - loop is due, it jumps backward to just after the LOOP - transformation; otherwise, it continues to the transformation - following END LOOP. */ - struct loop_trns { - struct pool *pool; - struct dataset *ds; - - /* Iteration limit. */ - int max_pass_count; /* Maximum number of passes (-1=unlimited). */ - int pass; /* Number of passes through the loop so far. */ - /* a=a TO b [BY c]. */ struct variable *index_var; /* Index variable. */ - struct expression *first_expr; /* Starting index. */ - struct expression *by_expr; /* Index increment (default 1.0 if null). */ - struct expression *last_expr; /* Terminal index. */ - double cur, by, last; /* Current value, increment, last value. */ + struct expression *first; /* Starting index. */ + struct expression *by; /* Index increment (or NULL). */ + struct expression *last; /* Terminal index. */ /* IF condition for LOOP or END LOOP. */ struct expression *loop_condition; struct expression *end_loop_condition; - /* Transformation indexes. */ - int past_LOOP_index; /* Just past LOOP transformation. */ - int past_END_LOOP_index; /* Just past END LOOP transformation. */ + /* Inner transformations. */ + struct transformation *xforms; + size_t n_xforms; }; -static const struct ctl_class loop_class; - -static trns_finalize_func loop_trns_finalize; -static trns_proc_func loop_trns_proc, end_loop_trns_proc, break_trns_proc; +static trns_proc_func loop_trns_proc; static trns_free_func loop_trns_free; -static struct loop_trns *create_loop_trns (struct dataset *); -static bool parse_if_clause (struct lexer *, - struct loop_trns *, struct expression **); +static bool parse_if_clause (struct lexer *, struct dataset *, + struct expression **); static bool parse_index_clause (struct dataset *, struct lexer *, - struct loop_trns *, bool *created_index_var); -static void close_loop (void *); + struct loop_trns *); /* LOOP. */ @@ -98,95 +69,59 @@ static void close_loop (void *); int cmd_loop (struct lexer *lexer, struct dataset *ds) { - struct loop_trns *loop; - bool created_index_var = false; - bool ok = true; + struct loop_trns *loop = xmalloc (sizeof *loop); + *loop = (struct loop_trns) { .index_var = NULL }; - loop = create_loop_trns (ds); + bool ok = true; while (lex_token (lexer) != T_ENDCMD && ok) { if (lex_match_id (lexer, "IF")) - ok = parse_if_clause (lexer, loop, &loop->loop_condition); + ok = parse_if_clause (lexer, ds, &loop->loop_condition); else - ok = parse_index_clause (ds, lexer, loop, &created_index_var); + ok = parse_index_clause (ds, lexer, loop); } + lex_end_of_command (lexer); - /* Clean up if necessary. */ - if (!ok) + proc_push_transformations (ds); + for (;;) { - loop->max_pass_count = 0; - if (loop->index_var != NULL && created_index_var) + if (lex_token (lexer) == T_STOP) { - dict_delete_var (dataset_dict (ds), loop->index_var); - loop->index_var = NULL; + lex_error (lexer, NULL); + ok = false; + break; } + else if (lex_match_phrase (lexer, "END LOOP")) + { + if (lex_match_id (lexer, "IF")) + ok = parse_if_clause (lexer, ds, &loop->end_loop_condition) && ok; + break; + } + else + cmd_parse_in_state (lexer, ds, CMD_STATE_NESTED); } + proc_pop_transformations (ds, &loop->xforms, &loop->n_xforms); - return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE; -} - -/* Parses END LOOP. */ -int -cmd_end_loop (struct lexer *lexer, struct dataset *ds) -{ - struct loop_trns *loop; - bool ok = true; - - loop = ctl_stack_top (&loop_class); - if (loop == NULL) - return CMD_CASCADING_FAILURE; - - assert (loop->ds == ds); - - /* Parse syntax. */ - if (lex_match_id (lexer, "IF")) - ok = parse_if_clause (lexer, loop, &loop->end_loop_condition); - if (ok) - ok = lex_end_of_command (lexer) == CMD_SUCCESS; + add_transformation (ds, loop_trns_proc, loop_trns_free, loop); - if (!ok) - loop->max_pass_count = 0; - - ctl_stack_pop (loop); - - return ok ? CMD_SUCCESS : CMD_FAILURE; + return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE; } /* Parses BREAK. */ int -cmd_break (struct lexer *lexer UNUSED, struct dataset *ds) +cmd_break (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) { - struct ctl_stmt *loop = ctl_stack_search (&loop_class); - if (loop == NULL) - return CMD_CASCADING_FAILURE; - - add_transformation (ds, break_trns_proc, NULL, loop); + //add_transformation (ds, break_trns_proc, NULL, NULL); return CMD_SUCCESS; } -/* Closes a LOOP construct by emitting the END LOOP - transformation and finalizing its members appropriately. */ -static void -close_loop (void *loop_) -{ - struct loop_trns *loop = loop_; - - add_transformation (loop->ds, end_loop_trns_proc, NULL, loop); - loop->past_END_LOOP_index = next_transformation (loop->ds); - - /* If there's nothing else limiting the number of loops, use - MXLOOPS as a limit. */ - if (loop->max_pass_count == -1 && loop->index_var == NULL) - loop->max_pass_count = settings_get_mxloops (); -} - /* Parses an IF clause for LOOP or END LOOP and stores the resulting expression to *CONDITION. Returns true if successful, false on failure. */ static bool -parse_if_clause (struct lexer *lexer, - struct loop_trns *loop, struct expression **condition) +parse_if_clause (struct lexer *lexer, struct dataset *ds, + struct expression **condition) { if (*condition != NULL) { @@ -194,17 +129,15 @@ parse_if_clause (struct lexer *lexer, return false; } - *condition = expr_parse_bool (lexer, loop->pool, loop->ds); + *condition = expr_parse_bool (lexer, ds); return *condition != NULL; } -/* Parses an indexing clause into LOOP. - Stores true in *CREATED_INDEX_VAR if the index clause created - a new variable, false otherwise. - Returns true if successful, false on failure. */ +/* Parses an indexing clause into LOOP. Returns true if successful, false on + failure. */ static bool parse_index_clause (struct dataset *ds, struct lexer *lexer, - struct loop_trns *loop, bool *created_index_var) + struct loop_trns *loop) { if (loop->index_var != NULL) { @@ -219,127 +152,102 @@ parse_index_clause (struct dataset *ds, struct lexer *lexer, } loop->index_var = dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)); - if (loop->index_var != NULL) - *created_index_var = false; - else - { - loop->index_var = dict_create_var_assert (dataset_dict (ds), - lex_tokcstr (lexer), 0); - *created_index_var = true; - } + if (!loop->index_var) + loop->index_var = dict_create_var_assert (dataset_dict (ds), + lex_tokcstr (lexer), 0); lex_get (lexer); if (!lex_force_match (lexer, T_EQUALS)) return false; - loop->first_expr = expr_parse (lexer, loop->pool, loop->ds, VAL_NUMERIC); - if (loop->first_expr == NULL) + loop->first = expr_parse (lexer, ds, VAL_NUMERIC); + if (loop->first == NULL) return false; for (;;) { struct expression **e; if (lex_match (lexer, T_TO)) - e = &loop->last_expr; + e = &loop->last; else if (lex_match (lexer, T_BY)) - e = &loop->by_expr; + e = &loop->by; else break; if (*e != NULL) { - lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY"); + lex_sbc_only_once (e == &loop->last ? "TO" : "BY"); return false; } - *e = expr_parse (lexer, loop->pool, loop->ds, VAL_NUMERIC); + *e = expr_parse (lexer, ds, VAL_NUMERIC); if (*e == NULL) return false; } - if (loop->last_expr == NULL) + if (loop->last == NULL) { lex_sbc_missing ("TO"); return false; } - if (loop->by_expr == NULL) - loop->by = 1.0; return true; } -/* Creates, initializes, and returns a new loop_trns. */ -static struct loop_trns * -create_loop_trns (struct dataset *ds) -{ - struct loop_trns *loop = pool_create_container (struct loop_trns, pool); - loop->max_pass_count = -1; - loop->pass = 0; - loop->index_var = NULL; - loop->first_expr = loop->by_expr = loop->last_expr = NULL; - loop->loop_condition = loop->end_loop_condition = NULL; - loop->ds = ds; - - add_transformation_with_finalizer (ds, loop_trns_finalize, - loop_trns_proc, loop_trns_free, loop); - loop->past_LOOP_index = next_transformation (ds); - - ctl_stack_push (&loop_class, loop); - - return loop; -} - -/* Finalizes LOOP by clearing the control stack, thus ensuring - that all open LOOPs are closed. */ -static void -loop_trns_finalize (void *do_if_ UNUSED) -{ - /* This will be called multiple times if multiple LOOPs were - executed, which is slightly unclean, but at least it's - idempotent. */ - ctl_stack_clear (); -} - /* Sets up LOOP for the first pass. */ -static int +static enum trns_result loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num) { struct loop_trns *loop = loop_; - if (loop->index_var != NULL) + double cur, by, last; + if (loop->index_var) { /* Evaluate loop index expressions. */ - loop->cur = expr_evaluate_num (loop->first_expr, *c, case_num); - if (loop->by_expr != NULL) - loop->by = expr_evaluate_num (loop->by_expr, *c, case_num); - loop->last = expr_evaluate_num (loop->last_expr, *c, case_num); + 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); /* 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) = loop->cur; + *case_num_rw (*c, loop->index_var) = cur; /* Throw out pathological cases. */ - 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)) - goto zero_pass; + if (!isfinite (cur) || !isfinite (by) || !isfinite (last) + || by == 0.0 + || (by > 0.0 && cur > last) + || (by < 0.0 && cur < last)) + return TRNS_CONTINUE; } + else + cur = by = last = 0.0; + + int max_pass = loop->index_var ? settings_get_mxloops () : -1; + for (int i = 0; max_pass < 0 || i < max_pass; i++) + { + if (loop->loop_condition + && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0) + break; - /* Initialize pass count. */ - loop->pass = 0; - if (loop->max_pass_count >= 0 && loop->pass >= loop->max_pass_count) - goto zero_pass; + enum trns_result r = transformations_execute ( + loop->xforms, loop->n_xforms, c, case_num); + if (r != TRNS_CONTINUE) + return r == TRNS_BREAK ? TRNS_CONTINUE : r; - /* Check condition. */ - if (loop->loop_condition != NULL - && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0) - goto zero_pass; + if (loop->end_loop_condition != NULL + && expr_evaluate_num (loop->end_loop_condition, *c, case_num) != 0.0) + break; - return loop->past_LOOP_index; + if (loop->index_var) + { + cur += by; + if (by > 0.0 ? cur > last : cur < last) + break; - zero_pass: - return loop->past_END_LOOP_index; + *c = case_unshare (*c); + *case_num_rw (*c, loop->index_var) = cur; + } + } + return TRNS_CONTINUE; } /* Frees LOOP. */ @@ -348,59 +256,15 @@ loop_trns_free (void *loop_) { struct loop_trns *loop = loop_; - pool_destroy (loop->pool); - return true; -} - -/* Finishes a pass through the loop and starts the next. */ -static int -end_loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num UNUSED) -{ - struct loop_trns *loop = loop_; - - if (loop->end_loop_condition != NULL - && expr_evaluate_num (loop->end_loop_condition, *c, case_num) != 0.0) - goto break_out; - - /* MXLOOPS limiter. */ - if (loop->max_pass_count >= 0 && ++loop->pass >= loop->max_pass_count) - goto break_out; - - /* Indexing clause limiter: counting downward. */ - if (loop->index_var != NULL) - { - loop->cur += loop->by; - if ((loop->by > 0.0 && loop->cur > loop->last) - || (loop->by < 0.0 && loop->cur < loop->last)) - goto break_out; - *c = case_unshare (*c); - *case_num_rw (*c, loop->index_var) = loop->cur; - } - - if (loop->loop_condition != NULL - && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0) - goto break_out; - - return loop->past_LOOP_index; + expr_free (loop->first); + expr_free (loop->by); + expr_free (loop->last); - break_out: - return loop->past_END_LOOP_index; -} + expr_free (loop->loop_condition); + expr_free (loop->end_loop_condition); -/* Executes BREAK. */ -static int -break_trns_proc (void *loop_, struct ccase **c UNUSED, - casenumber case_num UNUSED) -{ - struct loop_trns *loop = loop_; + transformations_destroy (loop->xforms, loop->n_xforms); - return loop->past_END_LOOP_index; + free (loop); + return true; } - -/* LOOP control structure class definition. */ -static const struct ctl_class loop_class = - { - "LOOP", - "END LOOP", - close_loop, - }; diff --git a/src/language/control/temporary.c b/src/language/control/temporary.c index b350759b02..c751441372 100644 --- a/src/language/control/temporary.c +++ b/src/language/control/temporary.c @@ -24,7 +24,6 @@ #include "data/value-labels.h" #include "data/variable.h" #include "language/command.h" -#include "language/control/control-stack.h" #include "language/lexer/lexer.h" #include "libpspp/message.h" #include "libpspp/str.h" diff --git a/src/language/data-io/data-list.c b/src/language/data-io/data-list.c index 02cabd8cde..a340f207f1 100644 --- a/src/language/data-io/data-list.c +++ b/src/language/data-io/data-list.c @@ -511,11 +511,11 @@ data_list_trns_free (void *trns_) } /* Handle DATA LIST transformation TRNS, parsing data into *C. */ -static int +static enum trns_result data_list_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { struct data_list_trns *trns = trns_; - int retval; + enum trns_result retval; *c = case_unshare (*c); if (data_parser_parse (trns->parser, trns->reader, *c)) diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index e2cfbd1bb8..6ce75f6a4d 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -155,7 +155,6 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds) } inp->trns_chain = proc_capture_transformations (inp->ds); - trns_chain_finalize (inp->trns_chain); inp->restart = TRNS_CONTINUE; @@ -265,7 +264,7 @@ cmd_end_case (struct lexer *lexer, struct dataset *ds UNUSED) } /* Outputs the current case */ -int +enum trns_result end_case_trns_proc (void *inp_, struct ccase **c UNUSED, casenumber case_nr UNUSED) { @@ -304,7 +303,7 @@ cmd_reread (struct lexer *lexer, struct dataset *ds) goto error; } - e = expr_parse (lexer, NULL, ds, VAL_NUMERIC); + e = expr_parse (lexer, ds, VAL_NUMERIC); if (!e) goto error; } @@ -350,7 +349,7 @@ error: } /* Executes a REREAD transformation. */ -static int +static enum trns_result reread_trns_proc (void *t_, struct ccase **c, casenumber case_num) { struct reread_trns *t = t_; @@ -395,7 +394,7 @@ cmd_end_file (struct lexer *lexer UNUSED, struct dataset *ds) } /* Executes an END FILE transformation. */ -static int +static enum trns_result end_file_trns_proc (void *trns_ UNUSED, struct ccase **c UNUSED, casenumber case_num UNUSED) { diff --git a/src/language/data-io/print-space.c b/src/language/data-io/print-space.c index f077e9c395..11b9dcb79b 100644 --- a/src/language/data-io/print-space.c +++ b/src/language/data-io/print-space.c @@ -77,7 +77,7 @@ cmd_print_space (struct lexer *lexer, struct dataset *ds) if (lex_token (lexer) != T_ENDCMD) { - expr = expr_parse (lexer, NULL, ds, VAL_NUMERIC); + expr = expr_parse (lexer, ds, VAL_NUMERIC); if (lex_token (lexer) != T_ENDCMD) { lex_error (lexer, _("expecting end of command")); @@ -112,7 +112,7 @@ error: } /* Executes a PRINT SPACE transformation. */ -static int +static enum trns_result print_space_trns_proc (void *t_, struct ccase **c, casenumber case_num UNUSED) { diff --git a/src/language/data-io/print.c b/src/language/data-io/print.c index 5c9ef7af99..26bb2e12cd 100644 --- a/src/language/data-io/print.c +++ b/src/language/data-io/print.c @@ -474,7 +474,7 @@ static void print_text_flush_records (struct print_trns *, struct u8_line *, bool *eject, int *record); /* Performs the transformation inside print_trns T on case C. */ -static int +static enum trns_result print_text_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { @@ -587,7 +587,7 @@ static void print_binary_flush_records (struct print_trns *, bool *eject, int *record); /* Performs the transformation inside print_trns T on case C. */ -static int +static enum trns_result print_binary_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { diff --git a/src/language/data-io/save.c b/src/language/data-io/save.c index a5848e59f5..190de124c3 100644 --- a/src/language/data-io/save.c +++ b/src/language/data-io/save.c @@ -364,7 +364,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds, } /* Writes case *C to the system file specified on XSAVE or XEXPORT. */ -static int +static enum trns_result output_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { struct output_trns *t = trns_; diff --git a/src/language/expressions/parse.c b/src/language/expressions/parse.c index ab603c0b89..22c7a41080 100644 --- a/src/language/expressions/parse.c +++ b/src/language/expressions/parse.c @@ -68,12 +68,9 @@ static union any_node *allocate_unary_variable (struct expression *, /* Parses an expression of the given TYPE. If DS is nonnull then variables and vectors within it may be referenced within the expression; otherwise, the expression must not reference any variables or vectors. Returns the new - expression if successful or a null pointer otherwise. If POOL is nonnull, - then destroying POOL will free the expression; otherwise, the caller must - eventually free it with expr_free(). */ + expression if successful or a null pointer otherwise. */ struct expression * -expr_parse (struct lexer *lexer, struct pool *pool, struct dataset *ds, - enum val_type type) +expr_parse (struct lexer *lexer, struct dataset *ds, enum val_type type) { assert (val_type_is_valid (type)); @@ -85,15 +82,12 @@ expr_parse (struct lexer *lexer, struct pool *pool, struct dataset *ds, return NULL; } - e = finish_expression (expr_optimize (n, e), e); - if (pool) - pool_add_subpool (pool, e->expr_pool); - return e; + return finish_expression (expr_optimize (n, e), e); } /* Parses a boolean expression, otherwise similar to expr_parse(). */ struct expression * -expr_parse_bool (struct lexer *lexer, struct pool *pool, struct dataset *ds) +expr_parse_bool (struct lexer *lexer, struct dataset *ds) { struct expression *e = expr_create (ds); union any_node *n = parse_or (lexer, e); @@ -116,17 +110,14 @@ expr_parse_bool (struct lexer *lexer, struct pool *pool, struct dataset *ds) return NULL; } - e = finish_expression (expr_optimize (n, e), e); - if (pool) - pool_add_subpool (pool, e->expr_pool); - return e; + return finish_expression (expr_optimize (n, e), e); } /* Parses a numeric expression that is intended to be assigned to newly created variable NEW_VAR_NAME. (This allows for a better error message if the expression is not numeric.) Otherwise similar to expr_parse(). */ struct expression * -expr_parse_new_variable (struct lexer *lexer, struct pool *pool, struct dataset *ds, +expr_parse_new_variable (struct lexer *lexer, struct dataset *ds, const char *new_var_name) { struct expression *e = expr_create (ds); @@ -149,10 +140,7 @@ expr_parse_new_variable (struct lexer *lexer, struct pool *pool, struct dataset return NULL; } - e = finish_expression (expr_optimize (n, e), e); - if (pool) - pool_add_subpool (pool, e->expr_pool); - return e; + return finish_expression (expr_optimize (n, e), e); } /* Free expression E. */ diff --git a/src/language/expressions/public.h b/src/language/expressions/public.h index a4313a40c0..950e3a17ba 100644 --- a/src/language/expressions/public.h +++ b/src/language/expressions/public.h @@ -29,15 +29,14 @@ struct lexer; struct pool; union value; -struct expression *expr_parse (struct lexer *lexer, struct pool *, - struct dataset *, enum val_type); -struct expression *expr_parse_bool (struct lexer *lexer, struct pool *, - struct dataset *); -struct expression *expr_parse_new_variable (struct lexer *lexer, struct pool *, - struct dataset *, +struct expression *expr_parse (struct lexer *, struct dataset *, enum val_type); +struct expression *expr_parse_bool (struct lexer *, struct dataset *); +struct expression *expr_parse_new_variable (struct lexer *, struct dataset *, const char *new_var_name); void expr_free (struct expression *); +struct expression *expr_create_false (void); + struct dataset; double expr_evaluate_num (struct expression *, const struct ccase *, int case_idx); diff --git a/src/language/stats/autorecode.c b/src/language/stats/autorecode.c index 1a74b1e4a9..a5fef75268 100644 --- a/src/language/stats/autorecode.c +++ b/src/language/stats/autorecode.c @@ -553,7 +553,7 @@ compare_arc_items (const void *a_, const void *b_, const void *direction_) return direction == ASCENDING ? cmp : -cmp; } -static int +static enum trns_result autorecode_trns_proc (void *arc_, struct ccase **c, casenumber case_idx UNUSED) { diff --git a/src/language/stats/descriptives.c b/src/language/stats/descriptives.c index 819e836d0e..1fcc309749 100644 --- a/src/language/stats/descriptives.c +++ b/src/language/stats/descriptives.c @@ -615,7 +615,7 @@ descriptives_set_all_sysmis_zscores (const struct dsc_trns *t, struct ccase *c) analyis. 4) any of the variables in the original analysis were missing (either system or user-missing values that weren't included). */ -static int +static enum trns_result descriptives_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED) { diff --git a/src/language/stats/quick-cluster.c b/src/language/stats/quick-cluster.c index e3bb76e422..3aff0e8a46 100644 --- a/src/language/stats/quick-cluster.c +++ b/src/language/stats/quick-cluster.c @@ -610,7 +610,7 @@ quick_cluster_show_centers (struct Kmeans *kmeans, bool initial, const struct qc /* A transformation function which juxtaposes the dataset with the (pre-prepared) dataset containing membership and/or distance values. */ -static int +static enum trns_result save_trans_func (void *aux, struct ccase **c, casenumber x UNUSED) { const struct save_trans_data *std = aux; diff --git a/src/language/stats/rank.c b/src/language/stats/rank.c index ecf9a65914..597c08fe3e 100644 --- a/src/language/stats/rank.c +++ b/src/language/stats/rank.c @@ -912,7 +912,7 @@ advance_ranking (struct rank_trns_input_var *iv) iv->current = casereader_read (iv->input); } -static int +static enum trns_result rank_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED) { struct rank_trns *trns = trns_; diff --git a/src/language/stats/regression.c b/src/language/stats/regression.c index e08f4a1d76..a65dd75767 100644 --- a/src/language/stats/regression.c +++ b/src/language/stats/regression.c @@ -159,7 +159,7 @@ save_trans_free (void *aux) return true; } -static int +static enum trns_result save_trans_func (void *aux, struct ccase **c, casenumber x UNUSED) { struct save_trans_data *save_trans_data = aux; @@ -191,7 +191,6 @@ save_trans_func (void *aux, struct ccase **c, casenumber x UNUSED) return TRNS_CONTINUE; } - int cmd_regression (struct lexer *lexer, struct dataset *ds) { diff --git a/src/language/xforms/compute.c b/src/language/xforms/compute.c index 9193dbc71e..ca8f200d4f 100644 --- a/src/language/xforms/compute.c +++ b/src/language/xforms/compute.c @@ -124,7 +124,7 @@ cmd_compute (struct lexer *lexer, struct dataset *ds) /* Transformation functions. */ /* Handle COMPUTE or IF with numeric target variable. */ -static int +static enum trns_result compute_num (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; @@ -142,7 +142,7 @@ compute_num (void *compute_, struct ccase **c, casenumber case_num) /* Handle COMPUTE or IF with numeric vector element target variable. */ -static int +static enum trns_result compute_num_vec (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; @@ -178,7 +178,7 @@ compute_num_vec (void *compute_, struct ccase **c, casenumber case_num) } /* Handle COMPUTE or IF with string target variable. */ -static int +static enum trns_result compute_str (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; @@ -198,7 +198,7 @@ compute_str (void *compute_, struct ccase **c, casenumber case_num) /* Handle COMPUTE or IF with string vector element target variable. */ -static int +static enum trns_result compute_str_vec (void *compute_, struct ccase **c, casenumber case_num) { struct compute_trns *compute = compute_; @@ -249,7 +249,7 @@ cmd_if (struct lexer *lexer, struct dataset *ds) compute = compute_trns_create (); /* Test expression. */ - compute->test = expr_parse_bool (lexer, NULL, ds); + compute->test = expr_parse_bool (lexer, ds); if (compute->test == NULL) goto fail; @@ -297,9 +297,9 @@ parse_rvalue (struct lexer *lexer, const struct lvalue *lvalue, struct dataset *ds) { if (lvalue->is_new_variable) - return expr_parse_new_variable (lexer, NULL, ds, var_get_name (lvalue->variable)); + return expr_parse_new_variable (lexer, ds, var_get_name (lvalue->variable)); else - return expr_parse (lexer, NULL, ds, lvalue_get_type (lvalue)); + return expr_parse (lexer, ds, lvalue_get_type (lvalue)); } /* Returns a new struct compute_trns after initializing its fields. */ @@ -362,7 +362,7 @@ lvalue_parse (struct lexer *lexer, struct dataset *ds) lex_get (lexer); if (!lex_force_match (lexer, T_LPAREN)) goto lossage; - lvalue->element = expr_parse (lexer, NULL, ds, VAL_NUMERIC); + lvalue->element = expr_parse (lexer, ds, VAL_NUMERIC); if (lvalue->element == NULL) goto lossage; if (!lex_force_match (lexer, T_RPAREN)) diff --git a/src/language/xforms/count.c b/src/language/xforms/count.c index 0369af1e5d..4dfc68bd89 100644 --- a/src/language/xforms/count.c +++ b/src/language/xforms/count.c @@ -337,7 +337,7 @@ count_string (struct criteria *crit, const struct ccase *c) } /* Performs the COUNT transformation T on case C. */ -static int +static enum trns_result count_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED) { diff --git a/src/language/xforms/fail.c b/src/language/xforms/fail.c index f23fcec3f1..ec94fe25a5 100644 --- a/src/language/xforms/fail.c +++ b/src/language/xforms/fail.c @@ -24,12 +24,10 @@ #include "language/command.h" #include "language/lexer/lexer.h" #include "libpspp/message.h" - -static int trns_fail (void *x, struct ccase **c, casenumber n); /* A transformation which is guaranteed to fail. */ -static int +static enum trns_result trns_fail (void *x UNUSED, struct ccase **c UNUSED, casenumber n UNUSED) { diff --git a/src/language/xforms/recode.c b/src/language/xforms/recode.c index a2d963188a..b359661bdf 100644 --- a/src/language/xforms/recode.c +++ b/src/language/xforms/recode.c @@ -690,7 +690,7 @@ find_src_string (struct recode_trns *trns, const uint8_t *value, } /* Performs RECODE transformation. */ -static int +static enum trns_result recode_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED) { struct recode_trns *trns = trns_; diff --git a/src/language/xforms/sample.c b/src/language/xforms/sample.c index 7184562ef2..072cd68e22 100644 --- a/src/language/xforms/sample.c +++ b/src/language/xforms/sample.c @@ -107,7 +107,7 @@ cmd_sample (struct lexer *lexer, struct dataset *ds) } /* Executes a SAMPLE transformation. */ -static int +static enum trns_result sample_trns_proc (void *t_, struct ccase **c UNUSED, casenumber case_num UNUSED) { diff --git a/src/language/xforms/select-if.c b/src/language/xforms/select-if.c index 72284f3653..313b5fc4fc 100644 --- a/src/language/xforms/select-if.c +++ b/src/language/xforms/select-if.c @@ -50,7 +50,7 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds) struct expression *e; struct select_if_trns *t; - e = expr_parse_bool (lexer, NULL, ds); + e = expr_parse_bool (lexer, ds); if (!e) return CMD_CASCADING_FAILURE; @@ -69,7 +69,7 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds) } /* Performs the SELECT IF transformation T on case C. */ -static int +static enum trns_result select_if_proc (void *t_, struct ccase **c, casenumber case_num) {