X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fdata-io%2Finpt-pgm.c;h=51c369810f9d2872810a00341a0623321f4f04c8;hb=b74d09af5e07f954c18e7cdb8aca3af47fa10208;hp=99bfb23bca7b83bf0abb9bbce91b948764bfec94;hpb=dcf9b154cbcaa35c3d8459a201b77eec8bcb30bd;p=pspp-builds.git diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index 99bfb23b..51c36981 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -18,28 +18,40 @@ 02110-1301, USA. */ #include -#include "message.h" + +#include + #include #include -#include "alloc.h" -#include "case.h" -#include "command.h" -#include "data-list.h" -#include "data-reader.h" -#include "dictionary.h" -#include "message.h" -#include "expressions/public.h" -#include "file-handle.h" -#include "lexer.h" -#include "misc.h" -#include "str.h" -#include "variable.h" -#include "procedure.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "gettext.h" #define _(msgid) gettext (msgid) -#include "debug-print.h" +/* Private result codes for use within INPUT PROGRAM. */ +enum cmd_result_extensions + { + CMD_END_INPUT_PROGRAM = CMD_PRIVATE_FIRST, + CMD_END_CASE + }; /* Indicates how a `union value' should be initialized. */ enum value_init_type @@ -53,48 +65,96 @@ enum value_init_type struct input_program_pgm { + struct trns_chain *trns_chain; + + size_t case_nr; /* Incremented by END CASE transformation. */ + write_case_func *write_case;/* Called by END CASE. */ + write_case_data wc_data; /* Aux data used by END CASE. */ + enum value_init_type *init; /* How to initialize each `union value'. */ size_t init_cnt; /* Number of elements in inp_init. */ size_t case_size; /* Size of case in bytes. */ }; -static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc; +static void destroy_input_program (struct input_program_pgm *); +static trns_proc_func end_case_trns_proc; +static trns_proc_func reread_trns_proc; +static trns_proc_func end_file_trns_proc; static trns_free_func reread_trns_free; -int -cmd_input_program (void) -{ - discard_variables (); +static const struct case_source_class input_program_source_class; - /* FIXME: we shouldn't do this here, but I'm afraid that other - code will check the class of vfm_source. */ - vfm_source = create_case_source (&input_program_source_class, NULL); +static bool inside_input_program; - return lex_end_of_command (); +/* Returns true if we're parsing the inside of a INPUT + PROGRAM...END INPUT PROGRAM construct, false otherwise. */ +bool +in_input_program (void) +{ + return inside_input_program; +} + +/* Emits an END CASE transformation for INP. */ +static void +emit_END_CASE (struct input_program_pgm *inp) +{ + add_transformation (end_case_trns_proc, NULL, inp); } int -cmd_end_input_program (void) +cmd_input_program (void) { struct input_program_pgm *inp; size_t i; + bool saw_END_CASE = false; - if (!case_source_is_class (vfm_source, &input_program_source_class)) + discard_variables (); + if (token != '.') + return lex_end_of_command (); + + inp = xmalloc (sizeof *inp); + inp->trns_chain = NULL; + inp->init = NULL; + + inside_input_program = true; + for (;;) { - msg (SE, _("No matching INPUT PROGRAM command.")); - return CMD_CASCADING_FAILURE; + enum cmd_result result; + lex_get (); + result = cmd_parse (CMD_STATE_INPUT_PROGRAM); + if (result == CMD_END_INPUT_PROGRAM) + break; + else if (result == CMD_END_CASE) + { + emit_END_CASE (inp); + saw_END_CASE = true; + } + else if (cmd_result_is_failure (result) && result != CMD_FAILURE) + { + if (result == CMD_EOF) + msg (SE, _("Unexpected end-of-file within INPUT PROGRAM.")); + inside_input_program = false; + discard_variables (); + destroy_input_program (inp); + return result; + } } - - if (dict_get_next_value_idx (default_dict) == 0) - msg (SW, _("No data-input or transformation commands specified " - "between INPUT PROGRAM and END INPUT PROGRAM.")); + if (!saw_END_CASE) + emit_END_CASE (inp); + inside_input_program = false; - /* Mark the boundary between INPUT PROGRAM transformations and - ordinary transformations. */ - f_trns = n_trns; + if (dict_get_next_value_idx (default_dict) == 0) + { + msg (SE, _("Input program did not create any variables.")); + discard_variables (); + destroy_input_program (inp); + return CMD_FAILURE; + } + + inp->trns_chain = proc_capture_transformations (); + trns_chain_finalize (inp->trns_chain); /* Figure out how to initialize each input case. */ - inp = xmalloc (sizeof *inp); inp->init_cnt = dict_get_next_value_idx (default_dict); inp->init = xnmalloc (inp->init_cnt, sizeof *inp->init); for (i = 0; i < inp->init_cnt; i++) @@ -106,7 +166,7 @@ cmd_end_input_program (void) size_t j; value_init = var->type == NUMERIC ? INP_NUMERIC : INP_STRING; - value_init |= var->reinit ? INP_REINIT : INP_INIT_ONCE; + value_init |= var->leave ? INP_INIT_ONCE : INP_REINIT; for (j = 0; j < var->nv; j++) inp->init[j + var->fv] = value_init; @@ -115,10 +175,16 @@ cmd_end_input_program (void) assert (inp->init[i] != -1); inp->case_size = dict_get_case_size (default_dict); - /* Put inp into vfm_source for later use. */ - vfm_source->aux = inp; + proc_set_source (create_case_source (&input_program_source_class, inp)); - return lex_end_of_command (); + return CMD_SUCCESS; +} + +int +cmd_end_input_program (void) +{ + assert (in_input_program ()); + return CMD_END_INPUT_PROGRAM; } /* Initializes case C. Called before the first case is read. */ @@ -178,85 +244,29 @@ input_program_source_read (struct case_source *source, write_case_data wc_data) { struct input_program_pgm *inp = source->aux; - size_t i; - - /* Nonzero if there were any END CASE commands in the set of - transformations. If so, we don't automatically write out - cases. */ - int end_case = 0; - - /* FIXME? This is the number of cases sent out of the input - program, not the number of cases written to the procedure. - The difference should only show up in $CASENUM in COMPUTE. - We should check behavior against SPSS. */ - int cases_written = 0; - assert (inp != NULL); - - /* Figure end_case. */ - for (i = 0; i < f_trns; i++) - if (t_trns[i].proc == end_case_trns_proc) - end_case = 1; - - /* FIXME: This is an ugly kluge. */ - for (i = 0; i < f_trns; i++) - if (t_trns[i].proc == repeating_data_trns_proc) - repeating_data_set_write_case (t_trns[i].private, write_case, wc_data); - - init_case (inp, c); - for (;;) + inp->case_nr = 1; + inp->write_case = write_case; + inp->wc_data = wc_data; + for (init_case (inp, c); ; clear_case (inp, c)) { - /* Perform transformations on `blank' case. */ - for (i = 0; i < f_trns; ) - { - int code; - - if (t_trns[i].proc == end_case_trns_proc) - { - cases_written++; - if (!write_case (wc_data)) - return false; - clear_case (inp, c); - i++; - continue; - } - - code = t_trns[i].proc (t_trns[i].private, c, cases_written + 1); - switch (code) - { - case TRNS_CONTINUE: - i++; - break; - - case TRNS_DROP_CASE: - abort (); - - case TRNS_ERROR: - return false; - - case TRNS_NEXT_CASE: - goto next_case; - - case TRNS_END_FILE: - return true; - - default: - i = code; - break; - } - } - - /* Write the case if appropriate. */ - if (!end_case) - { - cases_written++; - if (!write_case (wc_data)) - return false; - } + enum trns_result result = trns_chain_execute (inp->trns_chain, c, + &inp->case_nr); + if (result == TRNS_ERROR) + return false; + else if (result == TRNS_END_FILE) + return true; + } +} - /* Blank out the case for the next iteration. */ - next_case: - clear_case (inp, c); +static void +destroy_input_program (struct input_program_pgm *pgm) +{ + if (pgm != NULL) + { + trns_chain_destroy (pgm->trns_chain); + free (pgm->init); + free (pgm); } } @@ -266,16 +276,10 @@ input_program_source_destroy (struct case_source *source) { struct input_program_pgm *inp = source->aux; - cancel_transformations (); - - if (inp != NULL) - { - free (inp->init); - free (inp); - } + destroy_input_program (inp); } -const struct case_source_class input_program_source_class = +static const struct case_source_class input_program_source_class = { "INPUT PROGRAM", NULL, @@ -286,25 +290,24 @@ const struct case_source_class input_program_source_class = int cmd_end_case (void) { - if (!case_source_is_class (vfm_source, &input_program_source_class)) - { - msg (SE, _("This command may only be executed between INPUT PROGRAM " - "and END INPUT PROGRAM.")); - return CMD_CASCADING_FAILURE; - } - - add_transformation (end_case_trns_proc, NULL, NULL); - + assert (in_input_program ()); + if (token == '.') + return CMD_END_CASE; return lex_end_of_command (); } -/* Should never be called, because this is handled in - input_program_source_read(). */ +/* Sends the current case as the source's output. */ int -end_case_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED, - int case_num UNUSED) +end_case_trns_proc (void *inp_, struct ccase *c, int case_nr UNUSED) { - abort (); + struct input_program_pgm *inp = inp_; + + if (!inp->write_case (inp->wc_data)) + return TRNS_ERROR; + + inp->case_nr++; + clear_case (inp, c); + return TRNS_CONTINUE; } /* REREAD transformation. */ @@ -405,12 +408,7 @@ reread_trns_free (void *t_) int cmd_end_file (void) { - if (!case_source_is_class (vfm_source, &input_program_source_class)) - { - msg (SE, _("This command may only be executed between INPUT PROGRAM " - "and END INPUT PROGRAM.")); - return CMD_CASCADING_FAILURE; - } + assert (in_input_program ()); add_transformation (end_file_trns_proc, NULL, NULL);