cc65/src/ld65/cfgexpr.c

247 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;
}