From 3a66b403c8856da07a1de12c96e163971909e29a Mon Sep 17 00:00:00 2001 From: John Darrington Date: Mon, 7 Feb 2005 02:12:01 +0000 Subject: [PATCH] Fixed bug #11843 --- doc/q2c.texi | 3 ++ src/ChangeLog | 5 +++ src/crosstabs.q | 2 +- src/examine.q | 2 +- src/oneway.q | 2 +- src/q2c.c | 45 ++++++++++++++++++++++++-- tests/Makefile.am | 1 + tests/bugs/curtailed.sh | 71 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 125 insertions(+), 6 deletions(-) create mode 100755 tests/bugs/curtailed.sh diff --git a/doc/q2c.texi b/doc/q2c.texi index b24a8ee0..0e25019b 100644 --- a/doc/q2c.texi +++ b/doc/q2c.texi @@ -129,6 +129,7 @@ sbc-options ::= ::= sbc-options sbc-options sbc-option ::= * ::= + + ::= ^ sbc-defn ::= opt-prefix = specifiers ::= [ ID ] = array-sbc ::= opt-prefix = sbc-special-form @@ -142,6 +143,8 @@ keyword used for the default subcommand can be omitted in the PSPP syntax file. A plus sign (@samp{+}) is used to indicate that a subcommand can appear more than once; if it is not present then that subcommand can appear no more than once. +A carat sign (@samp{^}) is used to indicate that a subcommand must appear +at least once. The subcommand name appears after the option characters. diff --git a/src/ChangeLog b/src/ChangeLog index ad276e8c..cbdc0059 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +Mon Feb 7 09:58:15 WST 2005 John Darrington + + crosstabs.q examine.q oneway.q q2c.c: Added a q2c feature to + declare subcommands as mandatory. Closed bug #11843 + Sat Feb 5 20:35:10 WST 2005 John Darrington * getline.c command.[ch] command.def: Added (very rudimentary) diff --git a/src/crosstabs.q b/src/crosstabs.q index 9c17ed02..e61eb07f 100644 --- a/src/crosstabs.q +++ b/src/crosstabs.q @@ -59,7 +59,7 @@ /* (specification) crosstabs (crs_): - *tables=custom; + *^tables=custom; +variables=custom; +missing=miss:!table/include/report; +write[wr_]=none,cells,all; diff --git a/src/examine.q b/src/examine.q index 3454b66f..f92bba1f 100644 --- a/src/examine.q +++ b/src/examine.q @@ -49,7 +49,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* (specification) "EXAMINE" (xmn_): - *variables=custom; + *^variables=custom; +total=custom; +nototal=custom; +missing=miss:pairwise/!listwise, diff --git a/src/oneway.q b/src/oneway.q index 7277b79a..16a1e908 100644 --- a/src/oneway.q +++ b/src/oneway.q @@ -47,7 +47,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* (specification) "ONEWAY" (oneway_): - *variables=custom; + *^variables=custom; +missing=miss:!analysis/listwise, incl:include/!exclude; contrast= double list; diff --git a/src/q2c.c b/src/q2c.c index 13613204..37ec08f0 100644 --- a/src/q2c.c +++ b/src/q2c.c @@ -535,6 +535,13 @@ typedef enum } subcommand_type; +typedef enum + { + ARITY_ONCE_EXACTLY, /* must occur exactly once */ + ARITY_ONCE_ONLY, /* zero or once */ + ARITY_MANY /* 0, 1, ... , inf */ + }subcommand_arity; + /* A single subcommand. */ typedef struct subcommand subcommand; struct subcommand @@ -542,7 +549,7 @@ struct subcommand subcommand *next; /* Next in the chain. */ char *name; /* Subcommand name. */ subcommand_type type; /* One of SBC_*. */ - int once; /* 1=Subcommand may appear only once. */ + subcommand_arity arity; /* How many times should the subcommand occur*/ int narray; /* Index of next array element. */ const char *prefix; /* Prefix for variable and constant names. */ specifier *spec; /* Array of specifiers. */ @@ -759,6 +766,8 @@ parse_specifiers (subcommand *sbc) static void parse_subcommand (subcommand *sbc) { + sbc->arity = ARITY_MANY; + if (match_token ('*')) { if (def) @@ -766,7 +775,11 @@ parse_subcommand (subcommand *sbc) def = sbc; } - sbc->once = match_token ('+'); + if ( match_token('+')) + sbc->arity = ARITY_ONCE_ONLY ; + else if (match_token('^')) + sbc->arity = ARITY_ONCE_EXACTLY ; + force_id (); sbc->name = xstrdup (tokstr); @@ -1805,7 +1818,7 @@ dump_parser (int persistent) dump (0, "lex_match ('=');"); dump (0, "p->sbc_%s++;", st_lower (sbc->name)); - if (sbc->once) + if (sbc->arity != ARITY_MANY) { dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name)); dump (1, "{"); @@ -1820,6 +1833,8 @@ dump_parser (int persistent) outdent (); } } + + /* Now deal with the /ALGORITHM subcommand implicit to all commands */ dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))"); dump(1,"{"); @@ -1835,6 +1850,7 @@ dump_parser (int persistent) dump (-1, "}"); outdent (); + dump (1, "if (!lex_match ('/'))"); dump (0, "break;"); @@ -1847,6 +1863,29 @@ dump_parser (int persistent) dump (0, "goto lossage;"); dump (-1, "}"); dump (0, nullstr); + + outdent (); + + { + /* Check that mandatory subcommands have been specified */ + subcommand *sbc; + + for (sbc = subcommands; sbc; sbc = sbc->next) + { + + if ( sbc->arity == ARITY_ONCE_EXACTLY ) + { + dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name)); + dump (1, "{"); + dump (0, "msg (SE, _(\"%s subcommand must be given.\"));", + sbc->name); + dump (0, "goto lossage;"); + dump (-1, "}"); + dump (0, nullstr); + } + } + } + dump (-1, "return 1;"); dump (0, nullstr); dump (-1, "lossage:"); diff --git a/tests/Makefile.am b/tests/Makefile.am index 6cad0908..b211891b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -48,6 +48,7 @@ TESTS = \ bugs/comment-at-eof.sh \ bugs/compute-fmt.sh \ bugs/crosstabs.sh \ + bugs/curtailed.sh \ bugs/data-crash.sh \ bugs/double-frequency.sh \ bugs/get.sh \ diff --git a/tests/bugs/curtailed.sh b/tests/bugs/curtailed.sh new file mode 100755 index 00000000..a004ce59 --- /dev/null +++ b/tests/bugs/curtailed.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +# This program tests for a bug which crashed pspp when given certain +# invalid input + +TEMPDIR=/tmp/pspp-tst-$$ +TESTFILE=$TEMPDIR/`basename $0`.sps + +here=`pwd`; + +# ensure that top_srcdir is absolute +cd $top_srcdir; top_srcdir=`pwd` + +export STAT_CONFIG_PATH=$top_srcdir/config + + +cleanup() +{ + rm -rf $TEMPDIR +} + + +fail() +{ + echo $activity + echo FAILED + cleanup; + exit 1; +} + + +no_result() +{ + echo $activity + echo NO RESULT; + cleanup; + exit 2; +} + +pass() +{ + cleanup; + exit 0; +} + +mkdir -p $TEMPDIR + +cd $TEMPDIR + +activity="create program" +cat > $TESTFILE < /dev/null +if [ $? -ne 1 ] ; then fail ; fi + + +pass; -- 2.30.2