From 096def8f55e60953e4bf3353a1720b65660b642b Mon Sep 17 00:00:00 2001 From: "zik.saleeba" Date: Sun, 19 Apr 2009 11:49:01 +0000 Subject: [PATCH] Pointer arithmetic and NULL pointer support added git-svn-id: http://picoc.googlecode.com/svn/trunk@255 21eae674-98b7-11dd-bd71-f92a316d2d60 --- TODO | 4 ++ clibrary.c | 12 +++++ expression.c | 70 ++++++++++++++++++++---------- picoc.c | 1 + picoc.h | 2 + tests/19_pointer_arithmetic.c | 20 +++++++++ tests/19_pointer_arithmetic.expect | 3 ++ tests/Makefile | 3 +- 8 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 tests/19_pointer_arithmetic.c create mode 100644 tests/19_pointer_arithmetic.expect diff --git a/TODO b/TODO index ccc8aff..caef21d 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,9 @@ TODO +Bugs: +* assignment in declarators: int *b = &a; +* #define NORTH 1 ... startnode(NORTH,1,2); + Implement: * pointer arithmetic * NULL pointers and pointer comparison diff --git a/clibrary.c b/clibrary.c index 61b0f64..da98ca6 100644 --- a/clibrary.c +++ b/clibrary.c @@ -1,5 +1,8 @@ #include "picoc.h" +static int TRUEValue = 1; +static int ZeroValue = 0; + /* initialise a library */ void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction (*FuncList)[]) { @@ -22,6 +25,15 @@ void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct Libr } } +/* initialise the C library */ +void CLibraryInit() +{ + /* define some constants */ + VariableDefinePlatformVar(NULL, "NULL", &IntType, (union AnyValue *)&ZeroValue, FALSE); + VariableDefinePlatformVar(NULL, "TRUE", &IntType, (union AnyValue *)&TRUEValue, FALSE); + VariableDefinePlatformVar(NULL, "FALSE", &IntType, (union AnyValue *)&ZeroValue, FALSE); +} + /* print a string to a stream without using printf/sprintf */ void PrintStr(const char *Str, CharWriter *PutCh) { diff --git a/expression.c b/expression.c index 2f8b8a9..e323004 100644 --- a/expression.c +++ b/expression.c @@ -150,11 +150,13 @@ void ExpressionStackPushValueNode(struct ParseState *Parser, struct ExpressionSt } /* push a blank value on to the expression stack by type */ -void ExpressionStackPushValueByType(struct ParseState *Parser, struct ExpressionStack **StackTop, struct ValueType *PushType) +struct Value *ExpressionStackPushValueByType(struct ParseState *Parser, struct ExpressionStack **StackTop, struct ValueType *PushType) { debugf("ExpressionStackPushValueByType()\n"); struct Value *ValueLoc = VariableAllocValueFromType(Parser, PushType, FALSE, NULL); ExpressionStackPushValueNode(Parser, StackTop, ValueLoc); + + return ValueLoc; } /* push a value on to the expression stack */ @@ -427,32 +429,56 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack * ExpressionPushFP(Parser, StackTop, ResultFP); } #endif -#if 0 -XXX - finish this - else if ( (TopValue->Typ->Base == TypePointer && IS_INTEGER_COERCIBLE(BottomValue)) || - (IS_INTEGER_COERCIBLE(TopValue) && BottomValue->Typ->Base == TypePointer) ) + else if (BottomValue->Typ->Base == TypePointer && IS_INTEGER_COERCIBLE(TopValue)) { - /* pointer infix arithmetic */ - - switch (TopOperatorNode->Op) + /* pointer/integer infix arithmetic */ + int TopInt = COERCE_INTEGER(TopValue); + struct PointerValue Pointer; + struct Value *StackValue; + + if (Op == TokenEqual || Op == TokenNotEqual) { - case TokenEqual: ResultInt = BottomInt == TopInt; ResultIsInt = TRUE; break; - case TokenNotEqual: ResultInt = BottomInt != TopInt; ResultIsInt = TRUE; break; - case TokenLessThan: ResultInt = BottomInt < TopInt; ResultIsInt = TRUE; break; - case TokenGreaterThan: ResultInt = BottomInt > TopInt; ResultIsInt = TRUE; break; - case TokenLessEqual: ResultInt = BottomInt <= TopInt; ResultIsInt = TRUE; break; - case TokenGreaterEqual: ResultInt = BottomInt >= TopInt; ResultIsInt = TRUE; break; - case TokenPlus: Result = BottomInt + TopInt; break; - case TokenMinus: Result = BottomInt - TopInt; break; - default: ProgramFail(Parser, "invalid operation"); break; + /* comparison to a NULL pointer */ + if (TopInt != 0) + ProgramFail(Parser, "invalid operation"); + + if (Op == TokenEqual) + ExpressionPushInt(Parser, StackTop, BottomValue->Val->Pointer.Segment == NULL); + else + ExpressionPushInt(Parser, StackTop, BottomValue->Val->Pointer.Segment != NULL); + } + else if (Op == TokenPlus || Op == TokenMinus) + { + /* pointer arithmetic */ + int Size = TypeSize(BottomValue->Typ->FromType, 0); + + Pointer = BottomValue->Val->Pointer; + if (Pointer.Segment == NULL) + ProgramFail(Parser, "invalid use of a NULL pointer"); + + if (Op == TokenPlus) + Pointer.Offset += TopInt * Size; + else + Pointer.Offset -= TopInt * Size; + + /* check pointer bounds */ + if (Pointer.Offset < 0 || Pointer.Offset > TypeSizeValue(BottomValue->Val->Pointer.Segment) - Size) + Pointer.Offset = BottomValue->Val->Pointer.Offset; + + StackValue = ExpressionStackPushValueByType(Parser, StackTop, BottomValue->Typ); + StackValue->Val->Pointer = Pointer; + } + 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); } - - if (ResultIsInt) - ExpressionPushInt(Parser, StackTop, ResultInt); else - ExpressionPushPointer(Parser, StackTop, ResultInt); + ProgramFail(Parser, "invalid operation"); } -#endif else if (Op == TokenAssign) { /* assign a non-numeric type */ diff --git a/picoc.c b/picoc.c index e7a84b7..f877454 100644 --- a/picoc.c +++ b/picoc.c @@ -9,6 +9,7 @@ void Initialise() LexInit(); TypeInit(); LibraryInit(&GlobalTable, "c library", &CLibrary); + CLibraryInit(); PlatformLibraryInit(); LibraryInit(&GlobalTable, "platform library", &PlatformLibrary); } diff --git a/picoc.h b/picoc.h index 5d0f29b..6cc4688 100644 --- a/picoc.h +++ b/picoc.h @@ -241,6 +241,7 @@ extern struct ValueType MacroType; extern struct ValueType *CharPtrType; extern struct ValueType *CharArrayType; extern char *StrEmpty; +extern struct PointerValue NULLPointer; extern struct LibraryFunction CLibrary[]; extern struct LibraryFunction PlatformLibrary[]; @@ -322,6 +323,7 @@ void VariableStringLiteralDefine(char *Ident, struct Value *Val); /* library.c */ void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction (*FuncList)[]); +void CLibraryInit(); void PrintInt(int Num, CharWriter *PutCh); void PrintStr(const char *Str, CharWriter *PutCh); void PrintFP(double Num, CharWriter *PutCh); diff --git a/tests/19_pointer_arithmetic.c b/tests/19_pointer_arithmetic.c new file mode 100644 index 0000000..a85d1e1 --- /dev/null +++ b/tests/19_pointer_arithmetic.c @@ -0,0 +1,20 @@ +int a; +int *b; +int *c; + +a = 42; +b = &a; +c = NULL; + +printf("%d\n", *b); + +if (b == NULL) + printf("b is NULL\n"); +else + printf("b is not NULL\n"); + +if (c == NULL) + printf("c is NULL\n"); +else + printf("c is not NULL\n"); + diff --git a/tests/19_pointer_arithmetic.expect b/tests/19_pointer_arithmetic.expect new file mode 100644 index 0000000..0cf781b --- /dev/null +++ b/tests/19_pointer_arithmetic.expect @@ -0,0 +1,3 @@ +42 +b is not NULL +c is NULL diff --git a/tests/Makefile b/tests/Makefile index 2b90d43..6485fe4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -16,7 +16,8 @@ TESTS= 00_assignment.test \ 15_recursion.test \ 16_nesting.test \ 17_enum.test \ - 18_include.test + 18_include.test \ + 19_pointer_arithmetic.test %.test: %.expect %.c @echo Test: $*...