1 /*
2 * cook - file construction tool
3 * Copyright (C) 1994, 1997, 1998, 2006, 2007 Peter Miller;
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <common/ac/ctype.h>
22 #include <common/ac/string.h>
23
24 #include <make2cook/emit.h>
25 #include <make2cook/stmt/if.h>
26 #include <common/trace.h>
27 #include <make2cook/variable.h>
28
29 typedef struct stmt_if_ty stmt_if_ty;
30 struct stmt_if_ty
31 {
32 STMT
33 blob_list_ty *condition;
34 stmt_ty *then_clause;
35 stmt_ty *else_clause;
36 };
37
38
39 static void
destructor(stmt_ty * that)40 destructor(stmt_ty *that)
41 {
42 stmt_if_ty *this;
43
44 trace(("if::destructor()\n{\n"));
45 this = (stmt_if_ty *) that;
46 blob_list_free(this->condition);
47 stmt_free(this->then_clause);
48 if (this->else_clause)
49 stmt_free(this->else_clause);
50 trace(("}\n"));
51 }
52
53
54 static void
emit(stmt_ty * that)55 emit(stmt_ty *that)
56 {
57 stmt_if_ty *this;
58 size_t j;
59
60 trace(("if::emit()\n{\n"));
61 this = (stmt_if_ty *)that;
62 emit_line_number
63 (
64 this->condition->list[0]->line_number,
65 this->condition->list[0]->file_name
66 );
67 emit_str("#if");
68 for (j = 0; j < this->condition->length; ++j)
69 {
70 emit_char(' ');
71 emit_string(this->condition->list[j]->text);
72 }
73 emit_char('\n');
74
75 stmt_emit(this->then_clause);
76 emit_bol();
77
78 if (this->else_clause)
79 {
80 emit_str("#else\n");
81 stmt_emit(this->else_clause);
82 emit_bol();
83 }
84 emit_str("#endif\n");
85 trace(("}\n"));
86 }
87
88
89 static void
regroup(stmt_ty * that)90 regroup(stmt_ty *that)
91 {
92 stmt_if_ty *this;
93
94 trace(("if::regroup()\n{\n"));
95 this = (stmt_if_ty *) that;
96 stmt_regroup(this->then_clause);
97 if (this->else_clause)
98 stmt_regroup(this->else_clause);
99 trace(("}\n"));
100 }
101
102
103 static void
sort(stmt_ty * that)104 sort(stmt_ty *that)
105 {
106 stmt_if_ty *this;
107
108 trace(("if::sort()\n{\n"));
109 this = (stmt_if_ty *)that;
110 stmt_sort(this->then_clause);
111 if (this->else_clause)
112 stmt_sort(this->else_clause);
113 trace(("}\n"));
114 }
115
116
117 static stmt_method_ty method =
118 {
119 sizeof(stmt_if_ty),
120 "if",
121 0, /* constructor */
122 destructor,
123 emit,
124 regroup,
125 sort,
126 };
127
128
129 static blob_list_ty *
ifeq(blob_list_ty * blp,string_list_ty * ref)130 ifeq(blob_list_ty *blp, string_list_ty *ref)
131 {
132 blob_ty *arg;
133 blob_ty *bp;
134 blob_list_ty *result;
135 string_ty *s;
136 string_ty *s2;
137 char *cp;
138 size_t j;
139
140 /*
141 * allocate the result list
142 */
143 trace(("ifeq()\n{\n"));
144 result = blob_list_alloc();
145
146 /*
147 * make sure we were given enough arguments
148 */
149 if (blp->length < 2)
150 {
151 arg = blp->list[0];
152 blob_list_append
153 (
154 result,
155 blob_alloc(str_from_c("0"), arg->file_name, arg->line_number)
156 );
157 trace(("}\n"));
158 return result;
159 }
160
161 /*
162 * turn the list of arguments into a single string
163 */
164 arg = blp->list[1];
165 s = str_copy(blp->list[1]->text);
166 for (j = 2; j < blp->length; ++j)
167 {
168 s2 = str_format("%s %s", s->str_text, blp->list[j]->text->str_text);
169 str_free(s);
170 s = s2;
171 }
172 bp = blob_alloc(s, arg->file_name, arg->line_number);
173
174 /*
175 * rename the variables
176 * and reform to be a single string, again.
177 */
178 variable_rename(bp, result, ref, VAREN_NO_QUOQUO);
179 blob_free(bp);
180 s = result->length ? str_copy(result->list[0]->text) : str_from_c("0");
181 for (j = 1; j < result->length; ++j)
182 {
183 s2 = str_format("%s %s", s->str_text, result->list[j]->text->str_text);
184 str_free(s);
185 s = s2;
186 }
187 blob_list_free(result);
188
189 /*
190 * construct the result
191 */
192 result = blob_list_alloc();
193 switch (s->str_text[0])
194 {
195 case '(':
196 /*
197 * ifeq (xxx,yyy)
198 */
199 if (s->str_length < 3)
200 goto useless;
201 cp = strchr(s->str_text, ',');
202 if (cp == 0 || s->str_text[s->str_length - 1] != ')')
203 goto useless;
204
205 blob_list_append
206 (
207 result,
208 blob_alloc(str_from_c("[in"), arg->file_name, arg->line_number)
209 );
210
211 s2 = str_n_from_c(s->str_text + 1, cp - s->str_text - 1);
212 if (s2->str_length == 0)
213 s2 = str_from_c("\"\"");
214 bp = blob_alloc(s2, arg->file_name, arg->line_number);
215 blob_list_append(result, bp);
216
217 s2 = str_n_from_c(cp + 1, s->str_text + s->str_length - cp - 2);
218 if (s2->str_length == 0)
219 s2 = str_from_c("\"\"");
220 bp = blob_alloc(s2, arg->file_name, arg->line_number);
221 blob_list_append(result, bp);
222
223 blob_list_append
224 (
225 result,
226 blob_alloc(str_from_c("]"), arg->file_name, arg->line_number)
227 );
228 break;
229
230 case '\'':
231 case '"':
232 /*
233 * ifeq "xxx" "yyy"
234 */
235 if (s->str_length < 5)
236 goto useless;
237 cp = strchr(s->str_text + 1, s->str_text[0]);
238 if
239 (
240 !cp
241 ||
242 cp[1] != ' '
243 ||
244 cp[2] != s->str_text[0]
245 ||
246 s->str_text[s->str_length - 1] != s->str_text[0]
247 )
248 goto useless;
249
250 blob_list_append
251 (
252 result,
253 blob_alloc(str_from_c("[in"), arg->file_name, arg->line_number)
254 );
255
256 s2 = str_n_from_c(s->str_text + 1, cp - s->str_text - 1);
257 if (s2->str_length == 0)
258 s2 = str_from_c("\"\"");
259 bp = blob_alloc(s2, arg->file_name, arg->line_number);
260 blob_list_append(result, bp);
261
262 s2 = str_n_from_c(cp + 3, s->str_text + s->str_length - cp - 4);
263 if (s2->str_length == 0)
264 s2 = str_from_c("\"\"");
265 bp = blob_alloc(s2, arg->file_name, arg->line_number);
266 blob_list_append(result, bp);
267
268 blob_list_append
269 (
270 result,
271 blob_alloc(str_from_c("]"), arg->file_name, arg->line_number)
272 );
273 break;
274
275 default:
276 /*
277 * We were given some useless thing, just rename the
278 * variables and copy it through.
279 */
280 useless:
281 bp = blob_alloc(str_copy(s), arg->file_name, arg->line_number);
282 blob_list_append(result, bp);
283 break;
284 }
285 str_free(s);
286 trace(("}\n"));
287 return result;
288 }
289
290
291 static blob_list_ty *
ifneq(blob_list_ty * blp,string_list_ty * ref)292 ifneq(blob_list_ty *blp, string_list_ty *ref)
293 {
294 blob_ty *arg;
295 blob_list_ty *result;
296 blob_ty *bp;
297
298 arg = blp->list[0];
299 result = ifeq(blp, ref);
300 bp = blob_alloc(str_from_c("[not"), arg->file_name, arg->line_number);
301 blob_list_prepend(result, bp);
302 bp = blob_alloc(str_from_c("]"), arg->file_name, arg->line_number);
303 blob_list_append(result, bp);
304 return result;
305 }
306
307
308 static blob_list_ty *
ifdef(blob_list_ty * blp,string_list_ty * ref)309 ifdef(blob_list_ty *blp, string_list_ty *ref)
310 {
311 blob_ty *bp;
312 blob_list_ty *result;
313 size_t j;
314
315 bp = blp->list[0];
316 result = blob_list_alloc();
317 blob_list_append
318 (
319 result,
320 blob_alloc(str_from_c("[defined"), bp->file_name, bp->line_number)
321 );
322 for (j = 1; j < blp->length; ++j)
323 variable_rename(blp->list[j], result, ref, VAREN_QUOTE_SPACES);
324 blob_list_append
325 (
326 result,
327 blob_alloc(str_from_c("]"), bp->file_name, bp->line_number)
328 );
329 return result;
330 }
331
332
333 static blob_list_ty *
ifndef(blob_list_ty * blp,string_list_ty * ref)334 ifndef(blob_list_ty *blp, string_list_ty *ref)
335 {
336 blob_ty *arg;
337 blob_list_ty *result;
338 blob_ty *bp;
339
340 arg = blp->list[0];
341 result = ifdef(blp, ref);
342 bp = blob_alloc(str_from_c("[not"), arg->file_name, arg->line_number);
343 blob_list_prepend(result, bp);
344 bp = blob_alloc(str_from_c("]"), arg->file_name, arg->line_number);
345 blob_list_append(result, bp);
346 return result;
347 }
348
349
350 typedef struct table_ty table_ty;
351 struct table_ty
352 {
353 char *name;
354 blob_list_ty *(*rewrite)(blob_list_ty *, string_list_ty *);
355 string_ty *fast;
356 };
357
358 static table_ty table[] =
359 {
360 { "ifeq", ifeq, 0 },
361 { "ifneq", ifneq, 0 },
362 { "ifdef", ifdef, 0 },
363 { "ifndef", ifndef, 0 },
364 };
365
366
367 stmt_ty *
stmt_if_alloc(blob_list_ty * condition,stmt_ty * then_clause,stmt_ty * else_clause)368 stmt_if_alloc(blob_list_ty *condition, stmt_ty *then_clause,
369 stmt_ty *else_clause)
370 {
371 stmt_if_ty *result;
372 blob_list_ty *c2;
373 table_ty *tp;
374
375 trace(("stmt_if_alloc()\n{\n"));
376 result = (stmt_if_ty *)stmt_alloc(&method);
377
378 assert(condition->length >= 1);
379 for (tp = table; tp < ENDOF(table); ++tp)
380 {
381 if (!tp->fast)
382 tp->fast = str_from_c(tp->name);
383 if (str_equal(condition->list[0]->text, tp->fast))
384 break;
385 }
386 assert(tp < ENDOF(table));
387 if (tp >= ENDOF(table))
388 tp = &table[0];
389 c2 = tp->rewrite(condition, &result->ref);
390 blob_list_free(condition);
391
392 result->condition = c2;
393 result->then_clause = then_clause;
394 result->else_clause = else_clause;
395
396 stmt_variable_merge((stmt_ty *)result, then_clause);
397 if (else_clause)
398 stmt_variable_merge((stmt_ty *)result, else_clause);
399 trace(("}\n"));
400 return (stmt_ty *)result;
401 }
402