From 980f5b598fe4d5e581bd922b70209c39a1d92246 Mon Sep 17 00:00:00 2001 From: cuz Date: Wed, 12 Nov 2003 16:40:26 +0000 Subject: [PATCH] Precalculate some expressions git-svn-id: svn://svn.cc65.org/cc65/trunk@2651 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/ca65/expr.c | 181 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 153 insertions(+), 28 deletions(-) diff --git a/src/ca65/expr.c b/src/ca65/expr.c index ad2699c27..68baabb3f 100644 --- a/src/ca65/expr.c +++ b/src/ca65/expr.c @@ -189,6 +189,35 @@ int IsWordRange (long Val) +static int IsEasyConst (const ExprNode* E, long* Val) +/* Do some light checking if the given node is a constant. Don't care if E is + * a complex expression. If E is a constant, return true and place its value + * into Val, provided that Val is not NULL. + */ +{ + /* Resolve symbols, follow symbol chains */ + while (E->Op == EXPR_SYMBOL) { + E = SymResolve (E->V.Sym); + if (E == 0) { + /* Could not resolve */ + return 0; + } + } + + /* Symbols resolved, check for a literal */ + if (E->Op == EXPR_LITERAL) { + if (Val) { + *Val = E->V.Val; + } + return 1; + } + + /* Not found to be a const according to our tests */ + return 0; +} + + + static int FuncBlank (void) /* Handle the .BLANK builtin function */ { @@ -503,8 +532,10 @@ static ExprNode* Function (int (*F) (void)) static ExprNode* Factor (void) { + ExprNode* L; ExprNode* N; SymEntry* S; + long Val; switch (Tok) { @@ -540,14 +571,26 @@ static ExprNode* Factor (void) case TOK_MINUS: NextTok (); - N = NewExprNode (EXPR_UNARY_MINUS); - N->Left = Factor (); + L = Factor (); + if (IsEasyConst (L, &Val)) { + FreeExpr (L); + N = GenLiteralExpr (-Val); + } else { + N = NewExprNode (EXPR_UNARY_MINUS); + N->Left = L; + } break; case TOK_NOT: NextTok (); - N = NewExprNode (EXPR_NOT); - N->Left = Factor (); + L = Factor (); + if (IsEasyConst (L, &Val)) { + FreeExpr (L); + N = GenLiteralExpr (~Val); + } else { + N = NewExprNode (EXPR_NOT); + N->Left = L; + } break; case TOK_STAR: @@ -558,20 +601,38 @@ static ExprNode* Factor (void) case TOK_LT: NextTok (); - N = NewExprNode (EXPR_BYTE0); - N->Left = Factor (); + L = Factor (); + if (IsEasyConst (L, &Val)) { + FreeExpr (L); + N = GenLiteralExpr (Val & 0xFF); + } else { + N = NewExprNode (EXPR_BYTE0); + N->Left = L; + } break; case TOK_GT: NextTok (); - N = NewExprNode (EXPR_BYTE1); - N->Left = Factor (); + L = Factor (); + if (IsEasyConst (L, &Val)) { + FreeExpr (L); + N = GenLiteralExpr ((Val >> 8) & 0xFF); + } else { + N = NewExprNode (EXPR_BYTE1); + N->Left = L; + } break; case TOK_BANK: NextTok (); - N = NewExprNode (EXPR_BYTE2); - N->Left = Factor (); + L = Factor (); + if (IsEasyConst (L, &Val)) { + FreeExpr (L); + N = GenLiteralExpr ((Val >> 16) & 0xFF); + } else { + N = NewExprNode (EXPR_BYTE2); + N->Left = L; + } break; case TOK_LPAREN: @@ -627,7 +688,6 @@ static ExprNode* Factor (void) NextTok (); break; - case TOK_XMATCH: N = Function (FuncXMatch); break; @@ -658,25 +718,90 @@ static ExprNode* Term (void) Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL || Tok == TOK_SHR) { - /* Create the new node */ - ExprNode* Left = Root; - switch (Tok) { - case TOK_MUL: Root = NewExprNode (EXPR_MUL); break; - case TOK_DIV: Root = NewExprNode (EXPR_DIV); break; - case TOK_MOD: Root = NewExprNode (EXPR_MOD); break; - case TOK_AND: Root = NewExprNode (EXPR_AND); break; - case TOK_XOR: Root = NewExprNode (EXPR_XOR); break; - case TOK_SHL: Root = NewExprNode (EXPR_SHL); break; - case TOK_SHR: Root = NewExprNode (EXPR_SHR); break; - default: Internal ("Invalid token"); - } - Root->Left = Left; + long LVal, RVal, Val; + ExprNode* Left; + ExprNode* Right; - /* Skip the operator token */ - NextTok (); + /* Remember the token and skip it */ + enum Token T = Tok; + NextTok (); - /* Parse the right hand side */ - Root->Right = Factor (); + /* Move root to left side and read the right side */ + Left = Root; + Right = Factor (); + + /* If both expressions are constant, we can evaluate the term */ + if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) { + + switch (T) { + case TOK_MUL: + Val = LVal * RVal; + break; + + case TOK_DIV: + if (RVal == 0) { + Error ("Division by zero"); + Val = 1; + } else { + Val = LVal / RVal; + } + break; + + case TOK_MOD: + if (RVal == 0) { + Error ("Modulo operation with zero"); + Val = 1; + } else { + Val = LVal % RVal; + } + break; + + case TOK_AND: + Val = LVal & RVal; + break; + + case TOK_XOR: + Val = LVal ^ RVal; + break; + + case TOK_SHL: + Val = shl_l (LVal, RVal); + break; + + case TOK_SHR: + Val = shr_l (LVal, RVal); + break; + + default: + Internal ("Invalid token"); + } + + /* Generate a literal expression and delete the old left and + * right sides. + */ + FreeExpr (Left); + FreeExpr (Right); + Root = GenLiteralExpr (Val); + + } else { + + /* Generate an expression tree */ + unsigned char Op; + switch (T) { + case TOK_MUL: Op = EXPR_MUL; break; + case TOK_DIV: Op = EXPR_DIV; break; + case TOK_MOD: Op = EXPR_MOD; break; + case TOK_AND: Op = EXPR_AND; break; + case TOK_XOR: Op = EXPR_XOR; break; + case TOK_SHL: Op = EXPR_SHL; break; + case TOK_SHR: Op = EXPR_SHR; break; + default: Internal ("Invalid token"); + } + Root = NewExprNode (Op); + Root->Left = Left; + Root->Right = Right; + + } }