Working on the new parser
git-svn-id: svn://svn.cc65.org/cc65/trunk@290 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
66b40d1a84
commit
7e59a882c5
12 changed files with 1385 additions and 56 deletions
|
@ -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)
|
int IsTypePtr (const type* T)
|
||||||
/* Return true if this is a pointer type */
|
/* 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)
|
int IsClassPtr (const type* T)
|
||||||
/* Return true if this is a pointer type */
|
/* Return true if this is a pointer type */
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,9 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "attrib.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -223,67 +226,76 @@ type* Indirect (type* Type);
|
||||||
* given type points to.
|
* given type points to.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int IsTypeChar (const type* T);
|
int IsTypeChar (const type* T) attribute ((const));
|
||||||
/* Return true if this is a character type */
|
/* 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) */
|
/* 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) */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* Return true if this is a function pointer */
|
||||||
|
|
||||||
type GetType (const type* T);
|
type GetType (const type* T) attribute ((const));
|
||||||
/* Get the raw type */
|
/* Get the raw type */
|
||||||
|
|
||||||
type GetClass (const type* T);
|
type GetClass (const type* T) attribute ((const));
|
||||||
/* Get the class of a type string */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* 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 */
|
/* Get the FuncDesc pointer from a function or pointer-to-function type */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,11 @@
|
||||||
#define ERROR_H
|
#define ERROR_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "attrib.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Data */
|
/* Data */
|
||||||
|
@ -197,7 +202,7 @@ void PPError (unsigned ErrNum, ...);
|
||||||
void Fatal (unsigned FatNum, ...);
|
void Fatal (unsigned FatNum, ...);
|
||||||
/* Print a message about a fatal error and die */
|
/* 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. */
|
/* Print a message about an internal compiler error and die. */
|
||||||
|
|
||||||
void ErrorReport (void);
|
void ErrorReport (void);
|
||||||
|
|
208
src/cc65/exprheap.c
Normal file
208
src/cc65/exprheap.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
83
src/cc65/exprheap.h
Normal file
83
src/cc65/exprheap.h
Normal file
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
/* Initialize a new expression node */
|
||||||
{
|
{
|
||||||
E->Left = 0;
|
/* Intialize basic data */
|
||||||
E->Right = 0;
|
E->MData.Owner = Owner;
|
||||||
E->NT = NT_NONE;
|
E->NT = NT;
|
||||||
E->Type = 0;
|
E->Type = Type;
|
||||||
E->LValue = 0;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,16 +38,21 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "coll.h"
|
||||||
|
|
||||||
|
/* cc65 */
|
||||||
#include "datatype.h"
|
#include "datatype.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct ExprHeap;
|
||||||
struct SymEntry;
|
struct SymEntry;
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,9 +69,7 @@ typedef enum {
|
||||||
|
|
||||||
NT_SYM, /* Symbol */
|
NT_SYM, /* Symbol */
|
||||||
NT_CONST, /* A constant of some sort */
|
NT_CONST, /* A constant of some sort */
|
||||||
|
NT_ASM, /* Inline assembler */
|
||||||
NT_ICAST, /* Implicit type cast */
|
|
||||||
NT_ECAST, /* Explicit type cast */
|
|
||||||
|
|
||||||
NT_REG_A, /* A register */
|
NT_REG_A, /* A register */
|
||||||
NT_REG_X, /* X register */
|
NT_REG_X, /* X register */
|
||||||
|
@ -74,9 +77,12 @@ typedef enum {
|
||||||
NT_REG_AX, /* AX register */
|
NT_REG_AX, /* AX register */
|
||||||
NT_REG_EAX, /* EAX register */
|
NT_REG_EAX, /* EAX register */
|
||||||
|
|
||||||
NT_CALLFUNC, /* Function call */
|
NT_ARRAY_SUBSCRIPT, /* Array subscript */
|
||||||
NT_PUSH, /* Push the value onto the stack */
|
NT_STRUCT_ACCESS, /* Access of a struct field */
|
||||||
NT_POP, /* Pop the value from the stack */
|
NT_STRUCTPTR_ACCESS, /* Access via struct ptr */
|
||||||
|
NT_FUNCTION_CALL, /* Call a function */
|
||||||
|
|
||||||
|
NT_UNARY_MINUS,
|
||||||
|
|
||||||
NT_NOT, /* ~ */
|
NT_NOT, /* ~ */
|
||||||
NT_PLUS, /* + */
|
NT_PLUS, /* + */
|
||||||
|
@ -127,36 +133,79 @@ typedef enum {
|
||||||
typedef struct ExprNode ExprNode;
|
typedef struct ExprNode ExprNode;
|
||||||
struct ExprNode {
|
struct ExprNode {
|
||||||
|
|
||||||
ExprNode* Left; /* Left and right leaves */
|
/* Management data */
|
||||||
ExprNode* Right;
|
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 */
|
nodetype_t NT; /* Node type */
|
||||||
type* Type; /* Resulting type */
|
type* Type; /* Resulting type */
|
||||||
int LValue; /* True if this is an lvalue */
|
int LValue; /* True if this is an lvalue */
|
||||||
|
|
||||||
union {
|
union {
|
||||||
/* Branch data */
|
|
||||||
ExprNode* Test; /* Third expr for ternary op */
|
|
||||||
|
|
||||||
/* Leave data */
|
|
||||||
long I; /* Constant int value if any */
|
long I; /* Constant int value if any */
|
||||||
double F; /* Constant float value if any */
|
double F; /* Constant float value if any */
|
||||||
struct SymEntry* Sym; /* Symbol table entry if any */
|
|
||||||
} V;
|
} 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 */
|
/* 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 */
|
/* End of exprnode.h */
|
||||||
|
|
|
@ -24,8 +24,8 @@ OBJS = anonname.o \
|
||||||
declare.o \
|
declare.o \
|
||||||
error.o \
|
error.o \
|
||||||
expr.o \
|
expr.o \
|
||||||
|
exprheap.o \
|
||||||
exprnode.o \
|
exprnode.o \
|
||||||
exprtree.o \
|
|
||||||
funcdesc.o \
|
funcdesc.o \
|
||||||
function.o \
|
function.o \
|
||||||
global.o \
|
global.o \
|
||||||
|
@ -70,7 +70,7 @@ cc65: $(OBJS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~ core *.map
|
rm -f *~ core *.map
|
||||||
|
|
||||||
zap: clean
|
zap: clean
|
||||||
rm -f *.o $(EXECS) .depend
|
rm -f *.o $(EXECS) .depend
|
||||||
|
|
||||||
|
|
|
@ -73,14 +73,14 @@ OBJS = anonname.obj \
|
||||||
asmline.obj \
|
asmline.obj \
|
||||||
codegen.obj \
|
codegen.obj \
|
||||||
compile.obj \
|
compile.obj \
|
||||||
cpu.obj \
|
cpu.obj \
|
||||||
ctrans.obj \
|
ctrans.obj \
|
||||||
datatype.obj \
|
datatype.obj \
|
||||||
declare.obj \
|
declare.obj \
|
||||||
error.obj \
|
error.obj \
|
||||||
expr.obj \
|
expr.obj \
|
||||||
|
exprheap.obj \
|
||||||
exprnode.obj \
|
exprnode.obj \
|
||||||
exprtree.obj \
|
|
||||||
funcdesc.obj \
|
funcdesc.obj \
|
||||||
function.obj \
|
function.obj \
|
||||||
global.obj \
|
global.obj \
|
||||||
|
@ -138,8 +138,8 @@ FILE datatype.obj
|
||||||
FILE declare.obj
|
FILE declare.obj
|
||||||
FILE error.obj
|
FILE error.obj
|
||||||
FILE expr.obj
|
FILE expr.obj
|
||||||
|
FILE exprheap.obj
|
||||||
FILE exprnode.obj
|
FILE exprnode.obj
|
||||||
FILE exprtree.obj
|
|
||||||
FILE funcdesc.obj
|
FILE funcdesc.obj
|
||||||
FILE function.obj
|
FILE function.obj
|
||||||
FILE global.obj
|
FILE global.obj
|
||||||
|
|
783
src/cc65/parser.c
Normal file
783
src/cc65/parser.c
Normal file
|
@ -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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* 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 ();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
64
src/cc65/parser.h
Normal file
64
src/cc65/parser.h
Normal file
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ typedef enum token_t {
|
||||||
TOK_FASTCALL,
|
TOK_FASTCALL,
|
||||||
TOK_A,
|
TOK_A,
|
||||||
TOK_X,
|
TOK_X,
|
||||||
TOK_Y,
|
TOK_Y,
|
||||||
TOK_AX,
|
TOK_AX,
|
||||||
TOK_EAX,
|
TOK_EAX,
|
||||||
|
|
||||||
|
@ -148,10 +148,11 @@ typedef enum token_t {
|
||||||
typedef struct Token_ Token;
|
typedef struct Token_ Token;
|
||||||
struct Token_ {
|
struct Token_ {
|
||||||
token_t Tok; /* The token itself */
|
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 */
|
ident Ident; /* Identifier if IDENT */
|
||||||
unsigned Pos; /* Source line where the token comes from */
|
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 */
|
extern Token CurTok; /* The current token */
|
||||||
|
@ -161,12 +162,12 @@ extern Token NextTok; /* The next token */
|
||||||
#define curtok CurTok.Tok
|
#define curtok CurTok.Tok
|
||||||
#define curval CurTok.IVal
|
#define curval CurTok.IVal
|
||||||
#define curpos CurTok.Pos
|
#define curpos CurTok.Pos
|
||||||
#define curtype CurTok.IType
|
#define curtype CurTok.Type
|
||||||
|
|
||||||
#define nxttok NextTok.Tok
|
#define nxttok NextTok.Tok
|
||||||
#define nxtval NextTok.IVal
|
#define nxtval NextTok.IVal
|
||||||
#define nxtpos NextTok.Pos
|
#define nxtpos NextTok.Pos
|
||||||
#define nxttype NextTok.IType
|
#define nxttype NextTok.Type
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue