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 */