From 825c3932406eeec6761576e1fc8139c59d864897 Mon Sep 17 00:00:00 2001 From: "zik.saleeba" Date: Tue, 2 Jun 2009 05:51:51 +0000 Subject: [PATCH] Reworking of how assignment works. Now all places which do assignment of values should work the same. git-svn-id: http://picoc.googlecode.com/svn/trunk@314 21eae674-98b7-11dd-bd71-f92a316d2d60 --- Makefile | 2 +- expression.c | 153 +++++++++++++++++++++++++++++---------------------- heap.c | 15 +++++ parse.c | 21 ++++--- picoc.h | 6 +- type.c | 2 +- variable.c | 21 ++++--- 7 files changed, 131 insertions(+), 89 deletions(-) diff --git a/Makefile b/Makefile index 8e921ca..749248d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-Wall -g -DUNIX_HOST #-DDEBUG_EXPRESSIONS #-DDEBUG_LEXER +CFLAGS=-Wall -g -DUNIX_HOST #-DDEBUG_HEAP #-DDEBUG_EXPRESSIONS #-DDEBUG_LEXER LIBS=#-lm TARGET = picoc diff --git a/expression.c b/expression.c index bfbf58f..f247a3e 100644 --- a/expression.c +++ b/expression.c @@ -169,7 +169,7 @@ void ExpressionStackPushValueNode(struct ParseState *Parser, struct ExpressionSt struct Value *ExpressionStackPushValueByType(struct ParseState *Parser, struct ExpressionStack **StackTop, struct ValueType *PushType) { debugf("ExpressionStackPushValueByType()\n"); - struct Value *ValueLoc = VariableAllocValueFromType(Parser, PushType, FALSE, NULL); + struct Value *ValueLoc = VariableAllocValueFromType(Parser, PushType, FALSE, NULL, FALSE); ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); return ValueLoc; @@ -204,7 +204,7 @@ void ExpressionStackPushDereference(struct ParseState *Parser, struct Expression void ExpressionPushInt(struct ParseState *Parser, struct ExpressionStack **StackTop, int IntValue) { debugf("ExpressionPushInt()\n"); - struct Value *ValueLoc = VariableAllocValueFromType(Parser, &IntType, FALSE, NULL); + struct Value *ValueLoc = VariableAllocValueFromType(Parser, &IntType, FALSE, NULL, FALSE); ValueLoc->Val->Integer = IntValue; ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); } @@ -213,17 +213,16 @@ void ExpressionPushInt(struct ParseState *Parser, struct ExpressionStack **Stack void ExpressionPushFP(struct ParseState *Parser, struct ExpressionStack **StackTop, double FPValue) { debugf("ExpressionPushFP()\n"); - struct Value *ValueLoc = VariableAllocValueFromType(Parser, &FPType, FALSE, NULL); + struct Value *ValueLoc = VariableAllocValueFromType(Parser, &FPType, FALSE, NULL, FALSE); ValueLoc->Val->FP = FPValue; ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); } #endif /* assign to a pointer, leaving a value on the expression stack */ -struct Value *ExpressionAssignToPointer(struct ParseState *Parser, struct Value *ToValue, struct Value *FromValue, int MakeValue) +void ExpressionAssignToPointer(struct ParseState *Parser, struct Value *ToValue, struct Value *FromValue) { struct ValueType *PointedToType = ToValue->Typ->FromType; - struct Value *ValueLoc = NULL; struct Value *DerefVal = NULL; int DerefOffset; @@ -260,21 +259,75 @@ struct Value *ExpressionAssignToPointer(struct ParseState *Parser, struct Value ToValue->Val->NativePointer = DerefVal; #endif } - else - ProgramFail(Parser, "can't assign from a %t to a %t", FromValue->Typ, ToValue->Typ); - - if (MakeValue) + else if (IS_NUMERIC_COERCIBLE(FromValue) && COERCE_INTEGER(FromValue) == 0) { - /* put a copy of the pointer on the stack */ - ValueLoc = VariableAllocValueFromType(Parser, ToValue->Typ, TRUE, NULL); + /* null pointer assignment */ #ifndef NATIVE_POINTERS - ValueLoc->Val->Pointer = ToValue->Val->Pointer; + ToValue->Val->Pointer.Segment = NULL; + ToValue->Val->Pointer.Offset = 0; #else - ValueLoc->Val->NativePointer = ToValue->Val->NativePointer; + ToValue->Val->NativePointer = NULL; #endif } - - return ValueLoc; + else + ProgramFail(Parser, "can't assign from a %t to a %t", FromValue->Typ, ToValue->Typ); +} + +/* assign any kind of value */ +void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct Value *SourceValue, int Force) +{ + if (!DestValue->IsLValue && !Force) + ProgramFail(Parser, "can't assign to this"); + + switch (DestValue->Typ->Base) + { + case TypeInt: + if (!IS_NUMERIC_COERCIBLE(SourceValue)) + ProgramFail(Parser, "can't assign to this"); + + DestValue->Val->Integer = COERCE_INTEGER(SourceValue); + break; + + case TypeChar: + if (!IS_NUMERIC_COERCIBLE(SourceValue)) + ProgramFail(Parser, "can't assign to this"); + + DestValue->Val->Character = COERCE_INTEGER(SourceValue); + break; +#ifndef NO_FP + case TypeFP: + if (!IS_NUMERIC_COERCIBLE(SourceValue)) + ProgramFail(Parser, "can't assign to this"); + + DestValue->Val->FP = COERCE_FP(SourceValue); + break; +#endif + case TypePointer: + ExpressionAssignToPointer(Parser, DestValue, SourceValue); + break; + + case TypeArray: + if (DestValue->Typ != SourceValue->Typ) + ProgramFail(Parser, "can't assign from a %t to a %t", SourceValue->Typ, DestValue->Typ); + + if (DestValue->Val->Array.Size != SourceValue->Val->Array.Size) + ProgramFail(Parser, "can't assign from an array of size %d to one of size %d", SourceValue->Val->Array.Size, DestValue->Val->Array.Size); + + memcpy((void *)DestValue->Val->Array.Data, (void *)SourceValue->Val->Array.Data, DestValue->Val->Array.Size); + break; + + case TypeStruct: + case TypeUnion: + if (DestValue->Typ != SourceValue->Typ) + ProgramFail(Parser, "can't assign from a %t to a %t", SourceValue->Typ, DestValue->Typ); + + memcpy((void *)DestValue->Val, (void *)SourceValue->Val, TypeSizeValue(SourceValue)); + break; + + default: + ProgramFail(Parser, "can't assign to a %t", DestValue->Typ); + break; + } } /* evaluate a prefix operator */ @@ -299,7 +352,7 @@ void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack TempLValue = TopValue->LValueFrom; assert(TempLValue != NULL); - Result = VariableAllocValueFromType(Parser, TypeGetMatching(Parser, TopValue->Typ, TypePointer, 0, StrEmpty), FALSE, NULL); + Result = VariableAllocValueFromType(Parser, TypeGetMatching(Parser, TopValue->Typ, TypePointer, 0, StrEmpty), FALSE, NULL, FALSE); #ifndef NATIVE_POINTERS Result->Val->Pointer.Segment = TempLValue; if (Result->LValueFrom != NULL) @@ -528,7 +581,6 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack * ProgramFail(Parser, "illegal array index %d [0..%d]", ArrayIndex, BottomValue->Val->Array.Size-1); /* make the array element result */ - // XXX - need to handle char array access Result = VariableAllocValueFromExistingData(Parser, BottomValue->Typ->FromType, (union AnyValue *)(BottomValue->Val->Array.Data + TypeSize(BottomValue->Typ->FromType, 0, FALSE) * ArrayIndex), BottomValue->IsLValue, BottomValue->LValueFrom); ExpressionStackPushValueNode(Parser, StackTop, Result); } @@ -677,10 +729,9 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack * else if (Op == TokenAssign && TopInt == 0) { /* assign a NULL pointer */ - if (!BottomValue->IsLValue) - ProgramFail(Parser, "can't assign to this"); - - ExpressionStackPushValueByType(Parser, StackTop, BottomValue->Typ); + HeapUnpopStack(sizeof(struct Value)); // XXX - possible bug if lvalue is a temp value and takes more than sizeof(struct Value) + ExpressionAssign(Parser, BottomValue, TopValue, FALSE); + ExpressionStackPushValueNode(Parser, StackTop, BottomValue); } else ProgramFail(Parser, "invalid operation"); @@ -707,20 +758,9 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack * else if (Op == TokenAssign) { /* assign a non-numeric type */ - if (!BottomValue->IsLValue) - ProgramFail(Parser, "can't assign to this"); - - if (BottomValue->Typ->Base == TypePointer) - ExpressionStackPushValueNode(Parser, StackTop, ExpressionAssignToPointer(Parser, BottomValue, TopValue, TRUE)); /* pointer assignment */ - else - { - /* assign anything else */ - if (BottomValue->Typ != TopValue->Typ) - ProgramFail(Parser, "can't assign from a %t to a %t", TopValue->Typ, BottomValue->Typ); - - memcpy((void *)BottomValue->Val, (void *)TopValue->Val, TypeSizeValue(TopValue)); // XXX - need to handle arrays - ExpressionStackPushValue(Parser, StackTop, TopValue); - } + HeapUnpopStack(sizeof(struct Value)); // XXX - possible bug if lvalue is a temp value and takes more than sizeof(struct Value) + ExpressionAssign(Parser, BottomValue, TopValue, FALSE); + ExpressionStackPushValueNode(Parser, StackTop, BottomValue); } else ProgramFail(Parser, "invalid operation"); @@ -1043,7 +1083,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) HeapPopStack(StackTop->p.Val, sizeof(struct ExpressionStack) + sizeof(struct Value) + TypeStackSizeValue(StackTop->p.Val)); } - debugf("ExpressionParse() done\n"); + debugf("ExpressionParse() done\n\n"); #ifdef DEBUG_EXPRESSIONS ExpressionStackShow(StackTop); #endif @@ -1081,44 +1121,22 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta /* parse arguments */ ArgCount = 0; do { + if (Parser->Mode == RunModeRun && ArgCount < FuncValue->Val->FuncDef.NumParams) + ParamArray[ArgCount] = VariableAllocValueFromType(Parser, FuncValue->Val->FuncDef.ParamType[ArgCount], FALSE, NULL, FALSE); + if (ExpressionParse(Parser, &Param)) { if (Parser->Mode == RunModeRun) { - if (ArgCount >= FuncValue->Val->FuncDef.NumParams) + if (ArgCount < FuncValue->Val->FuncDef.NumParams) { - if (!FuncValue->Val->FuncDef.VarArgs) - ProgramFail(Parser, "too many arguments to %s()", FuncName); + ExpressionAssign(Parser, ParamArray[ArgCount], Param, TRUE); + VariableStackPop(Parser, Param); } else { - if (FuncValue->Val->FuncDef.ParamType[ArgCount] != Param->Typ) - { - /* parameter is the wrong type - can we coerce it to being the type we want? */ - if (IS_NUMERIC_COERCIBLE(Param)) - { - int IntVal = COERCE_INTEGER(Param); /* cast to int */ -#ifndef NO_FP - double FloatVal = COERCE_FP(Param); /* cast to float */ -#endif - VariableStackPop(Parser, Param); - Param = VariableAllocValueFromType(Parser, FuncValue->Val->FuncDef.ParamType[ArgCount], FALSE, NULL); - - if (FuncValue->Val->FuncDef.ParamType[ArgCount] == &IntType) - Param->Val->Integer = IntVal; - - else if (FuncValue->Val->FuncDef.ParamType[ArgCount] == &CharType) - Param->Val->Character = IntVal; -#ifndef NO_FP - else - Param->Val->FP = FloatVal; -#endif - } - else - ProgramFail(Parser, "parameter %d to %s() is %t instead of %t", ArgCount+1, FuncName, Param->Typ, FuncValue->Val->FuncDef.ParamType[ArgCount]); - } - - ParamArray[ArgCount] = Param; + if (!FuncValue->Val->FuncDef.VarArgs) + ProgramFail(Parser, "too many arguments to %s()", FuncName); } } @@ -1134,6 +1152,7 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta if (!TokenCloseBracket) ProgramFail(Parser, "bad argument"); } + } while (Token != TokenCloseBracket); if (Parser->Mode == RunModeRun) @@ -1152,7 +1171,7 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta TopStackFrame->NumParams = ArgCount; TopStackFrame->ReturnValue = ReturnValue; for (Count = 0; Count < FuncValue->Val->FuncDef.NumParams; Count++) - VariableDefine(Parser, FuncValue->Val->FuncDef.ParamName[Count], ParamArray[Count], TRUE); + VariableDefine(Parser, FuncValue->Val->FuncDef.ParamName[Count], ParamArray[Count], NULL, TRUE); if (!ParseStatement(&FuncParser)) ProgramFail(&FuncParser, "function body expected"); diff --git a/heap.c b/heap.c index 7e08ca7..efebaf3 100644 --- a/heap.c +++ b/heap.c @@ -55,6 +55,9 @@ void *HeapAllocStack(int Size) { void *NewMem = HeapStackTop; void *NewTop = HeapStackTop + MEM_ALIGN(Size); +#ifdef DEBUG_HEAP + printf("HeapAllocStack(%d) at 0x%lx\n", MEM_ALIGN(Size), (unsigned long)HeapStackTop); +#endif if (NewTop > HeapBottom) return NULL; @@ -63,6 +66,15 @@ void *HeapAllocStack(int Size) return NewMem; } +/* allocate some space on the stack, in the current stack frame */ +void HeapUnpopStack(int Size) +{ +#ifdef DEBUG_HEAP + printf("HeapUnpopStack(%d) at 0x%lx\n", MEM_ALIGN(Size), (unsigned long)HeapStackTop); +#endif + HeapStackTop = HeapStackTop + MEM_ALIGN(Size); +} + /* free some space at the top of the stack */ int HeapPopStack(void *Addr, int Size) { @@ -70,6 +82,9 @@ int HeapPopStack(void *Addr, int Size) if (ToLose > (HeapStackTop - (void *)&HeapMemory[0])) return FALSE; +#ifdef DEBUG_HEAP + printf("HeapPopStack(0x%lx, %d) back to 0x%lx\n", (unsigned long)Addr, MEM_ALIGN(Size), (unsigned long)HeapStackTop - ToLose); +#endif HeapStackTop -= ToLose; assert(HeapStackTop == Addr); diff --git a/parse.c b/parse.c index 3ecfae8..aee29cf 100644 --- a/parse.c +++ b/parse.c @@ -105,6 +105,7 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token) struct ValueType *BasicType; struct ValueType *Typ; struct Value *CValue; + struct Value *NewVariable; TypeParseFront(Parser, &BasicType); do @@ -126,17 +127,20 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token) if (Token == TokenVoidType && Identifier != StrEmpty) ProgramFail(Parser, "can't define a void variable"); - if (LexGetToken(Parser, NULL, FALSE) != TokenAssign) - VariableDefine(Parser, Identifier, VariableAllocValueFromType(Parser, Typ, TRUE, NULL), TRUE); - else - { /* we're assigning an initial value */ + NewVariable = VariableDefine(Parser, Identifier, NULL, Typ, TRUE); + + if (LexGetToken(Parser, NULL, FALSE) == TokenAssign) + { + /* we're assigning an initial value */ LexGetToken(Parser, NULL, TRUE); if (!ExpressionParse(Parser, &CValue)) ProgramFail(Parser, "expression expected"); - VariableDefine(Parser, Identifier, CValue, TRUE); if (Parser->Mode == RunModeRun) + { + ExpressionAssign(Parser, NewVariable, CValue, FALSE); VariableStackPop(Parser, CValue); + } } } } @@ -463,12 +467,7 @@ int ParseStatement(struct ParseState *Parser) if (!ExpressionParse(Parser, &CValue) && TopStackFrame->ReturnValue->Typ->Base != TypeVoid) ProgramFail(Parser, "value required in return"); - if (CValue->Typ != TopStackFrame->ReturnValue->Typ) - ProgramFail(Parser, "wrong return type"); - - // XXX - make assignment a separate function - // XXX - also arrays need cleverer assignment - memcpy((void *)TopStackFrame->ReturnValue->Val, (void *)CValue->Val, TypeSizeValue(CValue)); + ExpressionAssign(Parser, TopStackFrame->ReturnValue, CValue, TRUE); VariableStackPop(Parser, CValue); Parser->Mode = RunModeReturn; } diff --git a/picoc.h b/picoc.h index 73a556a..e3dc930 100644 --- a/picoc.h +++ b/picoc.h @@ -317,6 +317,7 @@ void ParserCopyPos(struct ParseState *To, struct ParseState *From); /* expression.c */ int ExpressionParse(struct ParseState *Parser, struct Value **Result); int ExpressionParseInt(struct ParseState *Parser); +void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct Value *SourceValue, int Force); /* type.c */ void TypeInit(); @@ -334,6 +335,7 @@ struct ValueType *TypeGetMatching(struct ParseState *Parser, struct ValueType *P void HeapInit(); void *HeapAllocStack(int Size); int HeapPopStack(void *Addr, int Size); +void HeapUnpopStack(int Size); void HeapPushStackFrame(); int HeapPopStackFrame(); void *HeapAlloc(int Size); @@ -348,10 +350,10 @@ void *VariableAlloc(struct ParseState *Parser, int Size, int OnHeap); void VariableStackPop(struct ParseState *Parser, struct Value *Var); struct Value *VariableAllocValueAndData(struct ParseState *Parser, int DataSize, int IsLValue, struct Value *LValueFrom, int OnHeap); struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value *FromValue, int OnHeap); -struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom); +struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom, int OnHeap); struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser, struct ValueType *Typ, union AnyValue *FromValue, int IsLValue, struct Value *LValueFrom); struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value *FromValue); -void VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, int MakeWritable); +struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable); int VariableDefined(const char *Ident); void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal); void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable); diff --git a/type.c b/type.c index c882317..c22457f 100644 --- a/type.c +++ b/type.c @@ -270,7 +270,7 @@ void TypeParseEnum(struct ParseState *Parser, struct ValueType **Typ) EnumValue = ExpressionParseInt(Parser); } - VariableDefine(Parser, EnumIdentifier, &InitValue, FALSE); + VariableDefine(Parser, EnumIdentifier, &InitValue, NULL, FALSE); Token = LexGetToken(Parser, NULL, TRUE); if (Token != TokenComma && Token != TokenRightBrace) diff --git a/variable.c b/variable.c index e47ca97..f6bc03b 100644 --- a/variable.c +++ b/variable.c @@ -99,16 +99,16 @@ struct Value *VariableAllocValueAndData(struct ParseState *Parser, int DataSize, } /* allocate a value given its type */ -struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom) +struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct ValueType *Typ, int IsLValue, struct Value *LValueFrom, int OnHeap) { int Size = TypeSize(Typ, Typ->ArraySize, FALSE); - struct Value *NewValue = VariableAllocValueAndData(Parser, Size, IsLValue, LValueFrom, FALSE); + struct Value *NewValue = VariableAllocValueAndData(Parser, Size, IsLValue, LValueFrom, OnHeap); assert(Size > 0 || Typ == &VoidType); NewValue->Typ = Typ; if (Typ->Base == TypeArray) { NewValue->Val->Array.Size = Typ->ArraySize; - NewValue->Val->Array.Data = (void *)NewValue->Val; + NewValue->Val->Array.Data = (void *)NewValue->Val + sizeof(struct ArrayValue); } return NewValue; @@ -121,6 +121,7 @@ struct Value *VariableAllocValueAndCopy(struct ParseState *Parser, struct Value struct Value *NewValue = VariableAllocValueAndData(Parser, CopySize, FromValue->IsLValue, FromValue->LValueFrom, OnHeap); NewValue->Typ = FromValue->Typ; memcpy((void *)NewValue->Val, (void *)FromValue->Val, CopySize); + return NewValue; } @@ -145,15 +146,21 @@ struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value * } /* define a variable. Ident must be registered */ -void VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, int MakeWritable) +struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable) { - struct Value *AssignValue = VariableAllocValueAndCopy(Parser, InitValue, TopStackFrame == NULL); + struct Value *AssignValue; - if (MakeWritable) - AssignValue->IsLValue = TRUE; + if (InitValue != NULL) + AssignValue = VariableAllocValueAndCopy(Parser, InitValue, TopStackFrame == NULL); + else + AssignValue = VariableAllocValueFromType(Parser, Typ, MakeWritable, NULL, TopStackFrame == NULL); + + AssignValue->IsLValue = MakeWritable; if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, AssignValue)) ProgramFail(Parser, "'%s' is already defined", Ident); + + return AssignValue; } /* check if a variable with a given name is defined. Ident must be registered */