#include "libpspp/str.h"
#include "libpspp/string-array.h"
+#include "gl/c-ctype.h"
+
#include "gettext.h"
#define _(msgid) gettext (msgid)
.expand = ctx->expand,
};
struct string function_output = DS_EMPTY_INITIALIZER;
- size_t function_consumed;
- if (expand_macro_function (&fctx, &function_output, &function_consumed))
+ size_t function_consumed = parse_function_arg (&fctx, 0, &function_output);
+ *tokens = p + function_consumed;
+ return ds_steal_cstr (&function_output);
+}
+
+/* Returns true if MT is valid as a macro operator. Only operators written as
+ symbols (e.g. <>) are usable in macro expressions, not operator written as
+ letters (e.g. EQ). */
+static bool
+is_macro_operator (const struct macro_token *mt)
+{
+ return (mt->representation.length > 0
+ && !c_isalpha (mt->representation.string[0]));
+}
+
+static enum token_type
+parse_relational_op (const struct macro_token *mt)
+{
+ switch (mt->token.type)
{
- *tokens = p + function_consumed;
- return ds_steal_cstr (&function_output);
- }
+ case T_EQUALS:
+ return T_EQ;
- *tokens = p + 1;
- return ss_xstrdup (p->representation);
+ case T_NE:
+ case T_LT:
+ case T_GT:
+ case T_LE:
+ case T_GE:
+ return is_macro_operator (mt) ? mt->token.type : T_STOP;
+
+ case T_MACRO_ID:
+ return (ss_equals_case (mt->token.string, ss_cstr ("!EQ")) ? T_EQ
+ : ss_equals_case (mt->token.string, ss_cstr ("!NE")) ? T_NE
+ : ss_equals_case (mt->token.string, ss_cstr ("!LT")) ? T_LT
+ : ss_equals_case (mt->token.string, ss_cstr ("!GT")) ? T_GT
+ : ss_equals_case (mt->token.string, ss_cstr ("!LE")) ? T_LE
+ : ss_equals_case (mt->token.string, ss_cstr ("!GE")) ? T_GE
+ : T_STOP);
+
+ default:
+ return T_STOP;
+ }
}
static char *
-macro_evaluate_logical (const struct expr_context *ctx,
+macro_evaluate_relational (const struct expr_context *ctx,
const struct macro_token **tokens,
const struct macro_token *end)
{
if (!lhs)
return NULL;
- enum token_type op = p < end ? p->token.type : T_STOP;
- if (op != T_EQUALS && op != T_EQ && op != T_NE && op != T_LT
- && op != T_GT && op != T_LE && op != T_GE)
+ enum token_type op = p >= end ? T_STOP : parse_relational_op (p);
+ if (op == T_STOP)
{
*tokens = p;
return lhs;
free (lhs);
free (rhs);
-
+
bool b = (op == T_EQUALS || op == T_EQ ? !cmp
: op == T_NE ? cmp
: op == T_LT ? cmp < 0
const struct macro_token *p = *tokens;
unsigned int negations = 0;
- while (p < end && p->token.type == T_NOT)
+ while (p < end
+ && (ss_equals_case (p->representation, ss_cstr ("!NOT"))
+ || ss_equals (p->representation, ss_cstr ("~"))))
{
p++;
negations++;
}
- char *operand = macro_evaluate_logical (ctx, &p, end);
+ char *operand = macro_evaluate_relational (ctx, &p, end);
if (!operand || !negations)
{
*tokens = p;
if (!lhs)
return NULL;
- while (p < end && p->token.type == T_AND)
+ while (p < end
+ && (ss_equals_case (p->representation, ss_cstr ("!AND"))
+ || ss_equals (p->representation, ss_cstr ("&"))))
{
p++;
char *rhs = macro_evaluate_not (ctx, &p, end);
if (!lhs)
return NULL;
- while (p < end && p->token.type == T_OR)
+ while (p < end
+ && (ss_equals_case (p->representation, ss_cstr ("!OR"))
+ || ss_equals (p->representation, ss_cstr ("|"))))
{
p++;
char *rhs = macro_evaluate_and (ctx, &p, end);