1 /* $Id: cunloop.c,v 1.10 2001/07/13 19:09:56 sandro Exp $ */
2
3 /*
4 * Copyright (c) 1997-2001 Sandro Sigala. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <ctype.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <err.h>
33
34 #include "config.h"
35 #include "tokens.h"
36
37 #define DEFAULT_PREFIX "l_"
38
39 /* From lexer.c */
40 #ifdef YYTEXT_POINTER
41 extern char *yytext;
42 #else
43 extern char yytext[];
44 #endif
45 extern char *token_buffer;
46 extern FILE *yyin;
47 extern int yylex(void);
48 extern void init_lex(void);
49 extern void done_lex(void);
50
51 static int lookahead;
52 static FILE *output_file;
53
54 static int opt_prefix; /* Indentifier prefix option. */
55 static char *opt_prefix_arg; /* Option argument. */
56
57 #define next_token() (lookahead = yylex())
58 #define outstr(s) fputs(s, output_file)
59 #define outch(c) fputc(c, output_file)
60
outtk(int tk)61 static void outtk(int tk)
62 {
63 switch (tk) {
64 case COMMENT:
65 case STRING:
66 case DIRECTIVE:
67 outstr(token_buffer);
68 break;
69 case KW_BREAK:
70 case KW_CONTINUE:
71 case KW_DO:
72 case KW_ELSE:
73 case KW_FOR:
74 case KW_IF:
75 case KW_SWITCH:
76 case KW_WHILE:
77 case KEYWORD:
78 case IDENTIFIER:
79 case CONSTANT:
80 case CHARACTER:
81 case OPERATOR:
82 outstr(yytext);
83 break;
84 default:
85 outch(tk);
86 }
87 }
88
89 static int label_counter;
90 static int label_continue;
91 static int label_break;
92
93 static int parse_until(int untiltk);
94
do_while(void)95 static void do_while(void)
96 {
97 int label_c = ++label_counter;
98 int label_b = ++label_counter;
99 int save_label_c = label_continue;
100 int save_label_b = label_break;
101
102 label_continue = label_c;
103 label_break = label_b;
104
105 while (lookahead != '(')
106 next_token();
107 next_token();
108
109 outstr("{\n");
110 fprintf(output_file, "%s%d:\n", opt_prefix_arg, label_c);
111 outstr("if (!(");
112 parse_until(UNTIL_CLOSEPAREN);
113 outstr(")\n");
114 fprintf(output_file, "goto %s%d;\n", opt_prefix_arg, label_b);
115 parse_until(UNTIL_ENDOFINSTR);
116 fprintf(output_file, "goto %s%d;\n", opt_prefix_arg, label_c);
117 fprintf(output_file, "%s%d:;\n", opt_prefix_arg, label_b);
118 outstr("}\n");
119
120 label_continue = save_label_c;
121 label_break = save_label_b;
122 }
123
do_do(void)124 static void do_do(void)
125 {
126 int label_c = ++label_counter;
127 int label_b = ++label_counter;
128 int save_label_c = label_continue;
129 int save_label_b = label_break;
130
131 label_continue = label_c;
132 label_break = label_b;
133
134 outstr("{\n");
135 fprintf(output_file, "%s%d:\n", opt_prefix_arg, label_c);
136 parse_until(UNTIL_ENDOFINSTR);
137
138 while (lookahead != '(')
139 next_token();
140 next_token();
141
142 outstr("if (");
143 parse_until(UNTIL_CLOSEPAREN);
144 fprintf(output_file, "\ngoto %s%d;\n", opt_prefix_arg, label_c);
145 fprintf(output_file, "%s%d:;\n", opt_prefix_arg, label_b);
146 outstr("}\n");
147
148 label_continue = save_label_c;
149 label_break = save_label_b;
150 }
151
do_for(void)152 static void do_for(void)
153 {
154 int label_l = ++label_counter;
155 int label_c = ++label_counter;
156 int label_b = ++label_counter;
157 int label_i = ++label_counter;
158 int save_label_c = label_continue;
159 int save_label_b = label_break;
160
161 label_continue = label_c;
162 label_break = label_b;
163
164 outstr("{\n");
165
166 while (lookahead != '(')
167 next_token();
168 next_token();
169
170 parse_until(UNTIL_ENDOFINSTR);
171
172 fprintf(output_file, "%s%d:\n", opt_prefix_arg, label_l);
173 outstr("if (!(");
174 if (!parse_until(UNTIL_ENDOFINSTR_NOECHO))
175 fprintf(output_file, "1");
176 outstr("))\n");
177 fprintf(output_file, "goto %s%d;\n", opt_prefix_arg, label_b);
178 fprintf(output_file, "goto %s%d;\n", opt_prefix_arg, label_i);
179 fprintf(output_file, "%s%d:", opt_prefix_arg, label_c);
180 parse_until(UNTIL_CLOSEPAREN_NOECHO);
181 outstr(";\n");
182 fprintf(output_file, "goto %s%d;\n", opt_prefix_arg, label_l);
183 fprintf(output_file, "%s%d:\n", opt_prefix_arg, label_i);
184 parse_until(UNTIL_ENDOFINSTR);
185 fprintf(output_file, "goto %s%d;\n", opt_prefix_arg, label_c);
186 fprintf(output_file, "%s%d:;\n", opt_prefix_arg, label_b);
187 outstr("}\n");
188
189 label_continue = save_label_c;
190 label_break = save_label_b;
191 }
192
do_switch(void)193 static void do_switch(void)
194 {
195 int save_label_b = label_break;
196
197 label_break = 0;
198
199 outstr("switch");
200 parse_until(UNTIL_ENDOFINSTR);
201
202 label_break = save_label_b;
203 }
204
do_if(void)205 static void do_if(void)
206 {
207 int label_l = ++label_counter;
208 int label_e;
209
210 while (lookahead != '(')
211 next_token();
212 next_token();
213
214 outstr("{\n");
215 outstr("if (!(");
216 parse_until(UNTIL_CLOSEPAREN);
217 outstr(")\n");
218 fprintf(output_file, "goto %s%d;\n", opt_prefix_arg, label_l);
219
220 parse_until(UNTIL_ENDOFINSTR);
221
222 while (isspace(lookahead))
223 next_token();
224 if (lookahead == KW_ELSE) {
225 label_e = ++label_counter;
226 fprintf(output_file, "goto %s%d;\n", opt_prefix_arg, label_e);
227 }
228 fprintf(output_file, "%s%d:;\n", opt_prefix_arg, label_l);
229 if (lookahead == KW_ELSE) {
230 next_token();
231 parse_until(UNTIL_ENDOFINSTR);
232 fprintf(output_file, "%s%d:;\n", opt_prefix_arg, label_e);
233 }
234
235 outstr("}\n");
236 }
237
238 /*
239 * The main parsing function.
240 */
parse_until(int untiltk)241 static int parse_until(int untiltk)
242 {
243 int nparens = 0, nblocks = 0;
244 int isexpr = 0;
245
246 if (untiltk == UNTIL_CLOSEPAREN || untiltk == UNTIL_CLOSEPAREN_NOECHO)
247 nparens++;
248
249 while (lookahead != 0)
250 switch (lookahead) {
251 case '(':
252 next_token();
253 isexpr = 1;
254 if (nblocks == 0)
255 nparens++;
256 outch('(');
257 break;
258 case ')':
259 next_token();
260 isexpr = 1;
261 if (nblocks == 0)
262 nparens--;
263 if (untiltk == UNTIL_CLOSEPAREN_NOECHO && nparens == 0)
264 return isexpr;
265 outch(')');
266 if (untiltk == UNTIL_CLOSEPAREN && nparens == 0)
267 return isexpr;
268 break;
269 case '{':
270 next_token();
271 isexpr = 1;
272 nblocks++;
273 outch('{');
274 break;
275 case '}':
276 next_token();
277 isexpr = 1;
278 nblocks--;
279 outch('}');
280 if (untiltk == UNTIL_ENDOFINSTR && nblocks == 0)
281 return isexpr;
282 break;
283 case ';':
284 next_token();
285 if (untiltk == UNTIL_ENDOFINSTR_NOECHO && nblocks == 0)
286 return isexpr;
287 outch(';');
288 if (untiltk == UNTIL_ENDOFINSTR && nblocks == 0)
289 return isexpr;
290 break;
291 case KW_DO:
292 next_token();
293 do_do();
294 if (untiltk == UNTIL_ENDOFINSTR && nblocks == 0)
295 return isexpr;
296 break;
297 case KW_WHILE:
298 next_token();
299 do_while();
300 if (untiltk == UNTIL_ENDOFINSTR && nblocks == 0)
301 return isexpr;
302 break;
303 case KW_FOR:
304 next_token();
305 do_for();
306 if (untiltk == UNTIL_ENDOFINSTR && nblocks == 0)
307 return isexpr;
308 break;
309 case KW_SWITCH:
310 next_token();
311 do_switch();
312 if (untiltk == UNTIL_ENDOFINSTR && nblocks == 0)
313 return isexpr;
314 break;
315 case KW_IF:
316 next_token();
317 do_if();
318 if (untiltk == UNTIL_ENDOFINSTR && nblocks == 0)
319 return isexpr;
320 break;
321 case KW_BREAK:
322 next_token();
323 if (label_break > 0)
324 fprintf(output_file, "goto %s%d", opt_prefix_arg, label_break);
325 else
326 outstr("break");
327 break;
328 case KW_CONTINUE:
329 next_token();
330 if (label_continue > 0)
331 fprintf(output_file, "goto %s%d", opt_prefix_arg, label_continue);
332 else
333 outstr("continue");
334 break;
335 default:
336 if (!isspace(lookahead))
337 isexpr = 1;
338 outtk(lookahead);
339 next_token();
340 }
341
342 return isexpr;
343 }
344
parse(void)345 static void parse(void)
346 {
347 next_token();
348 parse_until(0);
349 }
350
process_file(char * filename)351 static void process_file(char *filename)
352 {
353 if (filename != NULL && strcmp(filename, "-") != 0) {
354 if ((yyin = fopen(filename, "r")) == NULL)
355 err(1, "%s", filename);
356 } else
357 yyin = stdin;
358
359 init_lex();
360 label_continue = label_break = label_counter = 0;
361 parse();
362 done_lex();
363
364 if (yyin != stdin)
365 fclose(yyin);
366 }
367
368 /*
369 * Output the program syntax then exit.
370 */
usage(void)371 static void usage(void)
372 {
373 fprintf(stderr, "usage: cunroll [-V] [-o file] [-p prefix] [file ...]\n");
374 exit(1);
375 }
376
377 /*
378 * Used by the err() functions.
379 */
380 char *progname;
381
main(int argc,char ** argv)382 int main(int argc, char **argv)
383 {
384 int c;
385
386 progname = argv[0];
387 output_file = stdout;
388
389 while ((c = getopt(argc, argv, "Vo:p:")) != -1)
390 switch (c) {
391 case 'o':
392 if (output_file != stdout)
393 fclose(output_file);
394 if ((output_file = fopen(optarg, "w")) == NULL)
395 err(1, "%s", optarg);
396 break;
397 case 'p':
398 opt_prefix = 1;
399 opt_prefix_arg = optarg;
400 break;
401 case 'V':
402 fprintf(stderr, "%s\n", CUTILS_VERSION);
403 exit(0);
404 case '?':
405 default:
406 usage();
407 /* NOTREACHED */
408 }
409 argc -= optind;
410 argv += optind;
411
412 if (!opt_prefix)
413 opt_prefix_arg = DEFAULT_PREFIX;
414
415 if (argc < 1)
416 process_file(NULL);
417 else
418 while (*argv)
419 process_file(*argv++);
420
421 if (output_file != stdout)
422 fclose(output_file);
423
424 return 0;
425 }
426