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:
zik.saleeba 2011-02-16 00:13:11 +00:00
parent 4919d40cd2
commit 807b3d09ba
3 changed files with 123 additions and 42 deletions

View file

@ -6,6 +6,8 @@
#define BRACKET_PRECEDENCE 20 #define BRACKET_PRECEDENCE 20
#define IS_TYPE_TOKEN(t) ((t) >= TokenIntType && (t) <= TokenUnsignedType) #define IS_TYPE_TOKEN(t) ((t) >= TokenIntType && (t) <= TokenUnsignedType)
#define DEEP_PRECEDENCE (BRACKET_PRECEDENCE*1000)
#ifdef DEBUG_EXPRESSIONS #ifdef DEBUG_EXPRESSIONS
#define debugf printf #define debugf printf
#else #else
@ -67,7 +69,7 @@ static struct OpPrecedence OperatorPrecedence[] =
/* TokenOpenBracket, */ { 15, 0, 0, "(" }, /* TokenCloseBracket, */ { 0, 15, 0, ")" } /* 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 #ifdef DEBUG_EXPRESSIONS
/* show the contents of the expression stack */ /* show the contents of the expression stack */
@ -443,13 +445,6 @@ void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack
struct Value *Result; struct Value *Result;
union AnyValue *ValPtr; union AnyValue *ValPtr;
if (Parser->Mode != RunModeRun)
{
/* we're not running it so just return 0 */
ExpressionPushInt(Parser, StackTop, 0);
return;
}
debugf("ExpressionPrefixOperator()\n"); debugf("ExpressionPrefixOperator()\n");
switch (Op) switch (Op)
{ {
@ -545,13 +540,6 @@ void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack
/* evaluate a postfix operator */ /* evaluate a postfix operator */
void ExpressionPostfixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue) 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"); debugf("ExpressionPostfixOperator()\n");
if (IS_NUMERIC_COERCIBLE(TopValue)) if (IS_NUMERIC_COERCIBLE(TopValue))
{ {
@ -602,13 +590,6 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
struct Value *StackValue; struct Value *StackValue;
void *Pointer; void *Pointer;
if (Parser->Mode != RunModeRun)
{
/* we're not running it so just return 0 */
ExpressionPushInt(Parser, StackTop, 0);
return;
}
debugf("ExpressionInfixOperator()\n"); debugf("ExpressionInfixOperator()\n");
if (BottomValue == NULL || TopValue == NULL) if (BottomValue == NULL || TopValue == NULL)
ProgramFail(Parser, "invalid expression"); 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 */ /* 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; int FoundPrecedence = Precedence;
struct Value *TopValue; struct Value *TopValue;
@ -854,7 +835,16 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack *
*StackTop = TopOperatorNode->Next; *StackTop = TopOperatorNode->Next;
/* do the prefix operation */ /* 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; break;
case OrderPostfix: case OrderPostfix:
@ -868,7 +858,16 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack *
*StackTop = TopStackNode->Next->Next; *StackTop = TopStackNode->Next->Next;
/* do the postfix operation */ /* 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; break;
case OrderInfix: case OrderInfix:
@ -886,7 +885,16 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack *
*StackTop = TopOperatorNode->Next->Next; *StackTop = TopOperatorNode->Next->Next;
/* do the infix operation */ /* 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 else
FoundPrecedence = -1; FoundPrecedence = -1;
@ -897,6 +905,10 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack *
assert(TopOperatorNode->Order != OrderNone); assert(TopOperatorNode->Order != OrderNone);
break; break;
} }
/* if we've returned above the ignored precedence level turn ignoring off */
if (FoundPrecedence <= *IgnorePrecedence)
*IgnorePrecedence = DEEP_PRECEDENCE;
} }
#ifdef DEBUG_EXPRESSIONS #ifdef DEBUG_EXPRESSIONS
ExpressionStackShow(*StackTop); ExpressionStackShow(*StackTop);
@ -976,6 +988,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
int BracketPrecedence = 0; int BracketPrecedence = 0;
int LocalPrecedence; int LocalPrecedence;
int Precedence = 0; int Precedence = 0;
int IgnorePrecedence = DEEP_PRECEDENCE;
struct ExpressionStack *StackTop = NULL; struct ExpressionStack *StackTop = NULL;
int TernaryDepth = 0; 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 */ /* scan and collapse the stack to the precedence of this infix cast operator, then push */
Precedence = BracketPrecedence + OperatorPrecedence[(int)TokenCast].PrefixPrecedence; 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 = VariableAllocValueFromType(Parser, &TypeType, FALSE, NULL, FALSE);
CastTypeValue->Val->Typ = CastType; CastTypeValue->Val->Typ = CastType;
ExpressionStackPushValueNode(Parser, &StackTop, CastTypeValue); ExpressionStackPushValueNode(Parser, &StackTop, CastTypeValue);
@ -1034,7 +1047,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
else else
{ {
/* scan and collapse the stack to the precedence of this operator, then push */ /* 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); ExpressionStackPushOperator(Parser, &StackTop, OrderPrefix, Token, Precedence);
} }
} }
@ -1057,13 +1070,13 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
BracketPrecedence -= BRACKET_PRECEDENCE; BracketPrecedence -= BRACKET_PRECEDENCE;
/* collapse to the bracket precedence */ /* collapse to the bracket precedence */
ExpressionStackCollapse(Parser, &StackTop, BracketPrecedence); ExpressionStackCollapse(Parser, &StackTop, BracketPrecedence, &IgnorePrecedence);
break; break;
default: default:
/* scan and collapse the stack to the precedence of this operator, then push */ /* scan and collapse the stack to the precedence of this operator, then push */
Precedence = BracketPrecedence + OperatorPrecedence[(int)Token].PostfixPrecedence; Precedence = BracketPrecedence + OperatorPrecedence[(int)Token].PostfixPrecedence;
ExpressionStackCollapse(Parser, &StackTop, Precedence); ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence);
ExpressionStackPushOperator(Parser, &StackTop, OrderPostfix, Token, Precedence); ExpressionStackPushOperator(Parser, &StackTop, OrderPostfix, Token, Precedence);
break; 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 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 */ /* 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)) if (IS_LEFT_TO_RIGHT(OperatorPrecedence[(int)Token].InfixPrecedence))
ExpressionStackCollapse(Parser, &StackTop, Precedence); ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence);
else 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); ExpressionStackPushOperator(Parser, &StackTop, OrderInfix, Token, Precedence);
PrefixState = TRUE; PrefixState = TRUE;
@ -1115,11 +1138,11 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
if (LexGetToken(Parser, NULL, FALSE) == TokenOpenBracket) if (LexGetToken(Parser, NULL, FALSE) == TokenOpenBracket)
{ {
ExpressionParseFunctionCall(Parser, &StackTop, LexValue->Val->Identifier); ExpressionParseFunctionCall(Parser, &StackTop, LexValue->Val->Identifier, Parser->Mode == RunModeRun && Precedence < IgnorePrecedence);
} }
else else
{ {
if (Parser->Mode == RunModeRun) if (Parser->Mode == RunModeRun && Precedence < IgnorePrecedence)
{ {
struct Value *VariableValue = NULL; struct Value *VariableValue = NULL;
@ -1146,8 +1169,13 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
} }
else /* push a dummy value */ else /* push a dummy value */
ExpressionPushInt(Parser, &StackTop, 0); ExpressionPushInt(Parser, &StackTop, 0);
} }
/* if we've successfully ignored the RHS turn ignoring off */
if (Precedence <= IgnorePrecedence)
IgnorePrecedence = DEEP_PRECEDENCE;
PrefixState = FALSE; PrefixState = FALSE;
} }
else if ((int)Token > TokenCloseBracket && (int)Token <= TokenCharacterConstant) 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"); ProgramFail(Parser, "brackets not closed");
/* scan and collapse the stack to precedence 0 */ /* 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 */ /* fix up the stack and return the result if we're in run mode */
if (StackTop != NULL) if (StackTop != NULL)
@ -1298,7 +1326,7 @@ void ExpressionParseMacroCall(struct ParseState *Parser, struct ExpressionStack
} }
/* do a function call */ /* 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 *ReturnValue = NULL;
struct Value *FuncValue; struct Value *FuncValue;
@ -1306,8 +1334,9 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
struct Value **ParamArray = NULL; struct Value **ParamArray = NULL;
int ArgCount; int ArgCount;
enum LexToken Token = LexGetToken(Parser, NULL, TRUE); /* open bracket */ enum LexToken Token = LexGetToken(Parser, NULL, TRUE); /* open bracket */
enum RunMode OldMode = Parser->Mode;
if (Parser->Mode == RunModeRun) if (RunIt)
{ {
/* get the function definition */ /* get the function definition */
VariableGet(Parser, FuncName, &FuncValue); VariableGet(Parser, FuncName, &FuncValue);
@ -1330,17 +1359,20 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
ProgramFail(Parser, "out of memory"); ProgramFail(Parser, "out of memory");
} }
else else
{
ExpressionPushInt(Parser, StackTop, 0); ExpressionPushInt(Parser, StackTop, 0);
Parser->Mode = RunModeSkip;
}
/* parse arguments */ /* parse arguments */
ArgCount = 0; ArgCount = 0;
do { 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); ParamArray[ArgCount] = VariableAllocValueFromType(Parser, FuncValue->Val->FuncDef.ParamType[ArgCount], FALSE, NULL, FALSE);
if (ExpressionParse(Parser, &Param)) if (ExpressionParse(Parser, &Param))
{ {
if (Parser->Mode == RunModeRun) if (RunIt)
{ {
if (ArgCount < FuncValue->Val->FuncDef.NumParams) if (ArgCount < FuncValue->Val->FuncDef.NumParams)
{ {
@ -1369,7 +1401,7 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
} while (Token != TokenCloseBracket); } while (Token != TokenCloseBracket);
if (Parser->Mode == RunModeRun) if (RunIt)
{ {
/* run the function */ /* run the function */
if (ArgCount < FuncValue->Val->FuncDef.NumParams) if (ArgCount < FuncValue->Val->FuncDef.NumParams)
@ -1394,7 +1426,7 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
if (ParseStatement(&FuncParser, TRUE) != ParseResultOk) if (ParseStatement(&FuncParser, TRUE) != ParseResultOk)
ProgramFail(&FuncParser, "function body expected"); 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); ProgramFail(&FuncParser, "no value returned from a function returning %t", FuncValue->Val->FuncDef.ReturnType);
VariableStackFramePop(Parser); VariableStackFramePop(Parser);
@ -1404,9 +1436,11 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
HeapPopStackFrame(); HeapPopStackFrame();
} }
Parser->Mode = OldMode;
} }
/* parse an expression. operator precedence is not supported */ /* parse an expression */
long ExpressionParseInt(struct ParseState *Parser) long ExpressionParseInt(struct ParseState *Parser)
{ {
struct Value *Val; struct Value *Val;

View 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;
}

View 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