Logical operators now only evaluate the second argument if necessary, as specified in the C standard.
git-svn-id: http://picoc.googlecode.com/svn/trunk@542 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
parent
4919d40cd2
commit
807b3d09ba
118
expression.c
118
expression.c
|
@ -6,6 +6,8 @@
|
|||
#define BRACKET_PRECEDENCE 20
|
||||
#define IS_TYPE_TOKEN(t) ((t) >= TokenIntType && (t) <= TokenUnsignedType)
|
||||
|
||||
#define DEEP_PRECEDENCE (BRACKET_PRECEDENCE*1000)
|
||||
|
||||
#ifdef DEBUG_EXPRESSIONS
|
||||
#define debugf printf
|
||||
#else
|
||||
|
@ -67,7 +69,7 @@ static struct OpPrecedence OperatorPrecedence[] =
|
|||
/* TokenOpenBracket, */ { 15, 0, 0, "(" }, /* TokenCloseBracket, */ { 0, 15, 0, ")" }
|
||||
};
|
||||
|
||||
void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *FuncName);
|
||||
void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *FuncName, int RunIt);
|
||||
|
||||
#ifdef DEBUG_EXPRESSIONS
|
||||
/* show the contents of the expression stack */
|
||||
|
@ -443,13 +445,6 @@ void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack
|
|||
struct Value *Result;
|
||||
union AnyValue *ValPtr;
|
||||
|
||||
if (Parser->Mode != RunModeRun)
|
||||
{
|
||||
/* we're not running it so just return 0 */
|
||||
ExpressionPushInt(Parser, StackTop, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
debugf("ExpressionPrefixOperator()\n");
|
||||
switch (Op)
|
||||
{
|
||||
|
@ -545,13 +540,6 @@ void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack
|
|||
/* evaluate a postfix operator */
|
||||
void ExpressionPostfixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue)
|
||||
{
|
||||
if (Parser->Mode != RunModeRun)
|
||||
{
|
||||
/* we're not running it so just return 0 */
|
||||
ExpressionPushInt(Parser, StackTop, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
debugf("ExpressionPostfixOperator()\n");
|
||||
if (IS_NUMERIC_COERCIBLE(TopValue))
|
||||
{
|
||||
|
@ -602,13 +590,6 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
|
|||
struct Value *StackValue;
|
||||
void *Pointer;
|
||||
|
||||
if (Parser->Mode != RunModeRun)
|
||||
{
|
||||
/* we're not running it so just return 0 */
|
||||
ExpressionPushInt(Parser, StackTop, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
debugf("ExpressionInfixOperator()\n");
|
||||
if (BottomValue == NULL || TopValue == NULL)
|
||||
ProgramFail(Parser, "invalid expression");
|
||||
|
@ -815,7 +796,7 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
|
|||
}
|
||||
|
||||
/* take the contents of the expression stack and compute the top until there's nothing greater than the given precedence */
|
||||
void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack **StackTop, int Precedence)
|
||||
void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack **StackTop, int Precedence, int *IgnorePrecedence)
|
||||
{
|
||||
int FoundPrecedence = Precedence;
|
||||
struct Value *TopValue;
|
||||
|
@ -854,7 +835,16 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack *
|
|||
*StackTop = TopOperatorNode->Next;
|
||||
|
||||
/* do the prefix operation */
|
||||
ExpressionPrefixOperator(Parser, StackTop, TopOperatorNode->Op, TopValue);
|
||||
if (Parser->Mode == RunModeRun && FoundPrecedence < *IgnorePrecedence)
|
||||
{
|
||||
/* run the operator */
|
||||
ExpressionPrefixOperator(Parser, StackTop, TopOperatorNode->Op, TopValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we're not running it so just return 0 */
|
||||
ExpressionPushInt(Parser, StackTop, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case OrderPostfix:
|
||||
|
@ -868,7 +858,16 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack *
|
|||
*StackTop = TopStackNode->Next->Next;
|
||||
|
||||
/* do the postfix operation */
|
||||
ExpressionPostfixOperator(Parser, StackTop, TopOperatorNode->Op, TopValue);
|
||||
if (Parser->Mode == RunModeRun && FoundPrecedence < *IgnorePrecedence)
|
||||
{
|
||||
/* run the operator */
|
||||
ExpressionPostfixOperator(Parser, StackTop, TopOperatorNode->Op, TopValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we're not running it so just return 0 */
|
||||
ExpressionPushInt(Parser, StackTop, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case OrderInfix:
|
||||
|
@ -886,7 +885,16 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack *
|
|||
*StackTop = TopOperatorNode->Next->Next;
|
||||
|
||||
/* do the infix operation */
|
||||
ExpressionInfixOperator(Parser, StackTop, TopOperatorNode->Op, BottomValue, TopValue);
|
||||
if (Parser->Mode == RunModeRun && FoundPrecedence < *IgnorePrecedence)
|
||||
{
|
||||
/* run the operator */
|
||||
ExpressionInfixOperator(Parser, StackTop, TopOperatorNode->Op, BottomValue, TopValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we're not running it so just return 0 */
|
||||
ExpressionPushInt(Parser, StackTop, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
FoundPrecedence = -1;
|
||||
|
@ -897,6 +905,10 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack *
|
|||
assert(TopOperatorNode->Order != OrderNone);
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we've returned above the ignored precedence level turn ignoring off */
|
||||
if (FoundPrecedence <= *IgnorePrecedence)
|
||||
*IgnorePrecedence = DEEP_PRECEDENCE;
|
||||
}
|
||||
#ifdef DEBUG_EXPRESSIONS
|
||||
ExpressionStackShow(*StackTop);
|
||||
|
@ -976,6 +988,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|||
int BracketPrecedence = 0;
|
||||
int LocalPrecedence;
|
||||
int Precedence = 0;
|
||||
int IgnorePrecedence = DEEP_PRECEDENCE;
|
||||
struct ExpressionStack *StackTop = NULL;
|
||||
int TernaryDepth = 0;
|
||||
|
||||
|
@ -1019,7 +1032,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|||
/* scan and collapse the stack to the precedence of this infix cast operator, then push */
|
||||
Precedence = BracketPrecedence + OperatorPrecedence[(int)TokenCast].PrefixPrecedence;
|
||||
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence+1);
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence+1, &IgnorePrecedence);
|
||||
CastTypeValue = VariableAllocValueFromType(Parser, &TypeType, FALSE, NULL, FALSE);
|
||||
CastTypeValue->Val->Typ = CastType;
|
||||
ExpressionStackPushValueNode(Parser, &StackTop, CastTypeValue);
|
||||
|
@ -1034,7 +1047,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|||
else
|
||||
{
|
||||
/* scan and collapse the stack to the precedence of this operator, then push */
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence);
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence);
|
||||
ExpressionStackPushOperator(Parser, &StackTop, OrderPrefix, Token, Precedence);
|
||||
}
|
||||
}
|
||||
|
@ -1057,13 +1070,13 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|||
BracketPrecedence -= BRACKET_PRECEDENCE;
|
||||
|
||||
/* collapse to the bracket precedence */
|
||||
ExpressionStackCollapse(Parser, &StackTop, BracketPrecedence);
|
||||
ExpressionStackCollapse(Parser, &StackTop, BracketPrecedence, &IgnorePrecedence);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* scan and collapse the stack to the precedence of this operator, then push */
|
||||
Precedence = BracketPrecedence + OperatorPrecedence[(int)Token].PostfixPrecedence;
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence);
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence);
|
||||
ExpressionStackPushOperator(Parser, &StackTop, OrderPostfix, Token, Precedence);
|
||||
break;
|
||||
}
|
||||
|
@ -1081,10 +1094,20 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|||
/* for right to left order, only go down to the next higher precedence so we evaluate it in reverse order */
|
||||
/* for left to right order, collapse down to this precedence so we evaluate it in forward order */
|
||||
if (IS_LEFT_TO_RIGHT(OperatorPrecedence[(int)Token].InfixPrecedence))
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence);
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence);
|
||||
else
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence+1);
|
||||
ExpressionStackCollapse(Parser, &StackTop, Precedence+1, &IgnorePrecedence);
|
||||
|
||||
/* if it's a && or || operator we may not need to evaluate the right hand side of the expression */
|
||||
if ( (Token == TokenLogicalOr || Token == TokenLogicalAnd) && IS_NUMERIC_COERCIBLE(StackTop->Val))
|
||||
{
|
||||
long LHSInt = ExpressionCoerceInteger(StackTop->Val);
|
||||
if ( ( (Token == TokenLogicalOr && LHSInt) || (Token == TokenLogicalAnd && !LHSInt) ) &&
|
||||
(IgnorePrecedence > Precedence) )
|
||||
IgnorePrecedence = Precedence;
|
||||
}
|
||||
|
||||
/* push the operator on the stack */
|
||||
ExpressionStackPushOperator(Parser, &StackTop, OrderInfix, Token, Precedence);
|
||||
PrefixState = TRUE;
|
||||
|
||||
|
@ -1115,11 +1138,11 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|||
|
||||
if (LexGetToken(Parser, NULL, FALSE) == TokenOpenBracket)
|
||||
{
|
||||
ExpressionParseFunctionCall(Parser, &StackTop, LexValue->Val->Identifier);
|
||||
ExpressionParseFunctionCall(Parser, &StackTop, LexValue->Val->Identifier, Parser->Mode == RunModeRun && Precedence < IgnorePrecedence);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Parser->Mode == RunModeRun)
|
||||
if (Parser->Mode == RunModeRun && Precedence < IgnorePrecedence)
|
||||
{
|
||||
struct Value *VariableValue = NULL;
|
||||
|
||||
|
@ -1146,8 +1169,13 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|||
}
|
||||
else /* push a dummy value */
|
||||
ExpressionPushInt(Parser, &StackTop, 0);
|
||||
|
||||
}
|
||||
|
||||
/* if we've successfully ignored the RHS turn ignoring off */
|
||||
if (Precedence <= IgnorePrecedence)
|
||||
IgnorePrecedence = DEEP_PRECEDENCE;
|
||||
|
||||
PrefixState = FALSE;
|
||||
}
|
||||
else if ((int)Token > TokenCloseBracket && (int)Token <= TokenCharacterConstant)
|
||||
|
@ -1190,7 +1218,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
|||
ProgramFail(Parser, "brackets not closed");
|
||||
|
||||
/* scan and collapse the stack to precedence 0 */
|
||||
ExpressionStackCollapse(Parser, &StackTop, 0);
|
||||
ExpressionStackCollapse(Parser, &StackTop, 0, &IgnorePrecedence);
|
||||
|
||||
/* fix up the stack and return the result if we're in run mode */
|
||||
if (StackTop != NULL)
|
||||
|
@ -1298,7 +1326,7 @@ void ExpressionParseMacroCall(struct ParseState *Parser, struct ExpressionStack
|
|||
}
|
||||
|
||||
/* do a function call */
|
||||
void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *FuncName)
|
||||
void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *FuncName, int RunIt)
|
||||
{
|
||||
struct Value *ReturnValue = NULL;
|
||||
struct Value *FuncValue;
|
||||
|
@ -1306,8 +1334,9 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
|
|||
struct Value **ParamArray = NULL;
|
||||
int ArgCount;
|
||||
enum LexToken Token = LexGetToken(Parser, NULL, TRUE); /* open bracket */
|
||||
enum RunMode OldMode = Parser->Mode;
|
||||
|
||||
if (Parser->Mode == RunModeRun)
|
||||
if (RunIt)
|
||||
{
|
||||
/* get the function definition */
|
||||
VariableGet(Parser, FuncName, &FuncValue);
|
||||
|
@ -1330,17 +1359,20 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
|
|||
ProgramFail(Parser, "out of memory");
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpressionPushInt(Parser, StackTop, 0);
|
||||
Parser->Mode = RunModeSkip;
|
||||
}
|
||||
|
||||
/* parse arguments */
|
||||
ArgCount = 0;
|
||||
do {
|
||||
if (Parser->Mode == RunModeRun && ArgCount < FuncValue->Val->FuncDef.NumParams)
|
||||
if (RunIt && ArgCount < FuncValue->Val->FuncDef.NumParams)
|
||||
ParamArray[ArgCount] = VariableAllocValueFromType(Parser, FuncValue->Val->FuncDef.ParamType[ArgCount], FALSE, NULL, FALSE);
|
||||
|
||||
if (ExpressionParse(Parser, &Param))
|
||||
{
|
||||
if (Parser->Mode == RunModeRun)
|
||||
if (RunIt)
|
||||
{
|
||||
if (ArgCount < FuncValue->Val->FuncDef.NumParams)
|
||||
{
|
||||
|
@ -1369,7 +1401,7 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
|
|||
|
||||
} while (Token != TokenCloseBracket);
|
||||
|
||||
if (Parser->Mode == RunModeRun)
|
||||
if (RunIt)
|
||||
{
|
||||
/* run the function */
|
||||
if (ArgCount < FuncValue->Val->FuncDef.NumParams)
|
||||
|
@ -1394,7 +1426,7 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
|
|||
if (ParseStatement(&FuncParser, TRUE) != ParseResultOk)
|
||||
ProgramFail(&FuncParser, "function body expected");
|
||||
|
||||
if (FuncValue->Val->FuncDef.ReturnType != &VoidType && FuncParser.Mode == RunModeRun)
|
||||
if (FuncValue->Val->FuncDef.ReturnType != &VoidType && FuncParser.Mode == RunIt)
|
||||
ProgramFail(&FuncParser, "no value returned from a function returning %t", FuncValue->Val->FuncDef.ReturnType);
|
||||
|
||||
VariableStackFramePop(Parser);
|
||||
|
@ -1404,9 +1436,11 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
|
|||
|
||||
HeapPopStackFrame();
|
||||
}
|
||||
|
||||
Parser->Mode = OldMode;
|
||||
}
|
||||
|
||||
/* parse an expression. operator precedence is not supported */
|
||||
/* parse an expression */
|
||||
long ExpressionParseInt(struct ParseState *Parser)
|
||||
{
|
||||
struct Value *Val;
|
||||
|
|
27
tests/50_logical_second_arg.c
Normal file
27
tests/50_logical_second_arg.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int fred()
|
||||
{
|
||||
printf("fred\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int joe()
|
||||
{
|
||||
printf("joe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("%d\n", fred() && joe());
|
||||
printf("%d\n", fred() || joe());
|
||||
printf("%d\n", joe() && fred());
|
||||
printf("%d\n", joe() || fred());
|
||||
printf("%d\n", fred() && (1 + joe()));
|
||||
printf("%d\n", fred() || (1 + joe()));
|
||||
printf("%d\n", joe() && (1 + fred()));
|
||||
printf("%d\n", joe() || (1 + fred()));
|
||||
|
||||
return 0;
|
||||
}
|
20
tests/50_logical_second_arg.expect
Normal file
20
tests/50_logical_second_arg.expect
Normal file
|
@ -0,0 +1,20 @@
|
|||
fred
|
||||
0
|
||||
fred
|
||||
joe
|
||||
1
|
||||
joe
|
||||
fred
|
||||
0
|
||||
joe
|
||||
1
|
||||
fred
|
||||
0
|
||||
fred
|
||||
joe
|
||||
1
|
||||
joe
|
||||
fred
|
||||
1
|
||||
joe
|
||||
0
|
Loading…
Reference in a new issue