Implemented the ternary operator
git-svn-id: http://picoc.googlecode.com/svn/trunk@458 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
parent
d51b1d9726
commit
8021fed051
52
expression.c
52
expression.c
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
|
|
||||||
/* whether evaluation is left to right for a given precedence level */
|
/* 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 BRACKET_PRECEDENCE 20
|
||||||
#define IS_TYPE_TOKEN(t) ((t) >= TokenIntType && (t) <= TokenUnsignedType)
|
#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 */
|
/* evaluate a prefix operator */
|
||||||
void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue)
|
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);
|
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
|
#ifndef NO_FP
|
||||||
else if ( (TopValue->Typ == &FPType && BottomValue->Typ == &FPType) ||
|
else if ( (TopValue->Typ == &FPType && BottomValue->Typ == &FPType) ||
|
||||||
(TopValue->Typ == &FPType && IS_NUMERIC_COERCIBLE(BottomValue)) ||
|
(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 TokenArithmeticAndAssign: ResultInt = ExpressionAssignInt(Parser, BottomValue, BottomInt & TopInt, FALSE); break;
|
||||||
case TokenArithmeticOrAssign: 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 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 TokenLogicalOr: ResultInt = BottomInt || TopInt; break;
|
||||||
case TokenLogicalAnd: ResultInt = BottomInt && TopInt; break;
|
case TokenLogicalAnd: ResultInt = BottomInt && TopInt; break;
|
||||||
case TokenArithmeticOr: ResultInt = BottomInt | TopInt; break;
|
case TokenArithmeticOr: ResultInt = BottomInt | TopInt; break;
|
||||||
|
@ -940,7 +977,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
||||||
enum LexToken Token = LexGetToken(Parser, &LexValue, TRUE);
|
enum LexToken Token = LexGetToken(Parser, &LexValue, TRUE);
|
||||||
if ( ( ( (int)Token > TokenComma && (int)Token <= (int)TokenOpenBracket) ||
|
if ( ( ( (int)Token > TokenComma && (int)Token <= (int)TokenOpenBracket) ||
|
||||||
(Token == TokenCloseBracket && BracketPrecedence != 0)) &&
|
(Token == TokenCloseBracket && BracketPrecedence != 0)) &&
|
||||||
(Token != TokenColon || TernaryDepth != 0) )
|
(Token != TokenColon || TernaryDepth > 0) )
|
||||||
{
|
{
|
||||||
/* it's an operator with precedence */
|
/* it's an operator with precedence */
|
||||||
if (PrefixState)
|
if (PrefixState)
|
||||||
|
@ -1035,6 +1072,13 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result)
|
||||||
|
|
||||||
ExpressionStackPushOperator(Parser, &StackTop, OrderInfix, Token, Precedence);
|
ExpressionStackPushOperator(Parser, &StackTop, OrderInfix, Token, Precedence);
|
||||||
PrefixState = TRUE;
|
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 */
|
/* treat an open square bracket as an infix array index operator followed by an open bracket */
|
||||||
|
|
|
@ -29,6 +29,7 @@ TESTS= 00_assignment.test \
|
||||||
29_array_address.test \
|
29_array_address.test \
|
||||||
30_hanoi.test \
|
30_hanoi.test \
|
||||||
31_args.test \
|
31_args.test \
|
||||||
|
33_ternary_op.test \
|
||||||
34_array_assignment.test \
|
34_array_assignment.test \
|
||||||
35_sizeof.test \
|
35_sizeof.test \
|
||||||
36_array_initialisers.test \
|
36_array_initialisers.test \
|
||||||
|
|
17
variable.c
17
variable.c
|
@ -1,5 +1,8 @@
|
||||||
#include "picoc.h"
|
#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 */
|
/* the table of global definitions */
|
||||||
struct Table GlobalTable;
|
struct Table GlobalTable;
|
||||||
struct TableEntry *GlobalHashTable[GLOBAL_TABLE_SIZE];
|
struct TableEntry *GlobalHashTable[GLOBAL_TABLE_SIZE];
|
||||||
|
@ -109,13 +112,19 @@ struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct Value
|
||||||
return NewValue;
|
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 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);
|
int CopySize = TypeSizeValue(FromValue);
|
||||||
struct Value *NewValue = VariableAllocValueAndData(Parser, CopySize, FromValue->IsLValue, FromValue->LValueFrom, OnHeap);
|
|
||||||
NewValue->Typ = FromValue->Typ;
|
assert(CopySize <= MAX_TMP_COPY_BUF);
|
||||||
memcpy((void *)NewValue->Val, (void *)FromValue->Val, CopySize);
|
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;
|
return NewValue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue