Encapsulated lexer and updated calling functions accordingly.
[pspp-builds.git] / src / language / control / loop.c
index da1dc2fc49dfeda732b6f8e599ffe3d14fd92496..01aad6fdaad36ae9d414c9b30127d9fdb8b4e5d1 100644 (file)
    02110-1301, USA. */
 
 #include <config.h>
-#include <libpspp/message.h>
-#include <libpspp/alloc.h>
+
+#include "control-stack.h"
 #include <data/case.h>
-#include <language/command.h>
-#include <libpspp/compiler.h>
 #include <data/dictionary.h>
-#include "control-stack.h"
-#include <libpspp/message.h>
+#include <data/procedure.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/alloc.h>
+#include <libpspp/compiler.h>
+#include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
-#include <data/settings.h>
 #include <libpspp/str.h>
-#include <data/variable.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -56,6 +58,7 @@
 struct loop_trns
   {
     struct pool *pool;
+    struct dataset *ds;
 
     /* Iteration limit. */
     int max_pass_count;         /* Maximum number of passes (-1=unlimited). */
@@ -77,51 +80,53 @@ struct loop_trns
     int past_END_LOOP_index;    /* Just past END LOOP transformation. */
   };
 
-static struct ctl_class loop_class;
+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_free_func loop_trns_free;
 
-static struct loop_trns *create_loop_trns (void);
-static bool parse_if_clause (struct loop_trns *, struct expression **);
-static bool parse_index_clause (struct loop_trns *, char index_var_name[]);
+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 void close_loop (void *);
 \f
 /* LOOP. */
 
 /* Parses LOOP. */
 int
-cmd_loop (void)
+cmd_loop (struct lexer *lexer, struct dataset *ds)
 {
   struct loop_trns *loop;
   char index_var_name[LONG_NAME_LEN + 1];
   bool ok = true;
 
-  loop = create_loop_trns ();
-  while (token != '.' && ok) 
+  loop = create_loop_trns (ds);
+  while (lex_token (lexer) != '.' && ok) 
     {
-      if (lex_match_id ("IF")) 
-        ok = parse_if_clause (loop, &loop->loop_condition);
+      if (lex_match_id (lexer, "IF")) 
+        ok = parse_if_clause (lexer, loop, &loop->loop_condition);
       else
-        ok = parse_index_clause (loop, index_var_name);
+        ok = parse_index_clause (lexer, loop, index_var_name);
     }
 
   /* Find index variable and create if necessary. */
   if (ok && index_var_name[0] != '\0')
     {
-      loop->index_var = dict_lookup_var (default_dict, index_var_name);
+      loop->index_var = dict_lookup_var (dataset_dict (ds), index_var_name);
       if (loop->index_var == NULL)
-        loop->index_var = dict_create_var (default_dict, index_var_name, 0);
+        loop->index_var = dict_create_var (dataset_dict (ds), 
+                                          index_var_name, 0);
     }
   
   if (!ok)
     loop->max_pass_count = 0;
-  return ok ? CMD_SUCCESS : CMD_PART_SUCCESS;
+  return ok ? CMD_SUCCESS : CMD_FAILURE;
 }
 
 /* Parses END LOOP. */
 int
-cmd_end_loop (void)
+cmd_end_loop (struct lexer *lexer, struct dataset *ds)
 {
   struct loop_trns *loop;
   bool ok = true;
@@ -129,32 +134,34 @@ cmd_end_loop (void)
   loop = ctl_stack_top (&loop_class);
   if (loop == NULL)
     return CMD_CASCADING_FAILURE;
+
+  assert (loop->ds == ds);
   
   /* Parse syntax. */
-  if (lex_match_id ("IF"))
-    ok = parse_if_clause (loop, &loop->end_loop_condition);
+  if (lex_match_id (lexer, "IF"))
+    ok = parse_if_clause (lexer, loop, &loop->end_loop_condition);
   if (ok)
-    ok = lex_end_of_command () == CMD_SUCCESS;
+    ok = lex_end_of_command (lexer) == CMD_SUCCESS;
 
   if (!ok)
     loop->max_pass_count = 0;
 
   ctl_stack_pop (loop);
   
-  return ok ? CMD_SUCCESS : CMD_PART_SUCCESS;
+  return ok ? CMD_SUCCESS : CMD_FAILURE;
 }
 
 /* Parses BREAK. */
 int
