Implemented the ternary operator

git-svn-id: http://picoc.googlecode.com/svn/trunk@458 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
zik.saleeba 2010-07-04 19:52:52 +00:00
parent d51b1d9726
commit 8021fed051
3 changed files with 63 additions and 9 deletions

View file

@ -2,7 +2,7 @@
/* whether evaluation is left to right for a given precedence level */
#define IS_LEFT_TO_RIGHT(p) ((p) != 2 && (p) != 3 && (p) != 14)
#define IS_LEFT_TO_RIGHT(p) ((p) != 2 && (p) != 14)
#define BRACKET_PRECEDENCE 20
#define IS_TYPE_TOKEN(t) ((t) >= TokenIntType && (t) <= TokenUnsignedType)
@ -403,6 +403,39 @@ void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct
}
}
/* evaluate the first half of a ternary operator x ? y : z */
void ExpressionQuestionMarkOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *BottomValue, struct Value *TopValue)
{
if (!IS_NUMERIC_COERCIBLE(TopValue))
ProgramFail(Parser, "first argument to '?' should be a number");
if (ExpressionCoerceInteger(TopValue))
{
/* the condition's true, return the BottomValue */
ExpressionStackPushValue(Parser, StackTop, BottomValue);
}
else
{
/* the condition's false, return void */
ExpressionStackPushValueByType(Parser, StackTop, &VoidType);
}
}
/* evaluate the second half of a ternary operator x ? y : z */
void ExpressionColonOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *BottomValue, struct Value *TopValue)
{
if (TopValue->Typ->Base == TypeVoid)
{
/* invoke the "else" part - return the BottomValue */
ExpressionStackPushValue(Parser, StackTop, BottomValue);
}
else
{
/* it was a "then" - return the TopValue */
ExpressionStackPushValue(Parser, StackTop, TopValue);
}
}
/* evaluate a prefix operator */
void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue)
{
@ -610,6 +643,12 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
ExpressionStackPushValueNode(Parser, StackTop, Result);
}
else if (Op == TokenQuestionMark)
ExpressionQuestionMarkOperator(Parser, StackTop, TopValue, BottomValue);
else if (Op == TokenColon)
ExpressionColonOperator(Parser, StackTop, TopValue, BottomValue);
#ifndef NO_FP
else if ( (TopValue->Typ == &FPType && BottomValue->Typ == &FPType) ||
(TopValue->Typ == &FPType && IS_NUMERIC_COERCIBLE(BottomValue)) ||
@ -667,8 +706,6 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
case TokenArithmeticAndAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt & TopInt, FALSE); break;
case TokenArithmeticOrAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt | TopInt, FALSE); break;
case TokenArithmeticExorAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt ^ TopInt, FALSE); break;
case TokenQuestionMark: ProgramFail(Parser, "not supported"); break; /* XXX */
case TokenColon: ProgramFail(Parser, "not supported"); break; /* XXX */
case TokenLogicalOr: ResultInt = BottomInt || TopInt; break;
case TokenLogicalAnd: ResultInt = BottomInt && TopInt; break;
case TokenArithmeticOr: ResultInt = BottomInt | TopInt; break;
@ -939,8 +976,8 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
struct ParseState PreState = *Parser;
enum LexToken Token = LexGetToken(Parser, &LexValue, TRUE);
if ( ( ( (int)Token > TokenComma && (int)Token <= (int)TokenOpenBracket) ||
(Token == TokenCloseBracket && BracketPrecedence != 0)) &&
(Token != TokenColon || TernaryDepth != 0) )
(Token == TokenCloseBracket && BracketPrecedence != 0)) &&
(Token != TokenColon || TernaryDepth > 0) )
{
/* it's an operator with precedence */
if (PrefixState)
@ -1035,6 +1072,13 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
ExpressionStackPushOperator(Parser, &StackTop, OrderInfix, Token, Precedence);
PrefixState = TRUE;
switch (Token)
{
case TokenQuestionMark: TernaryDepth++; break;
case TokenColon: TernaryDepth--; break;
default: break;
}
}
/* treat an open square bracket as an infix array index operator followed by an open bracket */

View file

@ -29,6 +29,7 @@ TESTS= 00_assignment.test \
29_array_address.test \
30_hanoi.test \
31_args.test \
33_ternary_op.test \
34_array_assignment.test \
35_sizeof.test \
36_array_initialisers.test \

View file

@ -1,5 +1,8 @@
#include "picoc.h"
/* maximum size of a value to temporarily copy while we create a variable */
#define MAX_TMP_COPY_BUF 256
/* the table of global definitions */
struct Table GlobalTable;
struct TableEntry *GlobalHashTable[GLOBAL_TABLE_SIZE];
@ -109,13 +112,19 @@ struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct Value
return NewValue;
}
/* allocate a value either on the heap or the stack and copy its value */
/* allocate a value either on the heap or the stack and copy its value. handles overlapping data */
struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap)
{
struct ValueType *DType = FromValue->Typ;
struct Value *NewValue;
char TmpBuf[MAX_TMP_COPY_BUF];
int CopySize = TypeSizeValue(FromValue);
struct Value *NewValue = VariableAllocValueAndData(Parser, CopySize, FromValue->IsLValue, FromValue->LValueFrom, OnHeap);
NewValue->Typ = FromValue->Typ;
memcpy((void *)NewValue->Val, (void *)FromValue->Val, CopySize);
assert(CopySize <= MAX_TMP_COPY_BUF);
memcpy((void *)&TmpBuf[0], (void *)FromValue->Val, CopySize);
NewValue = VariableAllocValueAndData(Parser, CopySize, FromValue->IsLValue, FromValue->LValueFrom, OnHeap);
NewValue->Typ = DType;
memcpy((void *)NewValue->Val, (void *)&TmpBuf[0], CopySize);
return NewValue;
}