glsl/pp: Expand unknown identifiers to 0 in if/elif expressions.
[mesa.git] / src / glsl / pp / sl_pp_process.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_process.h"
31 #include "sl_pp_public.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 int
44 sl_pp_process_out(struct sl_pp_process_state *state,
45 const struct sl_pp_token_info *token)
46 {
47 if (state->out_len >= state->out_max) {
48 unsigned int new_max = state->out_max;
49
50 if (new_max < 0x100) {
51 new_max = 0x100;
52 } else if (new_max < 0x10000) {
53 new_max *= 2;
54 } else {
55 new_max += 0x10000;
56 }
57
58 state->out = realloc(state->out, new_max * sizeof(struct sl_pp_token_info));
59 if (!state->out) {
60 return -1;
61 }
62 state->out_max = new_max;
63 }
64
65 state->out[state->out_len++] = *token;
66 return 0;
67 }
68
69 int
70 sl_pp_process(struct sl_pp_context *context,
71 const struct sl_pp_token_info *input,
72 struct sl_pp_token_info **output)
73 {
74 unsigned int i = 0;
75 int found_eof = 0;
76 struct sl_pp_process_state state;
77
78 memset(&state, 0, sizeof(state));
79
80 if (context->line > 1) {
81 struct sl_pp_token_info ti;
82
83 ti.token = SL_PP_LINE;
84 ti.data.line.lineno = context->line - 1;
85 ti.data.line.fileno = context->file;
86 if (sl_pp_process_out(&state, &ti)) {
87 strcpy(context->error_msg, "out of memory");
88 return -1;
89 }
90
91 ti.token = SL_PP_NEWLINE;
92 if (sl_pp_process_out(&state, &ti)) {
93 strcpy(context->error_msg, "out of memory");
94 return -1;
95 }
96 }
97
98 while (!found_eof) {
99 skip_whitespace(input, &i);
100 if (input[i].token == SL_PP_HASH) {
101 i++;
102 skip_whitespace(input, &i);
103 switch (input[i].token) {
104 case SL_PP_IDENTIFIER:
105 {
106 int name;
107 int found_eol = 0;
108 unsigned int first;
109 unsigned int last;
110 struct sl_pp_token_info endof;
111
112 /* Directive name. */
113 name = input[i].data.identifier;
114 i++;
115 skip_whitespace(input, &i);
116
117 first = i;
118
119 while (!found_eol) {
120 switch (input[i].token) {
121 case SL_PP_NEWLINE:
122 /* Preserve newline just for the sake of line numbering. */
123 endof = input[i];
124 i++;
125 found_eol = 1;
126 break;
127
128 case SL_PP_EOF:
129 endof = input[i];
130 i++;
131 found_eof = 1;
132 found_eol = 1;
133 break;
134
135 default:
136 i++;
137 }
138 }
139
140 last = i - 1;
141
142 if (name == context->dict._if) {
143 if (sl_pp_process_if(context, input, first, last)) {
144 return -1;
145 }
146 } else if (name == context->dict.ifdef) {
147 if (sl_pp_process_ifdef(context, input, first, last)) {
148 return -1;
149 }
150 } else if (name == context->dict.ifndef) {
151 if (sl_pp_process_ifndef(context, input, first, last)) {
152 return -1;
153 }
154 } else if (name == context->dict.elif) {
155 if (sl_pp_process_elif(context, input, first, last)) {
156 return -1;
157 }
158 } else if (name == context->dict._else) {
159 if (sl_pp_process_else(context, input, first, last)) {
160 return -1;
161 }
162 } else if (name == context->dict.endif) {
163 if (sl_pp_process_endif(context, input, first, last)) {
164 return -1;
165 }
166 } else if (context->if_value) {
167 if (name == context->dict.define) {
168 if (sl_pp_process_define(context, input, first, last)) {
169 return -1;
170 }
171 } else if (name == context->dict.error) {
172 sl_pp_process_error(context, input, first, last);
173 return -1;
174 } else if (name == context->dict.extension) {
175 if (sl_pp_process_extension(context, input, first, last, &state)) {
176 return -1;
177 }
178 } else if (name == context->dict.line) {
179 if (sl_pp_process_line(context, input, first, last, &state)) {
180 return -1;
181 }
182 } else if (name == context->dict.pragma) {
183 if (sl_pp_process_pragma(context, input, first, last, &state)) {
184 return -1;
185 }
186 } else if (name == context->dict.undef) {
187 if (sl_pp_process_undef(context, input, first, last)) {
188 return -1;
189 }
190 } else {
191 strcpy(context->error_msg, "unrecognised directive name");
192 return -1;
193 }
194 }
195
196 if (sl_pp_process_out(&state, &endof)) {
197 strcpy(context->error_msg, "out of memory");
198 return -1;
199 }
200 context->line++;
201 }
202 break;
203
204 case SL_PP_NEWLINE:
205 /* Empty directive. */
206 if (sl_pp_process_out(&state, &input[i])) {
207 strcpy(context->error_msg, "out of memory");
208 return -1;
209 }
210 context->line++;
211 i++;
212 break;
213
214 case SL_PP_EOF:
215 /* Empty directive. */
216 if (sl_pp_process_out(&state, &input[i])) {
217 strcpy(context->error_msg, "out of memory");
218 return -1;
219 }
220 i++;
221 found_eof = 1;
222 break;
223
224 default:
225 strcpy(context->error_msg, "expected a directive name");
226 return -1;
227 }
228 } else {
229 int found_eol = 0;
230
231 while (!found_eol) {
232 switch (input[i].token) {
233 case SL_PP_WHITESPACE:
234 /* Drop whitespace all together at this point. */
235 i++;
236 break;
237
238 case SL_PP_NEWLINE:
239 /* Preserve newline just for the sake of line numbering. */
240 if (sl_pp_process_out(&state, &input[i])) {
241 strcpy(context->error_msg, "out of memory");
242 return -1;
243 }
244 context->line++;
245 i++;
246 found_eol = 1;
247 break;
248
249 case SL_PP_EOF:
250 if (sl_pp_process_out(&state, &input[i])) {
251 strcpy(context->error_msg, "out of memory");
252 return -1;
253 }
254 i++;
255 found_eof = 1;
256 found_eol = 1;
257 break;
258
259 case SL_PP_IDENTIFIER:
260 if (sl_pp_macro_expand(context, input, &i, NULL, &state,
261 context->if_value ? sl_pp_macro_expand_normal : sl_pp_macro_expand_mute)) {
262 return -1;
263 }
264 break;
265
266 default:
267 if (context->if_value) {
268 if (sl_pp_process_out(&state, &input[i])) {
269 strcpy(context->error_msg, "out of memory");
270 return -1;
271 }
272 }
273 i++;
274 }
275 }
276 }
277 }
278
279 if (context->if_ptr != SL_PP_MAX_IF_NESTING) {
280 strcpy(context->error_msg, "expected `#endif' directive");
281 return -1;
282 }
283
284 *output = state.out;
285 return 0;
286 }