From 7e59a882c579ae8d6c70ec88fa83e89a1012504c Mon Sep 17 00:00:00 2001 From: cuz Date: Sat, 19 Aug 2000 21:55:06 +0000 Subject: [PATCH] Working on the new parser git-svn-id: svn://svn.cc65.org/cc65/trunk@290 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/datatype.c | 24 ++ src/cc65/datatype.h | 54 +-- src/cc65/error.h | 7 +- src/cc65/exprheap.c | 208 +++++++++++ src/cc65/exprheap.h | 83 +++++ src/cc65/exprnode.c | 112 +++++- src/cc65/exprnode.h | 85 ++++- src/cc65/make/gcc.mak | 4 +- src/cc65/make/watcom.mak | 6 +- src/cc65/parser.c | 783 +++++++++++++++++++++++++++++++++++++++ src/cc65/parser.h | 64 ++++ src/cc65/scanner.h | 11 +- 12 files changed, 1385 insertions(+), 56 deletions(-) create mode 100644 src/cc65/exprheap.c create mode 100644 src/cc65/exprheap.h create mode 100644 src/cc65/parser.c create mode 100644 src/cc65/parser.h diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index ac86cfa49..59a0adddd 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -511,6 +511,22 @@ int IsTypeLong (const type* T) +int IsTypeFloat (const type* T) +/* Return true if this is a float type */ +{ + return (T[0] & T_MASK_TYPE) == T_TYPE_FLOAT; +} + + + +int IsTypeDouble (const type* T) +/* Return true if this is a double type */ +{ + return (T[0] & T_MASK_TYPE) == T_TYPE_DOUBLE; +} + + + int IsTypePtr (const type* T) /* Return true if this is a pointer type */ { @@ -551,6 +567,14 @@ int IsClassInt (const type* T) +int IsClassFloat (const type* T) +/* Return true if this is a float type */ +{ + return (T[0] & T_MASK_CLASS) == T_CLASS_FLOAT; +} + + + int IsClassPtr (const type* T) /* Return true if this is a pointer type */ { diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index 9224c78d8..680428c12 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -40,6 +40,9 @@ #include +/* common */ +#include "attrib.h" + /*****************************************************************************/ @@ -223,67 +226,76 @@ type* Indirect (type* Type); * given type points to. */ -int IsTypeChar (const type* T); +int IsTypeChar (const type* T) attribute ((const)); /* Return true if this is a character type */ -int IsTypeInt (const type* T); +int IsTypeInt (const type* T) attribute ((const)); /* Return true if this is an int type (signed or unsigned) */ -int IsTypeLong (const type* T); +int IsTypeLong (const type* T) attribute ((const)); /* Return true if this is a long type (signed or unsigned) */ -int IsTypePtr (const type* Type); +int IsTypeFloat (const type* T) attribute ((const)); +/* Return true if this is a float type */ + +int IsTypeDouble (const type* T) attribute ((const)); +/* Return true if this is a double type */ + +int IsTypePtr (const type* Type) attribute ((const)); /* Return true if this is a pointer type */ -int IsTypeArray (const type* Type); +int IsTypeArray (const type* Type) attribute ((const)); /* Return true if this is an array type */ -int IsTypeVoid (const type* Type); +int IsTypeVoid (const type* Type) attribute ((const)); /* Return true if this is a void type */ -int IsTypeFunc (const type* Type); +int IsTypeFunc (const type* Type) attribute ((const)); /* Return true if this is a function class */ -int IsClassInt (const type* Type); +int IsClassInt (const type* Type) attribute ((const)); /* Return true if this is an integer type */ -int IsClassPtr (const type* Type); +int IsClassFloat (const type* Type) attribute ((const)); +/* Return true if this is a float type */ + +int IsClassPtr (const type* Type) attribute ((const)); /* Return true if this is a pointer type */ -int IsClassStruct (const type* Type); +int IsClassStruct (const type* Type) attribute ((const)); /* Return true if this is a struct type */ -int IsSignUnsigned (const type* Type); +int IsSignUnsigned (const type* Type) attribute ((const)); /* Return true if this is an unsigned type */ -int IsQualConst (const type* T); +int IsQualConst (const type* T) attribute ((const)); /* Return true if the given type has a const memory image */ -int IsQualVolatile (const type* T); +int IsQualVolatile (const type* T) attribute ((const)); /* Return true if the given type has a volatile type qualifier */ -int IsFastCallFunc (const type* T); +int IsFastCallFunc (const type* T) attribute ((const)); /* Return true if this is a function type with __fastcall__ calling conventions */ -int IsTypeFuncPtr (const type* T); +int IsTypeFuncPtr (const type* T) attribute ((const)); /* Return true if this is a function pointer */ -type GetType (const type* T); +type GetType (const type* T) attribute ((const)); /* Get the raw type */ -type GetClass (const type* T); +type GetClass (const type* T) attribute ((const)); /* Get the class of a type string */ -type GetSignedness (const type* T); +type GetSignedness (const type* T) attribute ((const)); /* Get the sign of a type */ -type GetSizeModifier (const type* T); +type GetSizeModifier (const type* T) attribute ((const)); /* Get the size modifier of a type */ -type GetQualifier (const type* T); +type GetQualifier (const type* T) attribute ((const)); /* Get the qualifier from the given type string */ -struct FuncDesc* GetFuncDesc (const type* T); +struct FuncDesc* GetFuncDesc (const type* T) attribute ((const)); /* Get the FuncDesc pointer from a function or pointer-to-function type */ diff --git a/src/cc65/error.h b/src/cc65/error.h index afedb3dd3..d8b52ae47 100644 --- a/src/cc65/error.h +++ b/src/cc65/error.h @@ -37,6 +37,11 @@ #define ERROR_H + +/* common */ +#include "attrib.h" + + /*****************************************************************************/ /* Data */ @@ -197,7 +202,7 @@ void PPError (unsigned ErrNum, ...); void Fatal (unsigned FatNum, ...); /* Print a message about a fatal error and die */ -void Internal (char* Format, ...); +void Internal (char* Format, ...) attribute ((noreturn)); /* Print a message about an internal compiler error and die. */ void ErrorReport (void); diff --git a/src/cc65/exprheap.c b/src/cc65/exprheap.c new file mode 100644 index 000000000..cd5e49f79 --- /dev/null +++ b/src/cc65/exprheap.c @@ -0,0 +1,208 @@ +/*****************************************************************************/ +/* */ +/* exprheap.c */ +/* */ +/* Expression node heap manager */ +/* */ +/* */ +/* */ +/* (C) 2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +/* common */ +#include "check.h" +#include "xmalloc.h" + +/* cc65 */ +#include "exprheap.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* A block of expression nodes */ +typedef struct ExprNodeBlock ExprNodeBlock; +struct ExprNodeBlock { + ExprNodeBlock* Next; /* Pointer to next block */ + unsigned Count; /* Number of nodes in the block */ + unsigned Used; /* Number of nodes used */ + ExprNode Nodes[1]; /* Nodes, dynamically allocated */ +}; + +/* An expression heap */ +struct ExprHeap { + ExprHeap* Last; /* Upper level expression tree */ + ExprNodeBlock* BlockRoot; /* Root of node blocks */ + ExprNodeBlock* BlockLast; /* Last node block */ + ExprNode* FreeList; /* List of free nodes */ +}; + +/* The current expression heap */ +static ExprHeap* CurHeap = 0; + + + +/*****************************************************************************/ +/* struct ExprHeapBlock */ +/*****************************************************************************/ + + + +static ExprNodeBlock* NewExprNodeBlock (unsigned Count) +/* Create a new ExprNodeBlock, initialize and return it */ +{ + /* Calculate the size of the memory block requested */ + unsigned Size = sizeof (ExprNodeBlock) + (Count-1) * sizeof (ExprNode); + + /* Allocate memory */ + ExprNodeBlock* B = xmalloc (Size); + + /* Initialize the fields */ + B->Next = 0; + B->Count = Count; + B->Used = 0; + + /* Return the new block */ + return B; +} + + + +/*****************************************************************************/ +/* struct ExprHeap */ +/*****************************************************************************/ + + + +static ExprHeap* NewExprHeap (void) +/* Create and return a new expression tree */ +{ + /* Allocate memory */ + ExprHeap* H = xmalloc (sizeof (ExprHeap)); + + /* Allocate the first node block */ + H->BlockRoot = NewExprNodeBlock (64); + + /* Initialize the remaining fields */ + H->Last = 0; + H->BlockLast = H->BlockRoot; + H->FreeList = 0; + + /* Return the new heap */ + return H; +} + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void PushExprHeap (void) +/* Create a new expression heap and push it onto the expression heap stack, so + * it is the current expression heap. + */ +{ + /* Create a new heap */ + ExprHeap* H = NewExprHeap (); + + /* Push it onto the stack */ + H->Last = CurHeap; + CurHeap = H; +} + + + +ExprHeap* PopExprHeap (void) +/* Pop the current expression heap from the heap stack and return it */ +{ + ExprHeap* H; + + /* Cannot pop a non existant heap */ + PRECONDITION (CurHeap != 0); + + /* Pop the heap */ + H = CurHeap; + CurHeap = H->Last; + + /* Return the old heap */ + return H; +} + + + +ExprNode* AllocExprNode (nodetype_t NT, type* Type, int LValue) +/* Get a new node from the current expression heap */ +{ + ExprNode* N; + + /* Must have a heap */ + PRECONDITION (CurHeap != 0); + + /* Get a node from the freelist if possible */ + if (CurHeap->FreeList) { + /* There are nodes in the free list */ + N = CurHeap->FreeList; + CurHeap->FreeList = N->MData.Next; + } else { + /* Free list is empty, allocate a new node */ + ExprNodeBlock* B = CurHeap->BlockLast; + if (B->Used >= B->Count) { + /* No nodes left, allocate a new node block */ + B = NewExprNodeBlock (64); + CurHeap->BlockLast->Next = B; + CurHeap->BlockLast = B; + } + N = B->Nodes + B->Count++; + } + + /* Initialize and return the allocated node */ + return InitExprNode (N, NT, Type, LValue, CurHeap); +} + + + +void FreeExprNode (ExprNode* N) +/* Free an expression node from the current expression heap */ +{ + /* There must be a heap, and the node must be from this heap */ + PRECONDITION (CurHeap != 0 && N->MData.Owner == CurHeap); + + /* Insert the node in the freelist invalidating the owner pointer */ + N->MData.Next = CurHeap->FreeList; + CurHeap->FreeList = N; +} + + + + diff --git a/src/cc65/exprheap.h b/src/cc65/exprheap.h new file mode 100644 index 000000000..a87d04b54 --- /dev/null +++ b/src/cc65/exprheap.h @@ -0,0 +1,83 @@ +/*****************************************************************************/ +/* */ +/* exprheap.h */ +/* */ +/* Expression node heap manager */ +/* */ +/* */ +/* */ +/* (C) 2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef EXPRHEAP_H +#define EXPRHEAP_H + + + +#include "exprnode.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* An expression heap */ +typedef struct ExprHeap ExprHeap; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void PushExprHeap (void); +/* Create a new expression heap and push it onto the expression heap stack, so + * it is the current expression heap. + */ + +ExprHeap* PopExprHeap (void); +/* Pop the current expression heap from the heap stack and return it */ + +ExprNode* AllocExprNode (nodetype_t NT, type* Type, int LValue); +/* Get a new node from the current expression heap */ + +void FreeExprNode (ExprNode* N); +/* Free an expression node from the current expression heap */ + + + +/* End of exprheap.h */ + +#endif + + + diff --git a/src/cc65/exprnode.c b/src/cc65/exprnode.c index d8bc2eda0..c802fcf39 100644 --- a/src/cc65/exprnode.c +++ b/src/cc65/exprnode.c @@ -43,15 +43,115 @@ -void InitExprNode (ExprNode* E) +ExprNode* InitExprNode (ExprNode* E, nodetype_t NT, type* Type, + int LValue, struct ExprHeap* Owner) /* Initialize a new expression node */ { - E->Left = 0; - E->Right = 0; - E->NT = NT_NONE; - E->Type = 0; - E->LValue = 0; + /* Intialize basic data */ + E->MData.Owner = Owner; + E->NT = NT; + E->Type = Type; + E->LValue = LValue; + + /* Initialize the expression list in the node */ + InitCollection (&E->List); + + /* Return the node just initialized */ + return E; +} + + + +void* GetItem (ExprNode* N, unsigned Index) +/* Return one of the items from the nodes item list */ +{ + return CollAt (&N->List, Index); +} + + + +void AppendItem (ExprNode* N, void* Item) +/* Append an item to the nodes item list */ +{ + CollAppend (&N->List, Item); +} + + + +void SetItem (ExprNode* N, void* Item, unsigned Index) +/* Set a specific node item. The item list is filled with null pointers as + * needed. + */ +{ + if (Index >= CollCount (&N->List)) { + /* Fill up with NULL pointers */ + while (Index >= CollCount (&N->List) < Index) { + CollAppend (&N->List, 0); + } + /* Append the new item */ + CollAppend (&N->List, Item); + } else { + /* There is an item with this index, replace it */ + CollReplace (&N->List, Item, Index); + } +} + + + +ExprNode* GetNode (ExprNode* N, unsigned Index) +/* Get one of the sub-nodes from the list */ +{ + return GetNode (N, Index); +} + + + +ExprNode* GetLeftNode (ExprNode* N) +/* Get the left sub-node from the list */ +{ + return GetNode (N, IDX_LEFT); } +void SetLeftNode (ExprNode* Root, ExprNode* Left) +/* Set the left node in Root */ +{ + SetItem (Root, Left, IDX_LEFT); +} + + + +ExprNode* GetRightNode (ExprNode* N) +/* Get the right sub-node from the list */ +{ + return GetNode (N, IDX_RIGHT); +} + + + +void SetRightNode (ExprNode* Root, ExprNode* Right) +/* Set the right node in Root */ +{ + SetItem (Root, Right, IDX_RIGHT); +} + + + +struct SymEntry* GetNodeSym (ExprNode* N) +/* Get the symbol entry for a NT_SYM node */ +{ + return GetItem (N, IDX_SYM); +} + + + +void SetNodeSym (ExprNode* N, struct SymEntry* Sym) +/* Set the symbol entry in a NT_SYM node */ +{ + SetItem (N, Sym, IDX_SYM); +} + + + + diff --git a/src/cc65/exprnode.h b/src/cc65/exprnode.h index 969ee7506..83065d112 100644 --- a/src/cc65/exprnode.h +++ b/src/cc65/exprnode.h @@ -38,16 +38,21 @@ +/* common */ +#include "coll.h" + +/* cc65 */ #include "datatype.h" /*****************************************************************************/ -/* Forwards */ +/* Forwards */ /*****************************************************************************/ +struct ExprHeap; struct SymEntry; @@ -64,9 +69,7 @@ typedef enum { NT_SYM, /* Symbol */ NT_CONST, /* A constant of some sort */ - - NT_ICAST, /* Implicit type cast */ - NT_ECAST, /* Explicit type cast */ + NT_ASM, /* Inline assembler */ NT_REG_A, /* A register */ NT_REG_X, /* X register */ @@ -74,9 +77,12 @@ typedef enum { NT_REG_AX, /* AX register */ NT_REG_EAX, /* EAX register */ - NT_CALLFUNC, /* Function call */ - NT_PUSH, /* Push the value onto the stack */ - NT_POP, /* Pop the value from the stack */ + NT_ARRAY_SUBSCRIPT, /* Array subscript */ + NT_STRUCT_ACCESS, /* Access of a struct field */ + NT_STRUCTPTR_ACCESS, /* Access via struct ptr */ + NT_FUNCTION_CALL, /* Call a function */ + + NT_UNARY_MINUS, NT_NOT, /* ~ */ NT_PLUS, /* + */ @@ -127,36 +133,79 @@ typedef enum { typedef struct ExprNode ExprNode; struct ExprNode { - ExprNode* Left; /* Left and right leaves */ - ExprNode* Right; + /* Management data */ + union { + struct ExprHeap* Owner; /* Heap, this node is in */ + struct ExprNode* Next; /* Next in free list */ + } MData; + Collection List; /* List of subexpressions */ nodetype_t NT; /* Node type */ - type* Type; /* Resulting type */ - int LValue; /* True if this is an lvalue */ + type* Type; /* Resulting type */ + int LValue; /* True if this is an lvalue */ union { - /* Branch data */ - ExprNode* Test; /* Third expr for ternary op */ - - /* Leave data */ long I; /* Constant int value if any */ double F; /* Constant float value if any */ - struct SymEntry* Sym; /* Symbol table entry if any */ } V; +}; + + + +/* Predefined indices for node items in List */ +enum { + IDX_LEFT = 0, + IDX_RIGHT = 1, + IDX_SYM = 0 +}; +/* Some other constants for better readability */ +enum { + RVALUE = 0, + LVALUE = 1 }; /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ -void InitExprNode (ExprNode* E); +ExprNode* InitExprNode (ExprNode* E, nodetype_t NT, type* Type, + int LValue, struct ExprHeap* Owner); /* Initialize a new expression node */ +void* GetItem (ExprNode* N, unsigned Index); +/* Return one of the items from the nodes item list */ + +void AppendItem (ExprNode* N, void* Item); +/* Append an item to the nodes item list */ + +void SetItem (ExprNode* N, void* Item, unsigned Index); +/* Set a specific node item. The item list is filled with null pointers as + * needed. + */ + +ExprNode* GetLeftNode (ExprNode* N); +/* Get the left sub-node from the list */ + +void SetLeftNode (ExprNode* Root, ExprNode* Left); +/* Set the left node in Root */ + +ExprNode* GetRightNode (ExprNode* N); +/* Get the right sub-node from the list */ + +void SetRightNode (ExprNode* Root, ExprNode* Right); +/* Set the right node in Root */ + +struct SymEntry* GetNodeSym (ExprNode* N); +/* Get the symbol entry for a NT_SYM node */ + +void SetNodeSym (ExprNode* N, struct SymEntry* Sym); +/* Set the symbol entry in a NT_SYM node */ + /* End of exprnode.h */ diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 314d7415b..3639d8544 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -24,8 +24,8 @@ OBJS = anonname.o \ declare.o \ error.o \ expr.o \ + exprheap.o \ exprnode.o \ - exprtree.o \ funcdesc.o \ function.o \ global.o \ @@ -70,7 +70,7 @@ cc65: $(OBJS) clean: rm -f *~ core *.map - + zap: clean rm -f *.o $(EXECS) .depend diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index 2e7b04179..d171b2a87 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -73,14 +73,14 @@ OBJS = anonname.obj \ asmline.obj \ codegen.obj \ compile.obj \ - cpu.obj \ + cpu.obj \ ctrans.obj \ datatype.obj \ declare.obj \ error.obj \ expr.obj \ + exprheap.obj \ exprnode.obj \ - exprtree.obj \ funcdesc.obj \ function.obj \ global.obj \ @@ -138,8 +138,8 @@ FILE datatype.obj FILE declare.obj FILE error.obj FILE expr.obj +FILE exprheap.obj FILE exprnode.obj -FILE exprtree.obj FILE funcdesc.obj FILE function.obj FILE global.obj diff --git a/src/cc65/parser.c b/src/cc65/parser.c new file mode 100644 index 000000000..1cd0297ae --- /dev/null +++ b/src/cc65/parser.c @@ -0,0 +1,783 @@ +/*****************************************************************************/ +/* */ +/* parser.c */ +/* */ +/* Expression parser */ +/* */ +/* */ +/* */ +/* (C) 2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#include +#include +#include + +/* common */ +#include "check.h" +#include "xmalloc.h" + +/* cc65 */ +#include "datatype.h" +#include "declare.h" +#include "error.h" +#include "exprheap.h" +#include "funcdesc.h" +#include "function.h" +#include "global.h" +#include "litpool.h" +#include "macrotab.h" +#include "preproc.h" +#include "scanner.h" +#include "stdfunc.h" +#include "symtab.h" +#include "typecmp.h" +#include "parser.h" + + + +/*****************************************************************************/ +/* Forwards */ +/*****************************************************************************/ + + + +static ExprNode* UnaryExpr (void); +ExprNode* Expr1 (void); +ExprNode* Expr0 (void); + + + +/*****************************************************************************/ +/* Helper functions */ +/*****************************************************************************/ + + + +static int IsTypeExpr (void) +/* Return true if some sort of variable or type is waiting (helper for cast + * and sizeof() in hie10). + */ +{ + SymEntry* Entry; + + return curtok == TOK_LPAREN && ( + (nxttok >= TOK_FIRSTTYPE && nxttok <= TOK_LASTTYPE) || + (nxttok == TOK_CONST) || + (nxttok == TOK_IDENT && + (Entry = FindSym (NextTok.Ident)) != 0 && + IsTypeDef (Entry)) + ); +} + + + +/*****************************************************************************/ +/* Expression node helper functions */ +/*****************************************************************************/ + + + +static ExprNode* GetIntNode (int Value) +/* Allocate a new expression node from the tree, make it a valid integer + * node and return it. Often used if an error occurs to get a safe expression + * tree. + */ +{ + ExprNode* N = AllocExprNode (NT_CONST, type_int, RVALUE); + N->V.I = Value; + return N; +} + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +ExprNode* DoAsm (void) +/* This function parses ASM statements. The syntax of the ASM directive + * looks like the one defined for C++ (C has no ASM directive), that is, + * a string literal in parenthesis. + */ +{ + ExprNode* N; + + + /* Skip the ASM */ + NextToken (); + + /* Need left parenthesis */ + ConsumeLParen (); + + /* Create a new expression node and assign a void type */ + N = AllocExprNode (NT_ASM, type_void, RVALUE); + + /* String literal */ + if (curtok != TOK_SCONST) { + + /* Print an error */ + Error (ERR_STRLIT_EXPECTED); + + /* To be on the safe side later, insert an empty asm string */ + AppendItem (N, xstrdup ("")); + + } else { + + /* Insert a copy of the string into the expression node */ + AppendItem (N, xstrdup (GetLiteral (curval))); + + /* Reset the string pointer, effectivly clearing the string from the + * string table. Since we're working with one token lookahead, this + * will fail if the next token is also a string token, but that's a + * syntax error anyway, because we expect a right paren. + */ + ResetLiteralOffs (curval); + } + + /* Skip the string token */ + NextToken (); + + /* Closing paren needed */ + ConsumeRParen (); + + /* Return the created node */ + return N; +} + + + +static ExprNode* Primary (void) +/* Evaluate a primary expression */ +{ + ExprNode* N; + + /* Process a parenthesized subexpression. In this case we don't need to + * allocate a new node ourselves. + */ + if (curtok == TOK_LPAREN) { + NextToken (); + N = Expr0 (); + ConsumeRParen (); + return N; + } + + /* Check for an integer or character constant */ + if (curtok == TOK_ICONST || curtok == TOK_CCONST) { + + /* Create the new node */ + N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE); + N->V.I = CurTok.IVal; + + /* Skip the token and return the result */ + NextToken (); + return N; + } + + /* Check for a float constant */ + if (curtok == TOK_FCONST) { + + /* Create the new node */ + N = AllocExprNode (NT_CONST, CurTok.Type, RVALUE); + N->V.F = CurTok.FVal; + + /* Skip the token and return the result */ + NextToken (); + return N; + } + + /* All others may only be used if the expression evaluation is not called + * recursively by the preprocessor. + */ + if (Preprocessing) { + /* Illegal expression in PP mode */ + Error (ERR_CPP_EXPR_EXPECTED); + + /* Skip the token for error recovery */ + NextToken (); + + /* Return an integer constant */ + return GetIntNode (0); + } + + /* Identifier? */ + if (curtok == TOK_IDENT) { + + /* Identifier */ + SymEntry* Sym; + ident Ident; + + /* Get a pointer to the symbol table entry */ + Sym = FindSym (CurTok.Ident); + + /* Is the symbol known? */ + if (Sym) { + + /* We found the symbol - skip the name token */ + NextToken (); + + /* Check for illegal symbol types */ + if ((Sym->Flags & SC_LABEL) == SC_LABEL) { + /* Cannot use labels in expressions */ + Error (ERR_SYMBOL_KIND); + return GetIntNode (0); + } else if (Sym->Flags & SC_TYPE) { + /* Cannot use type symbols */ + Error (ERR_VAR_IDENT_EXPECTED); + /* Assume an int type to make lval valid */ + return GetIntNode (0); + } + + /* Handle enum values as constant integers */ + if ((Sym->Flags & SC_ENUM) == SC_ENUM) { + + N = GetIntNode (Sym->V.EnumVal); + + } else { + + /* All symbols besides functions and arrays are lvalues */ + int LVal = (!IsTypeFunc (Sym->Type) && !IsTypeArray (Sym->Type)); + + /* Create the node */ + N = AllocExprNode (NT_SYM, Sym->Type, LVal); + + /* Set the symbol pointer */ + SetNodeSym (N, Sym); + } + + /* The symbol is referenced now */ + Sym->Flags |= SC_REF; + + } else { + + /* We did not find the symbol. Remember the name, then skip it */ + strcpy (Ident, CurTok.Ident); + NextToken (); + + /* IDENT is either an auto-declared function or an undefined + * variable. + */ + if (curtok == TOK_LPAREN) { + + /* Warn about the use of a function without prototype */ + Warning (WARN_FUNC_WITHOUT_PROTO); + + /* Declare a function returning int. For that purpose, prepare + * a function signature for a function having an empty param + * list and returning int. + */ + Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC); + N = AllocExprNode (NT_SYM, Sym->Type, RVALUE); + SetNodeSym (N, Sym); + + } else { + + /* Print an error about an undeclared variable */ + Error (ERR_UNDEFINED_SYMBOL, Ident); + + /* Undeclared Variable */ + Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0); + N = AllocExprNode (NT_SYM, Sym->Type, LVALUE); + SetNodeSym (N, Sym); + + } + + } + + } else if (curtok == TOK_SCONST) { + + /* String literal */ + N = AllocExprNode (NT_CONST, GetCharArrayType (strlen (GetLiteral (curval))), RVALUE); + N->V.I = curval; + + } else if (curtok == TOK_ASM) { + + /* ASM statement? */ + N = DoAsm (); + + } else if (curtok == TOK_A) { + + /* A register */ + N = AllocExprNode (NT_REG_A, type_uchar, LVALUE); + + } else if (curtok == TOK_X) { + + /* X register */ + N = AllocExprNode (NT_REG_X, type_uchar, LVALUE); + + } else if (curtok == TOK_Y) { + + /* Y register */ + N = AllocExprNode (NT_REG_Y, type_uchar, LVALUE); + + } else if (curtok == TOK_AX) { + + /* AX pseudo register */ + N = AllocExprNode (NT_REG_AX, type_uint, LVALUE); + + } else if (curtok == TOK_EAX) { + + /* EAX pseudo register */ + N = AllocExprNode (NT_REG_EAX, type_ulong, LVALUE); + + } else { + + /* Illegal primary. */ + Error (ERR_EXPR_EXPECTED); + N = GetIntNode (0); + + } + + /* Return the new node */ + return N; +} + + + +static ExprNode* DoArray (ExprNode* Left) +/* Handle arrays */ +{ + ExprNode* Right; + ExprNode* Root; + type* ElementType; + + + /* Skip the bracket */ + NextToken (); + + /* Get the index */ + Right = Expr0 (); + + /* Check the types. As special "C" feature, accept a reversal of base and + * index types: + * char C = 3["abcdefg"]; + * is legal C! + */ + if (IsClassPtr (Left->Type)) { + /* Right side must be some sort of integer */ + if (!IsClassInt (Right->Type)) { + /* Print an error */ + Error (ERR_CANNOT_SUBSCRIPT); + /* To avoid problems later, create a new, legal subscript + * expression + */ + Right = GetIntNode (0); + } + } else if (IsClassPtr (Right->Type)) { + + ExprNode* Tmp; + + /* Left side must be some sort of integer */ + if (!IsClassInt (Right->Type)) { + /* Print an error */ + Error (ERR_CANNOT_SUBSCRIPT); + /* To avoid problems later, create a new, legal subscript + * expression + */ + Left = GetIntNode (0); + } + + /* Swap the expression to it's normal form */ + Tmp = Right; + Right = Left; + Left = Tmp; + + } else { + /* Invalid array expression. Skip the closing bracket, then return + * an integer instead of the array expression to be safe later. + */ + Error (ERR_CANNOT_SUBSCRIPT); + ConsumeRBrack (); + return GetIntNode (0); + } + + /* Skip the right bracket */ + ConsumeRBrack (); + + /* Get the type of the array elements */ + ElementType = Indirect (Left->Type); + + /* Allocate the branch node for the array expression */ + Root = AllocExprNode (NT_ARRAY_SUBSCRIPT, + ElementType, + IsTypeArray (ElementType)? RVALUE : LVALUE); + + /* Setup the branches */ + SetLeftNode (Root, Left); + SetRightNode (Root, Right); + + /* ...and return it */ + return Root; +} + + + +static ExprNode* DoStruct (ExprNode* Left) +/* Process struct field access */ +{ + nodetype_t NT; + ident Ident; + type* StructType; + ExprNode* Right; + ExprNode* Root; + SymEntry* Field; + + + /* Type check */ + StructType = Left->Type; + if (curtok == TOK_PTR_REF) { + NT = NT_STRUCTPTR_ACCESS; + if (!IsTypePtr (StructType)) { + Error (ERR_STRUCT_PTR_EXPECTED); + return GetIntNode (0); + } + StructType = Indirect (StructType); + } else { + NT = NT_STRUCT_ACCESS; + } + if (!IsClassStruct (StructType)) { + Error (ERR_STRUCT_EXPECTED); + return GetIntNode (0); + } + + /* Skip the token and check for an identifier */ + NextToken (); + if (curtok != TOK_IDENT) { + /* Print an error */ + Error (ERR_IDENT_EXPECTED); + /* Return an integer expression instead */ + return GetIntNode (0); + } + + /* Get the symbol table entry and check for a struct field */ + strcpy (Ident, CurTok.Ident); + NextToken (); + Field = FindStructField (StructType, Ident); + if (Field == 0) { + /* Struct field not found */ + Error (ERR_STRUCT_FIELD_MISMATCH, Ident); + /* Return an integer expression instead */ + return GetIntNode (0); + } + + /* Allocate and set up the right (== field) node */ + Right = AllocExprNode (NT_SYM, Field->Type, RVALUE); + SetNodeSym (Right, Field); + + /* Allocate the branch node for the resulting expression */ + Root = AllocExprNode (NT, Right->Type, + IsTypeArray (Right->Type)? RVALUE : LVALUE); + + /* Setup the branches */ + SetLeftNode (Root, Left); + SetRightNode (Root, Right); + + /* ...and return it */ + return Root; +} + + + +static ExprNode* DoFunctionCall (ExprNode* Left) +/* Process a function call */ +{ + type* ResultType; /* Type of function result */ + FuncDesc* Func; /* Function descriptor */ + ExprNode* Root; /* Function call node */ + int Ellipsis; /* True if we have an open param list */ + SymEntry* Param; /* Current formal parameter */ + unsigned ParamCount; /* Actual parameter count */ + unsigned ParamSize; /* Number of parameter bytes */ + + + /* Type check */ + if (!IsTypeFunc (Left->Type) && !IsTypeFuncPtr (Left->Type)) { + + /* Call to non function */ + Error (ERR_ILLEGAL_FUNC_CALL); + + /* Free the old node */ + FreeExprNode (Left); + + /* Return something safe */ + return GetIntNode (0); + } + + /* Get the type of the function result */ + ResultType = Left->Type; + if (IsTypeFuncPtr (Left->Type)) { + ++ResultType; + } + ResultType += DECODE_SIZE + 1; /* Set to result type */ + + /* Skip the opening parenthesis */ + NextToken (); + + /* Allocate the function call node */ + Root = AllocExprNode (NT_FUNCTION_CALL, ResultType, RVALUE); + + /* Get a pointer to the function descriptor from the type string */ + Func = GetFuncDesc (Left->Type); + + /* Initialize vars to keep gcc silent */ + Param = 0; + + /* Parse the parameter list */ + ParamSize = 0; + ParamCount = 0; + Ellipsis = 0; + while (curtok != TOK_RPAREN) { + + /* Count arguments */ + ++ParamCount; + + /* Fetch the pointer to the next argument, check for too many args */ + if (ParamCount <= Func->ParamCount) { + if (ParamCount == 1) { + /* First argument */ + Param = Func->SymTab->SymHead; + } else { + /* Next argument */ + Param = Param->NextSym; + CHECK ((Param->Flags & SC_PARAM) != 0); + } + } else if (!Ellipsis) { + /* Too many arguments. Do we have an open param list? */ + if ((Func->Flags & FD_ELLIPSIS) == 0) { + /* End of param list reached, no ellipsis */ + Error (ERR_TOO_MANY_FUNC_ARGS); + } + /* Assume an ellipsis even in case of errors to avoid an error + * message for each other argument. + */ + Ellipsis = 1; + } + + /* Get the parameter value expression tree and add it to the parameter + * list. (### check expr level) + */ + AppendItem (Root, Expr1 ()); + + /* Check for end of argument list */ + if (curtok != TOK_COMMA) { + break; + } + NextToken (); + } + + /* We need the closing bracket here */ + ConsumeRParen (); + + /* Check if we had enough parameters */ + if (ParamCount < Func->ParamCount) { + Error (ERR_TOO_FEW_FUNC_ARGS); + } + + /* Return the function call node */ + return Root; +} + + + +static ExprNode* PostfixExpr (void) +{ + /* Get the lower level expression */ + ExprNode* Root = Primary (); + + /* */ + while (curtok == TOK_LBRACK || curtok == TOK_LPAREN || + curtok == TOK_DOT || curtok == TOK_PTR_REF || + curtok == TOK_INC || curtok == TOK_DEC) { + + /* This is for us */ + switch (curtok) { + + case TOK_LBRACK: + Root = DoArray (Root); + break; + + case TOK_LPAREN: + Root = DoFunctionCall (Root); + break; + + case TOK_DOT: + case TOK_PTR_REF: + Root = DoStruct (Root); + break; + + case TOK_INC: + break; + + case TOK_DEC: + break; + + default: + Internal ("Unexpected token"); + + } + } + + /* Return the result */ + return Root; +} + + + +static ExprNode* DoPreIncDec (void) +/* Handle preincrement and predecrement */ +{ + ExprNode* Op; + ExprNode* Root; + + /* Determine the type of the node */ + nodetype_t NT = (curtok == TOK_INC)? NT_PRE_INC : NT_PRE_DEC; + + /* Skip the operator token */ + NextToken (); + + /* Get the expression to increment or decrement */ + Op = UnaryExpr (); + + /* The operand must be an lvalue */ + if (Op->LValue == 0) { + + /* Print a diagnostics */ + Error (ERR_LVALUE_EXPECTED); + + /* It is safe to return the operand expression and probably better + * than returning an int, since the operand expression already has + * the correct type as expected by the program at this place, and + * it is even an rvalue. + */ + return Op; + } + + /* Setup the expression tree */ + Root = AllocExprNode (NT, Op->Type, RVALUE); + SetLeftNode (Root, Op); + + /* Return the new node */ + return Root; +} + + + +static ExprNode* DoUnaryPlusMinus (void) +/* Handle unary +/- */ +{ + ExprNode* Op; + ExprNode* Root; + + /* Remember the current token for later, then skip it */ + token_t Tok = curtok; + NextToken (); + + /* Get the operand */ + Op = UnaryExpr (); + + /* Type check */ + if (!IsClassInt (Op->Type) && !IsClassFloat (Op->Type)) { + + /* Display diagnostic */ + Error (ERR_SYNTAX); + + /* Free the errorneous node */ + FreeExprNode (Op); + + /* Return something that makes sense later */ + return GetIntNode (0); + } + + /* In case of PLUS, we must do nothing */ + if (Tok == TOK_PLUS) { + + /* Use the operand unchanged */ + Root = Op; + + } else { + + /* Setup the expression tree */ + Root = AllocExprNode (NT_UNARY_MINUS, Op->Type, RVALUE); + SetLeftNode (Root, Op); + + } + + /* Return the new node */ + return Root; +} + + + +static ExprNode* UnaryExpr (void) +{ + /* */ + if (curtok == TOK_INC || curtok == TOK_DEC || + curtok == TOK_PLUS || curtok == TOK_MINUS || + curtok == TOK_AND || curtok == TOK_STAR || + curtok == TOK_COMP || curtok == TOK_BOOL_NOT || + curtok == TOK_SIZEOF || IsTypeExpr ()) { + + /* Check the token */ + switch (curtok) { + + case TOK_INC: + case TOK_DEC: + return DoPreIncDec (); + + case TOK_PLUS: + case TOK_MINUS: + return DoUnaryPlusMinus (); + + case TOK_AND: + break; + + case TOK_STAR: + break; + + case TOK_COMP: + break; + + case TOK_BOOL_NOT: + break; + + case TOK_SIZEOF: + break; + + default: + break; + + } + + } else { + + /* Call the lower level */ + return PostfixExpr (); + + } +} diff --git a/src/cc65/parser.h b/src/cc65/parser.h new file mode 100644 index 000000000..c2dda4ae6 --- /dev/null +++ b/src/cc65/parser.h @@ -0,0 +1,64 @@ +/*****************************************************************************/ +/* */ +/* parser.h */ +/* */ +/* Expression parser */ +/* */ +/* */ +/* */ +/* (C) 2000 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef PARSER_H +#define PARSER_H + + + +#include "exprnode.h" + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +ExprNode* DoAsm (void); +/* This function parses ASM statements. The syntax of the ASM directive + * looks like the one defined for C++ (C has no ASM directive), that is, + * a string literal in parenthesis. + */ + + + +/* End of parser.h */ + +#endif + + + diff --git a/src/cc65/scanner.h b/src/cc65/scanner.h index db10cb9b9..b7cd10ac5 100644 --- a/src/cc65/scanner.h +++ b/src/cc65/scanner.h @@ -129,7 +129,7 @@ typedef enum token_t { TOK_FASTCALL, TOK_A, TOK_X, - TOK_Y, + TOK_Y, TOK_AX, TOK_EAX, @@ -148,10 +148,11 @@ typedef enum token_t { typedef struct Token_ Token; struct Token_ { token_t Tok; /* The token itself */ - long IVal; /* The integer attribute */ + long IVal; /* The integer attribute */ + double FVal; /* The float attribute */ ident Ident; /* Identifier if IDENT */ unsigned Pos; /* Source line where the token comes from */ - type* IType; /* Type if integer constant */ + type* Type; /* Type if integer or float constant */ }; extern Token CurTok; /* The current token */ @@ -161,12 +162,12 @@ extern Token NextTok; /* The next token */ #define curtok CurTok.Tok #define curval CurTok.IVal #define curpos CurTok.Pos -#define curtype CurTok.IType +#define curtype CurTok.Type #define nxttok NextTok.Tok #define nxtval NextTok.IVal #define nxtpos NextTok.Pos -#define nxttype NextTok.IType +#define nxttype NextTok.Type -- 2.39.5