mirror of
https://github.com/cc65/cc65.git
synced 2024-10-20 08:24:29 +00:00
1797235794
git-svn-id: svn://svn.cc65.org/cc65/trunk@5215 b7a2c559-68d2-44c3-8de9-860c34a00d81
250 lines
7.3 KiB
C
250 lines
7.3 KiB
C
/*****************************************************************************/
|
|
/* */
|
|
/* cfgexpr.c */
|
|
/* */
|
|
/* Simple expressions for use with in configuration file */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* (C) 2005-2011, Ullrich von Bassewitz */
|
|
/* Roemerstrasse 52 */
|
|
/* D-70794 Filderstadt */
|
|
/* EMail: uz@cc65.org */
|
|
/* */
|
|
/* */
|
|
/* 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 "addrsize.h"
|
|
#include "strbuf.h"
|
|
|
|
/* ld65 */
|
|
#include "cfgexpr.h"
|
|
#include "error.h"
|
|
#include "exports.h"
|
|
#include "expr.h"
|
|
#include "lineinfo.h"
|
|
#include "scanner.h"
|
|
#include "spool.h"
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* Code */
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
static ExprNode* Factor (void)
|
|
/* Read and return a factor */
|
|
{
|
|
ExprNode* N = 0; /* Initialize to avoid compiler warnings */
|
|
Export* E;
|
|
unsigned Name;
|
|
|
|
|
|
switch (CfgTok) {
|
|
|
|
case CFGTOK_IDENT:
|
|
/* Get the name as an id */
|
|
Name = GetStrBufId (&CfgSVal);
|
|
|
|
/* Check if we know the symbol already */
|
|
E = FindExport (Name);
|
|
if (E != 0 && IsConstExport (E)) {
|
|
N = LiteralExpr (GetExportVal (E), 0);
|
|
} else {
|
|
N = NewExprNode (0, EXPR_SYMBOL);
|
|
N->V.Imp = InsertImport (GenImport (Name, ADDR_SIZE_ABS));
|
|
CollAppend (&N->V.Imp->RefLines, GenLineInfo (&CfgErrorPos));
|
|
}
|
|
|
|
/* Skip the symbol name */
|
|
CfgNextTok ();
|
|
break;
|
|
|
|
case CFGTOK_INTCON:
|
|
/* An integer constant */
|
|
N = LiteralExpr (CfgIVal, 0);
|
|
CfgNextTok ();
|
|
break;
|
|
|
|
case CFGTOK_PLUS:
|
|
/* Unary plus */
|
|
CfgNextTok ();
|
|
N = Factor ();
|
|
break;
|
|
|
|
case CFGTOK_MINUS:
|
|
/* Unary minus */
|
|
CfgNextTok ();
|
|
N = NewExprNode (0, EXPR_UNARY_MINUS);
|
|
N->Left = Factor ();
|
|
break;
|
|
|
|
case CFGTOK_LPAR:
|
|
/* Left parenthesis */
|
|
CfgNextTok ();
|
|
N = CfgExpr ();
|
|
CfgConsume (CFGTOK_RPAR, "')' expected");
|
|
break;
|
|
|
|
default:
|
|
CfgError (&CfgErrorPos, "Invalid expression: %d", CfgTok);
|
|
break;
|
|
}
|
|
|
|
/* Return the new expression node */
|
|
return N;
|
|
}
|
|
|
|
|
|
|
|
static ExprNode* Term (void)
|
|
/* Multiplicative operators: * and / */
|
|
{
|
|
/* Read left hand side */
|
|
ExprNode* Root = Factor ();
|
|
|
|
/* Handle multiplicative operators */
|
|
while (CfgTok == CFGTOK_MUL || CfgTok == CFGTOK_DIV) {
|
|
|
|
ExprNode* Left;
|
|
ExprNode* Right;
|
|
unsigned char Op;
|
|
|
|
/* Remember the token, then skip it */
|
|
cfgtok_t Tok = CfgTok;
|
|
CfgNextTok ();
|
|
|
|
/* Move root to left side, then read right side */
|
|
Left = Root;
|
|
Right = Factor ();
|
|
|
|
/* Handle the operation */
|
|
switch (Tok) {
|
|
case CFGTOK_MUL: Op = EXPR_MUL; break;
|
|
case CFGTOK_DIV: Op = EXPR_DIV; break;
|
|
default: Internal ("Unhandled token in Term: %d", Tok);
|
|
}
|
|
Root = NewExprNode (0, Op);
|
|
Root->Left = Left;
|
|
Root->Right = Right;
|
|
}
|
|
|
|
/* Return the expression tree we've created */
|
|
return Root;
|
|
}
|
|
|
|
|
|
|
|
static ExprNode* SimpleExpr (void)
|
|
/* Additive operators: + and - */
|
|
{
|
|
/* Read left hand side */
|
|
ExprNode* Root = Term ();
|
|
|
|
/* Handle additive operators */
|
|
while (CfgTok == CFGTOK_PLUS || CfgTok == CFGTOK_MINUS) {
|
|
|
|
ExprNode* Left;
|
|
ExprNode* Right;
|
|
unsigned char Op;
|
|
|
|
/* Remember the token, then skip it */
|
|
cfgtok_t Tok = CfgTok;
|
|
CfgNextTok ();
|
|
|
|
/* Move root to left side, then read right side */
|
|
Left = Root;
|
|
Right = Term ();
|
|
|
|
/* Handle the operation */
|
|
switch (Tok) {
|
|
case CFGTOK_PLUS: Op = EXPR_PLUS; break;
|
|
case CFGTOK_MINUS: Op = EXPR_MINUS; break;
|
|
default: Internal ("Unhandled token in SimpleExpr: %d", Tok);
|
|
}
|
|
Root = NewExprNode (0, Op);
|
|
Root->Left = Left;
|
|
Root->Right = Right;
|
|
}
|
|
|
|
/* Return the expression tree we've created */
|
|
return Root;
|
|
}
|
|
|
|
|
|
|
|
ExprNode* CfgExpr (void)
|
|
/* Full expression */
|
|
{
|
|
return SimpleExpr ();
|
|
}
|
|
|
|
|
|
|
|
long CfgConstExpr (void)
|
|
/* Read an integer expression, make sure its constant and return its value */
|
|
{
|
|
long Val;
|
|
|
|
/* Parse the expression */
|
|
ExprNode* Expr = CfgExpr ();
|
|
|
|
/* Check that it's const */
|
|
if (!IsConstExpr (Expr)) {
|
|
CfgError (&CfgErrorPos, "Constant expression expected");
|
|
}
|
|
|
|
/* Get the value */
|
|
Val = GetExprVal (Expr);
|
|
|
|
/* Cleanup E */
|
|
FreeExpr (Expr);
|
|
|
|
/* Return the value */
|
|
return Val;
|
|
}
|
|
|
|
|
|
|
|
long CfgCheckedConstExpr (long Min, long Max)
|
|
/* Read an expression, make sure it's an int and in range, then return its
|
|
* value.
|
|
*/
|
|
{
|
|
/* Get the value */
|
|
long Val = CfgConstExpr ();
|
|
|
|
/* Check the range */
|
|
if (Val < Min || Val > Max) {
|
|
CfgError (&CfgErrorPos, "Range error");
|
|
}
|
|
|
|
/* Return the value */
|
|
return Val;
|
|
}
|
|
|
|
|
|
|