1 /*****************************************************************************/
5 /* Simple expressions for use with in configuration file */
9 /* (C) 2005-2008, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
48 /*****************************************************************************/
50 /*****************************************************************************/
54 /* Type of a CfgExpr */
61 typedef struct CfgExpr CfgExpr;
63 unsigned Type; /* Type of the expression */
64 long IVal; /* Integer value if it's a string */
65 StrBuf SVal; /* String value if it's a string */
68 #define CFGEXPR_INITIALIZER { ceEmpty, 0, STATIC_STRBUF_INITIALIZER }
72 /*****************************************************************************/
74 /*****************************************************************************/
78 static void Expr (CfgExpr* E);
83 /*****************************************************************************/
85 /*****************************************************************************/
89 static void CE_Done (CfgExpr* E)
90 /* Cleanup a CfgExpr struct */
92 /* If the type is a string, we must delete the string buffer */
93 if (E->Type == ceString) {
100 static void CE_AssureInt (const CfgExpr* E)
101 /* Make sure, E contains an integer */
103 if (E->Type != ceInt) {
104 CfgError ("Integer type expected");
110 /*****************************************************************************/
112 /*****************************************************************************/
116 static void Factor (CfgExpr* E)
117 /* Read and return a factor in E */
125 /* An identifier - search an export with the given name */
126 Sym = FindExport (GetStringId (CfgSVal));
128 CfgError ("Unknown symbol in expression: `%s'", CfgSVal);
130 /* We can only handle constants */
131 if (!IsConstExport (Sym)) {
132 CfgError ("Value for symbol `%s' is not constant", CfgSVal);
135 /* Use the symbol value */
136 E->IVal = GetExportVal (Sym);
139 /* Skip the symbol name */
144 /* An integer constant */
151 /* A string constant */
152 SB_CopyStr (&E->SVal, CfgSVal);
173 /* Left parenthesis */
176 CfgConsume (CFGTOK_RPAR, "')' expected");
180 CfgError ("Invalid expression: %d", CfgTok);
187 static void Term (CfgExpr* E)
188 /* Multiplicative operators: * and / */
193 /* Handle multiplicative operators */
194 while (CfgTok == CFGTOK_MUL || CfgTok == CFGTOK_DIV) {
196 CfgExpr RightSide = CFGEXPR_INITIALIZER;
198 /* Remember the token, then skip it */
199 cfgtok_t Tok = CfgTok;
202 /* Left side must be an int */
205 /* Get the right operand and make sure it's an int */
207 CE_AssureInt (&RightSide);
209 /* Handle the operation */
213 E->IVal *= RightSide.IVal;
217 if (RightSide.IVal == 0) {
218 CfgError ("Division by zero");
220 E->IVal /= RightSide.IVal;
224 Internal ("Unhandled token in Term: %d", Tok);
227 /* Cleanup RightSide (this is not really needed since it may not
228 * contain strings at this point, but call it anyway for clarity.
230 CE_Done (&RightSide);
236 static void SimpleExpr (CfgExpr* E)
237 /* Additive operators: + and - */
242 /* Handle additive operators */
243 while (CfgTok == CFGTOK_PLUS || CfgTok == CFGTOK_MINUS) {
245 CfgExpr RightSide = CFGEXPR_INITIALIZER;
247 /* Remember the token, then skip it */
248 cfgtok_t Tok = CfgTok;
251 /* Get the right operand */
254 /* Make sure, left and right side are of the same type */
255 if (E->Type != RightSide.Type) {
256 CfgError ("Incompatible types in expression");
259 /* Handle the operation */
263 /* Plus is defined for strings and ints */
264 if (E->Type == ceInt) {
265 E->IVal += RightSide.IVal;
266 } else if (E->Type == ceString) {
267 SB_Append (&E->SVal, &RightSide.SVal);
269 Internal ("Unhandled type in '+' operator: %u", E->Type);
274 /* Operands must be ints */
276 E->IVal -= RightSide.IVal;
280 Internal ("Unhandled token in SimpleExpr: %d", Tok);
283 /* Cleanup RightSide */
284 CE_Done (&RightSide);
290 static void Expr (CfgExpr* E)
291 /* Full expression */
298 long CfgIntExpr (void)
299 /* Read an expression, make sure it's an int, and return its value */
303 CfgExpr E = CFGEXPR_INITIALIZER;
305 /* Parse the expression */
308 /* Make sure it's an integer */
317 /* Return the value */
323 long CfgCheckedIntExpr (long Min, long Max)
324 /* Read an expression, make sure it's an int and in range, then return its
329 long Val = CfgIntExpr ();
331 /* Check the range */
332 if (Val < Min || Val > Max) {
333 CfgError ("Range error");
336 /* Return the value */