1 /*
2 * cook - file construction tool
3 * Copyright (C) 1994, 1997, 2002, 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 %{
22
23 #include <common/ac/stdio.h>
24 #include <common/ac/stdlib.h>
25 #include <common/ac/string.h>
26
27 #include <common/trace.h>
28 #include <make2cook/vargram.h>
29 #include <make2cook/variable.h>
30
31 #ifdef DEBUG
32 #define YYDEBUG 1
33 #ifdef YYBISON
34 #define fprintf yytrace2
35 #else
36 #define printf trace_where(__FILE__, __LINE__), yytrace
37 #endif
38 extern int yydebug;
39 #endif
40
41
42 static string_ty *
patvar(string_ty * name,string_ty * from,string_ty * to)43 patvar(string_ty *name, string_ty *from, string_ty *to)
44 {
45 string_ty *tmp;
46 string_ty *result;
47 string_ty *s_from;
48 string_ty *s_to;
49
50 if (!strchr(from->str_text, '%'))
51 {
52 tmp = from;
53 if (tmp->str_length == 0)
54 from = str_from_c("%0%");
55 else if (tmp->str_text[0] == '.')
56 from = str_format("%%0%%%s", tmp->str_text);
57 else
58 from = str_format("%%0%%.%s", tmp->str_text);
59 str_free(tmp);
60 }
61 else
62 {
63 tmp = from;
64 s_from = str_from_c("%");
65 s_to = str_from_c("%0%");
66 from = str_substitute(s_from, s_to, tmp);
67 str_free(tmp);
68 }
69
70 if (!strchr(to->str_text, '%'))
71 {
72 tmp = to;
73 if (tmp->str_length == 0)
74 to = str_from_c("%0%");
75 else if (tmp->str_text[0] == '.')
76 to = str_format("%%0%%%s", tmp->str_text);
77 else
78 to = str_format("%%0%%.%s", tmp->str_text);
79 str_free(tmp);
80 }
81 else
82 {
83 tmp = to;
84 s_from = str_from_c("%");
85 s_to = str_from_c("%0%");
86 to = str_substitute(s_from, s_to, tmp);
87 str_free(tmp);
88 }
89
90 tmp = variable_mangle_lookup(name);
91 str_free(name);
92 result =
93 str_format
94 (
95 "[patsubst %s %s %s]",
96 from->str_text,
97 to->str_text,
98 tmp->str_text
99 );
100 str_free(tmp);
101 str_free(from);
102 str_free(to);
103 return result;
104 }
105
106
107 static string_ty *
function(string_ty * name,string_list_ty * args)108 function(string_ty *name, string_list_ty *args)
109 {
110 string_ty *s;
111 string_ty *result;
112 static string_ty *foreach;
113
114 if (!foreach)
115 foreach = str_from_c("foreach");
116 if (str_equal(name, foreach) && args->nstrings == 3)
117 {
118 string_ty *s_from;
119 string_ty *s_to;
120
121 /*
122 * The foreach function is treated specially. This is
123 * not an exact semantic mapping, but it is better than
124 * nothing.
125 */
126 variable_mangle_forget(args->string[0]);
127 s_from = str_format("[%s]", args->string[0]->str_text);
128 s_to = str_from_c("%");
129 s = str_substitute(s_from, s_to, args->string[2]);
130 result =
131 str_format
132 (
133 "[fromto %% %s %s]",
134 s->str_text,
135 args->string[1]->str_text
136 );
137 str_free(s);
138 str_free(s_from);
139 str_free(s_to);
140 }
141 else
142 {
143 /*
144 * Construct the function invokation. There are
145 * make-equivalents for all the function names built
146 * into cook, so there is no need to translate the
147 * function name.
148 */
149 s = wl2str(args, 0, args->nstrings - 1, (char *)0);
150 string_list_destructor(args);
151 result = str_format("[%s %s]", name->str_text, s->str_text);
152 str_free(s);
153 }
154 str_free(name);
155 string_list_destructor(args);
156 trace(("result = \"%s\";\n", result->str_text));
157 return result;
158 }
159
160 %}
161
162 %token COLON
163 %token COMMA
164 %token DOLLAR
165 %token EQU
166 %token LB
167 %token LP
168 %token PLAIN
169 %token RB
170 %token RP
171 %token SPACE
172
173 %union
174 {
175 string_ty *lv_string;
176 string_list_ty lv_list;
177 }
178
179 %type <lv_string> arg
180 %type <lv_string> argc
181 %type <lv_list> csl
182 %type <lv_string> gizzards
183 %type <lv_string> name
184 %type <lv_string> namec
185 %type <lv_string> oname
186 %type <lv_string> ossl
187 %type <lv_string> parens
188 %type <lv_string> PLAIN
189 %type <lv_list> ssl
190 %type <lv_string> var
191
192 %%
193
194 main
195 : dbg
196 { variable_mangle_result(str_from_c("")); }
197 | dbg strings
198 | error
199 { variable_mangle_result(str_from_c("")); }
200 ;
201
202 dbg
203 : /* empty */
204 {
205 #if YYDEBUG
206 yydebug = trace_pretest_;
207 #endif
208 }
209 ;
210
211 strings
212 : string
213 | strings string
214 | strings SPACE
215 ;
216
217 string
218 : gizzards
219 { variable_mangle_result($1); }
220 | gizzards LP ssl RP
221 {
222 size_t j;
223
224 for (j = 0; j < $3.nstrings; ++j)
225 {
226 variable_mangle_result
227 (
228 str_format("%s(%s)", $1->str_text, $3.string[j]->str_text)
229 );
230 }
231 str_free($1);
232 string_list_destructor(&$3);
233 }
234 ;
235
236 gizzards
237 : var
238 { $$ = $1; }
239 | gizzards var
240 {
241 $$ = str_catenate($1, $2);
242 str_free($1);
243 str_free($2);
244 }
245 ;
246
247 var
248 : DOLLAR DOLLAR
249 { $$ = str_from_c("$"); }
250 | DOLLAR PLAIN
251 {
252 $$ = variable_mangle_lookup($2);
253 str_free($2);
254 }
255 | DOLLAR LP name RP
256 {
257 $$ = variable_mangle_lookup($3);
258 str_free($3);
259 }
260 | DOLLAR LB name RB
261 {
262 $$ = variable_mangle_lookup($3);
263 str_free($3);
264 }
265 | DOLLAR LP name COLON oname EQU oname RP
266 { $$ = patvar($3, $5, $7); }
267 | DOLLAR LB name COLON oname EQU oname RB
268 { $$ = patvar($3, $5, $7); }
269 | DOLLAR LP name SPACE csl RP
270 { $$ = function($3, &$5); }
271 | DOLLAR LB name SPACE csl RB
272 { $$ = function($3, &$5); }
273 | PLAIN
274 { $$ = $1; }
275 ;
276
277 name
278 : namec
279 { $$ = $1; }
280 | name namec
281 {
282 $$ = str_catenate($1, $2);
283 str_free($1);
284 str_free($2);
285 }
286 ;
287
288 oname
289 : /* empty */
290 { $$ = str_from_c(""); }
291 | oname namec
292 {
293 $$ = str_catenate($1, $2);
294 str_free($1);
295 str_free($2);
296 }
297 ;
298
299 namec
300 : var
301 { $$ = $1; }
302 | COMMA
303 { $$ = str_from_c(","); }
304 ;
305
306 csl
307 : ossl
308 {
309 string_list_constructor(&$$);
310 string_list_append(&$$, $1);
311 str_free($1);
312 }
313 | csl comma ossl
314 {
315 $$ = $1;
316 string_list_append(&$$, $3);
317 str_free($3);
318 }
319 ;
320
321 ossl
322 : /* empty */
323 {
324 /*
325 * Guess that empty space separated lists were
326 * really a single space for substitution.
327 * E.g. $(subst $(\n), ,$(list))
328 */
329 $$ = str_from_c("\" \"");
330 }
331 | ssl
332 {
333 $$ = wl2str(&$1, 0, $1.nstrings - 1, (char *)0);
334 string_list_destructor(&$1);
335 }
336 | ssl SPACE
337 {
338 $$ = wl2str(&$1, 0, $1.nstrings - 1, (char *)0);
339 string_list_destructor(&$1);
340 }
341 ;
342
343 ssl
344 : arg
345 {
346 string_list_constructor(&$$);
347 string_list_append(&$$, $1);
348 str_free($1);
349 }
350 | ssl SPACE arg
351 {
352 $$ = $1;
353 string_list_append(&$$, $3);
354 str_free($3);
355 }
356 ;
357
358 arg
359 : argc
360 { $$ = $1; }
361 | arg argc
362 {
363 $$ = str_catenate($1, $2);
364 str_free($1);
365 str_free($2);
366 }
367 ;
368
369 argc
370 : PLAIN
371 { $$ = $1; }
372 | EQU
373 { $$ = str_from_c("\\="); }
374 | COLON
375 { $$ = str_from_c("\\:"); }
376 | var
377 { $$ = $1; }
378 | parens
379 { $$ = $1; }
380 | error
381 { $$ = str_from_c(""); }
382 ;
383
384 parens
385 : LP csl RP
386 {
387 string_ty *s;
388
389 s = wl2str(&$2, 0, $2.nstrings, ",");
390 string_list_destructor(&$2);
391 $$ = str_format("(%s)", s->str_text);
392 str_free(s);
393 }
394 ;
395
396 comma
397 : COMMA
398 | comma SPACE
399 ;
400