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:
cuz 2000-08-19 21:55:06 +00:00
parent 66b40d1a84
commit 7e59a882c5
12 changed files with 1385 additions and 56 deletions

View file

@ -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 */
{ {

View file

@ -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 */

View file

@ -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
View 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
View 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

View file

@ -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);
}

View file

@ -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 */

View file

@ -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

View file

@ -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
View 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
View 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

View file

@ -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