# include "splintMacros.nf"
# include "basic.h"
# include "cgrammar.h"
+# include "cscanner.h"
# include "cgrammar_tokens.h"
# include "exprChecks.h"
static bool exprNode_isEmptyStatement (exprNode p_e);
static /*@exposed@*/ exprNode exprNode_firstStatement (/*@returned@*/ exprNode p_e);
static bool exprNode_isFalseConstant (exprNode p_e) /*@*/ ;
-static bool exprNode_isBlock (exprNode p_e);
+static bool exprNode_isStatement (exprNode p_e);
static void checkGlobUse (uentry p_glob, bool p_isCall, /*@notnull@*/ exprNode p_e);
static void exprNode_addUse (exprNode p_e, /*@exposed@*/ sRef p_s);
static bool exprNode_matchArgType (ctype p_ct, exprNode p_e);
static /*@exposed@*/ exprNode
exprNode_lastStatement (/*@returned@*/ exprNode p_e);
-static /*@null@*/ sRef defref = sRef_undefined;
-static /*@only@*/ exprNode mustExitNode = exprNode_undefined;
+static /*@only@*/ exprNode s_mustExitNode = exprNode_undefined;
static int checkArgsReal (uentry p_fcn, /*@dependent@*/ exprNode p_f,
uentryList p_cl,
ctypeType = ctype_unknown;
filelocType = ctype_unknown;
- defref = sRef_undefined;
-
if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
{
cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
void
exprNode_destroyMod (void)
/*@globals killed regArg, killed outArg, killed outStringArg,
- killed mustExitNode, initMod @*/
+ killed s_mustExitNode, initMod @*/
{
if (initMod)
{
- uentry_free (regArg);
- uentry_free (outArg);
- uentry_free (outStringArg);
+ /* evans 2002-07-12: changed uentry_free to uentry_freeComplete */
+ uentry_freeComplete (regArg);
+ uentry_freeComplete (outArg);
+ uentry_freeComplete (outStringArg);
- exprNode_free (mustExitNode);
+ exprNode_free (s_mustExitNode);
initMod = FALSE;
- /*@-branchstate@*/
+ /*@-branchstate@*/
}
/*@=branchstate@*/
}
static void exprNode_resetSref (/*@notnull@*/ exprNode e)
{
- e->sref = defref;
+ e->sref = sRef_undefined;
}
exprNode exprNode_fakeCopy (exprNode e)
e->typ = c;
e->kind = XPR_EMPTY;
e->val = multiVal_undefined;
- e->sref = defref;
+ e->sref = sRef_undefined;
e->etext = cstring_undefined;
e->loc = fileloc_undefined;
e->guards = guardSet_undefined;
/*@observer@*/ exprNode exprNode_makeMustExit (void)
{
- if (exprNode_isUndefined (mustExitNode))
+ if (exprNode_isUndefined (s_mustExitNode))
{
- mustExitNode = exprNode_createPlain (ctype_unknown);
- mustExitNode->exitCode = XK_MUSTEXIT;
+ s_mustExitNode = exprNode_createPlain (ctype_unknown);
+ s_mustExitNode->exitCode = XK_MUSTEXIT;
}
- return mustExitNode;
+ return s_mustExitNode;
}
}
ret->kind = XPR_EMPTY;
- ret->sref = defref;
+ ret->sref = sRef_undefined;
ret->etext = cstring_undefined;
ret->exitCode = XK_NEVERESCAPE;
ret->canBreak = FALSE;
ret->val = multiVal_undefined;
ret->kind = XPR_EMPTY;
- ret->sref = defref;
+ ret->sref = sRef_undefined;
ret->etext = cstring_undefined;
ret->exitCode = XK_NEVERESCAPE;
ret->canBreak = FALSE;
ret->msets = sRefSet_undefined;
ret->kind = XPR_EMPTY;
- ret->sref = defref;
+ ret->sref = sRef_undefined;
ret->etext = cstring_undefined;
ret->exitCode = XK_NEVERESCAPE;
ret->canBreak = FALSE;
while (e->kind == XPR_PARENS)
{
e = exprData_getUopNode (e->edata);
- llassert (exprNode_isDefined (e));
+
+ if (!exprNode_isDefined (e))
+ {
+ return FALSE;
+ }
+
+ /* evans 2002-02-05: was llassert (exprNode_isDefined (e)); but this can fail */
}
if (e->kind == XPR_CONST)
exprNode_rawStringLiteral (/*@only@*/ cstring t, /*@only@*/ fileloc loc)
{
exprNode e = exprNode_createLoc (ctype_string, loc);
- int len = cstring_length (t);
+ size_t len = cstring_length (t);
if (context_getFlag (FLG_STRINGLITERALLEN))
{
- if (len > context_getValue (FLG_STRINGLITERALLEN))
+ if (len > size_fromInt (context_getValue (FLG_STRINGLITERALLEN)))
{
voptgenerror (FLG_STRINGLITERALLEN,
message
("String literal length (%d) exceeds maximum "
"length (%d): \"%s\"",
- len,
+ size_toInt (len),
context_getValue (FLG_STRINGLITERALLEN),
t),
e->loc);
{
exprNode res = exprNode_stringLiteral (t, loc);
res->typ = ctype_makeWideString ();
-
return res;
}
/*@only@*/ exprNode
exprNode_stringLiteral (/*@only@*/ cstring t, /*@only@*/ fileloc loc)
{
- int len = cstring_length (t) - 2;
+ size_t len = size_fromInt (cstring_length (t) - 2);
char *ts = cstring_toCharsSafe (t);
char *s = cstring_toCharsSafe (cstring_create (len + 1));
llassert (*ts == '\"' && *(ts + len + 1) == '\"');
- strncpy (s, ts+1, size_fromInt (len));
+ strncpy (s, ts+1, len);
*(s + len) = '\0';
cstring_free (t);
return exprNode_rawStringLiteral (cstring_fromCharsO (s), loc);
}
e->loc = loc; /* save loc was mangled */
- e->sref = defref;
+ e->sref = sRef_undefined;
if (usymtab_exists (c))
{
e->canBreak = FALSE;
e->mustBreak = FALSE;
- exprNode_defineConstraints(e);
-
+ exprNode_defineConstraints (e);
return e;
}
else
if (context_justPopped ()) /* watch out! c could be dead */
{
- uentry ce = usymtab_lookupSafe (LastIdentifier ());
+ uentry ce = usymtab_lookupSafe (cscanner_observeLastIdentifier ());
if (uentry_isValid (ce))
{
return ret;
}
-
static void exprNode_checkStringLiteralLength (ctype t1, exprNode e2)
{
multiVal mval = exprNode_getValue (e2);
cstring slit;
- int len;
+ size_t len;
if (ctype_isFixedArray (t1))
{
-
- int nelements = long_toInt (ctype_getArraySize (t1));
+ size_t nelements = ctype_getArraySize (t1);
llassert (multiVal_isString (mval));
slit = multiVal_forceString (mval);
len = cstring_lengthExpandEscapes (slit);
-
+ llassert (exprNode_isDefined (e2));
+
if (len == nelements)
{
mstring temp;
- temp = cstring_expandEscapes(slit);
+ temp = cstring_expandEscapes (slit);
if (temp[len-1] == '\0')
{
}
else
{
-
-
- voptgenerror
- (FLG_STRINGLITNOROOM,
- message ("String literal with %d character%& "
- "is assigned to %s (no room for null terminator): %s",
- len + 1,
- ctype_unparse (t1),
- exprNode_unparse (e2)),
- e2->loc);
+ voptgenerror
+ (FLG_STRINGLITNOROOM,
+ message ("String literal with %d character%& "
+ "is assigned to %s (no room for null terminator): %s",
+ len + 1,
+ ctype_unparse (t1),
+ exprNode_unparse (e2)),
+ e2->loc);
}
}
else if (len > nelements)
case 'p': /* pointer */
expecttype = ctype_makePointer (ctype_void);
- uentry_setDefState (regArg, SS_RELDEF); /* need not be defined */
- sRef_setPosNull (uentry_getSref (regArg), fileloc_undefined); /* could be null */
+ /* need not be defined */
+ uentry_setDefState (regArg, SS_RELDEF);
+ sRef_setPosNull (uentry_getSref (regArg),
+ fileloc_undefined);
+ /* could be null */
/*@switchbreak@*/ break;
case 'n': /* pointer to int, modified by call! */
}
else
{
- /* a->sref = defref; */
+ /* a->sref = sRef_undefined; */
}
}
}
case 'f': expecttype = ctype_float; break;
case 'b': expecttype = ctype_bool; break;
case 't': expecttype = ctypeType; break;
+ case 'p':
+ expecttype = ctype_makePointer (ctype_void);
+ /* need not be defined */
+ uentry_setDefState (regArg, SS_RELDEF);
+ sRef_setPosNull (uentry_getSref (regArg),
+ fileloc_undefined);
+ /* could be null */
+ /*@switchbreak@*/ break;
case 'l': expecttype = filelocType; break;
case '&': /* a wee bit of a hack methinks */
expecttype = ctype_int;
sRefSet srs = stateClause_getRefs (cl);
sRefModVal modf = stateClause_getEnsuresFunction (cl);
int eparam = stateClause_getStateParameter (cl);
-
+
+ llassert (modf != NULL);
+
DPRINTF (("Reflect after clause: %s / %s",
stateClause_unparse (cl),
sRefSet_unparse (srs)));
stateClause_unparse (cl),
sRefSet_unparse (srs)));
+ llassert (modf != NULL);
+
sRefSet_elements (srs, sel)
{
sRef s;
/* f->typ is already set to the return type */
DPRINTF (("Function: %s", uentry_unparseFull (le)));
- ret->sref = uentry_returnedRef (le, args);
+ ret->sref = uentry_returnedRef (le, args, exprNode_loc (f));
DPRINTF (("Returned: %s / %s",
uentry_unparseFull (le),
sRef_unparseFull (ret->sref)));
}
else
{
- ret->sref = defref;
+ ret->sref = sRef_undefined;
exprNode_checkSetAny (ret, uentry_rawName (le));
}
reflectEnsuresClause (ret, le, f, args);
setCodePoint ();
+ DPRINTF (("Here: %s", sRef_unparseFull (ret->sref)));
return (ret);
}
{
ctype t;
- setCodePoint ();
+# ifdef DEBUGSPLINT
+ usymtab_checkAllValid ();
+# endif
if (exprNode_isUndefined (f))
{
/*@only@*/ cstring f)
{
exprNode res = exprNode_fieldAccessAux (s, lltok_getLoc (dot), f);
- lltok_release (dot);
+ lltok_free (dot);
return res;
}
/*@only@*/ cstring f)
{
exprNode res = exprNode_arrowAccessAux (s, lltok_getLoc (arrow), f);
- lltok_release (arrow);
+ lltok_free (arrow);
return res;
}
if (exprNode_isError (e))
{
qtype_free (q);
- lltok_release (tok);
+ lltok_free (tok);
return exprNode_undefined;
}
ret->kind = XPR_CAST;
ret->edata = exprData_makeCast (tok, e, q);
- if (ctype_isRealSU (ctype_getBaseType (sRef_getType (e->sref))))
- {
- /*
- ** This is a bit of a hack to avoid a problem
- ** when the code does,
- ** (some other struct) x
- ** ...
- ** x->field
- */
+ ret->sref = sRef_copy (e->sref);
+
+ DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
- ret->sref = sRef_copy (e->sref);
- usymtab_addForceMustAlias (ret->sref, e->sref);
- sRef_setTypeFull (ret->sref, c);
- DPRINTF (("Cast: %s -> %s", sRef_unparseFull (e->sref),
- sRef_unparseFull (ret->sref)));
- }
- else
+ if (!sRef_isConst (e->sref))
{
- ret->sref = e->sref;
- sRef_setTypeFull (ret->sref, c);
- DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
+ usymtab_addForceMustAlias (ret->sref, e->sref);
}
+
+ DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
+ sRef_setTypeFull (ret->sref, c);
+ DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
/*
** we allow
if (ctype_isVoid (c)) /* cast to void is always okay --- discard value */
{
- ;
+ /* evans 2002-07-19: added this warning */
+ DPRINTF (("Checking: %s / %s", exprNode_unparse (ret), sRef_unparseFull (ret->sref)));
+ if (sRef_isFresh (ret->sref))
+ {
+ voptgenerror
+ (FLG_MUSTFREEFRESH,
+ message ("New fresh storage %q(type %s) cast to void (not released): %s",
+ sRef_unparseOpt (ret->sref),
+ ctype_unparse (exprNode_getType (ret)),
+ exprNode_unparse (ret)),
+ exprNode_loc (ret));
+ }
}
else if (ctype_isRealAP (c)) /* casting to array or pointer */
{
}
exprNode
-exprNode_assign (/*@only@*/ exprNode e1,
- /*@only@*/ exprNode e2, /*@only@*/ lltok op)
+exprNode_assign (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2, /*@only@*/ lltok op)
{
bool isalloc = FALSE;
bool isjustalloc = FALSE;
ctype_unparse (e1->typ),
ctype_unparse (e2->typ)));
- if (ctype_isNumeric (e2->typ)
- || ctype_isNumeric (e1->typ))
+ if (exprNode_isDefined (e1)
+ && exprNode_isDefined (e2))
{
- /* Its a pointer arithmetic expression like ptr += i */
- noalias = TRUE;
- }
- }
+ if (ctype_isNumeric (e2->typ)
+ || ctype_isNumeric (e1->typ))
+ {
+ /* Its a pointer arithmetic expression like ptr += i */
+ noalias = TRUE;
+ }
+ }
+ }
else
{
ret = exprNode_createPartialCopy (e1);
ctype te1 = exprNode_getType (e1);
ctype te2 = exprNode_getType (e2);
- if (!ctype_forceMatch (te1, te2))
+ if (ctype_isVoid (te2))
+ {
+ (void) gentypeerror
+ (te2, e2, te1, e1,
+ message ("Assignment of void value to %t: %s %s %s",
+ te1, exprNode_unparse (e1),
+ lltok_unparse (op),
+ exprNode_unparse (e2)),
+ e1->loc);
+ }
+ else if (!ctype_forceMatch (te1, te2))
{
if (exprNode_matchLiteral (te1, e2))
{
e1->loc);
}
}
+ else
+ {
+ /* Type checks okay */
+ }
}
exprNode_mergeUSs (ret, e2);
usymtab_setMustBreak ();
}
+ DPRINTF (("==> %s", exprNode_unparse (ret)));
return ret;
}
{
if (!exprNode_isError (e))
{
- exprNode_checkStatement(e);
+ exprChecks_checkStatementEffect(e);
}
return (exprNode_statementError (e, t));
}
}
+exprNode exprNode_compoundStatementExpression (/*@only@*/ lltok tlparen, /*@only@*/ exprNode e)
+{
+ exprNode laststmt;
+
+ DPRINTF (("Compound: %s", exprNode_unparse (e)));
+
+ if (!context_flagOn (FLG_GNUEXTENSIONS, exprNode_loc (e)))
+ {
+ (void) llgenhinterror
+ (FLG_SYNTAX,
+ message ("Compound statement expressions is not supported by ISO C99"),
+ message ("Use +gnuextensions to allow compound statement expressions (and other GNU language extensions) "
+ "without this warning"),
+ exprNode_loc (e));
+ }
+
+ /*
+ ** The type of a compoundStatementExpression is the type of the last statement
+ */
+
+ llassert (exprNode_isBlock (e));
+ laststmt = exprNode_lastStatement (e);
+
+ DPRINTF (("Last statement: %s / %s", exprNode_unparse (laststmt), ctype_unparse (exprNode_getType (laststmt))));
+ DPRINTF (("e: %s", exprNode_unparse (e)));
+ e->typ = exprNode_getType (laststmt);
+ return exprNode_addParens (tlparen, e);
+}
+
+
exprNode exprNode_makeBlock (/*@only@*/ exprNode e)
{
exprNode ret = exprNode_createPartialCopy (e);
ret->mustBreak = e->mustBreak;
}
+ DPRINTF (("Block e: %s", exprNode_unparse (e)));
ret->edata = exprData_makeSingle (e);
ret->kind = XPR_BLOCK;
+ DPRINTF (("Block: %s", exprNode_unparse (ret)));
return ret;
}
return (exprNode_isDefined (e)
&& ((e)->kind == XPR_BLOCK));
}
+
+bool exprNode_isStatement (exprNode e)
+{
+ return (exprNode_isDefined (e)
+ && ((e)->kind == XPR_STMT));
+}
bool exprNode_isAssign (exprNode e)
{
&& (lltok_isSemi (exprData_getTok (e->edata))));
}
+bool exprNode_isMultiStatement (exprNode e)
+{
+ return (exprNode_isDefined (e)
+ && ((e->kind == XPR_FOR)
+ || (e->kind == XPR_FORPRED)
+ || (e->kind == XPR_IF)
+ || (e->kind == XPR_IFELSE)
+ || (e->kind == XPR_WHILE)
+ || (e->kind == XPR_WHILEPRED)
+ || (e->kind == XPR_DOWHILE)
+ || (e->kind == XPR_BLOCK)
+ || (e->kind == XPR_STMT)
+ || (e->kind == XPR_STMTLIST)
+ || (e->kind == XPR_SWITCH)));
+}
+
void exprNode_checkIfPred (exprNode pred)
{
exprNode_checkPred (cstring_makeLiteralTemp ("if"), pred);
exprNodeSList_elements (el, current)
{
+
+ DPRINTF ((message("checkSwitchExpr current = %s ", exprNode_unparse(current) ) ));
+
if (exprNode_isDefined (current))
{
switch (current->kind)
if (ctype_isFixedArray (t1))
{
- int nelements = long_toInt (ctype_getArraySize (t1));
+ size_t nelements = ctype_getArraySize (t1);
DPRINTF (("Checked array: %s / %d",
ctype_unparse (t1), nelements));
}
else
{
- if (exprNodeList_size (vals) != nelements)
+ if (exprNodeList_size (vals) != size_toInt (nelements))
{
hasError = optgenerror
- (exprNodeList_size (vals) > nelements ? FLG_INITSIZE : FLG_INITALLELEMENTS,
+ (exprNodeList_size (vals) > size_toInt (nelements)
+ ? FLG_INITSIZE : FLG_INITALLELEMENTS,
message ("Initializer block for "
"%s has %d element%&, but declared as %s: %q",
exprNode_unparse (el),
return hasError;
}
-static exprNode
+static /*@notnull@*/ exprNode
exprNode_makeInitializationAux (/*@temp@*/ idDecl t)
{
exprNode ret;
exprData_free (ret->edata, ret->kind);
ret->edata = exprData_undefined;
-
ret->exitCode = XK_NEVERESCAPE;
ret->mustBreak = FALSE;
ret->kind = XPR_INIT;
uentry ue = usymtab_lookup (idDecl_observeId (t));
exprNode ret = exprNode_makeInitializationAux (t);
fileloc loc = exprNode_loc (e);
-
+
+ DPRINTF (("initialization: %s = %s", idDecl_unparse (t), exprNode_unparse (e)));
+
if (exprNode_isError (e))
{
e = exprNode_createUnknown ();
- idDecl_free (t);
-
/* error: assume initializer is defined */
sRef_setDefined (ret->sref, g_currentloc);
+ ret->edata = exprData_makeInit (t, e);
}
else
{
exprData_free (ret->edata, ret->kind);
ret->edata = exprData_makeInit (t, e);
+ DPRINTF (("ret: %s", exprNode_unparse (ret)));
exprNode_checkUse (ret, e->sref, e->loc);
sRef_setDefState (ret->sref, SS_PARTIAL, fileloc_undefined);
}
- doAssign (ret, e, TRUE);
+ if (exprNode_isStringLiteral (e)
+ && (ctype_isArray (ct))
+ && (ctype_isChar (ctype_realType (ctype_baseArrayPtr (ct)))))
+ {
+ /*
+ ** If t is a char [], the literal is copied.
+ */
+
+ exprNode_checkStringLiteralLength (ct, e);
+ sRef_setDefState (ret->sref, SS_DEFINED, e->loc);
+ ret->val = multiVal_copy (e->val);
+
+ sRef_setNullTerminatedState (ret->sref);
+
+ if (multiVal_isDefined (e->val))
+ {
+ cstring slit = multiVal_forceString (e->val);
+ sRef_setLen (ret->sref, cstring_length (slit) + 1);
+ }
+
+ if (ctype_isFixedArray (ct))
+ {
+ sRef_setSize (ret->sref, size_toInt (ctype_getArraySize (ct)));
+ }
+ }
+ else
+ {
+ doAssign (ret, e, TRUE);
+ }
if (uentry_isStatic (ue))
{
sRef_setDefState (ret->sref, SS_DEFINED, fileloc_undefined);
}
}
-
+
if (context_inIterDef ())
{
/* should check if it is yield */
}
exprNode_mergeUSs (ret, e);
+ DPRINTF (("Ret: %s %p %p",
+ exprNode_unparse (ret),
+ ret->requiresConstraints,
+ ret->ensuresConstraints));
+
+ DPRINTF (("Ret: %s %s %s",
+ exprNode_unparse (ret),
+ constraintList_unparse (ret->requiresConstraints),
+ constraintList_unparse (ret->ensuresConstraints)));
return ret;
}
e->kind = XPR_VAR;
e->val = multiVal_unknown ();
e->guards = guardSet_new ();
- e->sref = defref;
+ e->sref = sRef_undefined;
e->isJumpPoint = FALSE;
e->exitCode = XK_NEVERESCAPE;
{
if (exprNode_isDefined (e))
{
- /*@access sRef@*/
- if (e->sref == defref) /*@noaccess sRef@*/
+ if (sRef_isInvalid (e->sref))
{
/*@-mods@*/
e->sref = sRef_makeUnknown ();
exprNode_effect (exprData_getPairB (data)));
break;
case XPR_OP:
- ret = exprNode_op (exprNode_effect (exprData_getOpA (data)),
- exprNode_effect (exprData_getOpB (data)),
- exprData_getOpTok (data));
+ /*
+ ** evans 2002-03-15: for && and ||, need to do the guards also
+ ** this is what cgrammar.y does - should be
+ ** able to avoid duplication, but need to
+ ** time with grammar productions.
+ */
+
+ DPRINTF (("Effect: %s", exprNode_unparse (e)));
+
+ if (lltok_getTok (exprData_getOpTok (data)) == AND_OP)
+ {
+ exprNode e1 = exprNode_effect (exprData_getOpA (data));
+ exprNode e2;
+ exprNode_produceGuards (e1);
+ context_enterAndClause (e1);
+ e2 = exprNode_effect (exprData_getOpB (data));
+
+ ret = exprNode_op (e1, e2,
+ exprData_getOpTok (data));
+
+ context_exitAndClause (ret, e2);
+ }
+ else if (lltok_getTok (exprData_getOpTok (data)) == OR_OP)
+ {
+ exprNode e1 = exprNode_effect (exprData_getOpA (data));
+ exprNode e2;
+ exprNode_produceGuards (e1);
+ context_enterOrClause (e1);
+ e2 = exprNode_effect (exprData_getOpB (data));
+
+ ret = exprNode_op (e1, e2,
+ exprData_getOpTok (data));
+
+ context_exitOrClause (ret, e2);
+ }
+ else
+ {
+ ret = exprNode_op (exprNode_effect (exprData_getOpA (data)),
+ exprNode_effect (exprData_getOpB (data)),
+ exprData_getOpTok (data));
+ }
break;
case XPR_POSTOP:
break;
case XPR_BLOCK:
- ret = message ("{ %s }", exprNode_unparseFirst (exprData_getSingle (data)));
+ ret = message ("{ %s }", exprNode_unparse (exprData_getSingle (data)));
+ /* evans 2002-02-20 was unparseFirst! */
break;
case XPR_STMT:
- ret = cstring_copy (exprNode_unparse (exprData_getUopNode (data)));
+ ret = message ("%s;", exprNode_unparse (exprData_getUopNode (data)));
break;
case XPR_STMTLIST:
- ret = message ("%s; %s",
- exprNode_unparse (exprData_getPairA (data)),
- exprNode_unparse (exprData_getPairB (data)));
+ if (exprNode_isStatement (exprData_getPairA (data)))
+ {
+ /*
+ ** statement expressions already print the ;
+ */
+
+ ret = message ("%s %s",
+ exprNode_unparse (exprData_getPairA (data)),
+ exprNode_unparse (exprData_getPairB (data)));
+ }
+ else
+ {
+ ret = message ("%s; %s",
+ exprNode_unparse (exprData_getPairA (data)),
+ exprNode_unparse (exprData_getPairB (data)));
+ }
break;
case XPR_FTDEFAULT: