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