mirror of
https://github.com/cc65/cc65.git
synced 2025-08-13 08:25:28 +00:00
Working on the new parser
git-svn-id: svn://svn.cc65.org/cc65/trunk@291 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Data */
|
/* Data */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
@@ -63,6 +63,7 @@ type type_uint [] = { T_UINT, T_END };
|
|||||||
type type_long [] = { T_LONG, T_END };
|
type type_long [] = { T_LONG, T_END };
|
||||||
type type_ulong [] = { T_ULONG, T_END };
|
type type_ulong [] = { T_ULONG, T_END };
|
||||||
type type_void [] = { T_VOID, T_END };
|
type type_void [] = { T_VOID, T_END };
|
||||||
|
type type_size_t [] = { T_UINT, T_END };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -190,13 +191,34 @@ type* GetImplicitFuncType (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type* PointerTo (const type* T)
|
||||||
|
/* Return a type string that is "pointer to T". The type string is allocated
|
||||||
|
* on the heap and may be freed after use.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Get the size of the type string including the terminator */
|
||||||
|
unsigned Size = TypeLen (T) + 1;
|
||||||
|
|
||||||
|
/* Allocate the new type string */
|
||||||
|
type* P = TypeAlloc (Size + 1);
|
||||||
|
|
||||||
|
/* Create the return type... */
|
||||||
|
P[0] = T_PTR;
|
||||||
|
memcpy (P+1, T, Size * sizeof (type));
|
||||||
|
|
||||||
|
/* ...and return it */
|
||||||
|
return P;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static type PrintTypeComp (FILE* F, type T, type Mask, const char* Name)
|
static type PrintTypeComp (FILE* F, type T, type Mask, const char* Name)
|
||||||
/* Check for a specific component of the type. If it is there, print the
|
/* Check for a specific component of the type. If it is there, print the
|
||||||
* name and remove it. Return the type with the component removed.
|
* name and remove it. Return the type with the component removed.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
if ((T & Mask) == Mask) {
|
if ((T & Mask) == Mask) {
|
||||||
fprintf (F, "%s ", Name);
|
fprintf (F, "%s ", Name);
|
||||||
T &= ~Mask;
|
T &= ~Mask;
|
||||||
}
|
}
|
||||||
return T;
|
return T;
|
||||||
@@ -361,7 +383,7 @@ unsigned SizeOf (const type* T)
|
|||||||
|
|
||||||
case T_VOID:
|
case T_VOID:
|
||||||
Error (ERR_ILLEGAL_SIZE);
|
Error (ERR_ILLEGAL_SIZE);
|
||||||
return 0;
|
return 1; /* Return something that makes sense */
|
||||||
|
|
||||||
case T_SCHAR:
|
case T_SCHAR:
|
||||||
case T_UCHAR:
|
case T_UCHAR:
|
||||||
|
@@ -147,6 +147,7 @@ extern type type_uint [];
|
|||||||
extern type type_long [];
|
extern type type_long [];
|
||||||
extern type type_ulong [];
|
extern type type_ulong [];
|
||||||
extern type type_void [];
|
extern type type_void [];
|
||||||
|
extern type type_size_t [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -185,6 +186,11 @@ type* GetCharArrayType (unsigned Len);
|
|||||||
type* GetImplicitFuncType (void);
|
type* GetImplicitFuncType (void);
|
||||||
/* Return a type string for an inplicitly declared function */
|
/* Return a type string for an inplicitly declared function */
|
||||||
|
|
||||||
|
type* PointerTo (const type* T);
|
||||||
|
/* Return a type string that is "pointer to T". The type string is allocated
|
||||||
|
* on the heap and may be freed after use.
|
||||||
|
*/
|
||||||
|
|
||||||
void PrintType (FILE* F, const type* Type);
|
void PrintType (FILE* F, const type* Type);
|
||||||
/* Output translation of type array. */
|
/* Output translation of type array. */
|
||||||
|
|
||||||
|
@@ -121,7 +121,7 @@ static char* ErrMsg [ERR_COUNT-1] = {
|
|||||||
"Too many initializers",
|
"Too many initializers",
|
||||||
"Cannot initialize incomplete type",
|
"Cannot initialize incomplete type",
|
||||||
"Cannot subscript",
|
"Cannot subscript",
|
||||||
"Operation not allowed on these types",
|
"Operation not allowed with this type of argument",
|
||||||
"Struct expected",
|
"Struct expected",
|
||||||
"Struct/union has no field named `%s'",
|
"Struct/union has no field named `%s'",
|
||||||
"Struct pointer expected",
|
"Struct pointer expected",
|
||||||
|
@@ -81,10 +81,14 @@ typedef enum {
|
|||||||
NT_STRUCT_ACCESS, /* Access of a struct field */
|
NT_STRUCT_ACCESS, /* Access of a struct field */
|
||||||
NT_STRUCTPTR_ACCESS, /* Access via struct ptr */
|
NT_STRUCTPTR_ACCESS, /* Access via struct ptr */
|
||||||
NT_FUNCTION_CALL, /* Call a function */
|
NT_FUNCTION_CALL, /* Call a function */
|
||||||
|
NT_TYPECAST, /* A cast */
|
||||||
|
NT_ADDRESS, /* Address operator (&) */
|
||||||
|
NT_INDIRECT, /* Indirection operator (*) */
|
||||||
|
|
||||||
NT_UNARY_MINUS,
|
NT_UNARY_MINUS,
|
||||||
|
NT_COMPLEMENT, /* ~ */
|
||||||
|
NT_BOOL_NOT, /* ! */
|
||||||
|
|
||||||
NT_NOT, /* ~ */
|
|
||||||
NT_PLUS, /* + */
|
NT_PLUS, /* + */
|
||||||
NT_MINUS, /* - */
|
NT_MINUS, /* - */
|
||||||
NT_MUL, /* * */
|
NT_MUL, /* * */
|
||||||
@@ -111,7 +115,6 @@ typedef enum {
|
|||||||
NT_PRE_INC, /* ++ */
|
NT_PRE_INC, /* ++ */
|
||||||
NT_POST_INC, /* ++ */
|
NT_POST_INC, /* ++ */
|
||||||
|
|
||||||
NT_BOOL_NOT, /* ! */
|
|
||||||
NT_BOOL_OR, /* || */
|
NT_BOOL_OR, /* || */
|
||||||
NT_BOOL_AND, /* && */
|
NT_BOOL_AND, /* && */
|
||||||
|
|
||||||
|
@@ -605,6 +605,41 @@ static ExprNode* DoFunctionCall (ExprNode* Left)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ExprNode* DoPostIncDec (ExprNode* Left)
|
||||||
|
/* Handle postincrement and postdecrement */
|
||||||
|
{
|
||||||
|
ExprNode* Root;
|
||||||
|
|
||||||
|
/* Determine the type of the node */
|
||||||
|
nodetype_t NT = (curtok == TOK_INC)? NT_POST_INC : NT_POST_DEC;
|
||||||
|
|
||||||
|
/* Skip the operator token */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* The operand must be an lvalue */
|
||||||
|
if (Left->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 Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the expression tree */
|
||||||
|
Root = AllocExprNode (NT, Left->Type, RVALUE);
|
||||||
|
SetLeftNode (Root, Left);
|
||||||
|
|
||||||
|
/* Return the new node */
|
||||||
|
return Root;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static ExprNode* PostfixExpr (void)
|
static ExprNode* PostfixExpr (void)
|
||||||
{
|
{
|
||||||
/* Get the lower level expression */
|
/* Get the lower level expression */
|
||||||
@@ -632,9 +667,8 @@ static ExprNode* PostfixExpr (void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_INC:
|
case TOK_INC:
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_DEC:
|
case TOK_DEC:
|
||||||
|
Root = DoPostIncDec (Root);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -717,12 +751,26 @@ static ExprNode* DoUnaryPlusMinus (void)
|
|||||||
/* In case of PLUS, we must do nothing */
|
/* In case of PLUS, we must do nothing */
|
||||||
if (Tok == TOK_PLUS) {
|
if (Tok == TOK_PLUS) {
|
||||||
|
|
||||||
/* Use the operand unchanged */
|
/* Return the operand unchanged */
|
||||||
Root = Op;
|
return Op;
|
||||||
|
|
||||||
|
} else if (Op->NT == NT_CONST) {
|
||||||
|
|
||||||
|
/* The value is constant, change it according to the insn */
|
||||||
|
if (IsClassInt (Op->Type)) {
|
||||||
|
/* Integer */
|
||||||
|
Op->V.I = -Op->V.I;
|
||||||
|
} else {
|
||||||
|
/* Float */
|
||||||
|
Op->V.F = -Op->V.F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the operand itself */
|
||||||
|
return Op;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Setup the expression tree */
|
/* Non constant value, setup the expression tree */
|
||||||
Root = AllocExprNode (NT_UNARY_MINUS, Op->Type, RVALUE);
|
Root = AllocExprNode (NT_UNARY_MINUS, Op->Type, RVALUE);
|
||||||
SetLeftNode (Root, Op);
|
SetLeftNode (Root, Op);
|
||||||
|
|
||||||
@@ -734,13 +782,242 @@ static ExprNode* DoUnaryPlusMinus (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ExprNode* DoComplement (void)
|
||||||
|
/* Handle ~ */
|
||||||
|
{
|
||||||
|
ExprNode* Op;
|
||||||
|
ExprNode* Root;
|
||||||
|
|
||||||
|
/* Skip the operator token */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get the operand */
|
||||||
|
Op = UnaryExpr ();
|
||||||
|
|
||||||
|
/* Type check */
|
||||||
|
if (!IsClassInt (Op->Type)) {
|
||||||
|
|
||||||
|
/* Display diagnostic */
|
||||||
|
Error (ERR_OP_NOT_ALLOWED);
|
||||||
|
|
||||||
|
/* Free the errorneous node */
|
||||||
|
FreeExprNode (Op);
|
||||||
|
|
||||||
|
/* Return something that makes sense later */
|
||||||
|
return GetIntNode (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the operand is constant, handle the operation directly */
|
||||||
|
if (Op->NT == NT_CONST) {
|
||||||
|
|
||||||
|
/* Change the value and return the operand node */
|
||||||
|
Op->V.I = ~Op->V.I;
|
||||||
|
return Op;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Setup the expression tree and return the new node */
|
||||||
|
Root = AllocExprNode (NT_COMPLEMENT, Op->Type, RVALUE);
|
||||||
|
SetLeftNode (Root, Op);
|
||||||
|
return Root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ExprNode* DoBoolNot (void)
|
||||||
|
/* Handle ! */
|
||||||
|
{
|
||||||
|
ExprNode* Op;
|
||||||
|
ExprNode* Root;
|
||||||
|
|
||||||
|
/* Skip the operator token */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get the operand */
|
||||||
|
Op = UnaryExpr ();
|
||||||
|
|
||||||
|
/* The boolean NOT operator eats anything - no need for a type check. */
|
||||||
|
|
||||||
|
/* Setup the expression tree and return the new node */
|
||||||
|
Root = AllocExprNode (NT_BOOL_NOT, type_int, RVALUE);
|
||||||
|
SetLeftNode (Root, Op);
|
||||||
|
return Root;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ExprNode* DoAddress (void)
|
||||||
|
/* Handle the address operator & */
|
||||||
|
{
|
||||||
|
ExprNode* Op;
|
||||||
|
|
||||||
|
/* Skip the operator */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get the operand */
|
||||||
|
Op = UnaryExpr ();
|
||||||
|
|
||||||
|
/* Accept using the address operator with arrays. This is harmless, it
|
||||||
|
* will just be as using the array without the operator.
|
||||||
|
*/
|
||||||
|
if (IsTypeArray (Op->Type)) {
|
||||||
|
return Op;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We cannot operate on rvalues */
|
||||||
|
if (Op->LValue == 0) {
|
||||||
|
|
||||||
|
ExprNode* Root;
|
||||||
|
|
||||||
|
/* Print diagnostics */
|
||||||
|
Error (ERR_ILLEGAL_ADDRESS);
|
||||||
|
|
||||||
|
/* Free the problematic node */
|
||||||
|
FreeExprNode (Op);
|
||||||
|
|
||||||
|
/* Return something that is safe later */
|
||||||
|
Root = AllocExprNode (NT_CONST, PointerTo (type_void), 0);
|
||||||
|
Root->V.I = 0;
|
||||||
|
return Root;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the operator node and return it */
|
||||||
|
return AllocExprNode (NT_ADDRESS, PointerTo (Op->Type), RVALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ExprNode* DoIndirect (void)
|
||||||
|
/* Handle the indirection operaror * */
|
||||||
|
{
|
||||||
|
ExprNode* Op;
|
||||||
|
type* ResultType;
|
||||||
|
int LVal;
|
||||||
|
|
||||||
|
/* Skip the operator */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Get the operand */
|
||||||
|
Op = UnaryExpr ();
|
||||||
|
|
||||||
|
/* Type check */
|
||||||
|
if (!IsClassPtr (Op->Type)) {
|
||||||
|
|
||||||
|
/* Print diagnostics */
|
||||||
|
Error (ERR_ILLEGAL_INDIRECT);
|
||||||
|
|
||||||
|
/* Free the problematic node */
|
||||||
|
FreeExprNode (Op);
|
||||||
|
|
||||||
|
/* Return something that is safe later ### */
|
||||||
|
return GetIntNode (0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the type of the result */
|
||||||
|
ResultType = Indirect (Op->Type);
|
||||||
|
|
||||||
|
/* The result is an lvalue if it is not an array */
|
||||||
|
LVal = IsTypeArray (ResultType)? RVALUE : LVALUE;
|
||||||
|
|
||||||
|
/* Create the operator node and return it */
|
||||||
|
return AllocExprNode (NT_INDIRECT, ResultType, LVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ExprNode* DoSizeOf (void)
|
||||||
|
/* Handle the sizeof operator */
|
||||||
|
{
|
||||||
|
ExprNode* N;
|
||||||
|
unsigned long Size;
|
||||||
|
|
||||||
|
/* Skip the left paren */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* A type or an actual variable access may follow */
|
||||||
|
if (IsTypeExpr ()) {
|
||||||
|
|
||||||
|
type Type[MAXTYPELEN];
|
||||||
|
|
||||||
|
/* A type in parenthesis. Skip the left paren. */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Read the type and calculate the size. */
|
||||||
|
Size = SizeOf (ParseType (Type));
|
||||||
|
|
||||||
|
/* Closing paren must follow */
|
||||||
|
ConsumeRParen ();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Some other entity */
|
||||||
|
N = UnaryExpr ();
|
||||||
|
|
||||||
|
/* Get the size */
|
||||||
|
Size = SizeOf (N->Type);
|
||||||
|
|
||||||
|
/* Free the node */
|
||||||
|
FreeExprNode (N);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a constant node with type size_t and return it */
|
||||||
|
N = AllocExprNode (NT_CONST, type_size_t, RVALUE);
|
||||||
|
N->V.I = Size;
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ExprNode* DoTypeCast (void)
|
||||||
|
/* Handle type casts */
|
||||||
|
{
|
||||||
|
type TargetType[MAXTYPELEN];
|
||||||
|
ExprNode* Op;
|
||||||
|
ExprNode* Root;
|
||||||
|
|
||||||
|
/* Skip the left paren */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Read the type */
|
||||||
|
ParseType (TargetType);
|
||||||
|
|
||||||
|
/* Closing paren */
|
||||||
|
ConsumeRParen ();
|
||||||
|
|
||||||
|
/* Read the expression we have to cast */
|
||||||
|
Op = UnaryExpr ();
|
||||||
|
|
||||||
|
/* As a minor optimization, check if the type is already correct. If so,
|
||||||
|
* do nothing.
|
||||||
|
*/
|
||||||
|
if (TypeCmp (TargetType, Op->Type) >= TC_EQUAL) {
|
||||||
|
|
||||||
|
/* Just return the operand as is */
|
||||||
|
return Op;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Must be casted. Setup the expression tree and return the new node */
|
||||||
|
Root = AllocExprNode (NT_BOOL_NOT, TargetType, RVALUE);
|
||||||
|
SetLeftNode (Root, Op);
|
||||||
|
return Root;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static ExprNode* UnaryExpr (void)
|
static ExprNode* UnaryExpr (void)
|
||||||
{
|
{
|
||||||
/* */
|
/* */
|
||||||
if (curtok == TOK_INC || curtok == TOK_DEC ||
|
if (curtok == TOK_INC || curtok == TOK_DEC ||
|
||||||
curtok == TOK_PLUS || curtok == TOK_MINUS ||
|
curtok == TOK_PLUS || curtok == TOK_MINUS ||
|
||||||
curtok == TOK_AND || curtok == TOK_STAR ||
|
|
||||||
curtok == TOK_COMP || curtok == TOK_BOOL_NOT ||
|
curtok == TOK_COMP || curtok == TOK_BOOL_NOT ||
|
||||||
|
curtok == TOK_AND || curtok == TOK_STAR ||
|
||||||
curtok == TOK_SIZEOF || IsTypeExpr ()) {
|
curtok == TOK_SIZEOF || IsTypeExpr ()) {
|
||||||
|
|
||||||
/* Check the token */
|
/* Check the token */
|
||||||
@@ -754,23 +1031,24 @@ static ExprNode* UnaryExpr (void)
|
|||||||
case TOK_MINUS:
|
case TOK_MINUS:
|
||||||
return DoUnaryPlusMinus ();
|
return DoUnaryPlusMinus ();
|
||||||
|
|
||||||
case TOK_AND:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_STAR:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_COMP:
|
case TOK_COMP:
|
||||||
break;
|
return DoComplement ();
|
||||||
|
|
||||||
case TOK_BOOL_NOT:
|
case TOK_BOOL_NOT:
|
||||||
break;
|
return DoBoolNot ();
|
||||||
|
|
||||||
|
case TOK_AND:
|
||||||
|
return DoAddress ();
|
||||||
|
|
||||||
|
case TOK_STAR:
|
||||||
|
return DoIndirect ();
|
||||||
|
|
||||||
case TOK_SIZEOF:
|
case TOK_SIZEOF:
|
||||||
break;
|
return DoSizeOf ();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
/* Type cast */
|
||||||
|
return DoTypeCast ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user