Mercurial > repo
comparison interps/c-intercal/src/perpet.c @ 996:859f9b4339e6
<Gregor> tar xf egobot.tar.xz
author | HackBot |
---|---|
date | Sun, 09 Dec 2012 19:30:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
995:6883f5911eb7 | 996:859f9b4339e6 |
---|---|
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 */ |