glsl/pp: Fix macro formal argument parsing, more descriptive error msgs.
[mesa.git] / src / glsl / pp / sl_pp_if.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include "sl_pp_expression.h"
31 #include "sl_pp_process.h"
32
33
34 static void
35 skip_whitespace(const struct sl_pp_token_info *input,
36 unsigned int *pi)
37 {
38 while (input[*pi].token == SL_PP_WHITESPACE) {
39 (*pi)++;
40 }
41 }
42
43 static int
44 _parse_defined(struct sl_pp_context *context,
45 const struct sl_pp_token_info *input,
46 unsigned int *pi,
47 struct sl_pp_process_state *state)
48 {
49 int parens = 0;
50 int macro_name;
51 struct sl_pp_macro *macro;
52 int defined = 0;
53 struct sl_pp_token_info result;
54
55 skip_whitespace(input, pi);
56 if (input[*pi].token == SL_PP_LPAREN) {
57 (*pi)++;
58 skip_whitespace(input, pi);
59 parens = 1;
60 }
61
62 if (input[*pi].token != SL_PP_IDENTIFIER) {
63 strcpy(context->error_msg, "expected an identifier");
64 return -1;
65 }
66
67 macro_name = input[*pi].data.identifier;
68 for (macro = context->macro; macro; macro = macro->next) {
69 if (macro->name == macro_name) {
70 defined = 1;
71 break;
72 }
73 }
74 (*pi)++;
75
76 if (parens) {
77 skip_whitespace(input, pi);
78 if (input[*pi].token != SL_PP_RPAREN) {
79 strcpy(context->error_msg, "expected `)'");
80 return -1;
81 }
82 (*pi)++;
83 }
84
85 result.token = SL_PP_UINT;
86 result.data._uint = (defined ? context->dict._1 : context->dict._0);
87
88 if (sl_pp_process_out(state, &result)) {
89 strcpy(context->error_msg, "out of memory");
90 return -1;
91 }
92
93 return 0;
94 }
95
96 static unsigned int
97 _evaluate_if_stack(struct sl_pp_context *context)
98 {
99 unsigned int i;
100
101 for (i = context->if_ptr; i < SL_PP_MAX_IF_NESTING; i++) {
102 if (!(context->if_stack[i] & 1)) {
103 return 0;
104 }
105 }
106 return 1;
107 }
108
109 static int
110 _parse_if(struct sl_pp_context *context,
111 const struct sl_pp_token_info *input,
112 unsigned int first,
113 unsigned int last)
114 {
115 unsigned int i;
116 struct sl_pp_process_state state;
117 struct sl_pp_token_info eof;
118 int result;
119
120 if (!context->if_ptr) {
121 strcpy(context->error_msg, "`#if' nesting too deep");
122 return -1;
123 }
124
125 memset(&state, 0, sizeof(state));
126 for (i = first; i < last;) {
127 switch (input[i].token) {
128 case SL_PP_WHITESPACE:
129 i++;
130 break;
131
132 case SL_PP_IDENTIFIER:
133 if (input[i].data.identifier == context->dict.defined) {
134 i++;
135 if (_parse_defined(context, input, &i, &state)) {
136 free(state.out);
137 return -1;
138 }
139 } else {
140 if (sl_pp_macro_expand(context, input, &i, NULL, &state, 0)) {
141 free(state.out);
142 return -1;
143 }
144 }
145 break;
146
147 default:
148 if (sl_pp_process_out(&state, &input[i])) {
149 strcpy(context->error_msg, "out of memory");
150 free(state.out);
151 return -1;
152 }
153 i++;
154 }
155 }
156
157 eof.token = SL_PP_EOF;
158 if (sl_pp_process_out(&state, &eof)) {
159 strcpy(context->error_msg, "out of memory");
160 free(state.out);
161 return -1;
162 }
163
164 if (sl_pp_execute_expression(context, state.out, &result)) {
165 free(state.out);
166 return -1;
167 }
168
169 free(state.out);
170
171 context->if_ptr--;
172 context->if_stack[context->if_ptr] = result ? 1 : 0;
173 context->if_value = _evaluate_if_stack(context);
174
175 return 0;
176 }
177
178 static int
179 _parse_else(struct sl_pp_context *context)
180 {
181 if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
182 strcpy(context->error_msg, "no matching `#if'");
183 return -1;
184 }
185
186 /* Bit b1 indicates we already went through #else. */
187 if (context->if_stack[context->if_ptr] & 2) {
188 strcpy(context->error_msg, "no matching `#if'");
189 return -1;
190 }
191
192 /* Invert current condition value and mark that we are in the #else block. */
193 context->if_stack[context->if_ptr] = (1 - (context->if_stack[context->if_ptr] & 1)) | 2;
194 context->if_value = _evaluate_if_stack(context);
195
196 return 0;
197 }
198
199 int
200 sl_pp_process_if(struct sl_pp_context *context,
201 const struct sl_pp_token_info *input,
202 unsigned int first,
203 unsigned int last)
204 {
205 return _parse_if(context, input, first, last);
206 }
207
208 int
209 sl_pp_process_ifdef(struct sl_pp_context *context,
210 const struct sl_pp_token_info *input,
211 unsigned int first,
212 unsigned int last)
213 {
214 unsigned int i;
215
216 if (!context->if_ptr) {
217 strcpy(context->error_msg, "`#if' nesting too deep");
218 return -1;
219 }
220
221 for (i = first; i < last; i++) {
222 switch (input[i].token) {
223 case SL_PP_IDENTIFIER:
224 {
225 struct sl_pp_macro *macro;
226 int macro_name = input[i].data.identifier;
227 int defined = 0;
228
229 for (macro = context->macro; macro; macro = macro->next) {
230 if (macro->name == macro_name) {
231 defined = 1;
232 break;
233 }
234 }
235
236 context->if_ptr--;
237 context->if_stack[context->if_ptr] = defined ? 1 : 0;
238 context->if_value = _evaluate_if_stack(context);
239 }
240 return 0;
241
242 case SL_PP_WHITESPACE:
243 break;
244
245 default:
246 strcpy(context->error_msg, "expected an identifier");
247 return -1;
248 }
249 }
250
251 strcpy(context->error_msg, "expected an identifier");
252 return -1;
253 }
254
255 int
256 sl_pp_process_ifndef(struct sl_pp_context *context,
257 const struct sl_pp_token_info *input,
258 unsigned int first,
259 unsigned int last)
260 {
261 unsigned int i;
262
263 if (!context->if_ptr) {
264 strcpy(context->error_msg, "`#if' nesting too deep");
265 return -1;
266 }
267
268 for (i = first; i < last; i++) {
269 switch (input[i].token) {
270 case SL_PP_IDENTIFIER:
271 {
272 struct sl_pp_macro *macro;
273 int macro_name = input[i].data.identifier;
274 int defined = 0;
275
276 for (macro = context->macro; macro; macro = macro->next) {
277 if (macro->name == macro_name) {
278 defined = 1;
279 break;
280 }
281 }
282
283 context->if_ptr--;
284 context->if_stack[context->if_ptr] = defined ? 0 : 1;
285 context->if_value = _evaluate_if_stack(context);
286 }
287 return 0;
288
289 case SL_PP_WHITESPACE:
290 break;
291
292 default:
293 strcpy(context->error_msg, "expected an identifier");
294 return -1;
295 }
296 }
297
298 strcpy(context->error_msg, "expected an identifier");
299 return -1;
300 }
301
302 int
303 sl_pp_process_elif(struct sl_pp_context *context,
304 const struct sl_pp_token_info *input,
305 unsigned int first,
306 unsigned int last)
307 {
308 if (_parse_else(context)) {
309 return -1;
310 }
311
312 if (context->if_stack[context->if_ptr] & 1) {
313 context->if_ptr++;
314 if (_parse_if(context, input, first, last)) {
315 return -1;
316 }
317 }
318
319 /* We are still in the #if block. */
320 context->if_stack[context->if_ptr] = context->if_stack[context->if_ptr] & ~2;
321
322 return 0;
323 }
324
325 int
326 sl_pp_process_else(struct sl_pp_context *context,
327 const struct sl_pp_token_info *input,
328 unsigned int first,
329 unsigned int last)
330 {
331 return _parse_else(context);
332 }
333
334 int
335 sl_pp_process_endif(struct sl_pp_context *context,
336 const struct sl_pp_token_info *input,
337 unsigned int first,
338 unsigned int last)
339 {
340 if (context->if_ptr == SL_PP_MAX_IF_NESTING) {
341 strcpy(context->error_msg, "no matching `#if'");
342 return -1;
343 }
344
345 context->if_ptr++;
346 context->if_value = _evaluate_if_stack(context);
347
348 return 0;
349 }