From 8021fed0514ae9fa4ce2294949bfe08763df477c Mon Sep 17 00:00:00 2001 From: "zik.saleeba" Date: Sun, 4 Jul 2010 19:52:52 +0000 Subject: [PATCH] Implemented the ternary operator git-svn-id: http://picoc.googlecode.com/svn/trunk@458 21eae674-98b7-11dd-bd71-f92a316d2d60 --- expression.c | 54 +++++++++++++++++++++++++++++++++++++++++++++----- tests/Makefile | 1 + variable.c | 17 ++++++++++++---- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/expression.c b/expression.c index bbe7fe6..144735c 100644 --- a/expression.c +++ b/expression.c @@ -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 */ diff --git a/tests/Makefile b/tests/Makefile index b355bf8..2834b8c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -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 \ diff --git a/variable.c b/variable.c index 554f593..f61c596 100644 --- a/variable.c +++ b/variable.c @@ -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; }