1/*****************************************************************************/
2/* */
3/* cfgexpr.c */
4/* */
5/* Simple expressions for use with in configuration file */
6/* */
7/* */
8/* */
9/* (C) 2005-2011, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
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. */
18/* */
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: */
22/* */
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 */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36/* common */
37#include "addrsize.h"
38#include "strbuf.h"
39
40/* ld65 */
41#include "cfgexpr.h"
42#include "error.h"
43#include "exports.h"
44#include "expr.h"
45#include "lineinfo.h"
46#include "scanner.h"
47#include "spool.h"
48
49
50
51/*****************************************************************************/
52/* Code */
53/*****************************************************************************/
54
55
56
57static ExprNode* Factor (void)
58/* Read and return a factor */
59{
60 ExprNode* N = 0; /* Initialize to avoid compiler warnings */
61 Export* E;
62 unsigned Name;
63
64
65 switch (CfgTok) {
66
67 case CFGTOK_IDENT:
68 /* Get the name as an id */
69 Name = GetStrBufId (&CfgSVal);
70
71 /* Check if we know the symbol already */
72 E = FindExport (Name);
73 if (E != 0 && IsConstExport (E)) {
74 N = LiteralExpr (GetExportVal (E), 0);
75 } else {
76 N = NewExprNode (0, EXPR_SYMBOL);
77 N->V.Imp = InsertImport (GenImport (Name, ADDR_SIZE_ABS));
78 CollAppend (&N->V.Imp->RefLines, GenLineInfo (&CfgErrorPos));
79 }
80
81 /* Skip the symbol name */
82 CfgNextTok ();
83 break;
84
85 case CFGTOK_INTCON:
86 /* An integer constant */
87 N = LiteralExpr (CfgIVal, 0);
88 CfgNextTok ();
89 break;
90
91 case CFGTOK_PLUS:
92 /* Unary plus */
93 CfgNextTok ();
94 N = Factor ();
95 break;
96
97 case CFGTOK_MINUS:
98 /* Unary minus */
99 CfgNextTok ();
100 N = NewExprNode (0, EXPR_UNARY_MINUS);
101 N->Left = Factor ();
102 break;
103
104 case CFGTOK_LPAR:
105 /* Left parenthesis */
106 CfgNextTok ();
107 N = CfgExpr ();
108 CfgConsume (CFGTOK_RPAR, "')' expected");
109 break;
110
111 default:
112 CfgError (&CfgErrorPos, "Invalid expression: %d", CfgTok);
113 break;
114 }
115
116 /* Return the new expression node */
117 return N;
118}
119
120
121
122static ExprNode* Term (void)
123/* Multiplicative operators: * and / */
124{
125 /* Read left hand side */
126 ExprNode* Root = Factor ();
127
128 /* Handle multiplicative operators */
129 while (CfgTok == CFGTOK_MUL || CfgTok == CFGTOK_DIV) {
130
131 ExprNode* Left;
132 ExprNode* Right;
133 unsigned char Op;
134
135 /* Remember the token, then skip it */
136 cfgtok_t Tok = CfgTok;
137 CfgNextTok ();
138
139 /* Move root to left side, then read right side */
140 Left = Root;
141 Right = Factor ();
142
143 /* Handle the operation */
144 switch (Tok) {
145 case CFGTOK_MUL: Op = EXPR_MUL; break;
146 case CFGTOK_DIV: Op = EXPR_DIV; break;
147 default: Internal ("Unhandled token in Term: %d", Tok);
148 }
149 Root = NewExprNode (0, Op);
150 Root->Left = Left;
151 Root->Right = Right;
152 }
153
154 /* Return the expression tree we've created */
155 return Root;
156}
157
158
159
160static ExprNode* SimpleExpr (void)
161/* Additive operators: + and - */
162{
163 /* Read left hand side */
164 ExprNode* Root = Term ();
165
166 /* Handle additive operators */
167 while (CfgTok == CFGTOK_PLUS || CfgTok == CFGTOK_MINUS) {
168
169 ExprNode* Left;
170 ExprNode* Right;
171 unsigned char Op;
172
173 /* Remember the token, then skip it */
174 cfgtok_t Tok = CfgTok;
175 CfgNextTok ();
176
177 /* Move root to left side, then read right side */
178 Left = Root;
179 Right = Term ();
180
181 /* Handle the operation */
182 switch (Tok) {
183 case CFGTOK_PLUS: Op = EXPR_PLUS; break;
184 case CFGTOK_MINUS: Op = EXPR_MINUS; break;
185 default: Internal ("Unhandled token in SimpleExpr: %d", Tok);
186 }
187 Root = NewExprNode (0, Op);
188 Root->Left = Left;
189 Root->Right = Right;
190 }
191
192 /* Return the expression tree we've created */
193 return Root;
194}
195
196
197
198ExprNode* CfgExpr (void)
199/* Full expression */
200{
201 return SimpleExpr ();
202}
203
204
205
206long CfgConstExpr (void)
207/* Read an integer expression, make sure its constant and return its value */
208{
209 long Val;
210
211 /* Parse the expression */
212 ExprNode* Expr = CfgExpr ();
213
214 /* Check that it's const */
215 if (!IsConstExpr (Expr)) {
216 CfgError (&CfgErrorPos, "Constant expression expected");
217 }
218
219 /* Get the value */
220 Val = GetExprVal (Expr);
221
222 /* Cleanup E */
223 FreeExpr (Expr);
224
225 /* Return the value */
226 return Val;
227}
228
229
230
231long CfgCheckedConstExpr (long Min, long Max)
232/* Read an expression, make sure it's an int and in range, then return its
233** value.
234*/
235{
236 /* Get the value */
237 long Val = CfgConstExpr ();
238
239 /* Check the range */
240 if (Val < Min || Val > Max) {
241 CfgError (&CfgErrorPos, "Range error");
242 }
243
244 /* Return the value */
245 return Val;
246}
247