-cmd_break (void)
+cmd_break (struct lexer *lexer, struct dataset *ds)
 {
   struct ctl_stmt *loop = ctl_stack_search (&loop_class);
   if (loop == NULL)
     return CMD_CASCADING_FAILURE;
 
-  add_transformation (break_trns_proc, NULL, loop);
+  add_transformation (ds, break_trns_proc, NULL, loop);
 
-  return lex_end_of_command ();
+  return lex_end_of_command (lexer);
 }
 
 /* Closes a LOOP construct by emitting the END LOOP
@@ -164,8 +171,8 @@ close_loop (void *loop_)
 {
   struct loop_trns *loop = loop_;
   
-  add_transformation (end_loop_trns_proc, NULL, loop);
-  loop->past_END_LOOP_index = next_transformation ();
+  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. */
@@ -180,9 +187,10 @@ close_loop (void *loop_)
    resulting expression to *CONDITION.
    Returns true if successful, false on failure. */
 static bool
-parse_if_clause (struct loop_trns *loop, struct expression **condition) 
+parse_if_clause (struct lexer *lexer, 
+                struct loop_trns *loop, struct expression **condition) 
 {
-  *condition = expr_parse_pool (loop->pool, default_dict, EXPR_BOOLEAN);
+  *condition = expr_parse_pool (lexer, loop->pool, loop->ds, EXPR_BOOLEAN);
   return *condition != NULL;
 }
 
@@ -190,29 +198,30 @@ parse_if_clause (struct loop_trns *loop, struct expression **condition)
    Stores the index variable's name in INDEX_VAR_NAME[].
    Returns true if successful, false on failure. */
 static bool
-parse_index_clause (struct loop_trns *loop, char index_var_name[]) 
+parse_index_clause (struct lexer *lexer, struct loop_trns *loop, char index_var_name[]) 
 {
-  if (token != T_ID) 
+  if (lex_token (lexer) != T_ID) 
     {
-      lex_error (NULL);
+      lex_error (lexer, NULL);
       return false;
     }
-  strcpy (index_var_name, tokid);
-  lex_get ();
+  strcpy (index_var_name, lex_tokid (lexer));
+  lex_get (lexer);
 
-  if (!lex_force_match ('='))
+  if (!lex_force_match (lexer, '='))
     return false;
 
-  loop->first_expr = expr_parse_pool (loop->pool, default_dict, EXPR_NUMBER);
+  loop->first_expr = expr_parse_pool (lexer, loop->pool, 
+                                     loop->ds, EXPR_NUMBER);
   if (loop->first_expr == NULL)
     return false;
 
   for (;;)
     {
       struct expression **e;
-      if (lex_match (T_TO)) 
+      if (lex_match (lexer, T_TO)) 
         e = &loop->last_expr;
-      else if (lex_match (T_BY)) 
+      else if (lex_match (lexer, T_BY)) 
         e = &loop->by_expr;
       else
         break;
@@ -222,13 +231,13 @@ parse_index_clause (struct loop_trns *loop, char index_var_name[])
           lex_sbc_only_once (e == &loop->last_expr ? "TO" : "BY");
           return false;
         }
-      *e = expr_parse_pool (loop->pool, default_dict, EXPR_NUMBER);
+      *e = expr_parse_pool (lexer, loop->pool, loop->ds, EXPR_NUMBER);
       if (*e == NULL)
         return false;
     }
   if (loop->last_expr == NULL) 
     {
-      lex_sbc_missing ("TO");
+      lex_sbc_missing (lexer, "TO");
       return false;
     }
   if (loop->by_expr == NULL)
@@ -239,7 +248,7 @@ parse_index_clause (struct loop_trns *loop, char index_var_name[])
 
 /* Creates, initializes, and returns a new loop_trns. */
 static struct loop_trns *
-create_loop_trns (void
+create_loop_trns (struct dataset *ds
 {
   struct loop_trns *loop = pool_create_container (struct loop_trns, pool);
   loop->max_pass_count = -1;
@@ -247,18 +256,31 @@ create_loop_trns (void)
   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 (loop_trns_proc, loop_trns_free, loop);
-  loop->past_LOOP_index = next_transformation ();
+  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
-loop_trns_proc (void *loop_, struct ccase *c, int case_num)
+loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num)
 {
   struct loop_trns *loop = loop_;
 
@@ -310,7 +332,7 @@ 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, int case_num UNUSED)
+end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED)
 {
   struct loop_trns *loop = loop_;
 
@@ -348,7 +370,7 @@ end_loop_trns_proc (void *loop_, struct ccase *c, int case_num UNUSED)
 
 /* Executes BREAK. */
 static int
-break_trns_proc (void *loop_, struct ccase *c UNUSED, int case_num UNUSED)
+break_trns_proc (void *loop_, struct ccase *c UNUSED, casenumber case_num UNUSED)
 {
   struct loop_trns *loop = loop_;
 
@@ -356,7 +378,7 @@ break_trns_proc (void *loop_, struct ccase *c UNUSED, int case_num UNUSED)
 }
 
 /* LOOP control structure class definition. */
-static struct ctl_class loop_class =
+static const struct ctl_class loop_class =
   {
     "LOOP",
     "END LOOP",