X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fcontrol%2Floop.c;h=bfd364ccd1085a8d5874c6b018cfd2ded31fc4f8;hb=3b54533821614d17afc61f1cd3b87d3a06fbf4da;hp=0657777acc492b2dd9ffe1d05c9d037956120de2;hpb=480a0746507ce73d26f528b56dc3ed80195096e0;p=pspp
diff --git a/src/language/control/loop.c b/src/language/control/loop.c
index 0657777acc..bfd364ccd1 100644
--- a/src/language/control/loop.c
+++ b/src/language/control/loop.c
@@ -1,39 +1,39 @@
-/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 1997-9, 2000, 2009-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 2 of the
- License, or (at your option) any later version.
+ 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.
+ 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program. If not, see . */
#include
-#include "control-stack.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include "language/control/control-stack.h"
+
+#include "data/case.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/settings.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/expressions/public.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
@@ -61,7 +61,7 @@ struct loop_trns
/* Iteration limit. */
int max_pass_count; /* Maximum number of passes (-1=unlimited). */
- int pass; /* Number of passes thru the loop so far. */
+ int pass; /* Number of passes through the loop so far. */
/* a=a TO b [BY c]. */
struct variable *index_var; /* Index variable. */
@@ -86,8 +86,10 @@ static trns_proc_func loop_trns_proc, end_loop_trns_proc, break_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_index_clause (struct lexer *, struct loop_trns *, char index_var_name[]);
+static bool parse_if_clause (struct lexer *,
+ struct loop_trns *, struct expression **);
+static bool parse_index_clause (struct dataset *, struct lexer *,
+ struct loop_trns *, bool *created_index_var);
static void close_loop (void *);
/* LOOP. */
@@ -97,30 +99,30 @@ int
cmd_loop (struct lexer *lexer, struct dataset *ds)
{
struct loop_trns *loop;
- char index_var_name[LONG_NAME_LEN + 1];
+ bool created_index_var = false;
bool ok = true;
loop = create_loop_trns (ds);
- while (lex_token (lexer) != '.' && ok)
+ while (lex_token (lexer) != T_ENDCMD && ok)
{
- if (lex_match_id (lexer, "IF"))
+ if (lex_match_id (lexer, "IF"))
ok = parse_if_clause (lexer, loop, &loop->loop_condition);
else
- ok = parse_index_clause (lexer, loop, index_var_name);
+ ok = parse_index_clause (ds, lexer, loop, &created_index_var);
}
- /* Find index variable and create if necessary. */
- if (ok && index_var_name[0] != '\0')
+ /* Clean up if necessary. */
+ if (!ok)
{
- loop->index_var = dict_lookup_var (dataset_dict (ds), index_var_name);
- if (loop->index_var == NULL)
- loop->index_var = dict_create_var (dataset_dict (ds),
- index_var_name, 0);
+ loop->max_pass_count = 0;
+ if (loop->index_var != NULL && created_index_var)
+ {
+ dict_delete_var (dataset_dict (ds), loop->index_var);
+ loop->index_var = NULL;
+ }
}
-
- if (!ok)
- loop->max_pass_count = 0;
- return ok ? CMD_SUCCESS : CMD_FAILURE;
+
+ return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
}
/* Parses END LOOP. */
@@ -135,7 +137,7 @@ cmd_end_loop (struct lexer *lexer, struct dataset *ds)
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);
@@ -146,13 +148,13 @@ cmd_end_loop (struct lexer *lexer, struct dataset *ds)
loop->max_pass_count = 0;
ctl_stack_pop (loop);
-
+
return ok ? CMD_SUCCESS : CMD_FAILURE;
}
/* Parses BREAK. */
int
-cmd_break (struct lexer *lexer, struct dataset *ds)
+cmd_break (struct lexer *lexer UNUSED, struct dataset *ds)
{
struct ctl_stmt *loop = ctl_stack_search (&loop_class);
if (loop == NULL)
@@ -160,7 +162,7 @@ cmd_break (struct lexer *lexer, struct dataset *ds)
add_transformation (ds, break_trns_proc, NULL, loop);
- return lex_end_of_command (lexer);
+ return CMD_SUCCESS;
}
/* Closes a LOOP construct by emitting the END LOOP
@@ -169,48 +171,68 @@ 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->loop_condition == NULL
- && loop->end_loop_condition == NULL)
- loop->max_pass_count = get_mxloops ();
+ 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 loop_trns *loop, struct expression **condition)
{
+ if (*condition != NULL)
+ {
+ lex_sbc_only_once ("IF");
+ return false;
+ }
+
*condition = expr_parse_pool (lexer, loop->pool, loop->ds, EXPR_BOOLEAN);
return *condition != NULL;
}
/* Parses an indexing clause into LOOP.
- Stores the index variable's name in INDEX_VAR_NAME[].
+ Stores true in *CREATED_INDEX_VAR if the index clause created
+ a new variable, false otherwise.
Returns true if successful, false on failure. */
static bool
-parse_index_clause (struct lexer *lexer, struct loop_trns *loop, char index_var_name[])
+parse_index_clause (struct dataset *ds, struct lexer *lexer,
+ struct loop_trns *loop, bool *created_index_var)
{
- if (lex_token (lexer) != T_ID)
+ if (loop->index_var != NULL)
+ {
+ msg (SE, _("Only one index clause may be specified."));
+ return false;
+ }
+
+ if (lex_token (lexer) != T_ID)
{
lex_error (lexer, NULL);
return false;
}
- strcpy (index_var_name, lex_tokid (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;
+ }
lex_get (lexer);
- if (!lex_force_match (lexer, '='))
+ if (!lex_force_match (lexer, T_EQUALS))
return false;
- loop->first_expr = expr_parse_pool (lexer, loop->pool,
+ loop->first_expr = expr_parse_pool (lexer, loop->pool,
loop->ds, EXPR_NUMBER);
if (loop->first_expr == NULL)
return false;
@@ -218,14 +240,14 @@ parse_index_clause (struct lexer *lexer, struct loop_trns *loop, char index_var_
for (;;)
{
struct expression **e;
- if (lex_match (lexer, T_TO))
+ if (lex_match (lexer, T_TO))
e = &loop->last_expr;
- else if (lex_match (lexer, T_BY))
+ else if (lex_match (lexer, T_BY))
e = &loop->by_expr;
else
break;
- if (*e != NULL)
+ if (*e != NULL)
{
lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY");
return false;
@@ -234,9 +256,9 @@ parse_index_clause (struct lexer *lexer, struct loop_trns *loop, char index_var_
if (*e == NULL)
return false;
}
- if (loop->last_expr == NULL)
+ if (loop->last_expr == NULL)
{
- lex_sbc_missing (lexer, "TO");
+ lex_sbc_missing ("TO");
return false;
}
if (loop->by_expr == NULL)
@@ -247,7 +269,7 @@ parse_index_clause (struct lexer *lexer, struct loop_trns *loop, char index_var_
/* Creates, initializes, and returns a new loop_trns. */
static struct loop_trns *
-create_loop_trns (struct dataset *ds)
+create_loop_trns (struct dataset *ds)
{
struct loop_trns *loop = pool_create_container (struct loop_trns, pool);
loop->max_pass_count = -1;
@@ -267,9 +289,9 @@ create_loop_trns (struct dataset *ds)
}
/* Finalizes LOOP by clearing the control stack, thus ensuring
- that all open LOOPs are closed. */
+ that all open LOOPs are closed. */
static void
-loop_trns_finalize (void *do_if_ UNUSED)
+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
@@ -279,24 +301,26 @@ loop_trns_finalize (void *do_if_ UNUSED)
/* Sets up LOOP for the first pass. */
static int
-loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num)
+loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num)
{
struct loop_trns *loop = loop_;
if (loop->index_var != NULL)
{
/* Evaluate loop index expressions. */
- loop->cur = expr_evaluate_num (loop->first_expr, c, case_num);
+ 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);
+ loop->by = expr_evaluate_num (loop->by_expr, *c, case_num);
+ 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. */
- case_data_rw (c, loop->index_var)->f = loop->cur;
+ *c = case_unshare (*c);
+ case_data_rw (*c, loop->index_var)->f = loop->cur;
/* Throw out pathological cases. */
- if (!finite (loop->cur) || !finite (loop->by) || !finite (loop->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))
@@ -310,7 +334,7 @@ loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num)
/* Check condition. */
if (loop->loop_condition != NULL
- && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
+ && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0)
goto zero_pass;
return loop->past_LOOP_index;
@@ -331,34 +355,31 @@ loop_trns_free (void *loop_)
/* 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)
+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) != 1.0)
+ && expr_evaluate_num (loop->end_loop_condition, *c, case_num) != 0.0)
goto break_out;
/* MXLOOPS limiter. */
- if (loop->max_pass_count >= 0)
- {
- if (loop->pass >= loop->max_pass_count)
- goto break_out;
- loop->pass++;
- }
+ 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)
+ 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;
- case_data_rw (c, loop->index_var)->f = loop->cur;
+ *c = case_unshare (*c);
+ case_data_rw (*c, loop->index_var)->f = loop->cur;
}
if (loop->loop_condition != NULL
- && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
+ && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0)
goto break_out;
return loop->past_LOOP_index;
@@ -369,7 +390,8 @@ end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED)
/* Executes BREAK. */
static int
-break_trns_proc (void *loop_, struct ccase *c UNUSED, casenumber case_num UNUSED)
+break_trns_proc (void *loop_, struct ccase **c UNUSED,
+ casenumber case_num UNUSED)
{
struct loop_trns *loop = loop_;