settings: Add macro settings.
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 13 Apr 2021 19:17:01 +0000 (12:17 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 13 Apr 2021 19:17:20 +0000 (12:17 -0700)
doc/utilities.texi
src/data/settings.c
src/data/settings.h
src/language/utilities/set.c
tests/language/utilities/set.at

index bb248454abfad21b03aff6fddd6826a0f4c56573..da5de1ddceaf5164c80cd8788b6f65a921c40d14 100644 (file)
@@ -534,6 +534,12 @@ SET
         /SAFER=ON
         /LOCALE='@var{string}'
 
+(macros)
+        /MEXPAND=@{ON,OFF@}
+        /MPRINT=@{ON,OFF@}
+        /MITERATE=@var{number}
+        /MNEST=@var{number}
+
 (settings not yet implemented, but accepted and ignored)
         /BASETEXTDIRECTION=@{AUTOMATIC,RIGHTTOLEFT,LEFTTORIGHT@}
         /BLOCK='@var{c}'
@@ -543,10 +549,6 @@ SET
         /COMPRESSION=@{ON,OFF@}
         /CMPTRANS=@{ON,OFF@}
         /HEADER=@{NO,YES,BLANK@}
-        /MEXPAND=@{ON,OFF@}
-        /MITERATE=@var{number}
-        /MNEST=@var{number}
-        /MPRINT=@{ON,OFF@}
 @end display
 
 @cmd{SET} allows the user to adjust several parameters relating to
@@ -932,6 +934,28 @@ Contrary to intuition, this command does not affect any aspect
 of the system's locale.
 @end table
 
+The following subcommands affect the interpretation of macros.
+
+@table @asis
+@item MEXPAND
+Controls whether macros are expanded.  The default is ON.
+
+@item MPRINT
+Controls whether the expansion of macros is included in output.  This
+is separate from whether command syntax in general is included in
+output.  The default is OFF.
+
+@item MITERATE
+Limits the number of iterations executed in @code{!DO} loops within
+macros.  This does not affect other language constructs such as
+@cmd{LOOP}.  This must be set to a positive integer.  The default is
+1000.
+
+@item MNEST
+Limits the number of levels of nested macro expansion.  This must be
+set to a positive integer.  The default is 50.
+@end table
+
 The following subcommands are not yet implemented, but PSPP accepts
 them and ignores the settings.
 
@@ -944,10 +968,6 @@ them and ignores the settings.
 @itemx COMPRESSION
 @itemx CMPTRANS
 @itemx HEADER
-@itemx MEXPAND
-@itemx MITERATE
-@itemx MNEST
-@itemx MPRINT
 @end table
 
 @node SHOW
@@ -971,6 +991,10 @@ SHOW
         [FORMAT]
         [FUZZBITS]
         [LENGTH]
+        [MEXPAND]
+        [MPRINT]
+        [MITERATE]
+        [MNEST]
         [MXERRS]
         [MXLOOPS]
         [MXWARNS]
index 0dfa94751f974ff8ba1f6c50d05638c5d7a157d0..34649de73c3ed54d44e712afba1efc6dcfbc795a 100644 (file)
@@ -59,7 +59,13 @@ struct settings
   double blanks;
   int max_messages[MSG_N_SEVERITIES];
   bool printback;
-  bool mprint;
+
+  /* Macro settings. */
+  bool mexpand;                 /* Expand macros? */
+  bool mprint;                  /* Print macro expansions? */
+  int miterate;                 /* Maximum iterations of !FOR. */
+  int mnest;                    /* Maximum nested macro expansion levels. */
+
   int mxloops;
   size_t workspace;
   struct fmt_spec default_format;
@@ -101,7 +107,12 @@ static struct settings the_settings = {
   },
 
   .printback = true,
-  .mprint = true,
+
+  .mexpand = true,
+  .mprint = false,
+  .miterate = 1000,
+  .mnest = 50,
+
   .mxloops = 40,
   .workspace = 64L * 1024 * 1024,
   .default_format = { .type = FMT_F, .w = 8, .d = 2 },
@@ -384,6 +395,20 @@ settings_set_max_messages (enum msg_severity severity, int max)
   the_settings.max_messages[severity] = max;
 }
 
+/* Returns whether to expand macro invocations. */
+bool
+settings_get_mexpand (void)
+{
+  return the_settings.mexpand;
+}
+
+/* Sets whether to expand macro invocations. */
+void
+settings_set_mexpand (bool mexpand)
+{
+  the_settings.mexpand = mexpand;
+}
+
 /* Independent of get_printback, controls whether the commands
    generated by macro invocations are displayed. */
 bool
@@ -400,6 +425,35 @@ settings_set_mprint (bool mprint)
   the_settings.mprint = mprint;
 }
 
+/* Returns the limit for loop iterations within a macro. */
+int
+settings_get_miterate (void)
+{
+  return the_settings.miterate;
+}
+
+/* Sets the limit for loop iterations within a macro. */
+void
+settings_set_miterate (int miterate)
+{
+  the_settings.miterate = miterate;
+}
+
+/* Returns the limit for recursion macro expansions. */
+int settings_get_mnest (void)
+{
+  return the_settings.mnest;
+}
+
+/* Sets the limit for recursion macro expansions. */
+void
+settings_set_mnest (int mnest)
+{
+  the_settings.mnest = mnest;
+}
+
+int settings_get_mxloops (void);
+void settings_set_mxloops (int);
 /* Implied limit of unbounded loop. */
 int
 settings_get_mxloops (void)
