Fixed logical AND and logical OR.
This commit is contained in:
253
src/cc65/expr.c
253
src/cc65/expr.c
@@ -3184,58 +3184,135 @@ static void hieOrPP (ExprDesc *Expr)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp)
|
static int hieAnd (ExprDesc* Expr, unsigned TrueLab, int* UsedTrueLab)
|
||||||
/* Process "exp && exp" */
|
/* Process "exp && exp". This should only be called within hieOr.
|
||||||
|
** Return true if logic AND does occur.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
int FalseLab;
|
unsigned Flags = Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
int HasFalseJump = 0, HasTrueJump = 0;
|
||||||
|
CodeMark Start;
|
||||||
|
|
||||||
|
/* Get a label that we will use for false expressions */
|
||||||
|
int FalseLab = GetLocalLabel ();
|
||||||
|
|
||||||
|
/* Get lhs */
|
||||||
|
GetCodePos (&Start);
|
||||||
ExprWithCheck (hie2, Expr);
|
ExprWithCheck (hie2, Expr);
|
||||||
|
if ((Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) {
|
||||||
|
RemoveCode (&Start);
|
||||||
|
}
|
||||||
|
|
||||||
if (CurTok.Tok == TOK_BOOL_AND) {
|
if (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
|
||||||
/* Tell our caller that we're evaluating a boolean */
|
ExprDesc Expr2;
|
||||||
*BoolOp = 1;
|
|
||||||
|
|
||||||
/* Get a label that we will use for false expressions */
|
/* Check type */
|
||||||
FalseLab = GetLocalLabel ();
|
if (!ED_IsBool (Expr)) {
|
||||||
|
Error ("Scalar expression expected");
|
||||||
|
ED_MakeConstBool (Expr, 0);
|
||||||
|
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
if (!ED_IsConstAbs (Expr)) {
|
||||||
|
/* Set the test flag */
|
||||||
|
ED_RequireTest (Expr);
|
||||||
|
|
||||||
/* Set the test flag */
|
/* Load the value */
|
||||||
ED_RequireTest (Expr);
|
LoadExpr (CF_FORCECHAR, Expr);
|
||||||
|
|
||||||
/* Load the value */
|
/* Remember that the jump is used */
|
||||||
LoadExpr (CF_FORCECHAR, Expr);
|
HasFalseJump = 1;
|
||||||
|
|
||||||
/* Generate the jump */
|
/* Generate the jump */
|
||||||
g_falsejump (CF_NONE, FalseLab);
|
g_falsejump (CF_NONE, FalseLab);
|
||||||
|
} else if (Expr->IVal == 0) {
|
||||||
|
/* Skip remaining */
|
||||||
|
Flags |= E_EVAL_UNEVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse more boolean and's */
|
/* Parse more boolean and's */
|
||||||
while (CurTok.Tok == TOK_BOOL_AND) {
|
while (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
|
||||||
ExprDesc Expr2;
|
|
||||||
ED_Init (&Expr2);
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags = Flags;
|
||||||
|
|
||||||
/* Skip the && */
|
/* Skip the && */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Get rhs */
|
/* Get rhs */
|
||||||
|
GetCodePos (&Start);
|
||||||
hie2 (&Expr2);
|
hie2 (&Expr2);
|
||||||
ED_RequireTest (&Expr2);
|
if ((Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) {
|
||||||
LoadExpr (CF_FORCECHAR, &Expr2);
|
RemoveCode (&Start);
|
||||||
|
}
|
||||||
|
|
||||||
/* Do short circuit evaluation */
|
/* Check type */
|
||||||
if (CurTok.Tok == TOK_BOOL_AND) {
|
if (!ED_IsBool (&Expr2)) {
|
||||||
g_falsejump (CF_NONE, FalseLab);
|
Error ("Scalar expression expected");
|
||||||
} else {
|
ED_MakeConstBool (&Expr2, 0);
|
||||||
/* Last expression - will evaluate to true */
|
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
g_truejump (CF_NONE, TrueLab);
|
if (!ED_IsConstAbs (&Expr2)) {
|
||||||
|
ED_RequireTest (&Expr2);
|
||||||
|
LoadExpr (CF_FORCECHAR, &Expr2);
|
||||||
|
|
||||||
|
/* Do short circuit evaluation */
|
||||||
|
if (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
HasFalseJump = 1;
|
||||||
|
g_falsejump (CF_NONE, FalseLab);
|
||||||
|
} else {
|
||||||
|
/* We need the true label for the last expression */
|
||||||
|
HasTrueJump = 1;
|
||||||
|
}
|
||||||
|
} else if (Expr2.IVal == 0) {
|
||||||
|
/* Skip remaining */
|
||||||
|
Flags |= E_EVAL_UNEVAL;
|
||||||
|
/* The value of the expression will be false */
|
||||||
|
ED_MakeConstBool (Expr, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Define the false jump label here */
|
/* Last expression */
|
||||||
g_defcodelabel (FalseLab);
|
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
if (HasFalseJump || HasTrueJump) {
|
||||||
|
/* In either case we need the true label anyways */
|
||||||
|
HasTrueJump = 1;
|
||||||
|
if (!ED_IsConstAbs (&Expr2)) {
|
||||||
|
/* Will branch to true and fall to false */
|
||||||
|
g_truejump (CF_NONE, TrueLab);
|
||||||
|
} else {
|
||||||
|
/* Will jump away */
|
||||||
|
g_jump (TrueLab);
|
||||||
|
}
|
||||||
|
/* The result is an rvalue in primary */
|
||||||
|
ED_FinalizeRValLoad (Expr);
|
||||||
|
/* No need to test as the result will be jumped to */
|
||||||
|
ED_TestDone (Expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* The result is an rvalue in primary */
|
if (HasFalseJump) {
|
||||||
ED_FinalizeRValLoad (Expr);
|
/* Define the false jump label here */
|
||||||
ED_TestDone (Expr); /* Condition codes are set */
|
g_defcodelabel (FalseLab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert to bool */
|
||||||
|
if (ED_IsConstAbs (Expr) && Expr->IVal != 0) {
|
||||||
|
ED_MakeConstBool (Expr, 1);
|
||||||
|
} else {
|
||||||
|
Expr->Type = type_bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell our caller that we're used the true label */
|
||||||
|
if (HasTrueJump) {
|
||||||
|
*UsedTrueLab = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell our caller that we're evaluating a boolean */
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3243,69 +3320,131 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp)
|
|||||||
static void hieOr (ExprDesc *Expr)
|
static void hieOr (ExprDesc *Expr)
|
||||||
/* Process "exp || exp". */
|
/* Process "exp || exp". */
|
||||||
{
|
{
|
||||||
int BoolOp = 0; /* Did we have a boolean op? */
|
unsigned Flags = Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
int AndOp; /* Did we have a && operation? */
|
int AndOp; /* Did we have a && operation? */
|
||||||
unsigned TrueLab; /* Jump to this label if true */
|
unsigned TrueLab; /* Jump to this label if true */
|
||||||
unsigned DoneLab;
|
unsigned DoneLab;
|
||||||
|
int HasTrueJump = 0;
|
||||||
|
int HasNewTrueJump;
|
||||||
|
CodeMark Start;
|
||||||
|
|
||||||
/* Get a label */
|
/* Get a label that we will use for true expressions */
|
||||||
TrueLab = GetLocalLabel ();
|
TrueLab = GetLocalLabel ();
|
||||||
|
|
||||||
/* Call the next level parser */
|
/* Call the next level parser */
|
||||||
hieAnd (Expr, TrueLab, &BoolOp);
|
GetCodePos (&Start);
|
||||||
|
AndOp = hieAnd (Expr, TrueLab, &HasNewTrueJump);
|
||||||
|
if ((Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) {
|
||||||
|
RemoveCode (&Start);
|
||||||
|
} else {
|
||||||
|
/* Remember the jump */
|
||||||
|
HasTrueJump = HasNewTrueJump;
|
||||||
|
}
|
||||||
|
|
||||||
/* Any boolean or's? */
|
/* Any boolean or's? */
|
||||||
if (CurTok.Tok == TOK_BOOL_OR) {
|
if (CurTok.Tok == TOK_BOOL_OR) {
|
||||||
|
|
||||||
/* Set the test flag */
|
/* Check type */
|
||||||
ED_RequireTest (Expr);
|
if (!ED_IsBool (Expr)) {
|
||||||
|
Error ("Scalar expression expected");
|
||||||
|
ED_MakeConstBool (Expr, 0);
|
||||||
|
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
|
||||||
/* Get first expr */
|
if (!ED_IsConstAbs (Expr)) {
|
||||||
LoadExpr (CF_FORCECHAR, Expr);
|
/* Test the lhs if we haven't had && operators. If we had them, the
|
||||||
|
** jump is already in place and there's no need to do the test.
|
||||||
|
*/
|
||||||
|
if (!AndOp) {
|
||||||
|
/* Set the test flag */
|
||||||
|
ED_RequireTest (Expr);
|
||||||
|
|
||||||
/* For each expression jump to TrueLab if true. Beware: If we
|
/* Get first expr */
|
||||||
** had && operators, the jump is already in place!
|
LoadExpr (CF_FORCECHAR, Expr);
|
||||||
*/
|
|
||||||
if (!BoolOp) {
|
/* Remember that the jump is used */
|
||||||
g_truejump (CF_NONE, TrueLab);
|
HasTrueJump = 1;
|
||||||
|
|
||||||
|
/* Jump to TrueLab if true */
|
||||||
|
g_truejump (CF_NONE, TrueLab);
|
||||||
|
}
|
||||||
|
} else if (Expr->IVal != 0) {
|
||||||
|
/* Skip remaining */
|
||||||
|
Flags |= E_EVAL_UNEVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remember that we had a boolean op */
|
|
||||||
BoolOp = 1;
|
|
||||||
|
|
||||||
/* while there's more expr */
|
/* while there's more expr */
|
||||||
while (CurTok.Tok == TOK_BOOL_OR) {
|
while (CurTok.Tok == TOK_BOOL_OR) {
|
||||||
|
|
||||||
ExprDesc Expr2;
|
ExprDesc Expr2;
|
||||||
ED_Init (&Expr2);
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags = Flags;
|
||||||
|
|
||||||
/* skip the || */
|
/* skip the || */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Get a subexpr */
|
/* Get rhs subexpression */
|
||||||
AndOp = 0;
|
GetCodePos (&Start);
|
||||||
hieAnd (&Expr2, TrueLab, &AndOp);
|
AndOp = hieAnd (&Expr2, TrueLab, &HasNewTrueJump);
|
||||||
ED_RequireTest (&Expr2);
|
if ((Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) {
|
||||||
LoadExpr (CF_FORCECHAR, &Expr2);
|
RemoveCode (&Start);
|
||||||
|
} else {
|
||||||
|
/* Remember the jump */
|
||||||
|
HasTrueJump = HasTrueJump || HasNewTrueJump;
|
||||||
|
}
|
||||||
|
|
||||||
/* If there is more to come, add shortcut boolean eval. */
|
/* Check type */
|
||||||
g_truejump (CF_NONE, TrueLab);
|
if (!ED_IsBool (&Expr2)) {
|
||||||
|
Error ("Scalar expression expected");
|
||||||
|
ED_MakeConstBool (&Expr2, 0);
|
||||||
|
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
|
||||||
|
if (!ED_IsConstAbs (&Expr2)) {
|
||||||
|
/* If there is more to come, add shortcut boolean eval */
|
||||||
|
if (!AndOp) {
|
||||||
|
ED_RequireTest (&Expr2);
|
||||||
|
LoadExpr (CF_FORCECHAR, &Expr2);
|
||||||
|
|
||||||
|
HasTrueJump = 1;
|
||||||
|
g_truejump (CF_NONE, TrueLab);
|
||||||
|
}
|
||||||
|
} else if (Expr2.IVal != 0) {
|
||||||
|
/* Skip remaining */
|
||||||
|
Flags |= E_EVAL_UNEVAL;
|
||||||
|
/* The result is always true */
|
||||||
|
ED_MakeConstBool (Expr, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The result is an rvalue in primary */
|
/* Convert to bool */
|
||||||
ED_FinalizeRValLoad (Expr);
|
if (ED_IsConstAbs (Expr) && Expr->IVal != 0) {
|
||||||
ED_TestDone (Expr); /* Condition codes are set */
|
ED_MakeConstBool (Expr, 1);
|
||||||
|
} else {
|
||||||
|
Expr->Type = type_bool;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we really had boolean ops, generate the end sequence */
|
/* If we really had boolean ops, generate the end sequence if necessary */
|
||||||
if (BoolOp) {
|
if (HasTrueJump) {
|
||||||
|
/* False case needs to jump over true case */
|
||||||
DoneLab = GetLocalLabel ();
|
DoneLab = GetLocalLabel ();
|
||||||
g_getimmed (CF_INT | CF_CONST, 0, 0); /* Load FALSE */
|
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
g_falsejump (CF_NONE, DoneLab);
|
/* Load false only if the result is not true */
|
||||||
|
g_getimmed (CF_INT | CF_CONST, 0, 0); /* Load FALSE */
|
||||||
|
g_falsejump (CF_NONE, DoneLab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load the true value */
|
||||||
g_defcodelabel (TrueLab);
|
g_defcodelabel (TrueLab);
|
||||||
g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */
|
g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */
|
||||||
g_defcodelabel (DoneLab);
|
g_defcodelabel (DoneLab);
|
||||||
|
|
||||||
|
/* The result is an rvalue in primary */
|
||||||
|
ED_FinalizeRValLoad (Expr);
|
||||||
|
/* Condition codes are set */
|
||||||
|
ED_TestDone (Expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user