diff --git a/TODO b/TODO index fe195b0..bd2f6b5 100644 --- a/TODO +++ b/TODO @@ -9,6 +9,7 @@ Implement: * casts * char access/char array access/char * access * an easier way of checking pointers in library code +* evaluate only first argument of && and || if possible Improvements: * #define with arguments diff --git a/expression.c b/expression.c index 9f28c99..f051378 100644 --- a/expression.c +++ b/expression.c @@ -167,10 +167,11 @@ void ExpressionStackPushValue(struct ParseState *Parser, struct ExpressionStack ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); } -void ExpressionStackPushLValue(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *PushValue) +void ExpressionStackPushLValue(struct ParseState *Parser, struct ExpressionStack **StackTop, struct Value *PushValue, int Offset) { debugf("ExpressionStackPushLValue()\n"); struct Value *ValueLoc = VariableAllocValueShared(Parser, PushValue); + ValueLoc->Val = (void *)ValueLoc->Val + Offset; ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); } @@ -215,19 +216,15 @@ void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack TempLValue = TopValue->LValueFrom; Result = VariableAllocValueFromType(Parser, TypeGetMatching(Parser, TopValue->Typ, TypePointer, 0, StrEmpty), FALSE, NULL); Result->Val->Pointer.Segment = TempLValue; - Result->Val->Pointer.Offset = (void *)Result->Val - (void *)Result->LValueFrom; + if (Result->LValueFrom != NULL) + Result->Val->Pointer.Offset = (void *)Result->Val - (void *)Result->LValueFrom; + ExpressionStackPushValueNode(Parser, StackTop, Result); break; case TokenAsterisk: - if (TopValue->Typ->Base != TypePointer) - ProgramFail(Parser, "can't dereference this non-pointer"); - - if (TopValue->Val->Pointer.Segment == NULL) - ProgramFail(Parser, "can't dereference NULL pointer"); - - // XXX - should also do offset + checks - ExpressionStackPushLValue(Parser, StackTop, TopValue->Val->Pointer.Segment); + VariableCheckPointer(Parser, TopValue); + ExpressionStackPushLValue(Parser, StackTop, TopValue->Val->Pointer.Segment, TopValue->Val->Pointer.Offset); break; case TokenSizeof: @@ -611,19 +608,16 @@ void ExpressionGetStructElement(struct ParseState *Parser, struct ExpressionStac /* look up the struct element */ struct Value *ParamVal = (*StackTop)->p.Val; struct Value *StructVal = ParamVal; + int StructOffset = 0; struct Value *MemberValue; struct Value *Result; if (Token == TokenArrow) { /* dereference the struct pointer first */ - if (StructVal->Typ->Base != TypePointer) - ProgramFail(Parser, "can't dereference this non-pointer"); - - // XXX - should also do offset + checks + VariableCheckPointer(Parser, ParamVal); StructVal = ParamVal->Val->Pointer.Segment; - if (StructVal == NULL) - ProgramFail(Parser, "can't dereference NULL pointer"); + StructOffset = ParamVal->Val->Pointer.Offset; } if (StructVal->Typ->Base != TypeStruct && StructVal->Typ->Base != TypeUnion) @@ -637,7 +631,7 @@ void ExpressionGetStructElement(struct ParseState *Parser, struct ExpressionStac *StackTop = (*StackTop)->Next; /* make the result value for this member only */ - Result = VariableAllocValueFromExistingData(Parser, MemberValue->Typ, (void *)StructVal->Val + MemberValue->Val->Integer, TRUE, StructVal->LValueFrom); + Result = VariableAllocValueFromExistingData(Parser, MemberValue->Typ, (void *)StructVal->Val + StructOffset + MemberValue->Val->Integer, TRUE, StructVal->LValueFrom); ExpressionStackPushValueNode(Parser, StackTop, Result); } } @@ -679,7 +673,6 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) { /* boost the bracket operator precedence, then push */ BracketPrecedence += BRACKET_PRECEDENCE; - // XXX ExpressionStackPushOperator(Parser, &StackTop, OrderPrefix, Token, Precedence); } else { @@ -741,7 +734,6 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) { /* boost the bracket operator precedence, then push */ BracketPrecedence += BRACKET_PRECEDENCE; - // XXX ExpressionStackPushOperator(Parser, &StackTop, OrderPrefix, Token, Precedence); } } else @@ -774,7 +766,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) else if (VariableValue->Typ == TypeVoid) ProgramFail(Parser, "a void value isn't much use here"); else - ExpressionStackPushLValue(Parser, &StackTop, VariableValue); /* it's a value variable */ + ExpressionStackPushLValue(Parser, &StackTop, VariableValue, 0); /* it's a value variable */ } else /* push a dummy value */ ExpressionPushInt(Parser, &StackTop, 0); diff --git a/picoc.h b/picoc.h index 6cc4688..967e776 100644 --- a/picoc.h +++ b/picoc.h @@ -286,6 +286,7 @@ void TypeCleanup(); int TypeSize(struct ValueType *Typ, int ArraySize); int TypeSizeValue(struct Value *Val); int TypeStackSizeValue(struct Value *Val); +int TypeLastAccessibleOffset(struct Value *Val); int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ); void TypeParseIdentPart(struct ParseState *Parser, struct ValueType *BasicTyp, struct ValueType **Typ, char **Identifier); void TypeParse(struct ParseState *Parser, struct ValueType **Typ, char **Identifier); @@ -320,6 +321,7 @@ void VariableStackFrameAdd(struct ParseState *Parser, int NumParams); void VariableStackFramePop(struct ParseState *Parser); struct Value *VariableStringLiteralGet(char *Ident); void VariableStringLiteralDefine(char *Ident, struct Value *Val); +void VariableCheckPointer(struct ParseState *Parser, struct Value *PointerValue); /* library.c */ void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction (*FuncList)[]); diff --git a/type.c b/type.c index 24b3443..0987eaf 100644 --- a/type.c +++ b/type.c @@ -75,6 +75,15 @@ int TypeSizeValue(struct Value *Val) return sizeof(struct ArrayValue) + Val->Typ->FromType->Sizeof * Val->Val->Array.Size; } +/* the last accessible offset of a value */ +int TypeLastAccessibleOffset(struct Value *Val) +{ + if (Val->Typ->Base != TypeArray) + return 0; + else + return Val->Typ->FromType->Sizeof * (Val->Val->Array.Size-1); +} + /* memory used by a variable given its type and array size */ int TypeSize(struct ValueType *Typ, int ArraySize) { diff --git a/variable.c b/variable.c index 8490003..a9adf1a 100644 --- a/variable.c +++ b/variable.c @@ -260,3 +260,19 @@ void VariableStringLiteralDefine(char *Ident, struct Value *Val) { TableSet(&StringLiteralTable, Ident, Val); } + +/* check a pointer for validity */ +void VariableCheckPointer(struct ParseState *Parser, struct Value *PointerValue) +{ + struct Value *PointedToValue = PointerValue->Val->Pointer.Segment; + + if (PointerValue->Typ->Base != TypePointer) + ProgramFail(Parser, "pointer expected"); + + if (PointedToValue == NULL) + ProgramFail(Parser, "can't dereference NULL pointer"); + + if (PointerValue->Val->Pointer.Offset < 0 || PointerValue->Val->Pointer.Offset > TypeLastAccessibleOffset(PointedToValue)) + ProgramFail(Parser, "attempt to access invalid pointer"); +} +