index 1361bef3747cd7afe781d76fab9e5ceaf9c4732c..dafd114f8d816bae49756e470058c00cf6e4e988 100644 (file)
@@ -86,9 +86,19 @@ void settings_set_blanks (double);
 int settings_get_max_messages (enum msg_severity);
 void settings_set_max_messages (enum msg_severity, int max);
 
+/* Macro settings. */
+bool settings_get_mexpand (void);
+void settings_set_mexpand (bool);
+
 bool settings_get_mprint (void);
 void settings_set_mprint (bool);
 
+int settings_get_miterate (void);
+void settings_set_miterate (int);
+
+int settings_get_mnest (void);
+void settings_set_mnest (int);
+
 int settings_get_mxloops (void);
 void settings_set_mxloops (int);
 
index 11b3dac914db6d9a6cd7da97ac3b7a4606d4445c..cfd1ca96d56ad87e5b465308a84e511e83196716 100644 (file)
@@ -490,25 +490,39 @@ parse_MESSAGES (struct lexer *lexer)
 static bool
 parse_MEXPAND (struct lexer *lexer)
 {
-  return parse_unimplemented (lexer, "MEXPAND");
+  int mexpand = force_parse_bool (lexer);
+  if (mexpand != -1)
+    settings_set_mexpand (mexpand);
+  return mexpand != -1;
 }
 
 static bool
 parse_MITERATE (struct lexer *lexer)
 {
-  return parse_unimplemented (lexer, "MITERATE");
+  if (!lex_force_int_range (lexer, "MITERATE", 1, INT_MAX))
+    return false;
+  settings_set_miterate (lex_integer (lexer));
+  lex_get (lexer);
+  return true;
 }
 
 static bool
 parse_MNEST (struct lexer *lexer)
 {
-  return parse_unimplemented (lexer, "MNEST");
+  if (!lex_force_int_range (lexer, "MNEST", 1, INT_MAX))
+    return false;
+  settings_set_mnest (lex_integer (lexer));
+  lex_get (lexer);
+  return true;
 }
 
 static bool
 parse_MPRINT (struct lexer *lexer)
 {
-  return parse_unimplemented (lexer, "MPRINT");
+  int mprint = force_parse_bool (lexer);
+  if (mprint != -1)
+    settings_set_mprint (mprint);
+  return mprint != -1;
 }
 
 static bool
@@ -915,6 +929,30 @@ show_locale (const struct dataset *ds UNUSED)
   return xstrdup (get_default_encoding ());
 }
 
+static char *
+show_mexpand (const struct dataset *ds UNUSED)
+{
+  return xstrdup (settings_get_mexpand () ? "ON" : "OFF");
+}
+
+static char *
+show_mprint (const struct dataset *ds UNUSED)
+{
+  return xstrdup (settings_get_mprint () ? "ON" : "OFF");
+}
+
+static char *
+show_miterate (const struct dataset *ds UNUSED)
+{
+  return xasprintf ("%d", settings_get_miterate ());
+}
+
+static char *
+show_mnest (const struct dataset *ds UNUSED)
+{
+  return xasprintf ("%d", settings_get_mnest ());
+}
+
 static char *
 show_messages (const struct dataset *ds UNUSED)
 {
@@ -1141,6 +1179,10 @@ const struct show_sbc show_table[] =
     {"JOURNAL", show_journal},
     {"LENGTH", show_length},
     {"LOCALE", show_locale},
+    {"MEXPAND", show_mexpand},
+    {"MPRINT", show_mprint},
+    {"MITERATE", show_miterate},
+    {"MNEST", show_mnest},
     {"MESSAGES", show_messages},
     {"MXERRS", show_mxerrs},
     {"MXLOOPS", show_mxloops},
index ee66278dac8e4e16b801ff8d556b3d29cec6a828..04ef900c5ea66a62337473463288ef25cc24986a 100644 (file)
@@ -121,8 +121,42 @@ x,y,z
 
 AT_CLEANUP
 
-\f
+AT_SETUP([SET macro - MEXPAND MPRINT MITERATE MNEST])
+AT_DATA([set-macro.sps], [dnl
+show mexpand mprint miterate mnest.
+preserve.
+set mexpand=off mprint=on miterate=10 mnest=11.
+show mexpand mprint miterate mnest.
+restore.
+show mexpand mprint miterate mnest.
+])
+AT_CHECK([pspp -O format=csv set-macro.sps], [0], [dnl
+set-macro.sps:1: note: SHOW: MEXPAND is ON.
+
+set-macro.sps:1: note: SHOW: MPRINT is OFF.
+
+set-macro.sps:1: note: SHOW: MITERATE is 1000.
+
+set-macro.sps:1: note: SHOW: MNEST is 50.
+
+set-macro.sps:4: note: SHOW: MEXPAND is OFF.
+
+set-macro.sps:4: note: SHOW: MPRINT is ON.
+
+set-macro.sps:4: note: SHOW: MITERATE is 10.
 
+set-macro.sps:4: note: SHOW: MNEST is 11.
+
+set-macro.sps:6: note: SHOW: MEXPAND is ON.
+
+set-macro.sps:6: note: SHOW: MPRINT is OFF.
+
+set-macro.sps:6: note: SHOW: MITERATE is 1000.
+
+set-macro.sps:6: note: SHOW: MNEST is 50.
+])
+AT_CLEANUP
+\f
 AT_BANNER([PRESERVE and RESTORE])
 
 AT_SETUP([PRESERVE of SET FORMAT])