996
|
1 /****************************************************************************
|
|
2
|
|
3 NAME
|
|
4 perpet.c -- main routine for C-INTERCAL compiler.
|
|
5
|
|
6 DESCRIPTION
|
|
7 This is where all the dirty work begins and ends.
|
|
8
|
|
9 LICENSE TERMS
|
|
10 Copyright (C) 1996 Eric S. Raymond
|
|
11
|
|
12 This program is free software; you can redistribute it and/or modify
|
|
13 it under the terms of the GNU General Public License as published by
|
|
14 the Free Software Foundation; either version 2 of the License, or
|
|
15 (at your option) any later version.
|
|
16
|
|
17 This program is distributed in the hope that it will be useful,
|
|
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
20 GNU General Public License for more details.
|
|
21
|
|
22 You should have received a copy of the GNU General Public License
|
|
23 along with this program; if not, write to the Free Software
|
|
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
25
|
|
26 ****************************************************************************/
|
|
27 /*LINTLIBRARY */
|
|
28 #include "config.h" /* AIS: Generated by autoconf */
|
|
29 #include <stdio.h>
|
|
30 #include <stdlib.h>
|
|
31 #ifdef HAVE_UNISTD_H
|
|
32 # include <unistd.h>
|
|
33 #endif
|
|
34 #include <string.h>
|
|
35 #include <signal.h>
|
|
36 #include <time.h>
|
|
37 #include <assert.h>
|
|
38 #include "ick.h"
|
|
39 #include "feh.h"
|
|
40 #include "parser.h"
|
|
41 #include "sizes.h"
|
|
42 #include "ick_lose.h"
|
|
43 #include "uncommon.h"
|
|
44
|
|
45 /* AIS: split ICKDATADIR from ICKLIBDIR */
|
|
46 #ifndef ICKINCLUDEDIR
|
|
47 #define ICKINCLUDEDIR "/usr/local/include"
|
|
48 #endif
|
|
49 #ifndef ICKDATADIR
|
|
50 #define ICKDATADIR "/usr/local/share"
|
|
51 #endif
|
|
52 #ifndef ICKLIBDIR
|
|
53 #define ICKLIBDIR "/usr/local/lib"
|
|
54 #endif
|
|
55 #ifndef ICKBINDIR
|
|
56 #define ICKBINDIR "/usr/local/bin"
|
|
57 #endif
|
|
58 #ifndef CC
|
|
59 #define CC "gcc"
|
|
60 #endif
|
|
61
|
|
62 #define ARGSTRING "abcdefghlmoptuvwxyCEFHOPUYX@"
|
|
63
|
|
64 #define ICK_SYSTEM(x) do{if(showsystem)fprintf(stderr,"%s\n",x); \
|
|
65 (void) system(x);}while(0)
|
|
66
|
|
67 #ifdef USE_YYRESTART
|
|
68 /* function supplied by lex */
|
|
69 extern void yyrestart(FILE*);
|
|
70
|
|
71 #endif /* USE_YYRESTART */
|
|
72
|
|
73 /* function created by yacc */
|
|
74 extern int yyparse(void);
|
|
75
|
|
76 int yydebug;
|
|
77
|
|
78 /* compilation options */
|
|
79 ick_bool compile_only; /* just compile into C, don't run the linker */
|
|
80 ick_bool ick_traditional; /* insist on strict INTERCAL-72 conformance */
|
|
81 ick_bool nocompilerbug; /* disable error IE774 */
|
|
82 int yukdebug; /* AIS: Use the yuk debugger. */
|
|
83 int yukprofile; /* AIS: Use the yuk profiler. */
|
|
84 int useprintflow=0; /* AIS: Add +printflow support. */
|
|
85 extern int ick_coreonerr; /* AIS: Dump core on IE778. (defined in ick_lose.c) */
|
|
86 int multithread; /* AIS: Allow multithreading and backtracking. */
|
|
87 int variableconstants; /* AIS: Allow anything on the left of an assignment. */
|
|
88 int createsused=0; /* AIS: Allow the use of CREATE. */
|
|
89 int useickec; /* AIS: Link together INTERCAL and C. */
|
|
90 static int nosyslib=0; /* AIS: Don't link syslib under any circumstances. */
|
|
91 static int showsystem=0;/* AIS: Show the command lines in system() calls */
|
|
92 int cdebug; /* AIS: Pass -g to our C compiler, and leave C code. */
|
|
93 int optdebug; /* AIS: Debug the optimizer. Value is 0, 1, 2, or 3. */
|
|
94 int flowoptimize; /* AIS: Do flow optimizations (in INTERCAL!). */
|
|
95 int coopt; /* AIS: The constant-output optimization. This should
|
|
96 mean that INTERCAL will beat any other language at
|
|
97 many benchmark programs (!) */
|
|
98 extern int ick_printfopens; /* AIS: Print messages whenever attempting to open a
|
|
99 file: from uncommon.c */
|
|
100 extern int ick_checkforbugs;/* AIS: Try to find possible bugs in the source code */
|
|
101 int pickcompile; /* AIS: Compile for PIC? */
|
|
102 /*@-exportlocal@*/ /* AIS: relevant to the lexer */
|
|
103 int clclex; /* AIS: 1 means use CLC-INTERCAL meanings for @, ? */
|
|
104 /*@=exportlocal@*/
|
|
105 int ick_clcsemantics; /* AIS: CLC semantics for I/O, abstaining GIVE UP, &c*/
|
|
106 static int outtostdout; /* AIS: Output on stdout rather than the output file */
|
|
107
|
|
108 /* AIS: Autodetected compilation options */
|
|
109 int compucomecount=0; /* Computed COME FROM count */
|
|
110 int compucomesused=0; /* Are computed COME FROMs used? */
|
|
111 int gerucomesused=0; /* Is COME FROM gerund used? */
|
|
112 int nextfromsused=0; /* Is NEXT FROM used? */
|
|
113 int opoverused=0; /* Is operand overloading used? */
|
|
114 /*@null@*/ node* firstslat=0; /* The first slat expression in the program */
|
|
115 /*@null@*/ node* prevslat=0; /* The last slat expression used so far */
|
|
116
|
|
117 static ick_bool dooptimize; /* do optimizations? (controlled by -O) */
|
|
118 static ick_bool ick_clockface; /* set up output to do IIII for IV */
|
|
119
|
|
120 #define SKELETON "ick-wrap.c"
|
|
121 #define PSKELETON "pickwrap.c"
|
|
122 #define SYSLIB "syslib"
|
|
123
|
|
124 /* numeric base defaults, exported to other files */
|
|
125
|
|
126 #define DEFAULT_BASE 2
|
|
127 #define DEFAULT_SMALL_DIGITS 16
|
|
128 #define DEFAULT_LARGE_DIGITS 32
|
|
129 #define DEFAULT_MAX_SMALL 0xffffL
|
|
130 #define DEFAULT_MAX_LARGE 0xffffffffL
|
|
131
|
|
132 int ick_Base;
|
|
133 int ick_Small_digits;
|
|
134 int ick_Large_digits;
|
|
135 unsigned int ick_Max_small;
|
|
136 unsigned int ick_Max_large;
|
|
137
|
|
138 int ick_lineno; /* after yyparse, this is the total number of statements */
|
|
139
|
|
140 /* currently supported numeric bases, not exported */
|
|
141 static const int maxbase = 7;
|
|
142 static const int smallsizes[8] = {0, 0, 16, 10, 8, 6, 6, 5};
|
|
143 static const unsigned int maxsmalls[8] =
|
|
144 {0, 0, 65535, 59048, 65535, 15624, 46655, 16806};
|
|
145
|
|
146 /*@observer@*/ static const char *compiler;
|
|
147
|
|
148 atom *oblist = NULL, *obdex;
|
|
149 int obcount = 0;
|
|
150 int nonespots, ntwospots, ntails, nhybrids;
|
|
151 int nmeshes; /* AIS */
|
|
152
|
|
153 tuple *tuples = NULL;
|
|
154 int tuplecount = 0;
|
|
155
|
|
156 tuple *optuple = NULL; /* AIS: Tuple being optimized */
|
|
157
|
|
158 extern const assoc varstores[]; /* AIS: Need to know this for PIC compilation */
|
|
159
|
|
160 #ifndef HAVE_UNISTD_H
|
|
161 /* AIS: We don't have unistd.h, so we can't use getopt. Write our own version
|
|
162 that's less general but good enough. */
|
|
163 int optind=1;
|
|
164 int optopt;
|
|
165 int getopt(int argc, char * const *argv, const char *options)
|
|
166 {
|
|
167 if(optind>argc) return EOF; /* Out of command line */
|
|
168 if(!argv[optind]) return EOF; /* Out of command line */
|
|
169 while(!strcmp(argv[optind],"-"))
|
|
170 {
|
|
171 optind++; /* Go to ick_next argument */
|
|
172 if(!argv[optind]) return EOF;
|
|
173 }
|
|
174 if(*(argv[optind])!='-') return EOF; /* this arg is not an option */
|
|
175 optopt=argv[optind][1];
|
|
176 memmove(argv[optind]+1,argv[optind]+2,strlen(argv[optind]+1));
|
|
177 if(optopt=='-') {optind++; return EOF;} /* -- means end of options */
|
|
178 if(strchr(options, optopt)) return optopt; /* valid option */
|
|
179 return '?'; /* invalid option */
|
|
180 }
|
|
181 #endif
|
|
182
|
|
183 static int myfgetc(FILE* in)
|
|
184 {
|
|
185 char c;
|
|
186 (void) fread(&c,1,1,in);
|
|
187 if(feof(in)) return EOF;
|
|
188 return (int)c;
|
|
189 }
|
|
190
|
|
191 static RETSIGTYPE abend(int signim)
|
|
192 {
|
|
193 /*@-noeffect@*/ (void) signim; /*@=noeffect@*/
|
|
194 ick_lose(IE778, iyylineno, (const char *)NULL);
|
|
195 }
|
|
196 static void print_usage(const char *prog, const char *options)
|
|
197 {
|
|
198 fprintf(stderr,"Usage: %s [-%s] <file> [<file> ...]\n",prog,options);
|
|
199 fprintf(stderr,"\t-b\t:reduce the probability of E774 to zero\n");
|
|
200 fprintf(stderr,"\t-c\t:compile INTERCAL to C, but don't compile C\n");
|
|
201 fprintf(stderr,"\t-d\t:print yacc debugging information (implies -c)\n");
|
|
202 fprintf(stderr,"\t-e\t:link together INTERCAL and C files as one program\n");
|
|
203 fprintf(stderr,"\t\t (without this option, all INTERCAL files produce\n");
|
|
204 fprintf(stderr,"\t\t separate output files; with it, the first file given\n");
|
|
205 fprintf(stderr,"\t\t must be the only INTERCAL file) (prevents -mypPf)\n");
|
|
206 fprintf(stderr,"\t-E\t:never include the system library (prevents -P)\n");
|
|
207 fprintf(stderr,"\t-t\t:traditional mode, accept only INTERCAL-72\n");
|
|
208 fprintf(stderr,"\t-C\t:clockface output (e.g. use IIII instead of IV)\n");
|
|
209 fprintf(stderr,"\t-O\t:optimize expresssions in generated code\n");
|
|
210 /* AIS: Changed the help message for the previous line (because the
|
|
211 function of -O has changed). I wrote the next group of options. */
|
|
212 fprintf(stderr,"\t-f\t:optimize control flow in generated code "
|
|
213 "(prevents -yp)\n");
|
|
214 #ifdef HAVE_PROG_SH
|
|
215 # ifdef HAVE_SYS_INTERPRETER
|
|
216 fprintf(stderr,"\t-F\t:optimize everything in generated code for\n"
|
|
217 "\t\t speed, regardless of how slow the compiler becomes or how\n"
|
|
218 "\t\t large the object file becomes. Implies -fO, "
|
|
219 "prevents -cdeghpyH\n");
|
|
220 # else
|
|
221 fprintf(stderr,"\t-F\t:unsupported on computers without #! support\n");
|
|
222 # endif
|
|
223 #else
|
|
224 fprintf(stderr,"\t-F\t:unsupported on computers without sh or bash\n");
|
|
225 #endif
|
|
226 fprintf(stderr,"\t-h\t:print optimizer debugging information "
|
|
227 "(implies -cO)\n");
|
|
228 fprintf(stderr,"\t-H\t:print verbose optimizer debugging information "
|
|
229 "(implies -cO)\n");
|
|
230 fprintf(stderr,"\t-hH\t:print optimizer debugging information in a\n"
|
|
231 "\t\t different form (implies -cO)\n");
|
|
232 #ifdef HAVE_UNISTD_H
|
|
233 fprintf(stderr,"\t-y\t:run the yuk debugger on the code (prevents -fme)\n");
|
|
234 fprintf(stderr,"\t-p\t:run the yuk profiler on the code (prevents -fme)\n");
|
|
235 #else
|
|
236 fprintf(stderr,"\t-y\t:unsupported on computers without <unistd.h>\n");
|
|
237 fprintf(stderr,"\t-p\t:unsupported on computers without <unistd.h>\n");
|
|
238 #endif
|
|
239 fprintf(stderr,"\t-w\t:add support for the +printflow option\n");
|
|
240 fprintf(stderr,"\t-m\t:allow multithreading and backtracking\n"
|
|
241 "\t\t (prevents -ype, implies -w)\n");
|
|
242 fprintf(stderr,"\t-a\t:allow the use of CREATE (prevents -P)\n");
|
|
243 fprintf(stderr,"\t-v\t:allow anything on the left of an assignment. This "
|
|
244 "is required\n\t\t if you want operand overloading to change "
|
|
245 "meshes.\n\t\t (prevents -fFOP)\n");
|
|
246 fprintf(stderr,"\t-P\t:compile PIC-INTERCAL rather than INTERCAL\n");
|
|
247 fprintf(stderr,"\t\t (prevents -amFvxeE, implies -cfO)\n");
|
|
248 fprintf(stderr,"\t-o\t:output to stdout rather than .c (implies -c)\n");
|
|
249 fprintf(stderr,"\t-X\t:interpret ambiguous syntax as Princeton not\n"
|
|
250 "\t\t Atari (i.e. CLC-INTERCAL not C-INTERCAL)\n");
|
|
251 fprintf(stderr,"\t-x\t:use CLC-INTERCAL rules for I/O and abstaining\n"
|
|
252 "\t\t from a GIVE UP by label (prevents -P)\n");
|
|
253 fprintf(stderr,"\t-u\t:print a message whenever the compiler tries to "
|
|
254 "open a file\n");
|
|
255 fprintf(stderr,"\t-U\t:dump core on IE778 after printing an error\n");
|
|
256 fprintf(stderr,"\t-Y\t:display the command line used whenever an external\n"
|
|
257 "\t\t program is invoked\n");
|
|
258 fprintf(stderr,"\t-g\t:compile to both debuggable executable and C\n");
|
|
259 fprintf(stderr,"\t-l\t:attempt to report likely bugs "
|
|
260 "and nonportabilities (implies -O)\n");
|
|
261 /* AIS: End of options I added. */
|
|
262 fprintf(stderr,"\t<file>\tINTERCAL source file (use extension .i\n");
|
|
263 fprintf(stderr,"\t\tfor base 2 or .3i, etc., for base 3, etc.).\n");
|
|
264 }
|
|
265
|
|
266 #if __DJGPP__
|
|
267 /* AIS: Determine whether an environment variable exists (this is used to
|
|
268 find a temp directory) */
|
|
269 static int isenv(char* e)
|
|
270 {
|
|
271 char* x=getenv(e);
|
|
272 return x != NULL && *x != '\0';
|
|
273 }
|
|
274 #endif
|
|
275
|
|
276 extern int optind; /* set by getopt */
|
|
277
|
|
278 /**
|
|
279 * This parses command line options.
|
|
280 * @param argc What do you think?
|
|
281 * @param argv Likewise.
|
|
282 * @note May (directly) call ick_lose() with IE111 and IE256.
|
|
283 */
|
|
284 static void parse_options(int argc, char *argv[])
|
|
285 {
|
|
286 int c;
|
|
287
|
|
288 /* getopt is POSIX, and I provide my own version if the POSIX version
|
|
289 isn't found, so the unrecog warning is a false positive. */
|
|
290 /*@-unrecog@*/
|
|
291 while ((c = getopt(argc, argv, ARGSTRING)) != EOF)
|
|
292 /*@=unrecog@*/
|
|
293 {
|
|
294 switch (c)
|
|
295 {
|
|
296 case 'b':
|
|
297 nocompilerbug = ick_TRUE;
|
|
298 break;
|
|
299
|
|
300 case 'c':
|
|
301 compile_only = ick_TRUE;
|
|
302 /* AIS */ coopt = ick_FALSE;
|
|
303 break;
|
|
304
|
|
305 case 'o': /* AIS */
|
|
306 compile_only = ick_TRUE;
|
|
307 outtostdout = ick_TRUE;
|
|
308 coopt = ick_FALSE;
|
|
309 break;
|
|
310
|
|
311 case 'd':
|
|
312 yydebug = compile_only = ick_TRUE;
|
|
313 /* AIS */ coopt = ick_FALSE;
|
|
314 break;
|
|
315
|
|
316 case 'e': /* AIS */
|
|
317 useickec = ick_TRUE;
|
|
318 multithread = pickcompile = coopt = yukdebug = yukprofile = ick_FALSE;
|
|
319 break;
|
|
320
|
|
321 case 'E': /* AIS */
|
|
322 nosyslib = ick_TRUE;
|
|
323 pickcompile = ick_FALSE;
|
|
324 break;
|
|
325
|
|
326 case 'C':
|
|
327 ick_clockface = ick_TRUE;
|
|
328 break;
|
|
329
|
|
330 case 't':
|
|
331 ick_traditional = ick_TRUE;
|
|
332 if(multithread) ick_lose(IE111, 1, (const char*) NULL); /* AIS */
|
|
333 if(pickcompile) ick_lose(IE111, 1, (const char*) NULL); /* AIS */
|
|
334 break;
|
|
335
|
|
336 case 'O':
|
|
337 dooptimize = ick_TRUE;
|
|
338 variableconstants = ick_FALSE; /* AIS */
|
|
339 break;
|
|
340
|
|
341 case 'f': /* By AIS */
|
|
342 flowoptimize = ick_TRUE;
|
|
343 yukdebug = yukprofile = ick_FALSE;
|
|
344 variableconstants = ick_FALSE;
|
|
345 break;
|
|
346
|
|
347 case 'F': /* By AIS */
|
|
348 coopt = flowoptimize = dooptimize = ick_TRUE;
|
|
349 variableconstants = useickec = ick_FALSE;
|
|
350 yukdebug = yukprofile = yydebug = outtostdout =
|
|
351 compile_only = cdebug = ick_FALSE;
|
|
352 if(pickcompile) ick_lose(IE256, 1, (const char*) NULL);
|
|
353 break;
|
|
354
|
|
355 case 'h': /* By AIS */
|
|
356 optdebug|=1;
|
|
357 compile_only=dooptimize=ick_TRUE;
|
|
358 coopt=ick_FALSE;
|
|
359 break;
|
|
360
|
|
361 case 'H': /* By AIS */
|
|
362 optdebug|=2;
|
|
363 compile_only=dooptimize=ick_TRUE;
|
|
364 coopt=ick_FALSE;
|
|
365 break;
|
|
366
|
|
367 case 'y': /* By AIS */
|
|
368 #ifdef HAVE_UNISTD_H
|
|
369 yukdebug=ick_TRUE;
|
|
370 multithread=flowoptimize=coopt=useickec=ick_FALSE;
|
|
371 #endif
|
|
372 break;
|
|
373
|
|
374 case 'p': /* By AIS */
|
|
375 #ifdef HAVE_UNISTD_H
|
|
376 yukprofile=ick_TRUE;
|
|
377 multithread=flowoptimize=coopt=useickec=ick_FALSE;
|
|
378 #endif
|
|
379 break;
|
|
380
|
|
381 case 'w': /* By AIS */
|
|
382 useprintflow = ick_TRUE;
|
|
383 break;
|
|
384
|
|
385 case 'm': /* By AIS */
|
|
386 multithread=ick_TRUE;
|
|
387 yukprofile=ick_FALSE;
|
|
388 yukdebug=ick_FALSE;
|
|
389 useickec=ick_FALSE;
|
|
390 if(ick_traditional) ick_lose(IE111, 1, (const char*) NULL);
|
|
391 break;
|
|
392
|
|
393 case 'a': /* By AIS */
|
|
394 createsused=ick_TRUE;
|
|
395 pickcompile=ick_FALSE;
|
|
396 break;
|
|
397
|
|
398 case 'v': /* By AIS */
|
|
399 variableconstants=ick_TRUE;
|
|
400 dooptimize=ick_FALSE;
|
|
401 flowoptimize=ick_FALSE;
|
|
402 coopt=ick_FALSE;
|
|
403 pickcompile=ick_FALSE;
|
|
404 break;
|
|
405
|
|
406 case 'l': /* By AIS */
|
|
407 ick_checkforbugs=ick_TRUE;
|
|
408 dooptimize=ick_TRUE;
|
|
409 break;
|
|
410
|
|
411 case 'U': /* By AIS */
|
|
412 ick_coreonerr=ick_TRUE;
|
|
413 break;
|
|
414
|
|
415 case 'u': /* By AIS */
|
|
416 ick_printfopens=ick_TRUE;
|
|
417 break;
|
|
418
|
|
419 case 'Y': /* By AIS */
|
|
420 showsystem=ick_TRUE;
|
|
421 break;
|
|
422
|
|
423 case 'P': /* By AIS */
|
|
424 pickcompile=ick_TRUE;
|
|
425 multithread=coopt=variableconstants=createsused=ick_FALSE;
|
|
426 ick_clcsemantics=useickec=nosyslib=ick_FALSE;
|
|
427 compile_only=ick_TRUE;
|
|
428 dooptimize=flowoptimize=ick_TRUE; /* needed for PICs */
|
|
429 break;
|
|
430
|
|
431 case 'X': /* By AIS */
|
|
432 clclex=ick_TRUE;
|
|
433 break;
|
|
434
|
|
435 case 'x': /* By AIS */
|
|
436 ick_clcsemantics=ick_TRUE;
|
|
437 pickcompile=ick_FALSE;
|
|
438 break;
|
|
439
|
|
440 case 'g': /* By AIS */
|
|
441 cdebug=ick_TRUE;
|
|
442 coopt=ick_FALSE;
|
|
443 break;
|
|
444
|
|
445 case '?':
|
|
446 default:
|
|
447 case '@':
|
|
448 print_usage(argv[0], ARGSTRING);
|
|
449 exit(EXIT_FAILURE);
|
|
450 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
451 }
|
|
452 }
|
|
453 }
|
|
454
|
|
455
|
|
456 /**
|
|
457 * This code handles archives (for -e).
|
|
458 * @param libbuf Pointer to a buffer to which extra files to link in prelink()
|
|
459 * will be added. Need to be initialized up to the first zero byte.
|
|
460 * @param libbuf_size Size of the buffer libbuf.
|
|
461 * @param library The cmd line argument used for the library (but without the
|
|
462 * extension).
|
|
463 */
|
|
464 static void handle_archive(char *libbuf, size_t libbuf_size,
|
|
465 /*@observer@*/ const char* library)
|
|
466 {
|
|
467 /* AIS: request for a library. Given a filename of the form
|
|
468 libwhatever.a, it adds -lwhatever to libbuf (that's with
|
|
469 a preceding space). If the filename doesn't start with lib,
|
|
470 it instead adds a space and the filename to libbuf. */
|
|
471 if(library[0]=='l'&&library[1]=='i'&&
|
|
472 library[2]=='b')
|
|
473 ick_snprintf_or_die(libbuf+strlen(libbuf),libbuf_size - strlen(libbuf),
|
|
474 " -l%s",library+3);
|
|
475 else
|
|
476 ick_snprintf_or_die(libbuf+strlen(libbuf),libbuf_size - strlen(libbuf),
|
|
477 " %s.a",library);
|
|
478 }
|
|
479
|
|
480
|
|
481 /**
|
|
482 * This handles Befunge 98 (for -e).
|
|
483 * @param libbuf Pointer to a buffer to which extra files to link in prelink()
|
|
484 * will be added. Need to be initialized up to the first zero byte.
|
|
485 * @param libbuf_size Size of the buffer libbuf.
|
|
486 * @param libdir The ick library directory.
|
|
487 * @param argv0 Should be argv[0], which wasn't modified.
|
|
488 * @param filename The file name of the Befunge file (but without the extension).
|
|
489 * @note May (directly) call ick_lose() with IE888 and IE899.
|
|
490 */
|
|
491 static void handle_befunge98(char *libbuf, size_t libbuf_size,
|
|
492 /*@observer@*/ const char* libdir,
|
|
493 /*@observer@*/ const char* argv0,
|
|
494 /*@observer@*/ const char* filename)
|
|
495 {
|
|
496 /* AIS: Compile the .b98 file into a .cio so that it can be used
|
|
497 later, and include the necessary libraries to use it, or error
|
|
498 if the libraries aren't installed yet. I use a somewhat dubious
|
|
499 trick here: the .b98 file's .cio, and the necessary libraries,
|
|
500 are added in the libraries section of the command line, whereas
|
|
501 the space on the command line where the .b98 file was is used
|
|
502 for the expansion library ecto_b98. This is because ecto_b98
|
|
503 requires preprocessing/prelinking/interprocessing or whatever
|
|
504 you want to call it, whereas unlike for other .cios, the .cio
|
|
505 produced from the Befunge file doesn't.
|
|
506 */
|
|
507
|
|
508 #define MARKERMAX 128
|
|
509
|
|
510 FILE* of;
|
|
511 int x,y,jlb;
|
|
512 char outputfilename[BUFSIZ];
|
|
513 int markerposns[MARKERMAX][2];
|
|
514 int markercount=0;
|
|
515
|
|
516 /* Error if libick_ecto_b98.a is missing. It might be, and not
|
|
517 just due to installation problems. */
|
|
518 if(!ick_findandtestopen("libick_ecto_b98.a",libdir,"rb",argv0))
|
|
519 ick_lose(IE899,-1,(const char *)NULL);
|
|
520
|
|
521 /* Compile the .b98 file into a .cio. It's open on stdin right now,
|
|
522 so we just need to handle the output side of things. */
|
|
523
|
|
524 ick_snprintf_or_die(outputfilename, sizeof outputfilename, "%s.cio", filename);
|
|
525
|
|
526 if(!((of = ick_debfopen(outputfilename,"w"))))
|
|
527 ick_lose(IE888,-1,(const char *)NULL);
|
|
528
|
|
529 fprintf(of,"const unsigned char* ick_iffi_befungeString=\n\"");
|
|
530
|
|
531 x=0; y=0; jlb=0;
|
|
532 for(;;)
|
|
533 {
|
|
534 int c=getchar();
|
|
535 if(c==EOF) break;
|
|
536 if(c==0xB7)
|
|
537 {
|
|
538 /* Middot (0xB7) has special handling. */
|
|
539 c='M';
|
|
540 markerposns[markercount][0]=x;
|
|
541 markerposns[markercount++][1]=y;
|
|
542 }
|
|
543 if(c=='\r') {jlb = 1; x=0; y++; c='\n';}
|
|
544 else if(c=='\n' && jlb) {jlb = 0; continue;}
|
|
545 else if(c=='\n') {x=0; y++; jlb = 0;}
|
|
546 else x++;
|
|
547 fprintf(of,"\\x%x",(unsigned int)c);
|
|
548 if(!x) fprintf(of,"\"\n\"");
|
|
549 }
|
|
550 fprintf(of,"\";\n\nint ick_iffi_markercount=%d;\n"
|
|
551 "long long ick_iffi_markerposns[][2]={\n",markercount);
|
|
552 if(!markercount) fprintf(of,"{0,0}\n");
|
|
553 while(markercount--) fprintf(of,"{%d,%d},\n",
|
|
554 markerposns[markercount][0],
|
|
555 markerposns[markercount][1]);
|
|
556 fprintf(of,"};\n");
|
|
557
|
|
558 (void) fclose(of);
|
|
559
|
|
560 /* Put the libraries and .cio file in the command line. */
|
|
561 ick_snprintf_or_die(libbuf+strlen(libbuf),libbuf_size - strlen(libbuf),
|
|
562 " %s.cio -lick_ecto_b98 -lm -lncurses", filename);
|
|
563 }
|
|
564
|
|
565
|
|
566 /**
|
|
567 * This computes what type the INTERCAL source file is.
|
|
568 * It will change various globals.
|
|
569 * @param chp A pointer to the first letter of the extension of the file. Note
|
|
570 * that it won't be changed, but can't be const char* due to being
|
|
571 * passed as the second parameter to strtol() as well.
|
|
572 * @note May (directly) call ick_lose() with IE111, IE256 and IE998.
|
|
573 */
|
|
574 static void find_intercal_base(char* chp)
|
|
575 {
|
|
576 /* wwp: reset the base variables to defaults, because if the */
|
|
577 /* sourcefile has extension .i they will not be reset in the */
|
|
578 /* following chunk of code. but i don't want to modify the */
|
|
579 /* following chunk of code because i think it is very clever; */
|
|
580 /* grabs the base on the first pass, then validates the rest */
|
|
581 /* of the extension on the second. */
|
|
582 ick_Base = DEFAULT_BASE;
|
|
583 ick_Small_digits = DEFAULT_SMALL_DIGITS;
|
|
584 ick_Large_digits = DEFAULT_LARGE_DIGITS;
|
|
585 ick_Max_small = (unsigned)DEFAULT_MAX_SMALL;
|
|
586 ick_Max_large = (unsigned)DEFAULT_MAX_LARGE;
|
|
587
|
|
588 /* determine the file type from the extension */
|
|
589 while (strcmp(chp,"i"))
|
|
590 {
|
|
591 ick_Base = (int)strtol(chp,&chp,10);
|
|
592 if (ick_Base < 2 || ick_Base > maxbase)
|
|
593 ick_lose(IE998, 1, (const char *)NULL);
|
|
594 else if (ick_traditional && ick_Base != 2)
|
|
595 ick_lose(IE111, 1, (const char *)NULL);
|
|
596 else if (pickcompile && ick_Base != 2)
|
|
597 ick_lose(IE256, 1, (const char *)NULL); /* AIS */
|
|
598 ick_Small_digits = smallsizes[ick_Base];
|
|
599 ick_Large_digits = 2 * ick_Small_digits;
|
|
600 ick_Max_small = maxsmalls[ick_Base];
|
|
601 if (ick_Max_small == 0xffff)
|
|
602 ick_Max_large = (unsigned)0xffffffffLU;
|
|
603 else
|
|
604 ick_Max_large = (ick_Max_small + 1) * (ick_Max_small + 1) - 1;
|
|
605 }
|
|
606 }
|
|
607
|
|
608
|
|
609 /**
|
|
610 * This checks if we automagically need to include syslib
|
|
611 * @param buffer Output buffer that may be modified to contain the path of
|
|
612 * syslib.i or syslib.Ni (where N is 3-7).
|
|
613 * @param size Size of buffer.
|
|
614 * @param needsyslib Pointer to the ick_bool needsyslib declared in main().
|
|
615 * @param argv0 Should be argv[0], which wasn't modified.
|
|
616 * @param ick_datadir The ick data directory.
|
|
617 * @note May (directly) call ick_lose() with IE127.
|
|
618 */
|
|
619 static void check_syslib(/*@partial@*/ char *buffer,
|
|
620 size_t size,
|
|
621 /*@out@*/ ick_bool *needsyslib,
|
|
622 /*@observer@*/ const char *argv0,
|
|
623 /*@observer@*/ const char *ick_datadir)
|
|
624 {
|
|
625 tuple *tp;
|
|
626 /*
|
|
627 * check if we need to magically include the system library
|
|
628 */
|
|
629 *needsyslib = ick_FALSE;
|
|
630 if(!pickcompile) /* AIS: We never need syslib when compiling
|
|
631 for PIC, because it's preoptimized. */
|
|
632 {
|
|
633 for (tp = tuples; tp->type; tp++)
|
|
634 {
|
|
635 /*
|
|
636 * If some label in the (1000)-(2000) range is defined,
|
|
637 * then clearly the syslib is already there, so we
|
|
638 * can stop searching and won't need the syslib.
|
|
639 */
|
|
640 if (tp->label >= 1000 && tp->label <= 1999) {
|
|
641 *needsyslib = ick_FALSE;
|
|
642 break;
|
|
643 }
|
|
644 /*
|
|
645 * If some label in the (1000)-(2000) range is being
|
|
646 * called, we might need the system library.
|
|
647 */
|
|
648 if (tp->type == NEXT && tp->u.target >= 1000 &&
|
|
649 tp->u.target <= 1999)
|
|
650 *needsyslib = ick_TRUE;
|
|
651 }
|
|
652 }
|
|
653 if(nosyslib) *needsyslib = ick_FALSE; /* AIS */
|
|
654 if (*needsyslib)
|
|
655 { /* AIS: modified to use ick_findandfreopen */
|
|
656 if (ick_Base == 2) /* see code for opening the skeleton */
|
|
657 (void) ick_snprintf_or_die(buffer, size, "%s.i", SYSLIB);
|
|
658 else
|
|
659 (void) ick_snprintf_or_die(buffer, size, "%s.%di", SYSLIB, ick_Base);
|
|
660 if (ick_findandfreopen(buffer, ick_datadir, "r", argv0, stdin) == NULL)
|
|
661 ick_lose(IE127, 1, (const char*) NULL);
|
|
662 #ifdef USE_YYRESTART
|
|
663 yyrestart(stdin);
|
|
664 #endif /* USE_YYRESTART */
|
|
665 (void) yyparse();
|
|
666 textlinecount=iyylineno;
|
|
667 }
|
|
668 }
|
|
669
|
|
670
|
|
671 /**
|
|
672 * This code propagates type information up the expression tree.
|
|
673 * It also does some unrelated stuff such as checking for WRITE IN and disabling
|
|
674 * coopt if that is found.
|
|
675 */
|
|
676 static void propagate_typeinfo(void)
|
|
677 {
|
|
678 tuple *tp;
|
|
679 /*
|
|
680 * Now propagate type information up the expression tree.
|
|
681 * We need to do this because the unary-logical operations
|
|
682 * are sensitive to the type widths of their operands, so
|
|
683 * we have to generate different code depending on the
|
|
684 * deducible type of the operand.
|
|
685 */
|
|
686 for (tp = tuples; tp->type; tp++)
|
|
687 {
|
|
688 if (tp->type == GETS || tp->type == RESIZE
|
|
689 || tp->type == WRITE_IN || tp->type == READ_OUT
|
|
690 || tp->type == FROM || tp->type == MANYFROM
|
|
691 || tp->type == FORGET || tp->type == RESUME
|
|
692 || tp->type == COMPUCOME || tp->type == UNKNOWN)
|
|
693 typecast(tp->type == MANYFROM ? tp->u.node->lval : tp->u.node);
|
|
694 if (tp->type == WRITE_IN) coopt = 0; /* AIS: may as well do
|
|
695 this here */
|
|
696 }
|
|
697 }
|
|
698
|
|
699
|
|
700 /**
|
|
701 * This runs the optimiser.
|
|
702 */
|
|
703 static void run_optimiser(void)
|
|
704 {
|
|
705 tuple *tp;
|
|
706 /* perform optimizations */
|
|
707 if (dooptimize)
|
|
708 for (tp = tuples; tp->type; tp++)
|
|
709 {
|
|
710 /* AIS: Allow breaching of the only specification on tuples
|
|
711 at this point; I've checked that tuples isn't reallocated
|
|
712 during the block, so this is fine. */
|
|
713 /*@-onlytrans@*/
|
|
714 optuple = tp;
|
|
715 /*@=onlytrans@*/
|
|
716 if (tp->type == GETS || tp->type == RESIZE
|
|
717 || tp->type == FORGET || tp->type == RESUME
|
|
718 || tp->type == FROM || tp->type == COMPUCOME)
|
|
719 optimize(tp->u.node);
|
|
720 if (tp->type == MANYFROM) optimize(tp->u.node->lval);
|
|
721 } /* AIS: Added FROM and MANYFROM support. */
|
|
722
|
|
723 /* AIS: perform flow optimizations */
|
|
724 if (flowoptimize) optimizef();
|
|
725 }
|
|
726
|
|
727
|
|
728 /**
|
|
729 * Generate random line number for E774.
|
|
730 * @returns A random line number, or -1 for no random bug generated.
|
|
731 */
|
|
732 static int randomise_bugline(void)
|
|
733 {
|
|
734 /* decide if and where to place the compiler bug */
|
|
735 #ifdef USG
|
|
736 if (!nocompilerbug && lrand48() % 10 == 0)
|
|
737 return (int)(lrand48() % ick_lineno);
|
|
738 #else
|
|
739 if (!nocompilerbug && rand() % 10 == 0)
|
|
740 return rand() % ick_lineno;
|
|
741 #endif
|
|
742 else
|
|
743 return -1;
|
|
744 }
|
|
745
|
|
746
|
|
747 /**
|
|
748 * This opens the outfile.
|
|
749 * @param filename The filename to open.
|
|
750 * @returns A pointer to a FILE for the filename. If the global outtostdout is
|
|
751 * set then it will return stdout.
|
|
752 * @note May (directly) call ick_lose() with IE888.
|
|
753 */
|
|
754 static /*@dependent@*/ FILE* open_outfile(/*@observer@*/ const char * filename)
|
|
755 {
|
|
756 FILE *ofp;
|
|
757 /* AIS: ofp holds fopened storage if !outtostdout, and local-copy
|
|
758 storage if outtostdout, and this is not a bug, although it
|
|
759 confuses Splint. */
|
|
760 /*@-branchstate@*/
|
|
761 if(outtostdout) ofp=stdout; /* AIS */
|
|
762 else if((ofp = ick_debfopen(filename, "w")) == (FILE *)NULL)
|
|
763 ick_lose(IE888, 1, (const char *)NULL);
|
|
764 /*@=branchstate@*/
|
|
765 return ofp;
|
|
766 }
|
|
767
|
|
768
|
|
769 /**
|
|
770 * This generates the CC command line.
|
|
771 * @param buffer Output buffer.
|
|
772 * @param size Size of the output buffer.
|
|
773 * @param sourcefile The name of the C file.
|
|
774 * @param includedir The ick include directory.
|
|
775 * @param path The path of the ick binary (execuding filename).
|
|
776 * @param libdir The ick library directory.
|
|
777 * @param outputfile The name of the output file.
|
|
778 */
|
|
779 static void gen_cc_command(char* buffer, size_t size,
|
|
780 /*@observer@*/ const char* sourcefile,
|
|
781 /*@observer@*/ const char* includedir,
|
|
782 /*@observer@*/ const char* path,
|
|
783 /*@observer@*/ const char* libdir,
|
|
784 /*@observer@*/ const char* outputfile)
|
|
785 {
|
|
786 (void) ick_snprintf_or_die(buffer, size,
|
|
787 "%s %s%s-I%s -I%s -I%s/../include -L%s -L%s -L%s/../lib -O%c -o %s" EXEEXT " -lick%s%s",
|
|
788 #ifdef __DJGPP__
|
|
789 "",
|
|
790 #else
|
|
791 compiler,
|
|
792 #endif
|
|
793 #ifdef HAVE_CLOCK_GETTIME /* implies -lrt is available */
|
|
794 sourcefile, yukdebug||yukprofile?" -lyuk -lrt ":" ",
|
|
795 #else
|
|
796 sourcefile, yukdebug||yukprofile?" -lyuk ":" ",
|
|
797 #endif
|
|
798 includedir, path, path, libdir, path, path,
|
|
799 cdebug?'0':coopt?'3':'2', /* AIS: If coopting, optimize as much as possible
|
|
800 JH: [d]on't optimise when compiling with debugger support */
|
|
801 outputfile, multithread?"mt":"", cdebug?" -g":"");
|
|
802 /* AIS: Possibly link in the debugger yuk and/or libickmt.a here. */
|
|
803 /* AIS: Added -g support. */
|
|
804 /* AIS: Added argv[0] (now path) to the -I, -L settings. */
|
|
805 }
|
|
806
|
|
807
|
|
808 /**
|
|
809 * This generates the actual C code.
|
|
810 * @param ifp This should be opened to either ick-wrap.c or pickwrap.c.
|
|
811 * @param ofp The out file.
|
|
812 * @param source_name_stem Source name stem
|
|
813 * @param needsyslib Pointer to the needsyslib bool in main().
|
|
814 * @param bugline What line number to add a random bug to.
|
|
815 * @param compilercommand The compiler command line.
|
|
816 * @note May (directly) call ick_lose() with IE256.
|
|
817 */
|
|
818 static void generate_code(FILE *ifp, FILE *ofp,
|
|
819 /*@observer@*/ const char* source_name_stem,
|
|
820 ick_bool *needsyslib,
|
|
821 int bugline,
|
|
822 /*@observer@*/ const char* compilercommand)
|
|
823 {
|
|
824 int maxabstain;
|
|
825 int c, i;
|
|
826 tuple *tp;
|
|
827 atom *op;
|
|
828 while ((c = myfgetc(ifp)) != EOF)
|
|
829 if (c != (int)'$')
|
|
830 (void) fputc(c, ofp);
|
|
831 else switch(myfgetc(ifp))
|
|
832 {
|
|
833 case 'A': /* source name stem */
|
|
834 (void) fputs(source_name_stem, ofp);
|
|
835 break;
|
|
836
|
|
837 case 'B': /* # of statements */
|
|
838 (void) fprintf(ofp, "%d", ick_lineno);
|
|
839 break;
|
|
840
|
|
841 case 'C': /* initial abstentions */
|
|
842 /* AIS: Modified to check for coopt, pickcompile */
|
|
843 maxabstain = 0;
|
|
844 for (tp = tuples; tp->type; tp++)
|
|
845 if (((tp->exechance <= 0 || tp->exechance >= 101)
|
|
846 && tp - tuples + 1 > maxabstain)
|
|
847 || coopt || pickcompile)
|
|
848 maxabstain = tp - tuples + 1;
|
|
849 if (maxabstain)
|
|
850 {
|
|
851 if(!pickcompile) (void) fprintf(ofp, " = {");
|
|
852 for (tp = tuples; tp < tuples + maxabstain; tp++)
|
|
853 {
|
|
854 if(tp->exechance != 100 && tp->exechance != -100)
|
|
855 { /* AIS: The double-oh-seven operator prevents
|
|
856 coopt working. However, syslib contains a
|
|
857 double-oh-seven. feh.c has checked that that
|
|
858 isn't referenced; if it isn't, we can allow
|
|
859 one double-oh-seven if syslib was
|
|
860 automagically inclulded. */
|
|
861 if(*needsyslib) *needsyslib = 0; else coopt = 0;
|
|
862 }
|
|
863 if(!pickcompile)
|
|
864 {
|
|
865 if (tp->exechance > 0)
|
|
866 {
|
|
867 (void) fprintf(ofp, "0, ");
|
|
868 tp->initabstain=0; /* AIS: -f might not be
|
|
869 given, so we can't rely
|
|
870 on dekludge.c doing
|
|
871 this */
|
|
872 }
|
|
873 else {
|
|
874 (void) fprintf(ofp, "1, ");
|
|
875 tp->exechance = -tp->exechance;
|
|
876 tp->initabstain=1; /* AIS: As above */
|
|
877 /* AIS: If the line was ick_abstained, we need to
|
|
878 swap ONCEs and AGAINs on it round, to suit
|
|
879 the code degenerator. */
|
|
880 if(tp->onceagainflag == onceagain_ONCE)
|
|
881 tp->onceagainflag = onceagain_AGAIN;
|
|
882 else if(tp->onceagainflag == onceagain_AGAIN)
|
|
883 tp->onceagainflag = onceagain_ONCE;
|
|
884 }
|
|
885 if(tp->exechance >= 101)
|
|
886 {
|
|
887 /* AIS: This line has a MAYBE */
|
|
888 tp->maybe = 1;
|
|
889 tp->exechance /= 100;
|
|
890 }
|
|
891 else tp->maybe = 0;
|
|
892 }
|
|
893 else /* AIS: hardcoded abstain bits for PICs */
|
|
894 {
|
|
895 if(!tp->abstainable) continue;
|
|
896 if(tp->exechance > 0)
|
|
897 (void) fprintf(ofp, "ICK_INT1 ICKABSTAINED(%d)=0;\n",(int)(tp-tuples));
|
|
898 else
|
|
899 (void) fprintf(ofp, "ICK_INT1 ICKABSTAINED(%d)=1;\n",(int)(tp-tuples));
|
|
900 }
|
|
901 }
|
|
902 if(!pickcompile) (void) fprintf(ofp, "}");
|
|
903 }
|
|
904 break;
|
|
905
|
|
906 case 'D': /* linetypes array for abstention handling */
|
|
907 maxabstain = 0;
|
|
908 for (tp = tuples; tp->type; tp++)
|
|
909 if (tp->type == ENABLE || tp->type == DISABLE || tp->type == MANYFROM)
|
|
910 maxabstain++;
|
|
911 if (maxabstain || /* AIS */ gerucomesused)
|
|
912 {
|
|
913 int j=0; /* AIS */
|
|
914 /* AIS: Changed to use enablersm1 */
|
|
915 i = 0;
|
|
916 for (;i < (int)(sizeof(enablersm1)/sizeof(char *));i++)
|
|
917 (void) fprintf(ofp,
|
|
918 "#define %s\t%d\n",
|
|
919 enablersm1[i], i);
|
|
920
|
|
921 (void) fprintf(ofp, "int linetype[] = {\n");
|
|
922 for (tp = tuples; tp->type; tp++)
|
|
923 if(tp->ppnewtype) /* AIS */
|
|
924 (void) fprintf(ofp," %s,\n",
|
|
925 enablers[tp->ppnewtype - GETS]);
|
|
926 else if(tp->preproc) /* AIS */
|
|
927 (void) fprintf(ofp," PREPROC,\n");
|
|
928 else if (tp->type >= GETS && tp->type <= FROM)
|
|
929 /* AIS: FROM added */
|
|
930 (void) fprintf(ofp,
|
|
931 " %s,\n",
|
|
932 enablers[tp->type - GETS]);
|
|
933 else
|
|
934 /* AIS: I didn't change this code, but relied on
|
|
935 it when implementing just-in-case compilation;
|
|
936 SPLATTERED and UNKNOWN (the two types of
|
|
937 syntax error, unsalvageable and salvageable
|
|
938 respectively) both become UNKNOWN in the
|
|
939 linetypes array. */
|
|
940 (void) fprintf(ofp, " UNKNOWN,\n");
|
|
941 (void) fprintf(ofp, "};\n");
|
|
942 /* AIS: Implement the reverse of this array too (i.e.
|
|
943 from line types to lines); this significantly
|
|
944 speeds up up reinstate/abstain on gerunds. Joris
|
|
945 Huizer originally suggested the optimisation in
|
|
946 question; this implements the same algorithm in a
|
|
947 more maintainable way. (I didn't want to have to
|
|
948 keep five copies of the command list in sync; two
|
|
949 is bad enough!) */
|
|
950 (void) fprintf(ofp, "int revlinetype[] = {\n");
|
|
951 for(i=0;i < (int)(sizeof(enablersm1)/sizeof(char *));i++)
|
|
952 {
|
|
953 (void) fprintf(ofp,"/* %s */",enablersm1[i]);
|
|
954 for (tp = tuples; tp->type; tp++)
|
|
955 {
|
|
956 if((tp->ppnewtype && tp->ppnewtype-GETS == i-1) ||
|
|
957 (!tp->ppnewtype && tp->preproc &&
|
|
958 i-1 == PREPROC-GETS) ||
|
|
959 (!tp->ppnewtype && !tp->preproc &&
|
|
960 tp->type >= GETS && tp->type <= FROM &&
|
|
961 tp->type-GETS == i-1) ||
|
|
962 (!i && !tp->ppnewtype && !tp->preproc &&
|
|
963 (tp->type < GETS || tp->type > FROM)))
|
|
964 (void) fprintf(ofp, " %ld,",(long)(tp-tuples));
|
|
965 }
|
|
966 (void) fprintf(ofp,"\n");
|
|
967 }
|
|
968 (void) fprintf(ofp, "};\n");
|
|
969 (void) fprintf(ofp, "int revlineindex[] = {\n");
|
|
970 for(i=0;i < (int)(sizeof(enablersm1)/sizeof(char *));i++)
|
|
971 {
|
|
972 (void) fprintf(ofp,"/* %s */",enablersm1[i]);
|
|
973 (void) fprintf(ofp," %d,\n",j);
|
|
974 for (tp = tuples; tp->type; tp++)
|
|
975 {
|
|
976 if((tp->ppnewtype && tp->ppnewtype-GETS == i-1) ||
|
|
977 (!tp->ppnewtype && tp->preproc &&
|
|
978 i-1 == PREPROC-GETS) ||
|
|
979 (!tp->ppnewtype && !tp->preproc &&
|
|
980 tp->type >= GETS && tp->type <= FROM &&
|
|
981 tp->type-GETS == i-1) ||
|
|
982 (!i && !tp->ppnewtype && !tp->preproc &&
|
|
983 (tp->type < GETS || tp->type > FROM)))
|
|
984 j++;
|
|
985 }
|
|
986 }
|
|
987 (void) fprintf(ofp, "/* end */ %d\n};\n",j);
|
|
988 }
|
|
989 break;
|
|
990
|
|
991 case 'E': /* extern to intern map */
|
|
992 if(!pickcompile)
|
|
993 {
|
|
994 (void) fprintf(ofp,"int ick_Base = %d;\n",ick_Base);
|
|
995 (void) fprintf(ofp,"int ick_Small_digits = %d;\n",
|
|
996 ick_Small_digits);
|
|
997 (void) fprintf(ofp,"int ick_Large_digits = %d;\n",
|
|
998 ick_Large_digits);
|
|
999 (void) fprintf(ofp,"unsigned int ick_Max_small = 0x%x;\n",
|
|
1000 ick_Max_small);
|
|
1001 (void) fprintf(ofp,"unsigned int ick_Max_large = 0x%x;\n",
|
|
1002 ick_Max_large);
|
|
1003 if (yukprofile || yukdebug || multithread || useickec)
|
|
1004 { /* AIS: yuk.c, multithreading require all these to exist */
|
|
1005 if(!nonespots) nonespots = 1;
|
|
1006 if(!ntwospots) ntwospots = 1;
|
|
1007 if(!ntails) ntails = 1;
|
|
1008 if(!nhybrids) nhybrids = 1;
|
|
1009 }
|
|
1010 else if(opoverused)
|
|
1011 {
|
|
1012 /* AIS: The operand-overloading code requires onespot and
|
|
1013 twospot variables to exist. */
|
|
1014 if(!nonespots) nonespots = 1;
|
|
1015 if(!ntwospots) ntwospots = 1;
|
|
1016 }
|
|
1017 /* AIS:I de-staticed all these so they could be accessed by
|
|
1018 yuk and cesspool, and added all the mentions of yuk and
|
|
1019 multithread. Then I changed it so the variables would be
|
|
1020 allocated dynamically, to speed up multithreading. (It's
|
|
1021 an O(1) change to the speed of ordinary programs, so I
|
|
1022 thought I could get away with it. The order is wrt the
|
|
1023 number of lines in the program. The change is O(n) wrt
|
|
1024 the number of variables, but again I hope that doesn't
|
|
1025 matter, and I won't get the entire INTERCAL community
|
|
1026 angry with me for daring to implement an extension that
|
|
1027 slows down existing programs.) */
|
|
1028 if (variableconstants) /* AIS */
|
|
1029 {
|
|
1030 int temp=0;
|
|
1031 (void) fprintf(ofp, "ick_type32 meshes[%d] = {",nmeshes);
|
|
1032 while(temp<nmeshes)
|
|
1033 {
|
|
1034 (void) fprintf(ofp, "%luLU, ", varextern((unsigned long)temp,MESH));
|
|
1035 temp++;
|
|
1036 }
|
|
1037 (void) fprintf(ofp, "};\n");
|
|
1038 }
|
|
1039
|
|
1040 if (nonespots)
|
|
1041 {
|
|
1042 (void) fprintf(ofp,
|
|
1043 "ick_type16* ick_onespots;\n");
|
|
1044 (void) fprintf(ofp,
|
|
1045 "ick_bool* ick_oneforget;\n");
|
|
1046 if(yukprofile || yukdebug)
|
|
1047 {
|
|
1048 (void) fprintf(ofp,
|
|
1049 "ick_type16 oneold[%d];\n",
|
|
1050 nonespots);
|
|
1051 (void) fprintf(ofp,
|
|
1052 "signed char onewatch[%d];\n",
|
|
1053 nonespots);
|
|
1054 }
|
|
1055 if(multithread)
|
|
1056 {
|
|
1057 (void) fprintf(ofp,
|
|
1058 "int onespotcount = %d;\n",
|
|
1059 nonespots);
|
|
1060 }
|
|
1061 if(multithread || opoverused || useickec) /* AIS */
|
|
1062 {
|
|
1063 int temp=nonespots;
|
|
1064 (void) fprintf(ofp,
|
|
1065 "ick_overop* ick_oo_onespots = 0;\n");
|
|
1066 if(opoverused)
|
|
1067 while(temp--)
|
|
1068 (void) fprintf(ofp,
|
|
1069 "ick_type32 og1spot%d(ick_type32 t)\n{\n (void)t;\n return ick_onespots[%d];\n}\n"
|
|
1070 "void os1spot%d(ick_type32 val, void(*f)())\n{\n (void)f;\n ick_assign((void*)"
|
|
1071 "(ick_onespots+%d), ick_ONESPOT, ick_oneforget[%d], val);\n}\n",temp,temp,temp,temp,temp);
|
|
1072 }
|
|
1073 }
|
|
1074 if (ntwospots)
|
|
1075 {
|
|
1076 (void) fprintf(ofp,
|
|
1077 "ick_type32* ick_twospots;\n");
|
|
1078 (void) fprintf(ofp,
|
|
1079 "ick_bool* ick_twoforget;\n");
|
|
1080 if(yukprofile || yukdebug)
|
|
1081 {
|
|
1082 (void) fprintf(ofp,
|
|
1083 "ick_type32 twoold[%d];\n",
|
|
1084 ntwospots);
|
|
1085 (void) fprintf(ofp,
|
|
1086 "signed char twowatch[%d];\n",
|
|
1087 ntwospots);
|
|
1088 }
|
|
1089 if(multithread)
|
|
1090 {
|
|
1091 (void) fprintf(ofp,
|
|
1092 "int twospotcount = %d;\n",
|
|
1093 ntwospots);
|
|
1094 }
|
|
1095 if(multithread || opoverused || useickec) /* AIS */
|
|
1096 {
|
|
1097 int temp=ntwospots;
|
|
1098 (void) fprintf(ofp,
|
|
1099 "ick_overop* ick_oo_twospots = 0;\n");
|
|
1100 if(opoverused)
|
|
1101 while(temp--)
|
|
1102 (void) fprintf(ofp,
|
|
1103 "ick_type32 og2spot%d(ick_type32 t)\n{\n (void)t;\n return ick_twospots[%d];\n}\n"
|
|
1104 "void os2spot%d(ick_type32 val, void(*f)())\n{\n (void)f;\n ick_assign((void*)"
|
|
1105 "(ick_twospots+%d), ick_TWOSPOT, ick_twoforget[%d], val);\n}\n",temp,temp,temp,temp,temp);
|
|
1106 }
|
|
1107 }
|
|
1108 if (ntails)
|
|
1109 {
|
|
1110 (void) fprintf(ofp,
|
|
1111 "ick_array* ick_tails;\n");
|
|
1112 (void) fprintf(ofp,
|
|
1113 "ick_bool* ick_tailforget;\n");
|
|
1114 if(multithread)
|
|
1115 {
|
|
1116 (void) fprintf(ofp,
|
|
1117 "int tailcount = %d;\n",
|
|
1118 ntails);
|
|
1119 }
|
|
1120 }
|
|
1121 if (nhybrids)
|
|
1122 {
|
|
1123 (void) fprintf(ofp,
|
|
1124 "ick_array* ick_hybrids;\n");
|
|
1125 (void) fprintf(ofp,
|
|
1126 "ick_bool* ick_hyforget;\n");
|
|
1127 if(multithread)
|
|
1128 {
|
|
1129 (void) fprintf(ofp,
|
|
1130 "int hybridcount = %d;\n",
|
|
1131 nhybrids);
|
|
1132 }
|
|
1133 }
|
|
1134 if (yydebug || compile_only)
|
|
1135 {
|
|
1136 assert(oblist != NULL);
|
|
1137 for (op = oblist; op < obdex; op++)
|
|
1138 if(op->type!=MESH) /* AIS: Added this check */
|
|
1139 (void) fprintf(ofp, " /* %s %lu -> %lu */\n",
|
|
1140 nameof(op->type, vartypes),
|
|
1141 op->extindex,
|
|
1142 op->intindex);
|
|
1143 }
|
|
1144 if (yukdebug || yukprofile)
|
|
1145 { /* AIS: drop intern to extern map into the program */
|
|
1146 (void) fprintf(ofp, "\nyukvar yukvars[]={\n");
|
|
1147 assert(oblist != NULL);
|
|
1148 for (op = oblist; op < obdex; op++)
|
|
1149 if(op->type!=MESH) /* AIS: Added this check */
|
|
1150 (void) fprintf(ofp," {%s,%lu,%lu},\n",
|
|
1151 nameof(op->type, vartypes),
|
|
1152 op->extindex,
|
|
1153 op->intindex);
|
|
1154 (void) fprintf(ofp," {YUKEND,0,0}};\n");
|
|
1155 }
|
|
1156 else if(useickec)
|
|
1157 { /* AIS: likewise, but with different identifiers */
|
|
1158 (void) fprintf(ofp, "\nick_ec_var ick_ec_vars[]={\n");
|
|
1159 assert(oblist != NULL);
|
|
1160 for (op = oblist; op < obdex; op++)
|
|
1161 if(op->type!=MESH)
|
|
1162 (void) fprintf(ofp," {%s,%lu,%lu},\n",
|
|
1163 nameof(op->type, vartypes),
|
|
1164 op->extindex,
|
|
1165 op->intindex);
|
|
1166 (void) fprintf(ofp," {ICK_EC_VARS_END,0,0}};\n");
|
|
1167 }
|
|
1168 }
|
|
1169 else
|
|
1170 {
|
|
1171 /* Compiling for PIC */
|
|
1172 /* Arrays not supported on PICs */
|
|
1173 if(ntails || nhybrids)
|
|
1174 ick_lose(IE256, iyylineno, (const char*) NULL);
|
|
1175 /* and neither are variable constants */
|
|
1176 if(variableconstants)
|
|
1177 ick_lose(IE256, iyylineno, (const char*) NULL);
|
|
1178 assert(oblist != NULL);
|
|
1179 for (op = oblist; op < obdex; op++)
|
|
1180 {
|
|
1181 (void) fprintf(ofp, " /* %s %lu -> %lu */\n",
|
|
1182 nameof(op->type, vartypes),
|
|
1183 op->extindex,
|
|
1184 op->intindex);
|
|
1185 (void) fprintf(ofp, "#define %s%lu %s[%lu]\n",
|
|
1186 nameof(op->type, vartypes),
|
|
1187 op->extindex,
|
|
1188 nameof(op->type, varstores),
|
|
1189 op->intindex);
|
|
1190 if(op->ignorable)
|
|
1191 (void) fprintf(ofp, "ICK_INT1 ignore%s%lu = 0;\n",
|
|
1192 nameof(op->type, varstores),
|
|
1193 op->intindex);
|
|
1194 }
|
|
1195 (void) fprintf(ofp, "#include \"pick1.h\"\n");
|
|
1196 if(nonespots)
|
|
1197 {
|
|
1198 (void) fprintf(ofp,
|
|
1199 "ICK_INT16 ick_onespots[%d];\n"
|
|
1200 "ICK_INT16 onespotsstash[%d];\n",
|
|
1201 nonespots,
|
|
1202 nonespots);
|
|
1203 if(opoverused) /* AIS */
|
|
1204 {
|
|
1205 int temp=nonespots;
|
|
1206 (void) fprintf(ofp,"ick_overop* ick_oo_onespots;\n");
|
|
1207 while(temp--)
|
|
1208 (void) fprintf(ofp,
|
|
1209 "ick_type32 og1spot%d(ick_type32 t)\n{\n (void)t;\n return ick_onespots[%d];\n}\n"
|
|
1210 "void os1spot%d(ick_type32 val,void(*f)())\n{\n (void)f;\n if(!ignoreonespots%d)"
|
|
1211 " ick_onespots[%d]=val;\n}\n",temp,temp,temp,temp,temp);
|
|
1212 }
|
|
1213 }
|
|
1214 if(ntwospots)
|
|
1215 {
|
|
1216 (void) fprintf(ofp,
|
|
1217 "ICK_INT32 ick_twospots[%d];\n"
|
|
1218 "ICK_INT32 twospotsstash[%d];\n",
|
|
1219 ntwospots,
|
|
1220 ntwospots);
|
|
1221 if(opoverused) /* AIS */
|
|
1222 {
|
|
1223 int temp=ntwospots;
|
|
1224 (void) fprintf(ofp,"ick_overop* ick_oo_twospots;\n");
|
|
1225 while(temp--)
|
|
1226 (void) fprintf(ofp,
|
|
1227 "ick_type32 og2spot%d(ick_type32 t)\n{\n (void)t;\n return ick_twospots[%d];\n}\n"
|
|
1228 "void os2spot%d(ick_type32 val,void(*f)())\n{\n (void)f;\n if(!ignoretwospots%d)"
|
|
1229 " ick_twospots[%d]=val;\n}\n",temp,temp,temp,temp,temp);
|
|
1230 }
|
|
1231 }
|
|
1232 (void) fprintf(ofp, "#include \"pick2.h\"\n");
|
|
1233 }
|
|
1234 break;
|
|
1235
|
|
1236 case 'F': /* set options from command line */
|
|
1237 if (ick_clockface)
|
|
1238 (void) fprintf(ofp, "ick_clockface(ick_TRUE);\n");
|
|
1239 if (ick_clcsemantics) /* AIS */
|
|
1240 (void) fprintf(ofp, "ick_setclcsemantics(ick_TRUE);\n");
|
|
1241 break;
|
|
1242
|
|
1243 case 'G': /* degenerated code */
|
|
1244 for (tp = tuples, i = 0; tp->type; tp++, i++)
|
|
1245 {
|
|
1246 emit(tp, ofp);
|
|
1247 if (i == bugline)
|
|
1248 (void) fprintf(ofp, " ick_lose(IE774, ick_lineno, "
|
|
1249 "(char *)NULL);\n");
|
|
1250 }
|
|
1251 break;
|
|
1252
|
|
1253 case 'H': /* COMPUCOME, and dispatching for resumes */
|
|
1254 /* AIS: Added COMPUCOME here. This line must be fully guarded
|
|
1255 to prevent a longjmp to an uninitialised buffer (it's
|
|
1256 guarded by a ick_lose() in ick-wrap.c.) Also checks for
|
|
1257 multithread; programs that mix normal and computed COME
|
|
1258 FROM need to use the same conventions for both, so even
|
|
1259 if no computed COME FROMs are used, the normal ones need
|
|
1260 this line so that COME FROMs can be handled consistently.*/
|
|
1261 if(compucomesused || multithread)
|
|
1262 {
|
|
1263 (void) fprintf(ofp, "CCFL: ; CCF%d: longjmp(ick_cjb,1);\n",
|
|
1264 compucomecount);
|
|
1265 }
|
|
1266 break;
|
|
1267
|
|
1268 case 'J': /* # of source file lines */
|
|
1269 (void) fprintf(ofp, "%d", iyylineno);
|
|
1270 break;
|
|
1271
|
|
1272 case 'K': /* AIS: yuk information (or not) */
|
|
1273 if(yukdebug||yukprofile)
|
|
1274 {
|
|
1275 (void) fprintf(ofp, "#include \"config.h\"\n\n");
|
|
1276 (void) fprintf(ofp, "#include \"yuk.h\"\n\n");
|
|
1277 (void) fprintf(ofp, "char* textlines[] = {\n");
|
|
1278 emittextlines(ofp); /* from feh.c */
|
|
1279 (void) fprintf(ofp, "\"\"};\n\n");
|
|
1280 (void) fprintf(ofp, "char* yukexplain[] = {\n");
|
|
1281 for (tp = tuples; tp->type; tp++)
|
|
1282 {
|
|
1283 if (tp->type == GETS || tp->type == FORGET || tp->type == RESUME
|
|
1284 || tp->type == FROM || tp->type == COMPUCOME
|
|
1285 || tp->type == MANYFROM)
|
|
1286 {
|
|
1287 (void) fprintf(ofp, "\"");
|
|
1288 explexpr(tp->type == MANYFROM ? tp->u.node->lval :
|
|
1289 tp->type == GETS ? tp->u.node->rval : tp->u.node, ofp);
|
|
1290 (void) fprintf(ofp, "\",\n");
|
|
1291 }
|
|
1292 else (void) fprintf(ofp, "0,");
|
|
1293 }
|
|
1294 (void) fprintf(ofp, "0};\n\n");
|
|
1295 (void) fprintf(ofp, "int lineofaboff[] = {\n");
|
|
1296 for (tp = tuples; tp->type; tp++)
|
|
1297 {
|
|
1298 fprintf(ofp,"%d,",tp->ick_lineno);
|
|
1299 }
|
|
1300 (void) fprintf(ofp, "-1};\n\n");
|
|
1301 (void) fprintf(ofp, "int yukopts = %d;\n", yukprofile+yukdebug*2);
|
|
1302 (void) fprintf(ofp, "yptimer ypexectime[%d];\n", ick_lineno);
|
|
1303 (void) fprintf(ofp, "ypcounter ypexecount[%d];\n",ick_lineno);
|
|
1304 (void) fprintf(ofp, "ypcounter ypabscount[%d];\n",ick_lineno);
|
|
1305 }
|
|
1306 break;
|
|
1307
|
|
1308 case 'L': /* AIS: increase Emacs compatibility */
|
|
1309 (void) fprintf(ofp,
|
|
1310 "/* -*- mode:c; compile-command:\"%s%s%s\" -*- */",
|
|
1311 #ifdef __DJGPP__
|
|
1312 compiler," ",
|
|
1313 #else
|
|
1314 "","",
|
|
1315 #endif
|
|
1316 compilercommand);
|
|
1317 break;
|
|
1318
|
|
1319 case 'M': /* AIS: place new features defines in program */
|
|
1320 /* This is needed even in a non-multithread program, to let
|
|
1321 the header files know it's non-multithread */
|
|
1322 (void) fprintf(ofp, "#define MULTITHREAD %d\n", multithread);
|
|
1323 /* Likewise, to let the header files know whether it
|
|
1324 overloads operands (I don't think this is used at
|
|
1325 the moment, though) */
|
|
1326 (void) fprintf(ofp, "#define OPOVERUSED %d\n",opoverused);
|
|
1327 /* and whether to use the ICK_EC code */
|
|
1328 if(useickec)
|
|
1329 (void) fprintf(ofp, "#define ICK_EC 1\n");
|
|
1330 break;
|
|
1331
|
|
1332 case 'N': /* allocate variables */
|
|
1333 /* AIS:I de-staticed all these so they could be accessed by
|
|
1334 yuk and cesspool, and added all the mentions of yuk and
|
|
1335 multithread. Then I changed it so the variables would be
|
|
1336 allocated dynamically, to speed up multithreading (it's
|
|
1337 an O(1) change to the speed of ordinary programs, so I
|
|
1338 thought I could get away with it). At this point, the
|
|
1339 'E' case must already have been done. calloc sets all
|
|
1340 the integer values to 0, as before. In the case of
|
|
1341 arrays, it will not zero pointers, but the number-of-
|
|
1342 dimensions value will become 0, which can serve as a
|
|
1343 'deallocated' flag. */
|
|
1344 if (nonespots)
|
|
1345 {
|
|
1346 if(!pickcompile) /* AIS */
|
|
1347 {
|
|
1348 (void) fprintf(ofp,
|
|
1349 " ick_onespots = calloc("
|
|
1350 "%d, sizeof *ick_onespots);\n",
|
|
1351 nonespots);
|
|
1352 (void) fprintf(ofp,
|
|
1353 " ick_oneforget = calloc("
|
|
1354 "%d, sizeof *ick_oneforget);\n",
|
|
1355 nonespots);
|
|
1356 }
|
|
1357 if(opoverused)
|
|
1358 {
|
|
1359 int temp=nonespots;
|
|
1360 (void) fprintf(ofp,
|
|
1361 " ick_oo_onespots=malloc(%d*sizeof*ick_oo_onespots);\n",temp);
|
|
1362 while(temp--)
|
|
1363 (void) fprintf(ofp,
|
|
1364 " ick_oo_onespots[%d].get=og1spot%d;\n ick_oo_onespots[%d].set=os1spot%d;\n",
|
|
1365 temp,temp,temp,temp);
|
|
1366 }
|
|
1367 }
|
|
1368 if (ntwospots)
|
|
1369 {
|
|
1370 if(!pickcompile)
|
|
1371 {
|
|
1372 (void) fprintf(ofp,
|
|
1373 " ick_twospots = calloc("
|
|
1374 "%d, sizeof *ick_twospots);\n",
|
|
1375 ntwospots);
|
|
1376 (void) fprintf(ofp,
|
|
1377 " ick_twoforget = calloc("
|
|
1378 "%d, sizeof *ick_twoforget);\n",
|
|
1379 ntwospots);
|
|
1380 }
|
|
1381 if(opoverused)
|
|
1382 {
|
|
1383 int temp=ntwospots;
|
|
1384 (void) fprintf(ofp,
|
|
1385 " ick_oo_twospots=malloc(%d*sizeof*ick_oo_twospots);\n",temp);
|
|
1386 while(temp--)
|
|
1387 (void) fprintf(ofp,
|
|
1388 " ick_oo_twospots[%d].get=og2spot%d;\n ick_oo_twospots[%d].set=os2spot%d;\n",
|
|
1389 temp,temp,temp,temp);
|
|
1390 }
|
|
1391 }
|
|
1392 if (ntails&&!pickcompile)
|
|
1393 {
|
|
1394 (void) fprintf(ofp,
|
|
1395 " ick_tails = calloc("
|
|
1396 "%d, sizeof *ick_tails);\n",
|
|
1397 ntails);
|
|
1398 (void) fprintf(ofp,
|
|
1399 " ick_tailforget = calloc("
|
|
1400 "%d, sizeof *ick_tailforget);\n",
|
|
1401 ntails);
|
|
1402 }
|
|
1403 if (nhybrids&&!pickcompile)
|
|
1404 {
|
|
1405 (void) fprintf(ofp,
|
|
1406 " ick_hybrids = calloc("
|
|
1407 "%d, sizeof *ick_hybrids);\n",
|
|
1408 nhybrids);
|
|
1409 (void) fprintf(ofp,
|
|
1410 " ick_hyforget = calloc("
|
|
1411 "%d, sizeof *ick_hyforget);\n",
|
|
1412 nhybrids);
|
|
1413 }
|
|
1414 break;
|
|
1415 case 'O': /* AIS; for GERUCOME and operand overloading */
|
|
1416 if(gerucomesused || nextfromsused)
|
|
1417 fprintf(ofp,"unsigned truelineno = 0;\n");
|
|
1418 if(opoverused)
|
|
1419 fprintf(ofp,"%s trueval;\n",
|
|
1420 pickcompile?"ICK_INT32":"ick_type32");
|
|
1421 break;
|
|
1422 case 'P': /* AIS: for operand overloading */
|
|
1423 if(opoverused)
|
|
1424 emitslatproto(ofp);
|
|
1425 break;
|
|
1426 case 'Q': /* AIS: for operand overloading */
|
|
1427 if(opoverused)
|
|
1428 emitslat(ofp);
|
|
1429 break;
|
|
1430 }
|
|
1431 }
|
|
1432
|
|
1433
|
|
1434 /**
|
|
1435 * This runs the C compiler, and may invoke yuk.
|
|
1436 * @param cc_command The compiler command line to use. Constructed by gen_cc_command().
|
|
1437 * @param oldstdin The previous stdin, used for yuk.
|
|
1438 * @param yukcmdstr The command line to use for running yuk.
|
|
1439 * @param sourcefile The output filename.
|
|
1440 * @param binaryname The name of the binary.
|
|
1441 */
|
|
1442 static void run_cc_and_maybe_debugger(/*@observer@*/ const char *cc_command,
|
|
1443 int oldstdin,
|
|
1444 /*@observer@*/ const char *yukcmdstr,
|
|
1445 /*@observer@*/ const char *sourcefile,
|
|
1446 /*@observer@*/ const char *binaryname)
|
|
1447 {
|
|
1448 #ifndef __DJGPP__
|
|
1449 /* OK, now sic the C compiler on the results */
|
|
1450 if (!compile_only&&!yukdebug&&!yukprofile&&!useickec)
|
|
1451 {
|
|
1452 /* AIS: buf2 now assigned elsewhere so $L works */
|
|
1453 ICK_SYSTEM(cc_command);
|
|
1454 /* AIS: no unlink if cdebug */ if(!cdebug) (void) unlink(sourcefile);
|
|
1455 }
|
|
1456 else if(!compile_only&&!useickec)
|
|
1457 { /* AIS: run, then delete all output but yuk.out */
|
|
1458 /* Note that the output must be deleted for copyright
|
|
1459 reasons (so as not to GPL a non-GPL file automatically) */
|
|
1460 ICK_SYSTEM(cc_command);
|
|
1461 #ifdef HAVE_UNISTD_H
|
|
1462 (void) dup2(oldstdin,0); /* restore stdin */
|
|
1463 #endif
|
|
1464 ICK_SYSTEM(yukcmdstr);
|
|
1465 (void) unlink(sourcefile);
|
|
1466 (void) unlink(binaryname);
|
|
1467 }
|
|
1468 #else /* we are using DJGPP */
|
|
1469 /* OK, now sic the C compiler on the results */
|
|
1470 if (!compile_only&&!useickec)
|
|
1471 {
|
|
1472 /* AIS: buf2 now assigned elsewhere so $L works */
|
|
1473 /* AIS: This changes somewhat for DJGPP, due to the
|
|
1474 command-line cap. It creates a temporary file
|
|
1475 with the arguments needed to give gcc. */
|
|
1476 FILE* rsp;
|
|
1477 /* Use current dir as temp if needed */
|
|
1478 const char* tempfn="gcc @ickgcc.rsp";
|
|
1479 /* Four tries are used to find a temp directory.
|
|
1480 ICKTEMP is the preferred environment variable to check;
|
|
1481 if, as expected, this isn't set, try TMPDIR (which DJGPP
|
|
1482 sets to its own temp directory, at least when running under
|
|
1483 bash), TEMP and TMP (in that order). DJGPP offers /dev/env
|
|
1484 as a method of accessing environment variables in filenames.*/
|
|
1485 if(isenv("TMP")) tempfn="gcc @/dev/env/TMP/ickgcc.rsp";
|
|
1486 if(isenv("TEMP")) tempfn="gcc @/dev/env/TEMP/ickgcc.rsp";
|
|
1487 if(isenv("TMPDIR")) tempfn="gcc @/dev/env/TMPDIR/ickgcc.rsp";
|
|
1488 if(isenv("ICKTEMP")) tempfn="gcc @/dev/env/ICKTEMP/ickgcc.rsp";
|
|
1489 rsp=ick_debfopen(tempfn+5,"w");
|
|
1490 fprintf(rsp,"%s\n",cc_command);
|
|
1491 fclose(rsp);
|
|
1492 ICK_SYSTEM(tempfn);
|
|
1493 remove(tempfn+5);
|
|
1494 if(yukdebug || yukprofile)
|
|
1495 {
|
|
1496 char buffer[BUFSIZ];
|
|
1497 #ifdef HAVE_UNISTD_H
|
|
1498 dup2(oldstdin,0); /* restore stdin */
|
|
1499 #endif
|
|
1500 /* FIXME: This looks broken (the buf2 usage and such). */
|
|
1501 ick_snprintf_or_die(buffer, sizeof(buffer), "%s" EXEEXT,binaryname);
|
|
1502 ICK_SYSTEM(yukcmdstr);
|
|
1503 remove(sourcefile);
|
|
1504 remove(buffer);
|
|
1505 }
|
|
1506 else if(!cdebug)
|
|
1507 {
|
|
1508 remove(sourcefile);
|
|
1509 }
|
|
1510 }
|
|
1511 #endif
|
|
1512 }
|
|
1513
|
|
1514
|
|
1515 /**
|
|
1516 * This runs coopt.sh if -F is given and the program can be "coopted".
|
|
1517 * @param cooptsh Path to coopt.sh
|
|
1518 * @param binaryname The output binary filename.
|
|
1519 */
|
|
1520 static void run_coopt(/*@observer@*/ /*@null@*/ /*@unused@*/ const char* cooptsh,
|
|
1521 /*@observer@*/ /*@unused@*/ const char* binaryname)
|
|
1522 {
|
|
1523 /* Note: Params are marked unused because they may not be used if sh isn't supported. */
|
|
1524 #ifdef HAVE_PROG_SH
|
|
1525 # ifdef HAVE_SYS_INTERPRETER
|
|
1526 if(coopt) /* AIS */
|
|
1527 {
|
|
1528 /* The constant-output optimizer is a form of post-processor.
|
|
1529 IMPORTANT NOTE: This MUST NOT be run if the input program
|
|
1530 takes any input or is affected in any way by the state of
|
|
1531 the system, as the degenerated program may be wrong. At the
|
|
1532 moment, the only INTERCAL command that takes input is
|
|
1533 WRITE IN. Double-oh-sevens screw this up, too. */
|
|
1534 if(cooptsh)
|
|
1535 {
|
|
1536 char commandlinebuf[BUFSIZ];
|
|
1537 (void) ick_snprintf_or_die(commandlinebuf, sizeof commandlinebuf,
|
|
1538 "sh %s %s", cooptsh, binaryname);
|
|
1539 ICK_SYSTEM(commandlinebuf); /* replaces the output executable if
|
|
1540 neccesary */
|
|
1541 }
|
|
1542 }
|
|
1543 # endif
|
|
1544 #endif
|
|
1545 }
|
|
1546
|
|
1547
|
|
1548 /**
|
|
1549 * This is for -e, runs prelinking.
|
|
1550 * @param argc Exactly what you think.
|
|
1551 * @param argv Also what you think.
|
|
1552 * @param oldoptind The original optind.
|
|
1553 * @param libdir The ick library directory.
|
|
1554 * @param includedir The ick include directory.
|
|
1555 * @param path The path of the ick binary (execuding filename).
|
|
1556 * @param libbuf A string with -lfoo to add to compiler command line.
|
|
1557 * @note May (directly) call ick_lose() with IE666. IE778 and IE888.
|
|
1558 */
|
|
1559 static void prelink(int argc, char *argv[], int oldoptind,
|
|
1560 /*@observer@*/ const char* libdir,
|
|
1561 /*@observer@*/ const char *includedir,
|
|
1562 /*@observer@*/ const char* path,
|
|
1563 /*@observer@*/ const char* libbuf)
|
|
1564 {
|
|
1565 char buffer[BUFSIZ];
|
|
1566 FILE* cioin;
|
|
1567 FILE* cioallec;
|
|
1568 char* buf2ptr;
|
|
1569 long remspace;
|
|
1570 const char* tempfn="ickectmp.c";
|
|
1571 int needc99=0;
|
|
1572 #if __DJGPP__
|
|
1573 /* Look for a temp directory, as above. */
|
|
1574 if(isenv("TMP")) tempfn="/dev/env/TMP/ickectmp.c";
|
|
1575 if(isenv("TEMP")) tempfn="/dev/env/TEMP/ickectmp.c";
|
|
1576 if(isenv("TMPDIR")) tempfn="/dev/env/TMPDIR/ickectmp.c";
|
|
1577 if(isenv("ICKTEMP")) tempfn="/dev/env/ICKTEMP/ickectmp.c";
|
|
1578 #else
|
|
1579 tempfn="/tmp/ickectmp.c"; /* always a valid temporary folder on POSIX */
|
|
1580 #endif
|
|
1581 cioallec=ick_debfopen(tempfn,"w");
|
|
1582 if(cioallec == NULL)
|
|
1583 ick_lose(IE888, -1, (const char*) NULL);
|
|
1584 (void) fprintf(cioallec,"void ick_doresume(unsigned short,int);\n");
|
|
1585 (void) fprintf(cioallec,"extern int ick_global_checkmode;\n");
|
|
1586 (void) fprintf(cioallec,"void ick_allecfuncs(void)\n{\n");
|
|
1587
|
|
1588 /* Here, we run the C preprocessor on the files in question, then our
|
|
1589 own preprocessor, and finally link all the files together into one
|
|
1590 executable. */
|
|
1591 for(optind=oldoptind; optind < argc; optind++)
|
|
1592 {
|
|
1593 (void) ick_snprintf_or_die(buffer, sizeof buffer,
|
|
1594 "%s --std=c%d -E -DICK_HAVE_STDINT_H=%d "
|
|
1595 "-I%s -I%s -I%s/../include "
|
|
1596 "-x c %s.c%c%c > %s.cio",
|
|
1597 compiler, argv[optind][strlen(argv[optind])+2]=='9'?99:89,
|
|
1598 ICK_HAVE_STDINT_H+1-1,
|
|
1599 includedir, path, path, argv[optind],
|
|
1600 argv[optind][strlen(argv[optind])+2]=='9'?
|
|
1601 (needc99=1),'9':' ',
|
|
1602 argv[optind][strlen(argv[optind])+2]=='9'?'9':' ',
|
|
1603 argv[optind]);
|
|
1604 if(*(argv[optind]) && /* there is some file to compile */
|
|
1605 (argv[optind][strlen(argv[optind])+2]=='\0' /* a .c or .i file */
|
|
1606 ||argv[optind][strlen(argv[optind])+3]!='o')) /* not a .cio file */
|
|
1607 ICK_SYSTEM(buffer); /* run the C preprocessor */
|
|
1608 buf2ptr = strrchr(buffer,'>'); /* get the .cio's filename */
|
|
1609 cioin=NULL;
|
|
1610 /* Do our preprocessing, by editing the file in place using rb+. */
|
|
1611 if(buf2ptr != NULL && buf2ptr[1] != '\0' && buf2ptr[2] != '\0')
|
|
1612 cioin=ick_debfopen(buf2ptr+2,"rb+");
|
|
1613 if(cioin)
|
|
1614 {
|
|
1615 int inchar=fgetc(cioin);
|
|
1616 int toparencount=0;
|
|
1617 /* The ppnums are replacements for strings in the .cio file.
|
|
1618 The choice of 65538 means that we don't clash with any
|
|
1619 line numbers in the program, but do clash with the other
|
|
1620 C-INTERCAL preprocessor (that handles WHILE); that isn't a
|
|
1621 problem because external calls are inconsistent with
|
|
1622 multithreading anyway. */
|
|
1623 static long ppnum1=65538L*2L;
|
|
1624 static long ppnum2=65538L*2L;
|
|
1625 static long ppnum3=65538L*2L;
|
|
1626 static long ppnum6=65538L*2L;
|
|
1627 long ciopos=0L;
|
|
1628 /*@+charintliteral@*/ /* literal chars are ints */
|
|
1629 while(inchar != EOF)
|
|
1630 {
|
|
1631 if(inchar=='I')
|
|
1632 {
|
|
1633 /* Look for the ICK_EC_PP_ string that indicates preprocessing
|
|
1634 is needed. This method of doing it works as long as the
|
|
1635 ICK_EC_PP_ string is never preceded by something which looks
|
|
1636 like part of the same string, but luckily, it never is. */
|
|
1637 if((inchar=fgetc(cioin))!='C') continue;
|
|
1638 if((inchar=fgetc(cioin))!='K') continue;
|
|
1639 if((inchar=fgetc(cioin))!='_') continue;
|
|
1640 if((inchar=fgetc(cioin))!='E') continue;
|
|
1641 if((inchar=fgetc(cioin))!='C') continue;
|
|
1642 if((inchar=fgetc(cioin))!='_') continue;
|
|
1643 if((inchar=fgetc(cioin))!='P') continue;
|
|
1644 if((inchar=fgetc(cioin))!='P') continue;
|
|
1645 if((inchar=fgetc(cioin))!='_') continue;
|
|
1646 inchar=fgetc(cioin);
|
|
1647 toparencount=0;
|
|
1648 if(inchar=='0')
|
|
1649 {
|
|
1650 fprintf(cioallec,"#undef X\n");
|
|
1651 fprintf(cioallec,"#define X ");
|
|
1652 while(fputc(fgetc(cioin),cioallec) != ')') toparencount++;
|
|
1653 }
|
|
1654 (void) fseek(cioin,ciopos,SEEK_SET);
|
|
1655 switch(inchar)
|
|
1656 {
|
|
1657 case '0': /* a function exists */
|
|
1658 fprintf(cioin," ");
|
|
1659 fprintf(cioallec,"\nvoid X(void); X();\n"
|
|
1660 "if(ick_global_checkmode==5) ick_doresume(1,-1);\n");
|
|
1661 while(toparencount--) (void) fputc(' ',cioin);
|
|
1662 break;
|
|
1663 case '1':
|
|
1664 fprintf(cioin,"%-11ld",ppnum1++/2);
|
|
1665 break;
|
|
1666 case '2':
|
|
1667 fprintf(cioin,"%-11ld",ppnum2++/2);
|
|
1668 break;
|
|
1669 case '3':
|
|
1670 fprintf(cioin,"%-11ld",ppnum3++/2);
|
|
1671 break;
|
|
1672 case '4':
|
|
1673 fprintf(cioin,"%-11d",optind);
|
|
1674 break;
|
|
1675 case '6':
|
|
1676 fprintf(cioin,"%-11ld",ppnum6++/2);
|
|
1677 break;
|
|
1678 default:
|
|
1679 ick_lose(IE778, -1, (const char*) NULL);
|
|
1680 }
|
|
1681 (void) fseek(cioin,0L,SEEK_CUR); /* synch the file */
|
|
1682 }
|
|
1683 ciopos=ftell(cioin);
|
|
1684 inchar=fgetc(cioin);
|
|
1685 }
|
|
1686 /*@=charintliteral@*/
|
|
1687 (void) fclose(cioin);
|
|
1688 }
|
|
1689 }
|
|
1690 fprintf(cioallec,"if(ick_global_checkmode==2)\n");
|
|
1691 fprintf(cioallec," ick_global_checkmode=4;\n");
|
|
1692 fprintf(cioallec,"};\n");
|
|
1693 (void) fclose(cioallec);
|
|
1694
|
|
1695 /* NOTE: buffer changes use around here. */
|
|
1696
|
|
1697 /* This command line needs some explanation, and is specific to gcc and
|
|
1698 GNU ld. The -x causes gcc to interpret the .cio files as C; the
|
|
1699 -Wl,-z,muldefs is an instruction to GNU ld, telling it to link in the
|
|
1700 first main found and ignore the others. (That way, there can be a
|
|
1701 main function in each .cio, but the .cios can be linked in any order,
|
|
1702 with the right main function foremost each time.)
|
|
1703 */
|
|
1704 (void) ick_snprintf_or_die(buffer, sizeof buffer,
|
|
1705 "%s -L%s -L%s -L%s/../lib -O2 -o %s" EXEEXT "%s "
|
|
1706 #ifndef __DJGPP__
|
|
1707 "-Wl,-z,muldefs "
|
|
1708 #endif
|
|
1709 "-DICK_HAVE_STDINT_H=%d -x c --std=c%d %s", compiler, libdir,
|
|
1710 path, path, argv[oldoptind], cdebug?" -g":"", ICK_HAVE_STDINT_H+1==2?1:0,
|
|
1711 needc99?99:89,tempfn);
|
|
1712 remspace = (long)(sizeof buffer - strlen(buffer) - 1);
|
|
1713 for(optind=oldoptind; optind < argc; optind++)
|
|
1714 {
|
|
1715 if(!*(argv[optind])) continue;
|
|
1716 remspace -= strlen(argv[optind]) - 5; /* 5 for <space>.cio */
|
|
1717 if(remspace <= 0)
|
|
1718 ick_lose(IE666, -1, (const char*)NULL);
|
|
1719 strcat(buffer," ");
|
|
1720 strcat(buffer,argv[optind]);
|
|
1721 strcat(buffer,".cio");
|
|
1722 }
|
|
1723 remspace -= strlen(libbuf);
|
|
1724 if(remspace <= 0)
|
|
1725 ick_lose(IE666, -1, (const char*)NULL);
|
|
1726 strcat(buffer,libbuf);
|
|
1727 remspace -= strlen(" -lickec");
|
|
1728 if(remspace <= 0)
|
|
1729 ick_lose(IE666, -1, (const char*)NULL);
|
|
1730 strcat(buffer," -lickec");
|
|
1731 ICK_SYSTEM(buffer);
|
|
1732 (void) remove(tempfn);
|
|
1733 }
|
|
1734
|
|
1735
|
|
1736 /*@-redef@*/
|
|
1737 int main(int argc, char *argv[])
|
|
1738 /*@=redef@*/
|
|
1739 {
|
|
1740 char buf[BUFSIZ], buf2[BUFSIZ], *chp, yukcmdstr[BUFSIZ], path[BUFSIZ],
|
|
1741 libbuf[BUFSIZ];
|
|
1742 /*@-shadow@*/ /* no it doesn't, cesspool isn't linked to perpet */
|
|
1743 const char *includedir, *libdir, *ick_datadir;
|
|
1744 /*@=shadow@*/
|
|
1745 /* AIS: removed getenv(), added ick_datadir */
|
|
1746 const char *cooptsh; /* AIS */
|
|
1747 FILE *ifp, *ofp;
|
|
1748 int /* nextcount, AIS */ bugline;
|
|
1749 ick_bool needsyslib, firstfile;
|
|
1750 int oldoptind;
|
|
1751 #ifdef HAVE_UNISTD_H
|
|
1752 int oldstdin; /* AIS: for keeping track of where stdin was */
|
|
1753 #endif
|
|
1754 if (!(includedir = getenv("ICKINCLUDEDIR")))
|
|
1755 includedir = ICKINCLUDEDIR;
|
|
1756 if (!(libdir = getenv("ICKLIBDIR")))
|
|
1757 libdir = ICKLIBDIR;
|
|
1758 if (!(ick_datadir = getenv("ICKDATADIR"))) /* AIS */
|
|
1759 ick_datadir = ICKDATADIR;
|
|
1760 /*
|
|
1761 AIS: nothing actually uses this at the moment,
|
|
1762 commenting it out for future use
|
|
1763
|
|
1764 if (!(bindir = getenv("ICKBINDIR")))
|
|
1765 bindir = ICKBINDIR;
|
|
1766 */
|
|
1767 if (!(compiler = getenv("CC")))
|
|
1768 compiler = CC;
|
|
1769
|
|
1770 /* Parse the options. */
|
|
1771 parse_options(argc, argv);
|
|
1772
|
|
1773 (void) signal(SIGSEGV, abend);
|
|
1774 #ifdef SIGBUS
|
|
1775 (void) signal(SIGBUS, abend);
|
|
1776 #endif /* SIGBUS */
|
|
1777
|
|
1778 if (!nocompilerbug) {
|
|
1779 #ifdef USG
|
|
1780 srand48(time(NULL) + getpid());
|
|
1781 #else
|
|
1782 srand((unsigned)time(NULL));
|
|
1783 #endif /* UNIX */
|
|
1784 }
|
|
1785
|
|
1786 /* AIS: New function for enhanced file-finding */
|
|
1787 ifp = ick_findandfopen(pickcompile?PSKELETON:SKELETON,
|
|
1788 ick_datadir, "r", argv[0]);
|
|
1789 if(!ifp) ick_lose(IE999, 1, (const char *)NULL);
|
|
1790
|
|
1791 /* now substitute in tokens in the skeleton */
|
|
1792
|
|
1793 /* AIS: This doesn't actually seem to do anything, and buf is
|
|
1794 uninitialised at this point, so it's actually dangerous
|
|
1795 because it's undefined behaviour.
|
|
1796 buf[strlen(buf) - 2] = '\0'; */
|
|
1797
|
|
1798 /* AIS: Save the old stdin, if we can */
|
|
1799 #ifdef HAVE_UNISTD_H
|
|
1800 oldstdin=dup(0);
|
|
1801 #endif
|
|
1802
|
|
1803 oldoptind=optind; /* AIS */
|
|
1804 *libbuf = '\0'; /* AIS */
|
|
1805 /* Begin file loop */
|
|
1806 for (firstfile = ick_TRUE; optind < argc; optind++, firstfile = ick_FALSE)
|
|
1807 {
|
|
1808 /* AIS: Read as binary to pick up Latin-1 and UTF-8 better */
|
|
1809 if (/* AIS */ strrchr(argv[optind],'.') != NULL &&
|
|
1810 freopen(argv[optind], "rb", stdin) == (FILE *)NULL &&
|
|
1811 /* AIS */ strcmp(strchr(argv[optind],'.')+1,"a"))
|
|
1812 ick_lose(IE777, 1, (const char *)NULL);
|
|
1813 else
|
|
1814 {
|
|
1815 /* strip off the file extension */
|
|
1816 if(!(chp = strrchr(argv[optind],'.')))
|
|
1817 {
|
|
1818 if(useickec && firstfile == ick_FALSE) /* By AIS */
|
|
1819 {
|
|
1820 /* the filename indicates a request for an expansion library,
|
|
1821 along the same lines as CLC-INTERCAL's preloads. Search for
|
|
1822 it in the usual places, then make a copy in a temp directory
|
|
1823 and substitute that on the command line. */
|
|
1824 const char* tempfn;
|
|
1825 FILE* fromcopy;
|
|
1826 FILE* tocopy;
|
|
1827 int c2;
|
|
1828 fixexpansionlibrary:
|
|
1829 tempfn="%s.c";
|
|
1830 (void) ick_snprintf_or_die(buf2, sizeof buf2, "%s.c", argv[optind]);
|
|
1831 fromcopy = ick_findandfopen(buf2,ick_datadir,"rb",argv[0]);
|
|
1832 if(!fromcopy) /* same error as for syslib */
|
|
1833 ick_lose(IE127, 1, (const char*) NULL);
|
|
1834 #if __DJGPP__
|
|
1835 /* Look for a temp directory to store a copy of the C file,
|
|
1836 the resulting .cio, .o files, etc. */
|
|
1837 if(isenv("TMP")) tempfn="/dev/env/TMP/%s.c";
|
|
1838 if(isenv("TEMP")) tempfn="/dev/env/TEMP/%s.c";
|
|
1839 if(isenv("TMPDIR")) tempfn="/dev/env/TMPDIR/%s.c";
|
|
1840 if(isenv("ICKTEMP")) tempfn="/dev/env/ICKTEMP/%s.c";
|
|
1841 #else
|
|
1842 tempfn="/tmp/%s.c"; /* always valid on POSIX */
|
|
1843 #endif
|
|
1844 /*@-formatconst@*/ /* all possibilities are fine */
|
|
1845 (void) ick_snprintf_or_die(buf2, sizeof buf2, tempfn, argv[optind]);
|
|
1846 /*@=formatconst@*/
|
|
1847 if((tocopy = fopen(buf2,"wb")) == NULL)
|
|
1848 ick_lose(IE888, 1, (const char*) NULL);
|
|
1849
|
|
1850 for(;;)
|
|
1851 {
|
|
1852 c2=fgetc(fromcopy);
|
|
1853 if(c2==EOF) break;
|
|
1854 (void) fputc(c2,tocopy);
|
|
1855 }
|
|
1856 (void) fclose(fromcopy); (void) fclose(tocopy);
|
|
1857 /*@+onlytrans@*/
|
|
1858 /* this is a memory leak that will need sorting out later,
|
|
1859 thus the explicit turn-warning-on */
|
|
1860 argv[optind]=malloc(sizeof(buf2)+1);
|
|
1861 /*@=onlytrans@*/
|
|
1862 if(!(argv[optind]))
|
|
1863 ick_lose(IE888, 1, (const char*) NULL);
|
|
1864 strcpy(argv[optind],buf2);
|
|
1865 *(strrchr(argv[optind],'.')) = '\0';
|
|
1866 continue;
|
|
1867 }
|
|
1868
|
|
1869 ick_lose(IE998, 1, (const char *)NULL);
|
|
1870 }
|
|
1871 *chp++ = '\0';
|
|
1872
|
|
1873 /* Beginning of block that figures out file type from extension. */
|
|
1874 if(useickec && (!strcmp(chp,"c") || !strcmp(chp,"cio") ||
|
|
1875 !strcmp(chp,"c99"))) /* AIS */
|
|
1876 {
|
|
1877 if(firstfile != ick_FALSE) /* need exactly 1 INTERCAL file */
|
|
1878 ick_lose(IE998, 1, (const char *)NULL);
|
|
1879 continue; /* don't process C or cio files further yet */
|
|
1880 }
|
|
1881
|
|
1882 if(useickec && !strcmp(chp,"a"))
|
|
1883 {
|
|
1884 /* AIS: request for a library. Given a filename of the form
|
|
1885 libwhatever.a, it adds -lwhatever to libbuf (that's with
|
|
1886 a preceding space). If the filename doesn't start with lib,
|
|
1887 it instead adds a space and the filename to libbuf. */
|
|
1888 handle_archive(libbuf, sizeof libbuf,
|
|
1889 argv[optind] /* Archive name without extension. */);
|
|
1890 *argv[optind]='\0';
|
|
1891 continue;
|
|
1892 }
|
|
1893
|
|
1894 if(useickec && !strcmp(chp,"b98"))
|
|
1895 {
|
|
1896 handle_befunge98(libbuf, sizeof libbuf, libdir, argv[0],
|
|
1897 argv[optind] /* Filename without extension. */);
|
|
1898 /* Sort out the ecto_b98 expansion library. */
|
|
1899 argv[optind] = "ecto_b98";
|
|
1900 goto fixexpansionlibrary;
|
|
1901 }
|
|
1902
|
|
1903 if(useickec && firstfile == ick_FALSE) /* AIS */
|
|
1904 ick_lose(IE998, 1, (const char *)NULL);
|
|
1905
|
|
1906 /* determine the file type from the extension */
|
|
1907 /* AN: chp isn't used again after this it seems? */
|
|
1908 find_intercal_base(chp);
|
|
1909
|
|
1910 /* End of block that figures out file type from extension. */
|
|
1911
|
|
1912 /* zero out tuple and oblist storage */
|
|
1913 treset();
|
|
1914 politesse = 0;
|
|
1915 /* JH: default to no op-overusage and no computed come from */
|
|
1916 opoverused = 0;
|
|
1917 compucomesused = compucomecount = 0;
|
|
1918 gerucomesused = 0; /* AIS: you forgot this one */
|
|
1919 /* AIS: ensure that at least one variable exists, to prevent
|
|
1920 NULL pointers later on */
|
|
1921 (void) intern(ick_ONESPOT, 1); /* mention .1 */
|
|
1922
|
|
1923 /* reset the lex/yacc environment */
|
|
1924 if (!firstfile)
|
|
1925 {
|
|
1926 #ifdef NEED_YYRESTART
|
|
1927 yyrestart(stdin);
|
|
1928 #endif /* NEED_YYRESTART */
|
|
1929 iyylineno = 1;
|
|
1930 }
|
|
1931
|
|
1932 /* compile tuples from current input source */
|
|
1933 (void) yyparse();
|
|
1934
|
|
1935 if(variableconstants)
|
|
1936 {
|
|
1937 /* AIS: Up to 4 extra meshes may be needed by feh.c. */
|
|
1938 (void) intern(MESH, 0xFFFFFFFFLU);
|
|
1939 (void) intern(MESH, 0xFFFFLU);
|
|
1940 (void) intern(MESH, 0xAAAAAAAALU);
|
|
1941 (void) intern(MESH, 0x55555555LU);
|
|
1942 }
|
|
1943
|
|
1944
|
|
1945 /*
|
|
1946 * Miss Manners lives.
|
|
1947 */
|
|
1948 if (ick_lineno > 2)
|
|
1949 {
|
|
1950 if (politesse == 0 || (ick_lineno - 1) / politesse >= 5)
|
|
1951 ick_lose(IE079, iyylineno, (const char *)NULL);
|
|
1952 else if (ick_lineno / politesse < 3)
|
|
1953 ick_lose(IE099, iyylineno, (const char *)NULL);
|
|
1954 }
|
|
1955
|
|
1956 /* Check if we should auto add the system library. */
|
|
1957 check_syslib(buf2, sizeof buf2, &needsyslib, argv[0], ick_datadir);
|
|
1958
|
|
1959 /*
|
|
1960 * Now propagate type information up the expression tree.
|
|
1961 * We need to do this because the unary-logical operations
|
|
1962 * are sensitive to the type widths of their operands, so
|
|
1963 * we have to generate different code depending on the
|
|
1964 * deducible type of the operand.
|
|
1965 */
|
|
1966 propagate_typeinfo();
|
|
1967
|
|
1968 codecheck(); /* check for compile-time errors */
|
|
1969 /* AIS: And importantly, sort out line number references */
|
|
1970 run_optimiser();
|
|
1971
|
|
1972 /* decide if and where to place the compiler bug */
|
|
1973 bugline = randomise_bugline();
|
|
1974
|
|
1975 /* set up the generated C output file name */
|
|
1976 (void) ick_snprintf_or_die(buf, sizeof buf, "%s.c", argv[optind]);
|
|
1977 /* Open output file. */
|
|
1978 ofp = open_outfile(buf /* Output filename */);
|
|
1979
|
|
1980 (void) fseek(ifp,0L,0); /* rewind skeleton file */
|
|
1981
|
|
1982 /* AIS: Before changing argv[0], locate coopt.sh. */
|
|
1983 /* AN: Even though argv[0] isn't changed any more this breaks if moved out
|
|
1984 * of the per-file loop since ick_findandtestopen() returns a pointer to a
|
|
1985 * static buffer. Should be fixed.
|
|
1986 */
|
|
1987 cooptsh = ick_findandtestopen("coopt.sh", ick_datadir, "rb", argv[0]);
|
|
1988 /* AIS: and calculate yukcmdstr. */
|
|
1989 (void) ick_snprintf_or_die(yukcmdstr, sizeof yukcmdstr, "%s%s" EXEEXT " %s %s",
|
|
1990 strchr(argv[optind],'/')||strchr(argv[optind],'\\')?
|
|
1991 "":"./",argv[optind],ick_datadir,argv[0]);
|
|
1992
|
|
1993 /* AIS: Remove the filename from argv[0], leaving only a directory.
|
|
1994 If this would leave it blank, change argv[0] to '.'.
|
|
1995 This is so gcc can find the includes/libraries the same way that
|
|
1996 ick_findandfreopen does. */
|
|
1997 /* JH: use a copy of argv[0] for the path, to ensure argv[0] is
|
|
1998 * available for the next round
|
|
1999 */
|
|
2000 strcpy(path,argv[0]);
|
|
2001 if(strchr(path,'/')) *(strrchr(path,'/')) = '\0';
|
|
2002 else strcpy(path,".");
|
|
2003
|
|
2004 /* Generate the compiler command. */
|
|
2005 gen_cc_command(buf2 /* output */, sizeof buf2, buf /* Source filename. */,
|
|
2006 includedir, path, libdir, argv[optind] /* Output binary filename. */);
|
|
2007
|
|
2008 textlinecount=0; /* AIS: If there are no files, there's
|
|
2009 no need to free any textlines */
|
|
2010 /* Generate code using ick-wrap.c (or pickwrap.c) */
|
|
2011 generate_code(ifp, ofp, argv[optind] /* Source file name stem. */,
|
|
2012 &needsyslib, bugline, buf2 /* CC command. */);
|
|
2013
|
|
2014 if(!outtostdout) (void) fclose(ofp);
|
|
2015
|
|
2016 /* OK, now sic the C compiler on the results */
|
|
2017 /* Also: if -y was given, run debugger */
|
|
2018 run_cc_and_maybe_debugger(buf2, oldstdin, yukcmdstr, buf /* C file name */,
|
|
2019 argv[optind] /* Binary filename */);
|
|
2020
|
|
2021 /* Run the constant-output optimizer (a form of post-processor). */
|
|
2022 run_coopt(cooptsh, argv[optind]);
|
|
2023
|
|
2024 }
|
|
2025 }
|
|
2026 /* Here ends the per-file loop. */
|
|
2027 (void) fclose(ifp);
|
|
2028
|
|
2029 if(!compile_only && useickec) /* AIS */
|
|
2030 prelink(argc, argv, oldoptind, libdir, includedir, path, libbuf);
|
|
2031
|
|
2032 /* AIS: Free malloc'd memory. */
|
|
2033 if(textlines)
|
|
2034 {
|
|
2035 /* Marking what textlines points to as only would be the 'right'
|
|
2036 way to do this (because it is only), but I can't figure out the
|
|
2037 syntax to do it, so instead I'm supressing the warning that comes
|
|
2038 up because it isn't marked as only. */
|
|
2039 /*@-unqualifiedtrans@*/
|
|
2040 while(textlinecount--) free(textlines[textlinecount]);
|
|
2041 free(textlines);
|
|
2042 /*@=unqualifiedtrans@*/
|
|
2043 }
|
|
2044
|
|
2045 #ifdef HAVE_UNISTD_H
|
|
2046 (void) close(oldstdin); /* AIS */
|
|
2047 #endif
|
|
2048 /* This point is the very end of the program. So it's correct for
|
|
2049 normal DO NOT FREE UNDER ANY CIRCUMSTANCES globals to be free
|
|
2050 at this point, so supressing the warning given as a result. */
|
|
2051 /*@-globstate@*/
|
|
2052 return 0;
|
|
2053 /*@=globstate@*/
|
|
2054 }
|
|
2055
|
|
2056 /* perpet.c ends here */
|