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