1 /*****************************************************************************/
5 /* Simple expressions for use with in configuration file */
9 /* (C) 2005, Ullrich von Bassewitz */
10 /* Römerstrasse 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) {
94 DoneStrBuf (&E->SVal);
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 */
199 cfgtok_t Tok = CfgTok;
201 /* Left side must be an int */
204 /* Get the right operand and make sure it's an int */
206 CE_AssureInt (&RightSide);
208 /* Handle the operation */
212 E->IVal *= RightSide.IVal;
216 if (RightSide.IVal == 0) {
217 CfgError ("Division by zero");
219 E->IVal /= RightSide.IVal;
223 Internal ("Unhandled token in Term: %d", Tok);
226 /* Cleanup RightSide (this is not really needed since it may not
227 * contain strings at this point, but call it anyway for clarity.
229 CE_Done (&RightSide);
235 static void SimpleExpr (CfgExpr* E)
236 /* Additive operators: + and - */
241 /* Handle additive operators */
242 while (CfgTok == CFGTOK_PLUS || CfgTok == CFGTOK_MINUS) {
244 CfgExpr RightSide = CFGEXPR_INITIALIZER;
246 /* Remember the token, then skip it */
247 cfgtok_t Tok = CfgTok;
250 /* Get the right operand */
253 /* Make sure, left and right side are of the same type */
254 if (E->Type != RightSide.Type) {
255 CfgError ("Incompatible types in expression");
258 /* Handle the operation */
262 /* Plus is defined for strings and ints */
263 if (E->Type == ceInt) {
264 E->IVal += RightSide.IVal;
265 } else if (E->Type == ceString) {
266 SB_Append (&E->SVal, &RightSide.SVal);
268 Internal ("Unhandled type in '+' operator: %u", E->Type);
273 /* Operands must be ints */
275 E->IVal -= RightSide.IVal;
279 Internal ("Unhandled token in SimpleExpr: %d", Tok);
282 /* Cleanup RightSide */
283 CE_Done (&RightSide);
289 static void Expr (CfgExpr* E)
290 /* Full expression */
297 long CfgIntExpr (void)
298 /* Read an expression, make sure it's an int, and return its value */
302 CfgExpr E = CFGEXPR_INITIALIZER;
304 /* Parse the expression */
307 /* Make sure it's an integer */
316 /* Return the value */
322 long CfgCheckedIntExpr (long Min, long Max)
323 /* Read an expression, make sure it's an int and in range, then return its
328 long Val = CfgIntExpr ();
330 /* Check the range */
331 if (Val < Min || Val > Max) {
332 CfgError ("Range error");
335 /* Return the value */