X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fcontrol%2Fdo-if.c;h=f5ebe799e34c0eb091513889d8123f3215431fa7;hb=765362af497f7b1f9c9a5ef387d40eac474fbbe3;hp=a80dae31c9811936ea24908901c4518d5b9bebba;hpb=81579d9e9f994fb2908f50af41c3eb033d216e58;p=pspp diff --git a/src/language/control/do-if.c b/src/language/control/do-if.c index a80dae31c9..f5ebe799e3 100644 --- a/src/language/control/do-if.c +++ b/src/language/control/do-if.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2009, 2011 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2009-2013 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 @@ -19,11 +19,11 @@ #include #include "data/case.h" -#include "data/procedure.h" +#include "data/control-stack.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" @@ -76,9 +76,17 @@ struct do_if_trns struct dataset *ds; /* The dataset */ struct clause *clauses; /* Clauses. */ size_t clause_cnt; /* Number of clauses. */ + int DO_IF_index; /* DO IF transformation. */ int past_END_IF_index; /* Transformation just past last clause. */ }; +/* Jumps past the END IF. */ +struct end_if_trns + { + struct do_if_trns *do_if; + int index; + }; + static const struct ctl_class do_if_class; static int parse_clause (struct lexer *, struct do_if_trns *, struct dataset *ds); @@ -89,9 +97,8 @@ 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_free_func do_if_trns_free; +static trns_proc_func do_if_trns_proc, end_if_trns_proc; +static trns_free_func do_if_trns_free, end_if_trns_free; /* Parse DO IF. */ int @@ -101,10 +108,10 @@ cmd_do_if (struct lexer *lexer, struct dataset *ds) do_if->clauses = NULL; do_if->clause_cnt = 0; do_if->ds = ds; + do_if->DO_IF_index = next_transformation (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); + add_transformation (ds, do_if_trns_proc, do_if_trns_free, do_if); return parse_clause (lexer, do_if, ds); } @@ -121,29 +128,29 @@ cmd_else_if (struct lexer *lexer, struct dataset *ds) /* Parse ELSE. */ int -cmd_else (struct lexer *lexer, struct dataset *ds) +cmd_else (struct lexer *lexer UNUSED, struct dataset *ds) { struct do_if_trns *do_if = ctl_stack_top (&do_if_class); assert (ds == do_if->ds); if (do_if == NULL || !must_not_have_else (do_if)) return CMD_CASCADING_FAILURE; add_else (do_if); - return lex_end_of_command (lexer); + return CMD_SUCCESS; } /* Parse END IF. */ int -cmd_end_if (struct lexer *lexer, struct dataset *ds) +cmd_end_if (struct lexer *lexer UNUSED, struct dataset *ds) { struct do_if_trns *do_if = ctl_stack_top (&do_if_class); - assert (ds == do_if->ds); if (do_if == NULL) return CMD_CASCADING_FAILURE; + assert (ds == do_if->ds); ctl_stack_pop (do_if); - return lex_end_of_command (lexer); + return CMD_SUCCESS; } /* Closes out DO_IF, by adding a sentinel ELSE clause if @@ -174,7 +181,7 @@ must_not_have_else (struct do_if_trns *do_if) { if (has_else (do_if)) { - msg (SE, _("This command may not follow ELSE in DO IF...END IF.")); + msg (SE, _("This command may not follow %s in %s ... %s."), "ELSE", "DO IF", "END IF"); return false; } else @@ -204,7 +211,7 @@ parse_clause (struct lexer *lexer, struct do_if_trns *do_if, struct dataset *ds) add_clause (do_if, condition); - return lex_end_of_command (lexer); + return CMD_SUCCESS; } /* Adds a clause to DO_IF that tests for the given CONDITION and, @@ -216,7 +223,15 @@ add_clause (struct do_if_trns *do_if, struct expression *condition) struct clause *clause; if (do_if->clause_cnt > 0) - add_transformation (do_if->ds, break_trns_proc, NULL, do_if); + { + struct end_if_trns *end_if; + + end_if = xmalloc (sizeof *end_if); + end_if->do_if = do_if; + end_if->index = next_transformation (do_if->ds); + add_transformation (do_if->ds, + end_if_trns_proc, end_if_trns_free, end_if); + } do_if->clauses = xnrealloc (do_if->clauses, do_if->clause_cnt + 1, sizeof *do_if->clauses); @@ -225,17 +240,6 @@ add_clause (struct do_if_trns *do_if, struct expression *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 (); -} - /* DO IF transformation procedure. Checks each clause and jumps to the appropriate transformation. */ @@ -252,12 +256,12 @@ do_if_trns_proc (void *do_if_, struct ccase **c, casenumber case_num UNUSED) { double boolean = expr_evaluate_num (clause->condition, *c, case_num); if (boolean == 1.0) - return clause->target_index; + return clause->target_index - do_if->DO_IF_index; else if (boolean == SYSMIS) - return do_if->past_END_IF_index; + return do_if->past_END_IF_index - do_if->DO_IF_index; } else - return clause->target_index; + return clause->target_index - do_if->DO_IF_index; } return do_if->past_END_IF_index; } @@ -279,14 +283,23 @@ do_if_trns_free (void *do_if_) /* Breaks out of a DO IF construct. */ static int -break_trns_proc (void *do_if_, struct ccase **c UNUSED, +end_if_trns_proc (void *end_if_, struct ccase **c UNUSED, casenumber case_num UNUSED) { - struct do_if_trns *do_if = do_if_; + struct end_if_trns *end_if = end_if_; - return do_if->past_END_IF_index; + return end_if->do_if->past_END_IF_index - end_if->index; } +/* Frees an END IF transformation. */ +static bool +end_if_trns_free (void *end_if_) +{ + struct end_if_trns *end_if = end_if_; + + free (end_if); + return true; +} /* DO IF control structure class definition. */ static const struct ctl_class do_if_class = {