is new in SPSS 15 (14?), and a test for it.
* String Functions:: CONCAT INDEX LENGTH LOWER LPAD LTRIM NUMBER
RINDEX RPAD RTRIM STRING SUBSTR UPCASE
* Time & Date:: CTIME.xxx DATE.xxx TIME.xxx XDATE.xxx
-* Miscellaneous Functions:: LAG YRMODA
+* Miscellaneous Functions:: LAG YRMODA VALUELABEL
* Statistical Distribution Functions:: PDF CDF SIG IDF RV NPDF NCDF
@end menu
on or after 15 Oct 1582. 15 Oct 1582 has a value of 1.
@end deftypefn
+@cindex value label
+@deftypefn {Function} VALUELABEL (@var{variable})
+Returns a string matching the label associated with the current value
+of @var{variable}. If the current value of @var{variable} has no
+associated label, then this function returns the empty string.
+@var{variable} may be a numeric or string variable.
+@end deftypefn
+
@node Statistical Distribution Functions
@subsection Statistical Distribution Functions
+Sun Dec 10 16:49:33 2006 Ben Pfaff <blp@gnu.org>
+
+ * operations.def: Implement VALUELABEL function. Add DATEDIFF,
+ DATESUM unimplemented stubs.
+
+ * parse.c (type_coercion_core): Add support for OP_var type, which
+ is a name for a numeric or string variable.
+ (is_compatible) New function.
+ (check_operator) Only require values to be compatible with their
+ expected types, not identical.
+ (is_valid_node) Ditto.
+ (compare_names) Always return mismatch if the command name can't
+ be abbreviated.
+ (lookup_function_helper) Pass the new OPF_NO_ABBREV flag to the
+ comparison function.
+
+ * generate.pl (init_all_types): Add support for a type just called
+ "var" that may be a numeric or string variable name. Also, add a
+ no_abbrev option that prevents a function name from being
+ abbreviated (in case of naming conflict otherwise).
+
+ * parse.inc.pl: Output OPF_NO_ABBREV flag.
+
+ * private.h: Add OPF_NO_ABBREV flag.
+
Wed Jul 12 21:03:17 2006 Ben Pfaff <blp@gnu.org>
* evaluate.c (cmd_debug_evaluate): Don't try to resize a null
init_type ('str_var', 'leaf', C_TYPE => 'const struct variable *',
ATOM => 'variable', MANGLE => 'Vs',
HUMAN_NAME => 'string_variable');
+ init_type ('var', 'leaf', C_TYPE => 'const struct variable *',
+ ATOM => 'variable', MANGLE => 'V',
+ HUMAN_NAME => 'variable');
# Vectors.
init_type ('vector', 'leaf', C_TYPE => 'const struct vector *',
$op{ABSORB_MISS} = 1;
} elsif (match ('perm_only')) {
$op{PERM_ONLY} = 1;
+ } elsif (match ('no_abbrev')) {
+ $op{NO_ABBREV} = 1;
} else {
last;
}
function XDATE.WKDAY (date >= DAY_S) = calendar_offset_to_wday (date / DAY_S);
function XDATE.YEAR (date >= DAY_S) = calendar_offset_to_year (date / DAY_S);
+// Date arithmetic functions.
+function DATEDIFF (date1, date2, string unit) = unimplemented;
+function DATESUM (date, quantity, string unit) = unimplemented;
+function DATESUM (date, quantity, string unit, string roll_over)
+ = unimplemented;
+
// String functions.
string function CONCAT (string a[n])
expression e;
return empty_string;
}
+absorb_miss no_opt string function VALUELABEL (var v)
+ expression e;
+ case c;
+{
+ const char *label = var_lookup_value_label (v, case_data (c, v));
+ if (label != NULL)
+ return copy_string (e, label, strlen (label));
+ else
+ return empty_string;
+}
+
// Artificial.
operator SQUARE (x) = x * x;
boolean operator NUM_TO_BOOLEAN (x)
}
break;
+ case OP_var:
+ if ((*node)->type == OP_NUM_VAR || (*node)->type == OP_STR_VAR)
+ {
+ if (do_coercion)
+ *node = (*node)->composite.args[0];
+ return true;
+ }
+ break;
+
case OP_pos_int:
if ((*node)->type == OP_number
&& floor ((*node)->number.n) == (*node)->number.n
(union any_node **) node, NULL, false);
}
+/* Returns true if ACTUAL_TYPE is a kind of REQUIRED_TYPE, false
+ otherwise. */
+static bool
+is_compatible (atom_type required_type, atom_type actual_type)
+{
+ return (required_type == actual_type
+ || (required_type == OP_var
+ && (actual_type == OP_num_var || actual_type == OP_str_var)));
+}
+
/* How to parse an operator. */
struct operator
{
assert (o->arg_cnt == arg_cnt);
assert ((o->flags & OPF_ARRAY_OPERAND) == 0);
for (i = 0; i < arg_cnt; i++)
- assert (o->args[i] == arg_type);
+ assert (is_compatible (arg_type, o->args[i]));
return true;
}
}
static int
-compare_names (const char *test, const char *name)
+compare_names (const char *test, const char *name, bool abbrev_ok)
{
+ if (!abbrev_ok)
+ return true;
+
for (;;)
{
if (!word_matches (&test, &name))
}
static int
-compare_strings (const char *test, const char *name)
+compare_strings (const char *test, const char *name, bool abbrev_ok UNUSED)
{
return strcasecmp (test, name);
}
static bool
lookup_function_helper (const char *name,
- int (*compare) (const char *test, const char *name),
+ int (*compare) (const char *test, const char *name,
+ bool abbrev_ok),
const struct operation **first,
const struct operation **last)
{
for (f = operations + OP_function_first;
f <= operations + OP_function_last; f++)
- if (!compare (name, f->name))
+ if (!compare (name, f->name, !(f->flags & OPF_NO_ABBREV)))
{
*first = f;
- while (f <= operations + OP_function_last && !compare (name, f->name))
+ while (f <= operations + OP_function_last
+ && !compare (name, f->name, !(f->flags & OPF_NO_ABBREV)))
f++;
*last = f;
assert (is_composite (n->type));
assert (c->arg_cnt >= op->arg_cnt);
for (i = 0; i < op->arg_cnt; i++)
- assert (expr_node_returns (c->args[i]) == op->args[i]);
+ assert (is_compatible (op->args[i], expr_node_returns (c->args[i])));
if (c->arg_cnt > op->arg_cnt && !is_operator (n->type))
{
assert (op->flags & OPF_ARRAY_OPERAND);
for (i = 0; i < c->arg_cnt; i++)
- assert (operations[c->args[i]->type].returns
- == op->args[op->arg_cnt - 1]);
+ assert (is_compatible (op->args[op->arg_cnt - 1],
+ expr_node_returns (c->args[i])));
}
}
push (@flags, "OPF_EXTENSION") if $op->{EXTENSION};
push (@flags, "OPF_UNIMPLEMENTED") if $op->{UNIMPLEMENTED};
push (@flags, "OPF_PERM_ONLY") if $op->{PERM_ONLY};
+ push (@flags, "OPF_NO_ABBREV") if $op->{NO_ABBREV};
push (@members, @flags ? join (' | ', @flags) : 0);
push (@members, "OP_$op->{RETURNS}{NAME}");
/* If set, this operation may not occur after TEMPORARY.
(Currently this applies only to LAG.) */
- OPF_PERM_ONLY = 0100
+ OPF_PERM_ONLY = 0100,
+
+ /* If set, this operation's name may not be abbreviated. */
+ OPF_NO_ABBREV = 0200
};
#define EXPR_ARG_MAX 4
+Sun Dec 10 16:52:04 2006 Ben Pfaff <blp@gnu.org>
+
+ * automake.mk: Add new test.
+
+ * expressions/valuelabel.sh: New test, for VALUELABEL function.
+
Thu Nov 30 22:46:17 2006 Ben Pfaff <blp@gnu.org>
* automake.mk: Add new test.
- * tests/bugs/compute-sum.sh: New test, for bug #17422.
+ * bugs/compute-sum.sh: New test, for bug #17422.
Thu Nov 30 22:01:57 2006 Ben Pfaff <blp@gnu.org>
* automake.mk: Add new test.
- * tests/bugs/empty-do-repeat: New test, for bug #18407.
+ * bugs/empty-do-repeat: New test, for bug #18407.
Wed Nov 22 06:28:04 2006 Ben Pfaff <blp@gnu.org>
- * tests/bugs/signals.sh: Fix race condition.
+ * bugs/signals.sh: Fix race condition.
Sun Nov 19 09:23:34 2006 Ben Pfaff <blp@gnu.org>
* automake.mk: Add the new tests listed below.
- * tests/formats/bcd-in.sh: New test.
+ * formats/bcd-in.sh: New test.
- * tests/formats/bcd-in.expected.cmp.gz: New support file for
+ * formats/bcd-in.expected.cmp.gz: New support file for
bcd-in.sh.
- * tests/formats/date-in.sh: New test.
+ * formats/date-in.sh: New test.
- * tests/formats/ib-in.sh: New test.
+ * formats/ib-in.sh: New test.
- * tests/formats/ib-in.expected.cmp.gz: New test.
+ * formats/ib-in.expected.cmp.gz: New test.
- * tests/formats/legacy-in.sh: New test.
+ * formats/legacy-in.sh: New test.
- * tests/formats/legacy-in.expected.cmp.gz: New support file for
+ * formats/legacy-in.expected.cmp.gz: New support file for
legacy-in.sh.
- * tests/formats/month-in.sh: New test.
+ * formats/month-in.sh: New test.
- * tests/formats/num-in.sh: New test.
+ * formats/num-in.sh: New test.
- * tests/formats/num-in.expected.gz: New support file for num-in.sh.
+ * formats/num-in.expected.gz: New support file for num-in.sh.
- * tests/formats/time-in.sh: New test.
+ * formats/time-in.sh: New test.
- * tests/formats/wkday-in.sh: New test.
+ * formats/wkday-in.sh: New test.
- * tests/commands/no_case_size.sh: Update output to conform with
+ * commands/no_case_size.sh: Update output to conform with
update scientific notation code.
- * tests/formats/num-out.expected.cmp.gz: Ditto.
+ * formats/num-out.expected.cmp.gz: Ditto.
Thu Nov 2 20:58:12 2006 Ben Pfaff <blp@gnu.org>
* automake.mk: Add tests/formats/float-format.sh.
- * tests/formats/float-format.sh: New test.
+ * formats/float-format.sh: New test.
Sat Oct 7 11:06:59 WST 2006 John Darrington <john@darrington.wattle.id.au>
tests/expressions/expressions.sh \
tests/expressions/epoch.sh \
tests/expressions/randist.sh \
+ tests/expressions/valuelabel.sh \
tests/expressions/variables.sh \
tests/expressions/vectors.sh \
tests/libpspp/ll-test \
--- /dev/null
+#!/bin/sh
+
+# This program tests use of the VALUELABEL function in expressions.
+
+TEMPDIR=/tmp/pspp-tst-$$
+
+# ensure that top_srcdir and top_builddir are absolute
+if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
+if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
+top_srcdir=`cd $top_srcdir; pwd`
+top_builddir=`cd $top_builddir; pwd`
+PSPP=$top_builddir/src/ui/terminal/pspp
+
+STAT_CONFIG_PATH=$top_srcdir/config
+export STAT_CONFIG_PATH
+
+LANG=C
+export LANG
+
+cleanup()
+{
+ cd /
+ 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 > $TEMPDIR/valuelabel.stat <<EOF
+DATA LIST notable /n 1 s 2(a).
+VALUE LABELS /n 0 'Very dissatisfied'
+ 1 'Dissatisfied'
+ 2 'Neutral'
+ 3 'Satisfied'
+ 4 'Very satisfied'.
+VALUE LABELS /s 'a' 'Wouldn''t buy again'
+ 'b' 'Unhappy'
+ 'c' 'Bored'
+ 'd' 'Satiated'
+ 'e' 'Elated'.
+STRING nlabel slabel(a10).
+COMPUTE nlabel = VALUELABEL(n).
+COMPUTE slabel = VALUELABEL(s).
+LIST.
+BEGIN DATA.
+
+0a
+1b
+2c
+3d
+4e
+5f
+6g
+END DATA.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program"
+$SUPERVISOR $PSPP -o raw-ascii $TEMPDIR/valuelabel.stat
+if [ $? -ne 0 ] ; then fail ; fi
+
+activity="compare results"
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
+diff -b $TEMPDIR/pspp.list - <<EOF
+n s nlabel slabel
+- - ---------- ----------
+.
+0 a Very dissa Wouldn't b
+1 b Dissatisfi Unhappy
+2 c Neutral Bored
+3 d Satisfied Satiated
+4 e Very satis Elated
+5 f
+6 g
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+
+pass;