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 | |
57 | static 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 | |
122 | static 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 | |
160 | static 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 | |
198 | ExprNode* CfgExpr (void) |
199 | /* Full expression */ |
200 | { |
201 | return SimpleExpr (); |
202 | } |
203 | |
204 | |
205 | |
206 | long 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 | |
231 | long 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 | |