996
|
1 /****************************************************************************
|
|
2
|
|
3 Name
|
|
4 feh2.c -- code-generator back-end for ick parser
|
|
5
|
|
6 DESCRIPTION
|
|
7 This module provides storage manglement and code degeneration
|
|
8 for the INTERCAL compiler. Optimizations (formerly in this file)
|
|
9 were split into dekludge.c.
|
|
10
|
|
11 LICENSE TERMS
|
|
12 Copyright (C) 1996 Eric S. Raymond
|
|
13
|
|
14 This program is free software; you can redistribute it and/or modify
|
|
15 it under the terms of the GNU General Public License as published by
|
|
16 the Free Software Foundation; either version 2 of the License, or
|
|
17 (at your option) any later version.
|
|
18
|
|
19 This program is distributed in the hope that it will be useful,
|
|
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
22 GNU General Public License for more details.
|
|
23
|
|
24 You should have received a copy of the GNU General Public License
|
|
25 along with this program; if not, write to the Free Software
|
|
26 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
27
|
|
28 ****************************************************************************/
|
|
29 /*LINTLIBRARY */
|
|
30 #include "config.h"
|
|
31 #include <stdio.h>
|
|
32 #include <stdlib.h>
|
|
33 #include <string.h>
|
|
34 #include <assert.h>
|
|
35 #include "sizes.h"
|
|
36 #include "ick.h"
|
|
37 #include "parser.h"
|
|
38 #include "fiddle.h"
|
|
39 #include "ick_lose.h"
|
|
40 #include "feh.h"
|
|
41
|
|
42 /* AIS: Destaticed for dekludge.c */
|
|
43 int emitlineno; /* line number for errors encountered during emit */
|
|
44
|
|
45 /*@-exportlocal@*/ /* the parser uses this */
|
|
46 int mark112 = 0; /* AIS: Mark the ick_next generated tuple for W112 */
|
|
47 /*@=exportlocal@*/
|
|
48
|
|
49 /* AIS: From perpet.c */
|
|
50 extern int pickcompile;
|
|
51 extern int ick_clcsemantics;
|
|
52
|
|
53 /*************************************************************************
|
|
54 *
|
|
55 * Node allocation functions.
|
|
56 *
|
|
57 * Nodes are used to represent expression trees. The emit() function
|
|
58 * deallocates them.
|
|
59 *
|
|
60 **************************************************************************/
|
|
61
|
|
62 /*@partial@*/ node *newnode(void)
|
|
63 /* allocate and zero out a new expression node */
|
|
64 {
|
|
65 node* temp;
|
|
66 temp=calloc(sizeof(node), 1);
|
|
67 if(!temp) ick_lose(IE345, 0, (const char*) NULL);
|
|
68 return temp;
|
|
69 }
|
|
70
|
|
71 /*@partial@*/ node *cons(int type, /*@null@*/ /*@keep@*/ node *car, /*@null@*/ /*@keep@*/ node *cdr)
|
|
72 {
|
|
73 node *np = newnode();
|
|
74
|
|
75 np->opcode = type;
|
|
76 np->lval = car;
|
|
77 np->rval = cdr;
|
|
78
|
|
79 return(np);
|
|
80 }
|
|
81
|
|
82 /*************************************************************************
|
|
83 *
|
|
84 * Variable-name mapping
|
|
85 *
|
|
86 * This permits us to optimize use of variable storage at runtime
|
|
87 *
|
|
88 **************************************************************************/
|
|
89
|
|
90 unsigned long intern(int type, unsigned long index)
|
|
91 {
|
|
92 atom *x;
|
|
93
|
|
94 /* AIS: Allow use of a modifiable constant 0 or >65535. */
|
|
95 if ((index < 1LU || index > 65535LU) && type!=MESH)
|
|
96 ick_lose(IE200, iyylineno, (const char *)NULL);
|
|
97
|
|
98 /*@-branchstate@*/
|
|
99 if (!oblist)
|
|
100 {
|
|
101 /* initialize oblist and obdex */
|
|
102 oblist = malloc(ALLOC_CHUNK * sizeof(atom));
|
|
103 if (!oblist)
|
|
104 ick_lose(IE345, iyylineno, (const char *)NULL);
|
|
105 obdex = oblist;
|
|
106 obcount = ALLOC_CHUNK;
|
|
107 }
|
|
108 else
|
|
109 {
|
|
110 /* if it's already on the oblist, return its intindex */
|
|
111 for (x = oblist; x < obdex; x++)
|
|
112 if (x->type == type && x->extindex == index)
|
|
113 return(x->intindex);
|
|
114 }
|
|
115 /*@=branchstate@*/
|
|
116 assert(oblist != NULL);
|
|
117
|
|
118 /* else we must intern a new symbol */
|
|
119 /* AIS: Splint doesn't understand what's going on here at all. Disabling
|
|
120 the warnings; I've checked this and think it's correct. */
|
|
121 /*@-usedef@*/ /*@-usereleased@*/ /*@-branchstate@*/
|
|
122 if (obdex >= oblist + obcount)
|
|
123 {
|
|
124 obcount += ALLOC_CHUNK;
|
|
125 x = realloc(oblist, obcount * sizeof(atom));
|
|
126 if (!x)
|
|
127 ick_lose(IE333, iyylineno, (const char *)NULL);
|
|
128 obdex = x + (obdex - oblist);
|
|
129 oblist = x;
|
|
130 }
|
|
131 /*@=branchstate@*/ /*@=usereleased@*/ /*@=usedef@*/
|
|
132 obdex->type = type;
|
|
133 obdex->extindex = index;
|
|
134 obdex->memloc = 0; /* AIS: not placed in memory yet */
|
|
135 if (type == ick_ONESPOT)
|
|
136 obdex->intindex = (unsigned)nonespots++;
|
|
137 if (type == ick_TWOSPOT)
|
|
138 obdex->intindex = (unsigned)ntwospots++;
|
|
139 if (type == ick_TAIL)
|
|
140 obdex->intindex = (unsigned)ntails++;
|
|
141 if (type == ick_HYBRID)
|
|
142 obdex->intindex = (unsigned)nhybrids++;
|
|
143 if (type == MESH) /* AIS: count meshes too */
|
|
144 obdex->intindex = (unsigned)nmeshes++;
|
|
145 ++obdex;
|
|
146
|
|
147 /*@-usedef@*/
|
|
148 return(obdex[-1].intindex);
|
|
149 /*@=usedef@*/
|
|
150 }
|
|
151
|
|
152 /*************************************************************************
|
|
153 *
|
|
154 * This function insures a label is valid.
|
|
155 *
|
|
156 **************************************************************************/
|
|
157
|
|
158 /* AIS: I haven't modified this function, but I have repurposed it without
|
|
159 changing the code; this function must not now have side effects (apart from
|
|
160 an error exit), because some labels are initialised in the preprocessor
|
|
161 without causing this. */
|
|
162 void checklabel(int label)
|
|
163 {
|
|
164 if (label < 1 || label > 65535)
|
|
165 ick_lose(IE197, iyylineno, (const char *)NULL);
|
|
166 }
|
|
167
|
|
168 /*************************************************************************
|
|
169 *
|
|
170 * AIS: Search for the indexth COME_FROM sucking in the given tuple.
|
|
171 * Return an int representing the COME_FROM's tn-tuples+1, or -1.
|
|
172 * index is based at 1, not 0 as is usual for C.
|
|
173 *
|
|
174 ***************************************************************************/
|
|
175
|
|
176 int comefromsearch(tuple* tn, unsigned int index)
|
|
177 {
|
|
178 tuple* tp;
|
|
179 for (tp = tuples; tp < tuples + ick_lineno; tp++)
|
|
180 {
|
|
181 if((tp->type == COME_FROM || tp->type == NEXTFROMLABEL)
|
|
182 && tp->u.target == (unsigned)(tn-tuples+1))
|
|
183 index--;
|
|
184 if(!index) return tp-tuples+1;
|
|
185 }
|
|
186 return -1;
|
|
187 }
|
|
188
|
|
189 /*************************************************************************
|
|
190 *
|
|
191 * Tuple allocation functions.
|
|
192 *
|
|
193 **************************************************************************/
|
|
194
|
|
195 void treset(void)
|
|
196 {
|
|
197 tuplecount = 0;
|
|
198 if (tuples)
|
|
199 {
|
|
200 /* AIS: Splint doesn't understand lazy allocation, which is why it
|
|
201 thinks I'm treating an unqualified as an only (I am, but a lazy
|
|
202 list doesn't fit any of Splint's storage classes); also, I am
|
|
203 completely destroying the tuples, because any nodes in them ought
|
|
204 to have been deallocated in prexpr. */
|
|
205 /*@-unqualifiedtrans@*/ /*@-compdestroy@*/
|
|
206 free(tuples);
|
|
207 tuples = NULL;
|
|
208 /*@=unqualifiedtrans@*/ /*@=compdestroy@*/
|
|
209 }
|
|
210 nmeshes = nonespots = ntwospots = ntails = nhybrids = 0;
|
|
211 obdex = oblist;
|
|
212 ick_lineno = 0;
|
|
213 /* AIS: It's easier to mark tuples as 'always allocated', because
|
|
214 it usually is, and just supress the warnings. Maybe the 'proper'
|
|
215 way to do it would be to assert that tuples was non-null everywhere,
|
|
216 but again this is just problems with Splint not understanding how
|
|
217 lazy allocation works. So I tell Splint that it's allocated everywhere
|
|
218 and just supress the warnings it produces when it isn't. */
|
|
219 /*@-globstate@*/
|
|
220 }
|
|
221 /*@=globstate@*/
|
|
222
|
|
223 /*@out@*/ /*@dependent@*/ tuple *newtuple(void)
|
|
224 /* allocate and zero out a new expression tuple */
|
|
225 {
|
|
226 /* Patch by Joris Huizer: must leave at least 1 tuple empty */
|
|
227 if (ick_lineno >= tuplecount - 1 || tuples == NULL)
|
|
228 {
|
|
229 tuplecount += ALLOC_CHUNK;
|
|
230 if (tuples)
|
|
231 tuples = realloc(tuples, tuplecount * sizeof(tuple));
|
|
232 else
|
|
233 tuples = malloc(tuplecount * sizeof(tuple));
|
|
234 if (!tuples)
|
|
235 ick_lose(IE666, iyylineno, (const char *)NULL);
|
|
236 memset(tuples + ick_lineno, 0, (tuplecount - ick_lineno) * sizeof(tuple));
|
|
237 }
|
|
238 if(mark112) tuples[ick_lineno].warn112 = 1; mark112 = 0; /* AIS */
|
|
239 /* Yes, tuples is strictly speaking 'partial' at this point, but it's going
|
|
240 to be filled in later, and isn't marked as partial due to it not being
|
|
241 partial through most of the code, and you can't write out on a global.
|
|
242 So instead I'm just suppressing the warning, because it doesn't lead to
|
|
243 a problem long-term. */
|
|
244 /*@-compdef@*/
|
|
245 return(tuples + ick_lineno++);
|
|
246 /*@=compdef@*/
|
|
247 }
|
|
248
|
|
249 void tupleswap(int distback1, int distback2)
|
|
250 {
|
|
251 tuple temp;
|
|
252 memcpy(&temp, &tuples[ick_lineno-distback1], sizeof(tuple));
|
|
253 memcpy(&tuples[ick_lineno-distback1], &tuples[ick_lineno-distback2], sizeof(tuple));
|
|
254 memcpy(&tuples[ick_lineno-distback2], &temp, sizeof(tuple));
|
|
255 /* Splint doesn't understand memcpy, and so falsely things this is a memory leak. */
|
|
256 /*@-compdestroy@*/
|
|
257 }
|
|
258 /*@=compdestroy@*/
|
|
259
|
|
260 void ppinit(int tuplecount)
|
|
261 {
|
|
262 while(tuplecount)
|
|
263 {
|
|
264 /* 0 is an impossible exechance; make sure it's set for tuple elements. */
|
|
265 if(!tuples[ick_lineno-tuplecount].exechance)
|
|
266 tuples[ick_lineno-tuplecount].exechance=100;
|
|
267 /* The onceagainflag also needs to be set. */
|
|
268 tuples[ick_lineno-tuplecount].onceagainflag=onceagain_NORMAL;
|
|
269 tuplecount--;
|
|
270 }
|
|
271 }
|
|
272
|
|
273 /*************************************************************************
|
|
274 *
|
|
275 * The typecaster
|
|
276 *
|
|
277 * The theory here is that we associate a type with each node in order to
|
|
278 * know what widths of unary-logical operator to use.
|
|
279 *
|
|
280 **************************************************************************/
|
|
281
|
|
282 void typecast(node *np)
|
|
283 {
|
|
284 /* recurse so we typecast each node after all its subnodes */
|
|
285 if (np == (node *)NULL)
|
|
286 return;
|
|
287 else if (np->lval != (node *)NULL)
|
|
288 typecast(np->lval);
|
|
289 if (np->rval != (node *)NULL)
|
|
290 typecast(np->rval);
|
|
291
|
|
292 /*
|
|
293 * This is an entire set of type-deducing machinery right here.
|
|
294 */
|
|
295 /*@-nullderef@*/ /* AIS: because the opcode defines whether lval or rval are nonnull */
|
|
296 if (np->opcode == MESH || np->opcode == ick_ONESPOT || np->opcode == ick_TAIL)
|
|
297 np->width = 16;
|
|
298 else if (np->opcode == ick_TWOSPOT || np->opcode == ick_HYBRID
|
|
299 || np->opcode == MINGLE || np->opcode == MESH32
|
|
300 || np->opcode == UNKNOWNOP /* AIS */)
|
|
301 np->width = 32;
|
|
302 else if (np->opcode == AND || np->opcode == OR || np->opcode == XOR ||
|
|
303 np->opcode == FIN ||
|
|
304 (np->opcode >= WHIRL && np->opcode <= WHIRL5))
|
|
305 np->width = np->rval->width;
|
|
306 else if (np->opcode == SELECT)
|
|
307 np->width = np->rval->width; /* n-bit select has an n-bit result */
|
|
308 else if (np->opcode == INTERSECTION) /* AIS */
|
|
309 np->width = (np->rval ?
|
|
310 np->lval ? np->rval->width == 16 ? np->lval->width : 32 :
|
|
311 np->rval->width : np->lval ? np->lval->width : 32);
|
|
312 else if (np->opcode == BADCHAR) /* AIS */
|
|
313 np->width = 16;
|
|
314 else if (np->opcode == SUB)
|
|
315 np->width = np->lval->width; /* type of the array */
|
|
316 else if (np->opcode == SLAT || np->opcode == BACKSLAT)
|
|
317 np->width = np->lval->width; /* AIS: \ and / return their left arg */
|
|
318 /*@=nullderef@*/
|
|
319 }
|
|
320
|
|
321 /*************************************************************************
|
|
322 *
|
|
323 * The codechecker
|
|
324 *
|
|
325 * This checks for nasties like mismatched types in assignments that
|
|
326 * can be detected at compile time -- also for errors that could cause
|
|
327 * the compilation of the generated C to fail, like generated gotos to
|
|
328 * nonexistent labels or duplicate labels.
|
|
329 *
|
|
330 * AIS: codecheck has another important job, that of filling in information
|
|
331 * about COME FROM suckpoints and ABSTAIN/REINSTATE command numbers
|
|
332 * into the tuples.
|
|
333 *
|
|
334 **************************************************************************/
|
|
335
|
|
336 void codecheck(void)
|
|
337 {
|
|
338 tuple *tp, *up;
|
|
339 int notpast1900; /* AIS */
|
|
340
|
|
341 /* check for assignment type mismatches */
|
|
342 /* This check can't be done at compile time---RTFM. [LHH] */
|
|
343 /*
|
|
344 for (tp = tuples; tp < tuples + ick_lineno; tp++)
|
|
345 if (tp->type == GETS)
|
|
346 if (tp->u.node->lval->width == 16 && tp->u.node->rval->width == 32)
|
|
347 ick_lose(IE275, tp - tuples + 1, (const char *)NULL);
|
|
348 */
|
|
349
|
|
350 /* check for duplicate labels */
|
|
351 for (tp = tuples; tp < tuples + ick_lineno; tp++)
|
|
352 if (tp->label)
|
|
353 for (up = tuples; up < tuples + ick_lineno; up++)
|
|
354 if (tp != up && tp->label == up->label)
|
|
355 ick_lose(IE182, tp - tuples + 1, (const char *)NULL);
|
|
356
|
|
357 /*
|
|
358 * Check that every NEXT, ABSTAIN, REINSTATE and COME_FROM actually has a
|
|
359 * legitimate target label.
|
|
360 */
|
|
361 notpast1900 = ick_TRUE;
|
|
362 for (tp = tuples; tp < tuples + ick_lineno; tp++)
|
|
363 {
|
|
364 if (tp->label == 1900) notpast1900 = ick_FALSE; /* AIS */
|
|
365 if (tp->type == NEXT
|
|
366 || tp->type == ABSTAIN || tp->type == REINSTATE
|
|
367 || tp->type == COME_FROM || tp->type == FROM
|
|
368 || tp->type == NEXTFROMLABEL) /* AIS: added FROM, NEXTFROMLABEL. */
|
|
369 {
|
|
370 ick_bool foundit = ick_FALSE;
|
|
371
|
|
372 if (tp->u.target >= 1900 && tp->u.target <= 1998)
|
|
373 {
|
|
374 /* AIS: This program uses syslib.i's random number feature... or are
|
|
375 we in syslib already? */
|
|
376 if(notpast1900) coopt = 0;
|
|
377 }
|
|
378
|
|
379 if (tp->u.target > 65535 && !tp->preproc) /* AIS */
|
|
380 ick_lose(IE197, tp - tuples + 1, (const char*) NULL);
|
|
381
|
|
382 for (up = tuples; up < tuples + ick_lineno; up++)
|
|
383 if (tp->u.target == up->label)
|
|
384 {
|
|
385 foundit = ick_TRUE;
|
|
386 break;
|
|
387 }
|
|
388
|
|
389 if (!foundit)
|
|
390 {
|
|
391 /* AIS: Added the pickcompile check. Syslib has to be optimized
|
|
392 for PICs, so syslib.i isn't imported and so none of the lables
|
|
393 in it will appear in the program. Also added the useickec
|
|
394 check, as that's another legitimate way for a NEXT to target
|
|
395 a nonexistent line label */
|
|
396 if (tp->type == NEXT && !useickec &&
|
|
397 (!pickcompile||tp->u.target<1000||tp->u.target>1999))
|
|
398 ick_lose(IE129, tp - tuples + 1, (const char *)NULL);
|
|
399 else if (tp->type == NEXT) /* AIS */
|
|
400 {tp->nexttarget=0; continue;}
|
|
401 else if (useickec) /* AIS */
|
|
402 continue;
|
|
403 /* AIS: NEXTFROMLABEL's basically identical to COME_FROM */
|
|
404 else if (tp->type == COME_FROM || tp->type == NEXTFROMLABEL)
|
|
405 ick_lose(IE444, tp - tuples + 1, (const char *)NULL);
|
|
406 else
|
|
407 ick_lose(IE139, tp - tuples + 1, (const char *)NULL);
|
|
408 }
|
|
409 /* tell the other tuple if it is a COME FROM target */
|
|
410 /* AIS: NEXTFROMLABEL again */
|
|
411 else if (tp->type == COME_FROM || tp->type == NEXTFROMLABEL)
|
|
412 {
|
|
413 if (up->ncomefrom && !multithread) /* AIS: multithread check */
|
|
414 ick_lose(IE555, iyylineno, (const char *)NULL);
|
|
415 else
|
|
416 up->ncomefrom++; /* AIS: to handle multiple COME FROMs */
|
|
417 }
|
|
418 /* this substitutes line numbers for label numbers
|
|
419 AIS: COME FROM now uses this too. This changes the logic
|
|
420 slightly so that an !foundit condition would fall through,
|
|
421 but as long as ick_lose doesn't return, it's not a problem.
|
|
422 (I removed the else before the if.) */
|
|
423 if (tp->type != NEXT)
|
|
424 {
|
|
425 /* AIS: added this useickec condition. */
|
|
426 if(!useickec || (tp->type!=NEXTFROMLABEL && tp->type!=COME_FROM))
|
|
427 tp->u.target = (unsigned)(up - tuples + 1);
|
|
428 }
|
|
429 else /* AIS */
|
|
430 {
|
|
431 tp->nexttarget = (unsigned)(up - tuples + 1);
|
|
432 up->nextable = ick_TRUE;
|
|
433 }
|
|
434 }
|
|
435 }
|
|
436 }
|
|
437
|
|
438 /* AIS: Added the third argument to prexpr and prvar. It specifies
|
|
439 whether the node should be freed or not. I added the third
|
|
440 argument in all calls of prexpr/prvar. This protoype has been moved
|
|
441 up through the file so it can be used earlier. Destaticed so it can
|
|
442 be referenced by dekludge.c. */
|
|
443 void prexpr(node *np, FILE *fp, int freenode);
|
|
444 /*************************************************************************
|
|
445 *
|
|
446 * Code degeneration
|
|
447 *
|
|
448 * The theory behind this crock is that we've been handed a pointer to
|
|
449 * a tuple representing a single INTERCAL statement, possibly with an
|
|
450 * expression tree hanging off it and twisting slowly, slowly in the wind.
|
|
451 *
|
|
452 * Our mission, should we choose to accept it, is to emit C code which,
|
|
453 * when linked to the INTERCAL run-time support, will do something
|
|
454 * resembling the right thing.
|
|
455 *
|
|
456 **************************************************************************/
|
|
457
|
|
458 /*
|
|
459 * If the order of statement-token defines in parser.y ever changes,
|
|
460 * this will need to be reordered.
|
|
461 */
|
|
462 /*@observer@*/ const char *enablersm1[MAXTYPES+1] =
|
|
463 {
|
|
464 "UNKNOWN", /* AIS: so comments can be ABSTAINED/REINSTATED */
|
|
465 "GETS",
|
|
466 "RESIZE",
|
|
467 "NEXT",
|
|
468 "GO_AHEAD", /* AIS: Added for backtracking */
|
|
469 "GO_BACK", /* AIS: Added for backtracking */
|
|
470 "FORGET",
|
|
471 "RESUME",
|
|
472 "STASH",
|
|
473 "RETRIEVE",
|
|
474 "IGNORE",
|
|
475 "REMEMBER",
|
|
476 "ABSTAIN",
|
|
477 "REINSTATE",
|
|
478 "DISABLE",
|
|
479 "ENABLE",
|
|
480 "MANYFROM", /* AIS: Added ABSTAIN expr FROM gerunds */
|
|
481 "GIVE_UP",
|
|
482 "READ_OUT",
|
|
483 "WRITE_IN",
|
|
484 "PIN",
|
|
485 "COME_FROM",
|
|
486 "NEXTFROMLABEL", /* AIS */
|
|
487 "NEXTFROMEXPR", /* AIS */
|
|
488 "NEXTFROMGERUND", /* AIS */
|
|
489 "COMPUCOME", /* AIS: Added COMPUCOME */
|
|
490 "GERUCOME", /* AIS: This is COME FROM gerunds */
|
|
491 "PREPROC", /* AIS: Nonexistent statement */
|
|
492 "WHILE", /* AIS: statement WHILE statement */
|
|
493 "TRY_AGAIN", /* AIS: Added TRY AGAIN */
|
|
494 "CREATE", /* AIS */
|
|
495 "COMPUCREATE", /* AIS */
|
|
496 "FROM", /* AIS: ABSTAIN expr FROM LABEL */
|
|
497 };
|
|
498 const char** enablers = enablersm1+1;
|
|
499
|
|
500 const assoc vartypes[] =
|
|
501 {
|
|
502 { ick_ONESPOT, "ick_ONESPOT" },
|
|
503 { ick_TWOSPOT, "ick_TWOSPOT" },
|
|
504 { ick_TAIL, "ick_TAIL" },
|
|
505 { ick_HYBRID, "ick_HYBRID" },
|
|
506 { 0, (const char *)NULL }
|
|
507 };
|
|
508
|
|
509 static const assoc forgetbits[] =
|
|
510 {
|
|
511 { ick_ONESPOT, "ick_oneforget" },
|
|
512 { ick_TWOSPOT, "ick_twoforget" },
|
|
513 { ick_TAIL, "ick_tailforget" },
|
|
514 { ick_HYBRID, "ick_hyforget" },
|
|
515 { 0, (const char *)NULL }
|
|
516 };
|
|
517
|
|
518 /* AIS: Destatic. This is now needed in perpet.c. */
|
|
519 const assoc varstores[] =
|
|
520 {
|
|
521 { ick_ONESPOT, "ick_onespots" },
|
|
522 { ick_TWOSPOT, "ick_twospots" },
|
|
523 { ick_TAIL, "ick_tails" },
|
|
524 { ick_HYBRID, "ick_hybrids" },
|
|
525 { 0, (const char *)NULL }
|
|
526 };
|
|
527
|
|
528 /* AIS: A demangled version */
|
|
529 static const assoc varstoresdem[] =
|
|
530 {
|
|
531 { ick_ONESPOT, "onespots" },
|
|
532 { ick_TWOSPOT, "twospots" },
|
|
533 { ick_TAIL, "tails" },
|
|
534 { ick_HYBRID, "hybrids" },
|
|
535 { 0, (const char *)NULL }
|
|
536 };
|
|
537
|
|
538 static const assoc typedefs[] =
|
|
539 {
|
|
540 { ick_ONESPOT, "ick_type16" },
|
|
541 { ick_TWOSPOT, "ick_type32" },
|
|
542 { ick_TAIL, "ick_type16" },
|
|
543 { ick_HYBRID, "ick_type32" },
|
|
544 { 0, (const char *)NULL }
|
|
545 };
|
|
546
|
|
547 /*@observer@*/ const char *nameof(int value, const assoc table[])
|
|
548 /* return string corresponding to value in table */
|
|
549 {
|
|
550 const assoc *ap;
|
|
551
|
|
552 for (ap = table; ap->name; ap++)
|
|
553 if (ap->value == value)
|
|
554 return(ap->name);
|
|
555 return((const char *)NULL);
|
|
556 }
|
|
557
|
|
558 /* AIS: Code for printing explanations (mixed C/INTERCAL code that lets
|
|
559 the user know what the meaning of an expression is). This is paraphrased
|
|
560 from the prexpr/prvar code lower down. It's passed to yuk so that the
|
|
561 explain ('e') command works. It's also included in the degenerated C
|
|
562 code when the option -c is used, so the person looking at the code can
|
|
563 debug both the INTERCAL and ick itself more effectively, and used by
|
|
564 -h to produce its optimizer-debug output, and used to produce the variable
|
|
565 numbers used in ick_createdata. */
|
|
566
|
|
567 unsigned long varextern(unsigned long intern, int vartype)
|
|
568 {
|
|
569 atom *x;
|
|
570 if(!oblist) ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
571 for (x = oblist; x < obdex; x++)
|
|
572 if (x->type == vartype && (unsigned long)x->intindex == intern)
|
|
573 return(x->extindex);
|
|
574 if(vartype==MESH) return 0; /* the mesh wasn't used after all */
|
|
575 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
576 /*@-unreachable@*/ return 0; /*@=unreachable@*/
|
|
577 }
|
|
578
|
|
579 static void explvar(node* np, FILE* fp)
|
|
580 {
|
|
581 node *sp;
|
|
582 switch(np->opcode)
|
|
583 {
|
|
584 case ick_ONESPOT:
|
|
585 (void) fprintf(fp, ".%lu", varextern(np->constant,ick_ONESPOT));
|
|
586 break;
|
|
587 case ick_TWOSPOT:
|
|
588 (void) fprintf(fp, ":%lu", varextern(np->constant,ick_TWOSPOT));
|
|
589 break;
|
|
590 case ick_TAIL:
|
|
591 (void) fprintf(fp, ",%lu", varextern(np->constant,ick_TAIL));
|
|
592 break;
|
|
593 case ick_HYBRID:
|
|
594 (void) fprintf(fp, ";%lu", varextern(np->constant,ick_HYBRID));
|
|
595 break;
|
|
596 case SUB:
|
|
597 (void) fprintf(fp, "(");
|
|
598 explvar(np->lval, fp);
|
|
599 (void) fprintf(fp, " SUB ");
|
|
600 for (sp = np->rval ; sp ; sp = sp->rval)
|
|
601 explexpr(sp->lval, fp);
|
|
602 (void) fprintf(fp, ")");
|
|
603 break;
|
|
604 default:
|
|
605 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
606 }
|
|
607 }
|
|
608
|
|
609 /* unlike prexpr, this doesn't free its operands */
|
|
610 void explexpr(node* np, FILE* fp)
|
|
611 {
|
|
612 if(!np) return;
|
|
613 switch (np->opcode)
|
|
614 {
|
|
615 case MINGLE:
|
|
616 (void) fprintf(fp, "(");
|
|
617 explexpr(np->lval, fp);
|
|
618 (void) fprintf(fp, " $ ");
|
|
619 explexpr(np->rval, fp);
|
|
620 (void) fprintf(fp, ")");
|
|
621 break;
|
|
622
|
|
623 case SELECT:
|
|
624 (void) fprintf(fp, "(");
|
|
625 explexpr(np->lval, fp);
|
|
626 (void) fprintf(fp, " ~ ");
|
|
627 explexpr(np->rval, fp);
|
|
628 (void) fprintf(fp, ")");
|
|
629 break;
|
|
630
|
|
631 case UNKNOWNOP:
|
|
632 (void) fprintf(fp, "(");
|
|
633 explexpr(np->rval->lval, fp);
|
|
634 if(np->lval->constant < 256)
|
|
635 (void) fprintf(fp, " %c ", (char)np->lval->constant);
|
|
636 else
|
|
637 (void) fprintf(fp, " %c^H%c ",
|
|
638 (char)(np->lval->constant / 256),
|
|
639 (char)(np->lval->constant % 256));
|
|
640 explexpr(np->rval->rval, fp);
|
|
641 (void) fprintf(fp, ")");
|
|
642 break;
|
|
643
|
|
644 case SLAT:
|
|
645 (void) fprintf(fp, "(");
|
|
646 explexpr(np->lval, fp);
|
|
647 (void) fprintf(fp, " / ");
|
|
648 explexpr(np->rval, fp);
|
|
649 (void) fprintf(fp, ")");
|
|
650 break;
|
|
651
|
|
652 case BACKSLAT:
|
|
653 (void) fprintf(fp, "(");
|
|
654 explexpr(np->lval, fp);
|
|
655 (void) fprintf(fp, " \\ ");
|
|
656 explexpr(np->rval, fp);
|
|
657 (void) fprintf(fp, ")");
|
|
658 break;
|
|
659
|
|
660 case AND:
|
|
661 (void) fprintf(fp, "(& ");
|
|
662 explexpr(np->rval, fp);
|
|
663 (void) fprintf(fp, ")");
|
|
664 break;
|
|
665
|
|
666 case OR:
|
|
667 (void) fprintf(fp, "(V ");
|
|
668 explexpr(np->rval, fp);
|
|
669 (void) fprintf(fp, ")");
|
|
670 break;
|
|
671
|
|
672 case XOR:
|
|
673 (void) fprintf(fp, "(? ");
|
|
674 explexpr(np->rval, fp);
|
|
675 (void) fprintf(fp, ")");
|
|
676 break;
|
|
677
|
|
678 case FIN:
|
|
679 if (ick_Base < 3)
|
|
680 ick_lose(IE997, emitlineno, (const char *)NULL);
|
|
681 (void) fprintf(fp, "(^ ");
|
|
682 explexpr(np->rval, fp);
|
|
683 (void) fprintf(fp, ")");
|
|
684 break;
|
|
685
|
|
686 case WHIRL:
|
|
687 case WHIRL2:
|
|
688 case WHIRL3:
|
|
689 case WHIRL4:
|
|
690 case WHIRL5:
|
|
691 if (np->opcode - WHIRL + 3 > ick_Base)
|
|
692 ick_lose(IE997, emitlineno, (const char *)NULL);
|
|
693 if(np->opcode == WHIRL)
|
|
694 (void) fprintf(fp, "(@ ");
|
|
695 else
|
|
696 (void) fprintf(fp, "(%d@ ", np->opcode - WHIRL + 1);
|
|
697 explexpr(np->rval, fp);
|
|
698 (void) fprintf(fp, ")");
|
|
699 break;
|
|
700
|
|
701 case MESH:
|
|
702 if(variableconstants) /* AIS */
|
|
703 (void) fprintf(fp, "meshes[%lu]", np->constant);
|
|
704 else
|
|
705 (void) fprintf(fp, "0x%lx", np->constant);
|
|
706 break;
|
|
707
|
|
708 case MESH32:
|
|
709 (void) fprintf(fp, "0x%lx", np->constant);
|
|
710 break;
|
|
711
|
|
712 case ick_ONESPOT:
|
|
713 case ick_TWOSPOT:
|
|
714 case ick_TAIL:
|
|
715 case ick_HYBRID:
|
|
716 case SUB:
|
|
717 explvar(np, fp);
|
|
718 break;
|
|
719
|
|
720 /* cases from here down are generated by the optimizer */
|
|
721 case C_AND:
|
|
722 (void) fprintf(fp, "(");
|
|
723 explexpr(np->lval, fp);
|
|
724 (void) fprintf(fp, " & ");
|
|
725 explexpr(np->rval, fp);
|
|
726 (void) fprintf(fp, ")");
|
|
727 break;
|
|
728
|
|
729 case C_OR:
|
|
730 (void) fprintf(fp, "(");
|
|
731 explexpr(np->lval, fp);
|
|
732 (void) fprintf(fp, " | ");
|
|
733 explexpr(np->rval, fp);
|
|
734 (void) fprintf(fp, ")");
|
|
735 break;
|
|
736
|
|
737 case C_XOR:
|
|
738 (void) fprintf(fp, "(");
|
|
739 explexpr(np->lval, fp);
|
|
740 (void) fprintf(fp, " ^ ");
|
|
741 explexpr(np->rval, fp);
|
|
742 (void) fprintf(fp, ")");
|
|
743 break;
|
|
744
|
|
745 case C_NOT:
|
|
746 (void) fprintf(fp, "(~ ");
|
|
747 explexpr(np->rval, fp);
|
|
748 (void) fprintf(fp, ")");
|
|
749 break;
|
|
750
|
|
751 case C_NOTEQUAL:
|
|
752 (void) fprintf(fp, "(");
|
|
753 explexpr(np->lval, fp);
|
|
754 (void) fprintf(fp, " != ");
|
|
755 explexpr(np->rval, fp);
|
|
756 (void) fprintf(fp, ")");
|
|
757 break;
|
|
758
|
|
759 case C_A:
|
|
760 (void) fprintf(fp, "a");
|
|
761 break;
|
|
762
|
|
763 case C_RSHIFTBY:
|
|
764 (void) fprintf(fp, "(");
|
|
765 explexpr(np->lval, fp);
|
|
766 (void) fprintf(fp, " >> ");
|
|
767 explexpr(np->rval, fp);
|
|
768 (void) fprintf(fp, ")");
|
|
769 break;
|
|
770
|
|
771 case C_LOGICALNOT:
|
|
772 (void) fprintf(fp, "(! ");
|
|
773 explexpr(np->rval, fp);
|
|
774 (void) fprintf(fp, ")");
|
|
775 break;
|
|
776
|
|
777 case C_LSHIFTBY:
|
|
778 (void) fprintf(fp, "(");
|
|
779 explexpr(np->lval, fp);
|
|
780 (void) fprintf(fp, " << ");
|
|
781 explexpr(np->rval, fp);
|
|
782 (void) fprintf(fp, ")");
|
|
783 break;
|
|
784
|
|
785 case C_PLUS:
|
|
786 (void) fprintf(fp, "(");
|
|
787 explexpr(np->lval, fp);
|
|
788 (void) fprintf(fp, " + ");
|
|
789 explexpr(np->rval, fp);
|
|
790 (void) fprintf(fp, ")");
|
|
791 break;
|
|
792
|
|
793 case C_MINUS:
|
|
794 (void) fprintf(fp, "(");
|
|
795 explexpr(np->lval, fp);
|
|
796 (void) fprintf(fp, " - ");
|
|
797 explexpr(np->rval, fp);
|
|
798 (void) fprintf(fp, ")");
|
|
799 break;
|
|
800
|
|
801 case C_TIMES:
|
|
802 (void) fprintf(fp, "(");
|
|
803 explexpr(np->lval, fp);
|
|
804 (void) fprintf(fp, " * ");
|
|
805 explexpr(np->rval, fp);
|
|
806 (void) fprintf(fp, ")");
|
|
807 break;
|
|
808
|
|
809 case C_DIVIDEBY:
|
|
810 (void) fprintf(fp, "(");
|
|
811 explexpr(np->lval, fp);
|
|
812 (void) fprintf(fp, " / ");
|
|
813 explexpr(np->rval, fp);
|
|
814 (void) fprintf(fp, ")");
|
|
815 break;
|
|
816
|
|
817 case C_MODULUS:
|
|
818 (void) fprintf(fp, "(");
|
|
819 explexpr(np->lval, fp);
|
|
820 (void) fprintf(fp, " %% ");
|
|
821 explexpr(np->rval, fp);
|
|
822 (void) fprintf(fp, ")");
|
|
823 break;
|
|
824
|
|
825 case C_GREATER:
|
|
826 (void) fprintf(fp, "(");
|
|
827 explexpr(np->lval, fp);
|
|
828 (void) fprintf(fp, " > ");
|
|
829 explexpr(np->rval, fp);
|
|
830 (void) fprintf(fp, ")");
|
|
831 break;
|
|
832
|
|
833 case C_LESS:
|
|
834 (void) fprintf(fp, "(");
|
|
835 explexpr(np->lval, fp);
|
|
836 (void) fprintf(fp, " < ");
|
|
837 explexpr(np->rval, fp);
|
|
838 (void) fprintf(fp, ")");
|
|
839 break;
|
|
840
|
|
841 case C_ISEQUAL:
|
|
842 (void) fprintf(fp, "(");
|
|
843 explexpr(np->lval, fp);
|
|
844 (void) fprintf(fp, " == ");
|
|
845 explexpr(np->rval, fp);
|
|
846 (void) fprintf(fp, ")");
|
|
847 break;
|
|
848
|
|
849 case C_LOGICALAND:
|
|
850 (void) fprintf(fp, "(");
|
|
851 explexpr(np->lval, fp);
|
|
852 (void) fprintf(fp, " && ");
|
|
853 explexpr(np->rval, fp);
|
|
854 (void) fprintf(fp, ")");
|
|
855 break;
|
|
856
|
|
857 case C_LOGICALOR:
|
|
858 (void) fprintf(fp, "(");
|
|
859 explexpr(np->lval, fp);
|
|
860 (void) fprintf(fp, " || ");
|
|
861 explexpr(np->rval, fp);
|
|
862 (void) fprintf(fp, ")");
|
|
863 break;
|
|
864
|
|
865 case INTERSECTION:
|
|
866 explexpr(np->lval, fp);
|
|
867 (void) fprintf(fp, " + ");
|
|
868 explexpr(np->rval, fp);
|
|
869 break;
|
|
870
|
|
871 case GETS:
|
|
872 case RESIZE:
|
|
873 explexpr(np->lval, fp);
|
|
874 (void) fprintf(fp, " <- ");
|
|
875 explexpr(np->rval, fp);
|
|
876 break;
|
|
877
|
|
878 case BY:
|
|
879 explexpr(np->lval, fp);
|
|
880 (void) fprintf(fp, " BY ");
|
|
881 explexpr(np->rval, fp);
|
|
882 break;
|
|
883
|
|
884 default:
|
|
885 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
886 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
887 }
|
|
888 }
|
|
889
|
|
890 /* AIS: Added the third argument to prexpr and prvar. It specifies
|
|
891 whether the node should be freed or not. I added the third
|
|
892 argument in all calls of prexpr/prvar. */
|
|
893
|
|
894 /* AIS: I moved prexpr's prototype higher in the file.
|
|
895 Destaticed so the optimizer can access it. */
|
|
896
|
|
897 static void prvar(node *np, FILE *fp, int freenode)
|
|
898 /* print out args to pass to storage manager for reference */
|
|
899 {
|
|
900 node *sp;
|
|
901 int dim;
|
|
902
|
|
903 switch (np->opcode)
|
|
904 {
|
|
905 case ick_ONESPOT:
|
|
906 (void) fprintf(fp, "ick_onespots[%lu]", np->constant);
|
|
907 break;
|
|
908
|
|
909 case ick_TWOSPOT:
|
|
910 (void) fprintf(fp, "ick_twospots[%lu]", np->constant);
|
|
911 break;
|
|
912
|
|
913 case ick_TAIL:
|
|
914 (void) fprintf(fp, "ick_TAIL, &ick_tails[%lu]", np->constant);
|
|
915 break;
|
|
916
|
|
917 case ick_HYBRID:
|
|
918 (void) fprintf(fp, "ick_HYBRID, &ick_hybrids[%lu]", np->constant);
|
|
919 break;
|
|
920
|
|
921 case SUB:
|
|
922 {
|
|
923 (void) fprintf(fp, "ick_aref(");
|
|
924 prvar(np->lval, fp, freenode);
|
|
925
|
|
926 dim = 0;
|
|
927 for (sp = np->rval ; sp ; sp = sp->rval)
|
|
928 dim++;
|
|
929 (void) fprintf(fp, ", %d", dim);
|
|
930
|
|
931 for (sp = np->rval ; sp ; sp = sp->rval) {
|
|
932 (void) fprintf(fp, ", ");
|
|
933 prexpr(sp->lval, fp, freenode);
|
|
934 }
|
|
935 (void) fprintf(fp, ")");
|
|
936 }
|
|
937 break;
|
|
938 default: /* Added by AIS */
|
|
939 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
940 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
941 }
|
|
942 }
|
|
943
|
|
944 static void ooprvar(node *np, FILE *fp, int freenode)
|
|
945 /* AIS: Print out the overloaded version */
|
|
946 {
|
|
947 node *sp;
|
|
948 int dim;
|
|
949
|
|
950 switch (np->opcode)
|
|
951 {
|
|
952 case ick_ONESPOT:
|
|
953 (void) fprintf(fp, "ick_oo_onespots[%lu]", np->constant);
|
|
954 break;
|
|
955
|
|
956 case ick_TWOSPOT:
|
|
957 (void) fprintf(fp, "ick_oo_twospots[%lu]", np->constant);
|
|
958 break;
|
|
959
|
|
960 case ick_TAIL:
|
|
961 case ick_HYBRID:
|
|
962 /* This should never be reached */
|
|
963 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
964 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
965
|
|
966 case SUB:
|
|
967 {
|
|
968 (void) fprintf(fp, "ick_aref(");
|
|
969 prvar(np->lval, fp, freenode);
|
|
970
|
|
971 dim = 0;
|
|
972 for (sp = np->rval ; sp ; sp = sp->rval)
|
|
973 dim++;
|
|
974 (void) fprintf(fp, ", %d", dim);
|
|
975
|
|
976 for (sp = np->rval ; sp ; sp = sp->rval) {
|
|
977 (void) fprintf(fp, ", ");
|
|
978 prexpr(sp->lval, fp, freenode);
|
|
979 }
|
|
980 (void) fprintf(fp, ")");
|
|
981 }
|
|
982 break;
|
|
983 default:
|
|
984 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
985 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
986 }
|
|
987 }
|
|
988
|
|
989 /* AIS: Give us a mesh with value x */
|
|
990 static unsigned long meshval(unsigned long x)
|
|
991 {
|
|
992 if(variableconstants)
|
|
993 return intern(MESH, x);
|
|
994 else
|
|
995 return x;
|
|
996 }
|
|
997
|
|
998 /* AIS: This is the reverse of prexpr, in a way.
|
|
999 It degenerates an expression that causes *np to become equal to *target.
|
|
1000 If this is impossible at any point, it degenerates code that causes
|
|
1001 error 277 (and itself causes error 278 if the situation is inevitable).
|
|
1002 As for the annotations; there quite possibly are memory allocation mistakes
|
|
1003 here, but just about every line is a false positive (because we're operating
|
|
1004 at the subobject level in terms of copy/free/allocate) for Splint, and so
|
|
1005 disabling the warnings doesn't make the output any less useful. (When there
|
|
1006 are so many false positives, disabling the true positives doesn't make them
|
|
1007 any harder to find by eye. */
|
|
1008 /*@-temptrans@*/ /*@-kepttrans@*/ /*@-compdestroy@*/ /*@-branchstate@*/
|
|
1009 static void revprexpr(node *np, FILE *fp, node *target)
|
|
1010 {
|
|
1011 node* temp;
|
|
1012 switch (np->opcode)
|
|
1013 {
|
|
1014 case MINGLE:
|
|
1015 /* We can use select to determine what np->lval and np->rval have
|
|
1016 to become equal to, as long as we're in base 2. */
|
|
1017 if(ick_Base!=2)
|
|
1018 {
|
|
1019 fprintf(fp, " ick_lose(IE277, ick_lineno, (const char*) NULL);\n");
|
|
1020 ick_lwarn(W278, emitlineno, (const char*) NULL);
|
|
1021 break;
|
|
1022 }
|
|
1023 temp=cons(MESH,0,0);
|
|
1024 temp->constant=meshval(0xAAAAAAAALU);
|
|
1025 temp->width=32;
|
|
1026 temp=cons(SELECT,target,temp);
|
|
1027 temp->width=target->width;
|
|
1028 revprexpr(np->lval, fp, temp);
|
|
1029 free(temp->rval);
|
|
1030 free(temp);
|
|
1031 temp=cons(MESH,0,0);
|
|
1032 temp->constant=meshval(0x55555555LU);
|
|
1033 temp->width=32;
|
|
1034 temp=cons(SELECT,target,temp);
|
|
1035 temp->width=target->width;
|
|
1036 revprexpr(np->rval, fp, temp);
|
|
1037 free(temp->rval);
|
|
1038 free(temp);
|
|
1039 break;
|
|
1040
|
|
1041 case SELECT:
|
|
1042 /* Set the left of the select to the target, and the right
|
|
1043 to 0xffffffff or 0xffff. This only works in base 2. */
|
|
1044 if(ick_Base!=2)
|
|
1045 {
|
|
1046 fprintf(fp, " ick_lose(IE277, ick_lineno, (const char*) NULL);\n");
|
|
1047 ick_lwarn(W278, emitlineno, (const char*) NULL);
|
|
1048 break;
|
|
1049 }
|
|
1050 temp=cons(MESH,0,0);
|
|
1051 temp->constant=meshval(target->width==32?0xFFFFFFFFLU:0xFFFFLU);
|
|
1052 temp->width=target->width;
|
|
1053 revprexpr(np->lval, fp, target);
|
|
1054 revprexpr(np->rval, fp, temp);
|
|
1055 free(temp);
|
|
1056 break;
|
|
1057
|
|
1058 case UNKNOWNOP: /* don't be silly */
|
|
1059 fprintf(fp, " ick_lose(IE277, ick_lineno, (const char*) NULL);\n");
|
|
1060 ick_lwarn(W278, emitlineno, (const char*) NULL);
|
|
1061 break;
|
|
1062
|
|
1063 case BACKSLAT:
|
|
1064 /* Unimplemented. This isn't even in the parser yet, so it's a
|
|
1065 ick_mystery how we got here. */
|
|
1066 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
1067 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
1068
|
|
1069 case SLAT:
|
|
1070 /* We need to set the true value of the LHS... */
|
|
1071
|
|
1072 /* Copied and modified from the GETS code */
|
|
1073 if(!pickcompile)
|
|
1074 {
|
|
1075 (void) fprintf(fp," (void) ick_assign((char*)&");
|
|
1076 prvar(np->lval, fp, 0);
|
|
1077 (void) fprintf(fp,", %s", nameof(np->lval->opcode, vartypes));
|
|
1078 (void) fprintf(fp,", %s[%lu], ", nameof(np->lval->opcode, forgetbits),
|
|
1079 np->lval->constant);
|
|
1080 prexpr(target, fp, 0);
|
|
1081 (void) fprintf(fp,"); \n");
|
|
1082 }
|
|
1083 else /* AIS: Added this case for the simpler PIC assignment rules */
|
|
1084 {
|
|
1085 (void) fprintf(fp,"\t""if(ignore%s%lu) ",
|
|
1086 nameof(np->lval->opcode,varstores),
|
|
1087 np->lval->constant);
|
|
1088 prexpr(np->lval, fp, 0);
|
|
1089 (void) fprintf(fp, " = ");
|
|
1090 prexpr(target, fp, 0);
|
|
1091 (void) fprintf(fp, "; \n");
|
|
1092 }
|
|
1093
|
|
1094 /* ... and we need to cause overloading to happen. This is a copy
|
|
1095 of part of the code for SLAT, modified to work in this context. */
|
|
1096 ooprvar(np->lval, fp, 0);
|
|
1097 /* Do something highly non-portable with pointers that should work
|
|
1098 anyway. Each pointer needs to be given a unique code; so we use
|
|
1099 the hex representation of np casted to an unsigned long.
|
|
1100 Technically speaking, np->rval could be casted to anything; but
|
|
1101 all implementations I've ever seen cast unique pointers to unique
|
|
1102 numbers, which is good enough for our purposes. */
|
|
1103 (void) fprintf(fp, ".get=ick_og%lx;\n ", (unsigned long)np->rval);
|
|
1104 ooprvar(np->lval, fp, 0);
|
|
1105 (void) fprintf(fp, ".set=ick_os%lx;\n", (unsigned long)np->rval);
|
|
1106 break;
|
|
1107
|
|
1108 case AND:
|
|
1109 case OR:
|
|
1110 case XOR:
|
|
1111 case FIN:
|
|
1112 case WHIRL:
|
|
1113 case WHIRL2:
|
|
1114 case WHIRL3:
|
|
1115 case WHIRL4:
|
|
1116 case WHIRL5:
|
|
1117 temp=cons(np->opcode-AND+REV_AND,0,target);
|
|
1118 temp->width=temp->rval->width=np->width;
|
|
1119 revprexpr(np->rval, fp, temp);
|
|
1120 free(temp);
|
|
1121 break;
|
|
1122
|
|
1123 case MESH:
|
|
1124 if(!variableconstants)
|
|
1125 {
|
|
1126 /* Can't set a mesh in this case */
|
|
1127 fprintf(fp, " ick_lose(IE277, ick_lineno, (const char*) NULL);\n");
|
|
1128 ick_lwarn(W278, emitlineno, (const char*) NULL);
|
|
1129 break;
|
|
1130 }
|
|
1131 (void) fprintf(fp," meshes[%lu] = ",np->constant);
|
|
1132 prexpr(target, fp, 0);
|
|
1133 (void) fprintf(fp,";\n");
|
|
1134 break;
|
|
1135
|
|
1136 case ick_ONESPOT:
|
|
1137 case ick_TWOSPOT:
|
|
1138 case ick_TAIL:
|
|
1139 case ick_HYBRID:
|
|
1140 case SUB:
|
|
1141 /* Copy the code for the GETS statement; this is almost the same
|
|
1142 thing. Modified because we're assigning target to np, not
|
|
1143 np->lval to np->rval, and to not free(). */
|
|
1144 if(opoverused&&
|
|
1145 (np->opcode==ick_ONESPOT||np->opcode==ick_TWOSPOT)) /* AIS */
|
|
1146 {
|
|
1147 (void) fprintf(fp," ");
|
|
1148 ooprvar(np, fp, 0);
|
|
1149 (void) fprintf(fp,".set(");
|
|
1150 prexpr(target, fp, 0);
|
|
1151 (void) fprintf(fp,",os%dspot%lu);\n",
|
|
1152 (np->opcode==ick_TWOSPOT)+1, np->constant);
|
|
1153 }
|
|
1154 else if(!pickcompile)
|
|
1155 {
|
|
1156 node* sp;
|
|
1157
|
|
1158 if (np->opcode != SUB) {
|
|
1159 sp = np;
|
|
1160 (void) fprintf(fp," (void) ick_assign((char*)&");
|
|
1161 }
|
|
1162 else {
|
|
1163 sp = np->lval;
|
|
1164 (void) fprintf(fp," (void) ick_assign(");
|
|
1165 }
|
|
1166 prvar(np, fp, 0);
|
|
1167 (void) fprintf(fp,", %s", nameof(sp->opcode, vartypes));
|
|
1168 (void) fprintf(fp,", %s[%lu], ", nameof(sp->opcode, forgetbits),
|
|
1169 sp->constant);
|
|
1170 prexpr(target, fp, 0);
|
|
1171 (void) fprintf(fp,");\n");
|
|
1172 }
|
|
1173 else /* AIS: Added this case for the simpler PIC assignment rules */
|
|
1174 {
|
|
1175 (void) fprintf(fp," if(ignore%s%lu) ",
|
|
1176 nameof(np->opcode,varstores),
|
|
1177 np->constant);
|
|
1178 prexpr(np, fp, 0);
|
|
1179 (void) fprintf(fp, " = ");
|
|
1180 prexpr(target, fp, 0);
|
|
1181 (void) fprintf(fp, ";\n");
|
|
1182 }
|
|
1183 break;
|
|
1184
|
|
1185 /* cases from here down are generated by the optimizer, and so
|
|
1186 should never come up here and are errors. The exception is
|
|
1187 C_A, which should only ever appear in a target expression,
|
|
1188 so is also an error. */
|
|
1189 case MESH32:
|
|
1190 case C_AND:
|
|
1191 case C_OR:
|
|
1192 case C_XOR:
|
|
1193 case C_NOT:
|
|
1194 case C_NOTEQUAL:
|
|
1195 case C_A:
|
|
1196 case C_RSHIFTBY:
|
|
1197 case C_LOGICALNOT:
|
|
1198 case C_LSHIFTBY:
|
|
1199 case C_PLUS:
|
|
1200 case C_MINUS:
|
|
1201 case C_TIMES:
|
|
1202 case C_DIVIDEBY:
|
|
1203 case C_MODULUS:
|
|
1204 case C_GREATER:
|
|
1205 case C_LESS:
|
|
1206 case C_ISEQUAL:
|
|
1207 case C_LOGICALAND:
|
|
1208 case C_LOGICALOR:
|
|
1209 case GETS: /* should never come up */
|
|
1210 default:
|
|
1211 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
1212 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
1213 }
|
|
1214 }
|
|
1215 /*@=temptrans@*/ /*@=kepttrans@*/ /*@=compdestroy@*/ /*@=branchstate@*/
|
|
1216
|
|
1217 /*@observer@*/ static char* E000string; /* AIS */
|
|
1218
|
|
1219 static int prunknownstr(node*, FILE*); /* AIS */
|
|
1220
|
|
1221 /* AIS: Destaticed */
|
|
1222 /* Splint doesn't understand the concept of a function which might or might
|
|
1223 not free its argument. That's a pity, because its checking would come in
|
|
1224 useful here, but as it is we have to annotate memory checking off for this
|
|
1225 function. */
|
|
1226 /*@-temptrans@*/ /*@-onlytrans@*/ /*@-compdestroy@*/ /*@-branchstate@*/
|
|
1227 void prexpr(node *np, FILE *fp, int freenode)
|
|
1228 /* print out C-function equivalent of an expression */
|
|
1229 {
|
|
1230 int tempint;
|
|
1231 switch (np->opcode)
|
|
1232 {
|
|
1233 case MINGLE:
|
|
1234 (void) fprintf(fp, "ick_mingle(");
|
|
1235 prexpr(np->lval, fp, freenode);
|
|
1236 (void) fprintf(fp, ", ");
|
|
1237 prexpr(np->rval, fp, freenode);
|
|
1238 (void) fprintf(fp, ")");
|
|
1239 break;
|
|
1240
|
|
1241 case SELECT:
|
|
1242 (void) fprintf(fp, "ick_iselect(");
|
|
1243 prexpr(np->lval, fp, freenode);
|
|
1244 (void) fprintf(fp, ", ");
|
|
1245 prexpr(np->rval, fp, freenode);
|
|
1246 (void) fprintf(fp, ")");
|
|
1247 break;
|
|
1248
|
|
1249 case UNKNOWNOP: /* AIS */
|
|
1250 if(!useickec || !createsused)
|
|
1251 {
|
|
1252 /* CREATEd operators require -ea */
|
|
1253 (void) fprintf(fp, "(ick_lose(IE000, ick_lineno, \"%s\"),0)",
|
|
1254 E000string);
|
|
1255 break;
|
|
1256 }
|
|
1257 /* We need to do the same as UNKNOWN statements, but as an expression.
|
|
1258 This is achieved with the helper function ick_dounop in ick_ec.c. */
|
|
1259 (void) fprintf(fp, "ick_dounop(\"");
|
|
1260 prunknownstr(np->lval, fp);
|
|
1261 if(freenode) free(np->lval);
|
|
1262 (void) fprintf(fp, "\", ");
|
|
1263 prexpr(np->rval->lval, fp, 0);
|
|
1264 (void) fprintf(fp, ", ");
|
|
1265 prexpr(np->rval->rval, fp, 0);
|
|
1266 (void) fprintf(fp,
|
|
1267 ", ick_lineno, %luUL, %luUL, %luUL"
|
|
1268 ", ick_og%lx, ick_og%lx, og2spot%lu"
|
|
1269 ", ick_os%lx, ick_os%lx, os2spot%lu, \"%s\")",
|
|
1270 intern(ick_TWOSPOT, 1601),
|
|
1271 intern(ick_TWOSPOT, 1602),
|
|
1272 intern(ick_TWOSPOT, 1603),
|
|
1273 (unsigned long) np->rval->lval,
|
|
1274 (unsigned long) np->rval->rval,
|
|
1275 intern(ick_TWOSPOT, 1603),
|
|
1276 (unsigned long) np->rval->lval,
|
|
1277 (unsigned long) np->rval->rval,
|
|
1278 intern(ick_TWOSPOT, 1603),
|
|
1279 E000string);
|
|
1280 if(freenode) free(np->rval);
|
|
1281 break;
|
|
1282
|
|
1283 case BACKSLAT: /* AIS */
|
|
1284 /* Unimplemented. This isn't even in the parser yet, so it's a
|
|
1285 ick_mystery how we got here. */
|
|
1286 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
1287 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
1288
|
|
1289 case SLAT: /* AIS */
|
|
1290 (void) fprintf(fp,"((");
|
|
1291 ooprvar(np->lval, fp, 0);
|
|
1292 /* Do something highly non-portable with pointers that should work
|
|
1293 anyway. Each pointer needs to be given a unique code; so we use
|
|
1294 the hex representation of np casted to an unsigned long.
|
|
1295 Technically speaking, np->rval could be casted to anything; but
|
|
1296 all implementations I've ever seen cast unique pointers to unique
|
|
1297 numbers, which is good enough for our purposes. */
|
|
1298 (void) fprintf(fp, ".get=ick_og%lx),(", (unsigned long)np->rval);
|
|
1299 ooprvar(np->lval, fp, 0);
|
|
1300 (void) fprintf(fp, ".set=ick_os%lx),(", (unsigned long)np->rval);
|
|
1301 prvar(np->lval, fp, freenode);
|
|
1302 /* np->rval will be freed later, when its expression is printed */
|
|
1303 (void) fprintf(fp, "))");
|
|
1304 return; /* mustn't be freed */
|
|
1305
|
|
1306 case AND:
|
|
1307 (void) fprintf(fp, "ick_and%d(", np->width);
|
|
1308 prexpr(np->rval, fp, freenode);
|
|
1309 (void) fprintf(fp, ")");
|
|
1310 break;
|
|
1311
|
|
1312 case OR:
|
|
1313 (void) fprintf(fp, "ick_or%d(", np->width);
|
|
1314 prexpr(np->rval, fp, freenode);
|
|
1315 (void) fprintf(fp, ")");
|
|
1316 break;
|
|
1317
|
|
1318 case XOR:
|
|
1319 (void) fprintf(fp, "ick_xor%d(", np->width);
|
|
1320 prexpr(np->rval, fp, freenode);
|
|
1321 (void) fprintf(fp, ")");
|
|
1322 break;
|
|
1323
|
|
1324 case FIN:
|
|
1325 if (ick_Base < 3)
|
|
1326 ick_lose(IE997, emitlineno, (const char *)NULL);
|
|
1327 (void) fprintf(fp, "ick_fin%d(", np->width);
|
|
1328 prexpr(np->rval, fp, freenode);
|
|
1329 (void) fprintf(fp, ")");
|
|
1330 break;
|
|
1331
|
|
1332 case WHIRL:
|
|
1333 case WHIRL2:
|
|
1334 case WHIRL3:
|
|
1335 case WHIRL4:
|
|
1336 case WHIRL5:
|
|
1337 if (np->opcode - WHIRL + 3 > ick_Base)
|
|
1338 ick_lose(IE997, emitlineno, (const char *)NULL);
|
|
1339 (void) fprintf(fp, "ick_whirl%d(%d, ", np->width, np->opcode - WHIRL + 1);
|
|
1340 prexpr(np->rval, fp, freenode);
|
|
1341 (void) fprintf(fp, ")");
|
|
1342 break;
|
|
1343
|
|
1344 /* AIS: Reversed operations */
|
|
1345 case REV_AND:
|
|
1346 (void) fprintf(fp, "ick_rev_and%d(", np->width);
|
|
1347 prexpr(np->rval, fp, freenode);
|
|
1348 (void) fprintf(fp, ")");
|
|
1349 break;
|
|
1350
|
|
1351 case REV_OR:
|
|
1352 (void) fprintf(fp, "ick_rev_or%d(", np->width);
|
|
1353 prexpr(np->rval, fp, freenode);
|
|
1354 (void) fprintf(fp, ")");
|
|
1355 break;
|
|
1356
|
|
1357 case REV_XOR:
|
|
1358 (void) fprintf(fp, "ick_rev_xor%d(", np->width);
|
|
1359 prexpr(np->rval, fp, freenode);
|
|
1360 (void) fprintf(fp, ")");
|
|
1361 break;
|
|
1362
|
|
1363 case REV_FIN:
|
|
1364 if (ick_Base < 3)
|
|
1365 ick_lose(IE997, emitlineno, (const char *)NULL);
|
|
1366 (void) fprintf(fp, "rev_fin%d(", np->width);
|
|
1367 prexpr(np->rval, fp, freenode);
|
|
1368 (void) fprintf(fp, ")");
|
|
1369 break;
|
|
1370
|
|
1371 case REV_WHIRL:
|
|
1372 case REV_WHIRL2:
|
|
1373 case REV_WHIRL3:
|
|
1374 case REV_WHIRL4:
|
|
1375 case REV_WHIRL5:
|
|
1376 if (np->opcode - WHIRL + 3 > ick_Base)
|
|
1377 ick_lose(IE997, emitlineno, (const char *)NULL);
|
|
1378 (void) fprintf(fp,
|
|
1379 "rev_whirl%d(%d, ", np->width, np->opcode - WHIRL + 1);
|
|
1380 prexpr(np->rval, fp, freenode);
|
|
1381 (void) fprintf(fp, ")");
|
|
1382 break;
|
|
1383
|
|
1384 case MESH:
|
|
1385 if(variableconstants) /* AIS */
|
|
1386 (void) fprintf(fp, "meshes[%lu]", np->constant);
|
|
1387 else
|
|
1388 (void) fprintf(fp, "0x%lx", np->constant);
|
|
1389 break;
|
|
1390
|
|
1391 case MESH32:
|
|
1392 (void) fprintf(fp, "0x%lx", np->constant);
|
|
1393 break;
|
|
1394
|
|
1395 case ick_ONESPOT:
|
|
1396 case ick_TWOSPOT:
|
|
1397 case ick_TAIL:
|
|
1398 case ick_HYBRID:
|
|
1399 if(!opoverused||np->opcode==ick_TAIL||np->opcode==ick_HYBRID)
|
|
1400 prvar(np, fp, freenode);
|
|
1401 else /* AIS */
|
|
1402 {
|
|
1403 ooprvar(np, fp, freenode);
|
|
1404 fprintf(fp, ".get(");
|
|
1405 prvar(np, fp, freenode);
|
|
1406 fprintf(fp,")");
|
|
1407 }
|
|
1408 break;
|
|
1409
|
|
1410 case SUB:
|
|
1411 (void) fprintf(fp, "*(%s*)", nameof(np->lval->opcode, typedefs));
|
|
1412 prvar(np, fp, freenode);
|
|
1413 break;
|
|
1414
|
|
1415 /* cases from here down are generated by the optimizer */
|
|
1416 case C_AND:
|
|
1417 (void) fprintf(fp, "(");
|
|
1418 prexpr(np->lval, fp, freenode);
|
|
1419 (void) fprintf(fp, " & ");
|
|
1420 prexpr(np->rval, fp, freenode);
|
|
1421 (void) fprintf(fp, ")");
|
|
1422 break;
|
|
1423
|
|
1424 case C_OR:
|
|
1425 (void) fprintf(fp, "(");
|
|
1426 prexpr(np->lval, fp, freenode);
|
|
1427 (void) fprintf(fp, " | ");
|
|
1428 prexpr(np->rval, fp, freenode);
|
|
1429 (void) fprintf(fp, ")");
|
|
1430 break;
|
|
1431
|
|
1432 case C_XOR:
|
|
1433 (void) fprintf(fp, "(");
|
|
1434 prexpr(np->lval, fp, freenode);
|
|
1435 (void) fprintf(fp, " ^ ");
|
|
1436 prexpr(np->rval, fp, freenode);
|
|
1437 (void) fprintf(fp, ")");
|
|
1438 break;
|
|
1439
|
|
1440 case C_NOT:
|
|
1441 (void) fprintf(fp, "(~");
|
|
1442 tempint=np->rval->width; /* AIS */
|
|
1443 prexpr(np->rval, fp, freenode);
|
|
1444 if (tempint == ick_Small_digits)
|
|
1445 (void) fprintf(fp, " & ick_Max_small)");
|
|
1446 else
|
|
1447 (void) fprintf(fp, " & ick_Max_large)");
|
|
1448 break;
|
|
1449
|
|
1450 /* AIS: I added the rest of the cases */
|
|
1451 case C_NOTEQUAL:
|
|
1452 (void) fprintf(fp, "(");
|
|
1453 prexpr(np->lval, fp, freenode);
|
|
1454 (void) fprintf(fp, " != ");
|
|
1455 prexpr(np->rval, fp, freenode);
|
|
1456 (void) fprintf(fp, ")");
|
|
1457 break;
|
|
1458
|
|
1459 case C_A:
|
|
1460 (void) fprintf(fp, "a");
|
|
1461 break;
|
|
1462
|
|
1463 case C_RSHIFTBY:
|
|
1464 (void) fprintf(fp, "(");
|
|
1465 prexpr(np->lval, fp, freenode);
|
|
1466 (void) fprintf(fp, " >> ");
|
|
1467 prexpr(np->rval, fp, freenode);
|
|
1468 (void) fprintf(fp, ")");
|
|
1469 break;
|
|
1470
|
|
1471 case C_LOGICALNOT:
|
|
1472 (void) fprintf(fp, "(!");
|
|
1473 prexpr(np->rval, fp, freenode);
|
|
1474 (void) fprintf(fp, ")");
|
|
1475 break;
|
|
1476
|
|
1477 case C_LSHIFTBY:
|
|
1478 (void) fprintf(fp, "(");
|
|
1479 prexpr(np->lval, fp, freenode);
|
|
1480 (void) fprintf(fp, " << ");
|
|
1481 prexpr(np->rval, fp, freenode);
|
|
1482 (void) fprintf(fp, ")");
|
|
1483 break;
|
|
1484
|
|
1485 case C_PLUS:
|
|
1486 (void) fprintf(fp, "(");
|
|
1487 prexpr(np->lval, fp, freenode);
|
|
1488 (void) fprintf(fp, " + ");
|
|
1489 prexpr(np->rval, fp, freenode);
|
|
1490 (void) fprintf(fp, ")");
|
|
1491 break;
|
|
1492
|
|
1493 case C_MINUS:
|
|
1494 (void) fprintf(fp, "(");
|
|
1495 prexpr(np->lval, fp, freenode);
|
|
1496 (void) fprintf(fp, " - ");
|
|
1497 prexpr(np->rval, fp, freenode);
|
|
1498 (void) fprintf(fp, ")");
|
|
1499 break;
|
|
1500
|
|
1501 case C_TIMES:
|
|
1502 (void) fprintf(fp, "(");
|
|
1503 prexpr(np->lval, fp, freenode);
|
|
1504 (void) fprintf(fp, " * ");
|
|
1505 prexpr(np->rval, fp, freenode);
|
|
1506 (void) fprintf(fp, ")");
|
|
1507 break;
|
|
1508
|
|
1509 case C_DIVIDEBY:
|
|
1510 (void) fprintf(fp, "(");
|
|
1511 prexpr(np->lval, fp, freenode);
|
|
1512 (void) fprintf(fp, " / ");
|
|
1513 prexpr(np->rval, fp, freenode);
|
|
1514 (void) fprintf(fp, ")");
|
|
1515 break;
|
|
1516
|
|
1517 case C_MODULUS:
|
|
1518 (void) fprintf(fp, "(");
|
|
1519 prexpr(np->lval, fp, freenode);
|
|
1520 (void) fprintf(fp, " %% ");
|
|
1521 prexpr(np->rval, fp, freenode);
|
|
1522 (void) fprintf(fp, ")");
|
|
1523 break;
|
|
1524
|
|
1525 case C_GREATER:
|
|
1526 (void) fprintf(fp, "(");
|
|
1527 prexpr(np->lval, fp, freenode);
|
|
1528 (void) fprintf(fp, " > ");
|
|
1529 prexpr(np->rval, fp, freenode);
|
|
1530 (void) fprintf(fp, ")");
|
|
1531 break;
|
|
1532
|
|
1533 case C_LESS:
|
|
1534 (void) fprintf(fp, "(");
|
|
1535 prexpr(np->lval, fp, freenode);
|
|
1536 (void) fprintf(fp, " < ");
|
|
1537 prexpr(np->rval, fp, freenode);
|
|
1538 (void) fprintf(fp, ")");
|
|
1539 break;
|
|
1540
|
|
1541 case C_ISEQUAL:
|
|
1542 (void) fprintf(fp, "(");
|
|
1543 prexpr(np->lval, fp, freenode);
|
|
1544 (void) fprintf(fp, " == ");
|
|
1545 prexpr(np->rval, fp, freenode);
|
|
1546 (void) fprintf(fp, ")");
|
|
1547 break;
|
|
1548
|
|
1549 case C_LOGICALAND:
|
|
1550 (void) fprintf(fp, "(");
|
|
1551 prexpr(np->lval, fp, freenode);
|
|
1552 (void) fprintf(fp, " && ");
|
|
1553 prexpr(np->rval, fp, freenode);
|
|
1554 (void) fprintf(fp, ")");
|
|
1555 break;
|
|
1556
|
|
1557 case C_LOGICALOR:
|
|
1558 (void) fprintf(fp, "(");
|
|
1559 prexpr(np->lval, fp, freenode);
|
|
1560 (void) fprintf(fp, " || ");
|
|
1561 prexpr(np->rval, fp, freenode);
|
|
1562 (void) fprintf(fp, ")");
|
|
1563 break;
|
|
1564
|
|
1565 case GETS: /* AIS: this is used only if freenode == 0 */
|
|
1566 if(freenode) ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
1567 prexpr(np->lval, fp, freenode);
|
|
1568 (void) fprintf(fp, " = ");
|
|
1569 prexpr(np->rval, fp, freenode);
|
|
1570 break;
|
|
1571
|
|
1572 default: /* Added by AIS */
|
|
1573 if(!freenode) break; /* Be less careful when not freeing, because
|
|
1574 this is used by -hH to print out its
|
|
1575 intermediate optimization stages */
|
|
1576 ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
1577 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
1578 }
|
|
1579
|
|
1580 if(freenode) (void) free(np);
|
|
1581 }
|
|
1582 /*@=temptrans@*/ /*@=onlytrans@*/ /*@=compdestroy@*/ /*@=branchstate@*/
|
|
1583
|
|
1584 /* By AIS: Helper function for prunknown */
|
|
1585 static int prunknownstr(node *np, FILE* fp)
|
|
1586 {
|
|
1587 int i;
|
|
1588 switch(np->opcode)
|
|
1589 {
|
|
1590 case INTERSECTION:
|
|
1591 i=prunknownstr(np->lval, fp);
|
|
1592 i+=prunknownstr(np->rval, fp);
|
|
1593 return i;
|
|
1594 case BADCHAR:
|
|
1595 if (np->constant > 256)
|
|
1596 (void) fprintf(fp, "o%xx%x",
|
|
1597 (unsigned int)(np->constant / 256),
|
|
1598 (unsigned int)(np->constant % 256));
|
|
1599 else
|
|
1600 (void) fprintf(fp, "u%x", (unsigned int)np->constant);
|
|
1601 return 2;
|
|
1602 case US_ID: (void) fputc((char)np->constant, fp); return 0;
|
|
1603 case US_ELEM: (void) fputc(';', fp); return 1;
|
|
1604 case US_SCALAR: (void) fputc('.', fp); return 1;
|
|
1605 case US_ARRVAR: (void) fputc(',', fp); return 1;
|
|
1606 case US_EXPR: (void) fputc('~', fp); return 1;
|
|
1607 default: ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
1608 }
|
|
1609 /*@-unreachable@*/ return 0; /*@=unreachable@*/
|
|
1610 }
|
|
1611
|
|
1612 /* By AIS: Helper function for prunknown */
|
|
1613 static void prunknowncreatedata(node *np, FILE* fp)
|
|
1614 {
|
|
1615 unsigned long ve;
|
|
1616 switch(np->opcode)
|
|
1617 {
|
|
1618 case INTERSECTION:
|
|
1619 prunknowncreatedata(np->lval, fp);
|
|
1620 prunknowncreatedata(np->rval, fp);
|
|
1621 return;
|
|
1622 case US_ID: return; /* nothing to do */
|
|
1623 case US_SCALAR:
|
|
1624 ve=varextern(np->rval->constant,np->rval->opcode);
|
|
1625 fprintf(fp,"\t\t{%d,0,%lu,",np->rval->width,ve);
|
|
1626 break;
|
|
1627 case US_ARRVAR: /* an array doesn't itself have a value */
|
|
1628 ve=varextern(np->rval->constant,np->rval->opcode);
|
|
1629 fprintf(fp,"\t\t{%d,1,%lu,{ick_ieg277,ick_ies277},0},\n",
|
|
1630 np->rval->width,ve);
|
|
1631 return;
|
|
1632 case US_ELEM: /* these two cases are actually treated the same way, */
|
|
1633 case US_EXPR: /* because expressions can be assigned to */
|
|
1634 fprintf(fp,"\t\t{%d,0,0,",np->rval->width);
|
|
1635 break;
|
|
1636 default: ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
1637 }
|
|
1638 if(createsused)
|
|
1639 fprintf(fp,"{ick_og%lx,ick_os%lx},",
|
|
1640 (unsigned long)np->rval,(unsigned long)np->rval);
|
|
1641 else
|
|
1642 fprintf(fp,"{0,0},");
|
|
1643 prexpr(np->rval,fp,0);
|
|
1644 fprintf(fp,"},\n");
|
|
1645 }
|
|
1646
|
|
1647 /* This function by AIS. Print a check to see if a just-in-case compiled
|
|
1648 statement actually has a meaning yet, or if we should error. */
|
|
1649 static void prunknown(node *np, FILE* fp)
|
|
1650 {
|
|
1651 static long negcounter=-65538;
|
|
1652 int i,j;
|
|
1653 fprintf(fp,"\tif((ick_skipto=ick_jicmatch(\"");
|
|
1654 i=prunknownstr(np, fp);
|
|
1655 fprintf(fp, "\")))\n\t{\n\t ick_createdata icd[]={\n");
|
|
1656 prunknowncreatedata(np, fp);
|
|
1657 fprintf(fp, "\t };\n");
|
|
1658 if(createsused)
|
|
1659 {
|
|
1660 j=i;
|
|
1661 while(j--)
|
|
1662 (void) fprintf(fp, "\t\t""ICKSTASH(ick_TWOSPOT, %lu, "
|
|
1663 "ick_twospots, ick_oo_twospots);\n"
|
|
1664 "\t\t""ick_oo_twospots[%lu]=icd[%d].accessors;\n",
|
|
1665 intern(ick_TWOSPOT,1601+j),
|
|
1666 intern(ick_TWOSPOT,1601+j),j);
|
|
1667 }
|
|
1668 if(useickec)
|
|
1669 {
|
|
1670 fprintf(fp,"\t\t""ick_global_createdata=icd;\n");
|
|
1671 fprintf(fp,"\t\t""ick_dogoto(ick_skipto,ick_lineno,1);\n");
|
|
1672 }
|
|
1673 else
|
|
1674 {
|
|
1675 fprintf(fp,"\t\t""ick_pushnext(%ld); ick_skipto=-ick_skipto; goto top; "
|
|
1676 "case %ld:;\n",negcounter,negcounter);
|
|
1677 negcounter--;
|
|
1678 }
|
|
1679 if(createsused)
|
|
1680 {
|
|
1681 j=i;
|
|
1682 while(j--)
|
|
1683 (void) fprintf(fp, "\t\t""ICKRETRIEVE(ick_twospots, %lu, "
|
|
1684 "ick_TWOSPOT, ick_twoforget, ick_oo_twospots);\n",
|
|
1685 intern(ick_TWOSPOT,1601+j));
|
|
1686
|
|
1687 }
|
|
1688 fprintf(fp, "\t} else\n");
|
|
1689 }
|
|
1690
|
|
1691 /*@dependent@*/ static char *nice_text(char *texts[], int lines)
|
|
1692 {
|
|
1693 #define MAXNICEBUF 512
|
|
1694 static char buf[MAXNICEBUF];
|
|
1695 char *cp, *text;
|
|
1696 int i;
|
|
1697
|
|
1698 if (lines < 1)
|
|
1699 lines = 1;
|
|
1700 for (cp = buf, i = 0 ; i < lines ; ++i) {
|
|
1701 if (cp>buf+MAXNICEBUF-10)
|
|
1702 {
|
|
1703 (*cp++) = '.';
|
|
1704 (*cp++) = '.';
|
|
1705 (*cp++) = '.';
|
|
1706 *cp = '\0';
|
|
1707 return buf;
|
|
1708 }
|
|
1709 if (i) {
|
|
1710 (*cp++) = '\\';
|
|
1711 (*cp++) = 'n';
|
|
1712 (*cp++) = '\\';
|
|
1713 (*cp++) = '\n';
|
|
1714 (*cp++) = '\t';
|
|
1715 }
|
|
1716 for (text = texts[i] ; text != NULL && *text != '\0'; cp++, text++) {
|
|
1717 if (cp>buf+MAXNICEBUF-10)
|
|
1718 {
|
|
1719 (*cp++) = '.';
|
|
1720 (*cp++) = '.';
|
|
1721 (*cp++) = '.';
|
|
1722 *cp = '\0';
|
|
1723 return buf;
|
|
1724 }
|
|
1725 if(*text == '"' || *text == '\\') {
|
|
1726 (*cp++) = '\\';
|
|
1727 }
|
|
1728 if(*text == 'K') /* AIS: break the string so that the ick_ec
|
|
1729 preprocessor doesn't trigger on the string
|
|
1730 ICKNUMBERPAIR */
|
|
1731 {
|
|
1732 (*cp++) = '"';
|
|
1733 (*cp++) = '"';
|
|
1734 }
|
|
1735 *cp = *text;
|
|
1736 }
|
|
1737 }
|
|
1738 *cp = '\0';
|
|
1739 return buf;
|
|
1740 }
|
|
1741
|
|
1742 static void emit_guard(tuple *tn, FILE *fp)
|
|
1743 /* emit execution guard for giiven tuple (note the unbalanced trailing {!) */
|
|
1744 {
|
|
1745 if(tn->maybe) /* AIS */
|
|
1746 {
|
|
1747 if(!multithread) ick_lose(IE405, emitlineno, (const char *)NULL);
|
|
1748 (void) fprintf(fp, " gonebackto = setjmp(btjb); choicepoint();\n");
|
|
1749 }
|
|
1750 if(!flowoptimize || tn->abstainable) /* This condition by AIS */
|
|
1751 {
|
|
1752 (void) fprintf(fp, " if (");
|
|
1753 if (tn->maybe) /* AIS */
|
|
1754 (void) fprintf(fp, "gonebackto == !(");
|
|
1755 if (tn->exechance < 100)
|
|
1756 (void) fprintf(fp, "ick_roll(%d) && ", tn->exechance);
|
|
1757 if ((tn->type != NEXT && tn->type != GO_BACK && tn->type != COME_FROM
|
|
1758 && /* AIS */ tn->type != NEXTFROMLABEL && tn->type != UNKNOWN)
|
|
1759 || tn->onceagainflag == onceagain_NORMAL)
|
|
1760 (void) fprintf(fp, "!ICKABSTAINED(%d))%s {\n", (int)(tn - tuples),
|
|
1761 /* AIS */ tn->maybe?")":"");
|
|
1762 else /* AIS: [NEXT, GO_BACK, COME_FROM] ONCE needs specially
|
|
1763 handled abstentions */
|
|
1764 (void) fprintf(fp, "!ick_oldabstain)%s {\n",
|
|
1765 /* AIS */ tn->maybe?")":"");
|
|
1766 }
|
|
1767 else
|
|
1768 { /* AIS */
|
|
1769 if(tn->maybe) ick_lose(IE778, emitlineno, (const char*) NULL);
|
|
1770 if(!tn->initabstain)
|
|
1771 {
|
|
1772 if(tn->type != COMPUCOME && tn->type != GERUCOME
|
|
1773 && tn->type != NEXTFROMEXPR && tn->type != NEXTFROMGERUND)
|
|
1774 (void) fprintf(fp, " {\n");
|
|
1775 else (void) fprintf(fp, " if(1) {\n"); /* COMPUCOME specifically needs
|
|
1776 an if() so it can have
|
|
1777 an else. */
|
|
1778 }
|
|
1779 else (void) fprintf(fp, " if(0) {\n"); /* for exceptional cases like
|
|
1780 DON'T COME FROM #1 where we
|
|
1781 need a label or an else. */
|
|
1782 }
|
|
1783 }
|
|
1784
|
|
1785 void emittextlines(FILE *fp)
|
|
1786 {
|
|
1787 int i=0; /* The first textline is line 1 */
|
|
1788 (void) fprintf(fp, "\"\",\n");
|
|
1789 while(++i<iyylineno)
|
|
1790 {
|
|
1791 (void) fprintf(fp, "\"%s\",\n",nice_text(textlines + i, 0));
|
|
1792 }
|
|
1793 (void) fprintf(fp, "\"\"\n");
|
|
1794 }
|
|
1795
|
|
1796 void emit(tuple *tn, FILE *fp)
|
|
1797 /* emit code for the given tuple */
|
|
1798 {
|
|
1799 node *np, *sp;
|
|
1800 int dim;
|
|
1801 int generatecfjump=0; /* AIS */
|
|
1802 static int pasttryagain=0; /* AIS */
|
|
1803 extern int cdebug;
|
|
1804
|
|
1805 /* grind out label and source dump */
|
|
1806 if (yydebug || cdebug || compile_only)
|
|
1807 (void) fprintf(fp, " /* line %03d */\n", tn->ick_lineno);
|
|
1808 if (tn->label)
|
|
1809 {
|
|
1810 if(!useickec) /* AIS */
|
|
1811 (void) fprintf(fp, "case -%u: ; L%u:\n", tn->label, tn->label);
|
|
1812 else
|
|
1813 /* AIS: start one of ick_ec's labeled blocks. */
|
|
1814 (void) fprintf(fp, "ick_labeledblock(%uU,{",tn->label);
|
|
1815 }
|
|
1816 if (yydebug || cdebug || compile_only)
|
|
1817 {
|
|
1818 (void) fprintf(fp, "\t""/* %s */", textlines[tn->ick_lineno]);
|
|
1819 /* AIS: grind out an expression explanation */
|
|
1820 if (tn->type == GETS || tn->type == FORGET || tn->type == RESUME
|
|
1821 || tn->type == FROM || tn->type == COMPUCOME
|
|
1822 || tn->type == MANYFROM || tn->type == NEXTFROMEXPR)
|
|
1823 {
|
|
1824 (void) fprintf(fp, "\n\t/* Expression is ");
|
|
1825 explexpr(tn->type == MANYFROM ? tn->u.node->lval :
|
|
1826 tn->type == GETS ? tn->u.node->rval : tn->u.node, fp);
|
|
1827 (void) fprintf(fp, " */");
|
|
1828 }
|
|
1829 }
|
|
1830 (void) fputc('\n', fp);
|
|
1831
|
|
1832 /* set up the "next" lexical line number for error messages */
|
|
1833 if (tn->type == NEXT) {
|
|
1834 tuple *up;
|
|
1835 for (up = tuples; up < tuples + ick_lineno; up++)
|
|
1836 if (tn->u.target == up->label) {
|
|
1837 emitlineno = up->ick_lineno;
|
|
1838 break;
|
|
1839 }
|
|
1840 }
|
|
1841 else if (tn->ncomefrom)
|
|
1842 {
|
|
1843 /* AIS: For multithreading. Return the 1st if we're forking. */
|
|
1844 emitlineno = comefromsearch(tn,1);
|
|
1845 if(emitlineno != -1)
|
|
1846 emitlineno = tuples[emitlineno-1].ick_lineno;
|
|
1847 }
|
|
1848 else if (tn < tuples + ick_lineno - 1)
|
|
1849 emitlineno = tn[1].ick_lineno;
|
|
1850 else
|
|
1851 emitlineno = iyylineno;
|
|
1852 if(!pickcompile) /* AIS: PICs can't report errors,
|
|
1853 so don't bother with ick_lineno */
|
|
1854 (void) fprintf(fp, " ick_lineno = %d;\n", emitlineno);
|
|
1855
|
|
1856 /* AIS: figure out which line we're on, so E000 can be done correctly */
|
|
1857 if (tn < tuples + ick_lineno - 1)
|
|
1858 dim = tn[1].ick_lineno - tn->ick_lineno;
|
|
1859 else
|
|
1860 dim = iyylineno - tn->ick_lineno;
|
|
1861 if (tn->sharedline)
|
|
1862 ++dim;
|
|
1863 E000string=nice_text(textlines + tn->ick_lineno, dim);
|
|
1864
|
|
1865 /* AIS: set weaving status if necessary */
|
|
1866 if(tn->setweave)
|
|
1867 (void) fprintf(fp, " weaving = %d;\n", tn->setweave>0);
|
|
1868
|
|
1869 /* AIS: print warnings on -l */
|
|
1870 if(ick_checkforbugs)
|
|
1871 {
|
|
1872 if(tn->warn112) ick_lwarn(W112, emitlineno, (const char*) NULL);
|
|
1873 if(tn->warn128) ick_lwarn(W128, emitlineno, (const char*) NULL);
|
|
1874 if(tn->warn534) ick_lwarn(W534, emitlineno, (const char*) NULL);
|
|
1875 if(tn->warn018) ick_lwarn(W018, emitlineno, (const char*) NULL);
|
|
1876 if(tn->warn016) ick_lwarn(W016, emitlineno, (const char*) NULL);
|
|
1877 if(tn->warn276) ick_lwarn(W276, emitlineno, (const char*) NULL);
|
|
1878 if(tn->warn239) ick_lwarn(W239, emitlineno, (const char*) NULL);
|
|
1879 if(tn->warn622) ick_lwarn(W622, emitlineno, (const char*) NULL);
|
|
1880 }
|
|
1881
|
|
1882 /* AIS: emit debugging information */
|
|
1883 if (yukdebug||yukprofile)
|
|
1884 {
|
|
1885 (void) fprintf(fp, " YUK(%d,%d);\n",
|
|
1886 (int)(tn-tuples),emitlineno);
|
|
1887 }
|
|
1888
|
|
1889 /* AIS: The +mystery option on degenerated code causes the code to
|
|
1890 unexpectedly terminate after 4 billion commands are run, thus
|
|
1891 preventing an infinite loop. Of course, it will enhance the fun
|
|
1892 if we don't tell the user that. (This is necessary for the
|
|
1893 constant-output optimizer to work properly.) */
|
|
1894 if(coopt) (void) fprintf(fp, " ick_MYSTERYLINE;\n");
|
|
1895
|
|
1896 /* AIS: If the tuple is ONCE/AGAIN flagged, we need a delayed-action
|
|
1897 set of its abstention status to the AGAIN-flagged status. The
|
|
1898 problem is that some statements, like COME FROM, need to set after
|
|
1899 the command has finished, and some, like NEXT, need it before the
|
|
1900 command has started. At the moment, only NEXT and GO_BACK have a
|
|
1901 ONCE/AGAIN before it, rather than after (because neither of them
|
|
1902 continue in the normal fashion). UNKNOWN is also handled this way,
|
|
1903 because CREATEd statements can be NEXT-like but not COME FROM-like. */
|
|
1904 if ((tn->type == NEXT || tn->type == GO_BACK || tn->type == UNKNOWN) &&
|
|
1905 tn->onceagainflag != onceagain_NORMAL)
|
|
1906 {
|
|
1907 /* ONCE/AGAIN has already been swapped by perpet.c in the case
|
|
1908 of a preabstained statement ('DO NOT'...). So if we currently have
|
|
1909 a ONCE, it means that being abstained is the attractive state,
|
|
1910 and if we currently have an AGAIN, it means that being
|
|
1911 reinstated is the attractive state. Semantics with computed
|
|
1912 ABSTAIN: Don't change the abstention count unless necessary, in
|
|
1913 which case change it to 0 or 1. */
|
|
1914 fprintf(fp," ick_oldabstain = ICKABSTAINED(%d);\n", (int)(tn - tuples));
|
|
1915 fprintf(fp," ICKABSTAINED(%d) = %s;\n",
|
|
1916 (int)(tn - tuples),
|
|
1917 tn->onceagainflag==onceagain_ONCE ? "ick_oldabstain ? ick_oldabstain : 1"
|
|
1918 : "0");
|
|
1919 /* This test-and-set must be atomic. As all statements are atomic anyway
|
|
1920 in the current version of ick, that isn't a problem, but if anyone
|
|
1921 wants to try using POSIX's multithreading features, the above two
|
|
1922 lines need to be a critical section. */
|
|
1923 }
|
|
1924
|
|
1925 /* AIS: in the case of COMPUCOME, we need an extra guard unless useickec. */
|
|
1926 if ((!useickec && (tn->type == COMPUCOME || tn->type == NEXTFROMEXPR))
|
|
1927 || tn->type == GERUCOME || tn->type == NEXTFROMGERUND)
|
|
1928 {
|
|
1929 fprintf(fp," if(0)\n {\n");
|
|
1930 fprintf(fp,"CCF%d:\n",compucomecount++);
|
|
1931 if(tn->type == COMPUCOME || tn->type == NEXTFROMEXPR)
|
|
1932 {
|
|
1933 fprintf(fp," if(ick_skipto&&ick_skipto==");
|
|
1934 prexpr(tn->u.node, fp, 1);
|
|
1935 }
|
|
1936 else if(tn->type == GERUCOME || tn->type == NEXTFROMGERUND)
|
|
1937 {
|
|
1938 fprintf(fp," if(");
|
|
1939 for (np = tn->u.node; np; np = np->rval)
|
|
1940 {
|
|
1941 if (np->constant == ABSTAIN) {
|
|
1942 (void) fprintf(fp,
|
|
1943 "linetype[truelineno] == %s || linetype[truelineno] == %s || "
|
|
1944 "linetype[truelineno] == %s || linetype[truelineno] == %s || ",
|
|
1945 enablers[np->constant-GETS],
|
|
1946 enablers[np->constant-GETS+2],
|
|
1947 enablers[FROM-GETS], enablers[MANYFROM-GETS]);
|
|
1948 } else if (np->constant == REINSTATE) {
|
|
1949 (void) fprintf(fp,
|
|
1950 "linetype[truelineno] == %s || linetype[truelineno] == %s || ",
|
|
1951 enablers[np->constant-GETS],
|
|
1952 enablers[np->constant-GETS+2]);
|
|
1953 } else if (np->constant == GETS) {
|
|
1954 (void) fprintf(fp,
|
|
1955 "linetype[truelineno] == %s || linetype[truelineno] == %s || ",
|
|
1956 enablers[GETS-GETS],
|
|
1957 enablers[RESIZE-GETS]);
|
|
1958 } else if (np->constant == COME_FROM) {
|
|
1959 (void) fprintf(fp,
|
|
1960 "linetype[truelineno] == %s || linetype[truelineno] == %s || "
|
|
1961 "linetype[truelineno] == %s || ",
|
|
1962 enablers[COME_FROM-GETS],
|
|
1963 enablers[COMPUCOME-GETS],
|
|
1964 enablers[GERUCOME-GETS]);
|
|
1965 } else if (np->constant == NEXTFROMLABEL) {
|
|
1966 (void) fprintf(fp,
|
|
1967 "linetype[truelineno] == %s || linetype[truelineno] == %s || "
|
|
1968 "linetype[truelineno] == %s || ",
|
|
1969 enablers[NEXTFROMLABEL-GETS],
|
|
1970 enablers[NEXTFROMEXPR-GETS],
|
|
1971 enablers[NEXTFROMGERUND-GETS]);
|
|
1972 } else {
|
|
1973 (void) fprintf(fp, "linetype[truelineno] == %s || ",
|
|
1974 enablers[np->constant-GETS]);
|
|
1975 }
|
|
1976 }
|
|
1977 fprintf(fp, "0");
|
|
1978 }
|
|
1979 fprintf(fp,") {\n");
|
|
1980 }
|
|
1981
|
|
1982 /* AIS: With this block placed here, you can't even have a comment
|
|
1983 after a TRY AGAIN line. Move it below the next check if this seems
|
|
1984 to be undesirable behaviour. */
|
|
1985 if(pasttryagain) /* AIS */
|
|
1986 {
|
|
1987 ick_lose(IE993, emitlineno, (const char*)NULL);
|
|
1988 }
|
|
1989
|
|
1990 if(flowoptimize && tn->initabstain && !tn->abstainable
|
|
1991 && tn->type != COMPUCOME && tn->type != COME_FROM &&
|
|
1992 tn->type != NEXT && tn->type != GERUCOME &&
|
|
1993 tn->type != NEXTFROMLABEL && tn->type != NEXTFROMEXPR &&
|
|
1994 tn->type != NEXTFROMGERUND) /* AIS */
|
|
1995 goto skipcomment; /* Look, a comment! We can completely skip all
|
|
1996 degeneration of this statement (although with
|
|
1997 -c, comments will appear in the degenerated
|
|
1998 code in its place). The COMPUCOME condition is
|
|
1999 because it is so weird. COME_FROM and NEXT are
|
|
2000 exempted so labels are generated. */
|
|
2001
|
|
2002 /* emit conditional-execution prefixes */
|
|
2003 /* AIS: added the useickec condition */
|
|
2004 if ((tn->type != COME_FROM && tn->type != NEXTFROMLABEL) || useickec)
|
|
2005 emit_guard(tn, fp);
|
|
2006
|
|
2007 /* now emit the code for the statement body */
|
|
2008 switch(tn->type)
|
|
2009 {
|
|
2010 case GETS:
|
|
2011 /* AIS: variableconstants means GETS has been generalised */
|
|
2012 if(variableconstants)
|
|
2013 {
|
|
2014 revprexpr(tn->u.node->lval, fp, tn->u.node->rval);
|
|
2015 nodefree(tn->u.node);
|
|
2016 break;
|
|
2017 }
|
|
2018
|
|
2019 /* Start of AIS optimization */
|
|
2020 np = tn->u.node;
|
|
2021 if(np->lval->opcode == SUB) np = np->lval;
|
|
2022 if(flowoptimize && ick_Base == 2 && !opoverused && !variableconstants &&
|
|
2023 (np->lval->opcode == ick_TWOSPOT
|
|
2024 || np->lval->opcode == ick_HYBRID
|
|
2025 || !(tn->u.node->rval->optdata & ~0xffffLU)))
|
|
2026 {
|
|
2027 atom* op;
|
|
2028 int ignorable = 1;
|
|
2029 assert(oblist != NULL);
|
|
2030 for(op = oblist; op < obdex; op++)
|
|
2031 {
|
|
2032 if(op->type == np->lval->opcode &&
|
|
2033 (unsigned long)op->intindex == np->lval->constant)
|
|
2034 {
|
|
2035 ignorable &= op->ignorable;
|
|
2036 }
|
|
2037 }
|
|
2038 if(!ignorable)
|
|
2039 { /* Variable can't be ignored, and expression must be in range */
|
|
2040 (void) fprintf(fp,"\t""");
|
|
2041 prexpr(tn->u.node->lval, fp, 1);
|
|
2042 (void) fprintf(fp, " = ");
|
|
2043 prexpr(tn->u.node->rval, fp, 1);
|
|
2044 (void) fprintf(fp, ";\n");
|
|
2045 break;
|
|
2046 }
|
|
2047 }
|
|
2048 /* End of AIS optimization */
|
|
2049 if(opoverused&&
|
|
2050 (tn->u.node->lval->opcode==ick_ONESPOT||
|
|
2051 tn->u.node->lval->opcode==ick_TWOSPOT)) /* AIS */
|
|
2052 {
|
|
2053 (void) fprintf(fp,"\t""");
|
|
2054 ooprvar(tn->u.node->lval, fp, 1);
|
|
2055 (void) fprintf(fp,".set(");
|
|
2056 prexpr(tn->u.node->rval, fp, 1);
|
|
2057 (void) fprintf(fp,",os%dspot%lu);\n",
|
|
2058 (tn->u.node->lval->opcode==ick_TWOSPOT)+1,
|
|
2059 tn->u.node->lval->constant);
|
|
2060 }
|
|
2061 else if(!pickcompile)
|
|
2062 {
|
|
2063 np = tn->u.node;
|
|
2064
|
|
2065 if (np->lval->opcode != SUB) {
|
|
2066 sp = np->lval;
|
|
2067 (void) fprintf(fp,"\t""(void) ick_assign((char*)&");
|
|
2068 }
|
|
2069 else {
|
|
2070 sp = np->lval->lval;
|
|
2071 (void) fprintf(fp,"\t""(void) ick_assign(");
|
|
2072 }
|
|
2073 prvar(np->lval, fp, 1);
|
|
2074 (void) fprintf(fp,", %s", nameof(sp->opcode, vartypes));
|
|
2075 (void) fprintf(fp,", %s[%lu], ", nameof(sp->opcode, forgetbits),
|
|
2076 sp->constant);
|
|
2077 prexpr(np->rval, fp, 1);
|
|
2078 (void) fprintf(fp,");\n");
|
|
2079 }
|
|
2080 else /* AIS: Added this case for the simpler PIC assignment rules */
|
|
2081 {
|
|
2082 (void) fprintf(fp,"\t""if(ignore%s%lu) ",
|
|
2083 nameof(tn->u.node->lval->opcode,varstores),
|
|
2084 tn->u.node->lval->constant);
|
|
2085 prexpr(tn->u.node->lval, fp, 1);
|
|
2086 (void) fprintf(fp, " = ");
|
|
2087 prexpr(tn->u.node->rval, fp, 1);
|
|
2088 (void) fprintf(fp, ";\n");
|
|
2089 }
|
|
2090 break;
|
|
2091
|
|
2092 case RESIZE:
|
|
2093 if(pickcompile) ick_lose(IE256, emitlineno, (const char*) NULL); /* AIS */
|
|
2094 np = tn->u.node;
|
|
2095 dim = 0;
|
|
2096 for (sp = np->rval; sp; sp = sp->rval)
|
|
2097 dim++;
|
|
2098 (void) fprintf(fp, "\t""ick_resize(");
|
|
2099 prvar(np->lval, fp, 1);
|
|
2100 (void) fprintf(fp, ", %s[%lu]", nameof(np->lval->opcode, forgetbits),
|
|
2101 np->lval->constant);
|
|
2102 (void) fprintf(fp, ", %d", dim);
|
|
2103 for (sp = np->rval; sp; sp = sp->rval) {
|
|
2104 (void) fprintf(fp, ", (size_t)");
|
|
2105 prexpr(sp->lval, fp, 1);
|
|
2106 }
|
|
2107 (void) fprintf(fp, ");\n");
|
|
2108 break;
|
|
2109
|
|
2110 case NEXT:
|
|
2111 /* AIS: if using ickec, use its features for the next */
|
|
2112 if(useickec)
|
|
2113 {
|
|
2114 (void) fprintf(fp,"\t""ick_dogoto(%uU,ick_lineno,1);\n",tn->u.target);
|
|
2115 break;
|
|
2116 }
|
|
2117 /* Start of AIS optimization */
|
|
2118 if(tn->u.target>=1000 && tn->u.target<=1999 && pickcompile)
|
|
2119 {
|
|
2120 /* optimize syslib call on a PIC */
|
|
2121 (void) fprintf(fp, "\t""syslibopt%u();\n", tn->u.target);
|
|
2122 break;
|
|
2123 }
|
|
2124 if(tn->optversion)
|
|
2125 { /* optimizef has checked that this is a valid optimization */
|
|
2126 (void) fprintf(fp, "\t""if(1 == ");
|
|
2127 prexpr(tn->u.node, fp, 1); /* frees optimizef's nodecopy */
|
|
2128 /* AIS: Everything now in one giant switch(), with some very strange
|
|
2129 constructs (including ;{;} as a null statement; this makes
|
|
2130 degenerating the code slightly easier) */
|
|
2131 (void) fprintf(fp, ") {ick_pushnext(%d); ick_skipto=%uU; goto top;}} case %d:;{;\n",
|
|
2132 (int)(tn - tuples + 1), tn->nexttarget, (int)(tn - tuples + 1));
|
|
2133 break;
|
|
2134 }
|
|
2135 /* End of AIS optimization */
|
|
2136 (void) fprintf(fp, /* same change as above (case rather than a label) */
|
|
2137 "\t""ick_pushnext(%d); goto L%u;} case %d:;{;\n",
|
|
2138 (int)(tn - tuples + 1), tn->u.target, (int)(tn - tuples + 1));
|
|
2139 break;
|
|
2140
|
|
2141 case GO_BACK: /* By AIS */
|
|
2142 if(!multithread) ick_lose(IE405, emitlineno, (const char*) NULL);
|
|
2143 (void) fprintf(fp, "\t""choiceback();\n");
|
|
2144 break;
|
|
2145
|
|
2146 case GO_AHEAD: /* By AIS */
|
|
2147 if(!multithread) ick_lose(IE405, emitlineno, (const char*) NULL);
|
|
2148 (void) fprintf(fp, "\t""choiceahead();\n");
|
|
2149 break;
|
|
2150
|
|
2151 case RESUME:
|
|
2152 if(useickec) /* AIS */
|
|
2153 {
|
|
2154 (void) fprintf(fp, "\t""ick_doresume(");
|
|
2155 prexpr(tn->u.node, fp, 1);
|
|
2156 (void) fprintf(fp, ", ick_lineno);\n");
|
|
2157 break;
|
|
2158 }
|
|
2159 (void) fprintf(fp, "\t""ick_skipto = ick_resume(");
|
|
2160 prexpr(tn->u.node, fp, 1);
|
|
2161 (void) fprintf(fp, "); goto top;\n");
|
|
2162 break;
|
|
2163
|
|
2164 case FORGET:
|
|
2165 if(useickec) /* AIS */
|
|
2166 {
|
|
2167 (void) fprintf(fp, "\t""ick_forget(");
|
|
2168 prexpr(tn->u.node, fp, 1);
|
|
2169 (void) fprintf(fp, ");\n");
|
|
2170 break;
|
|
2171 }
|
|
2172
|
|
2173 (void) fprintf(fp, "\t""ick_popnext(");
|
|
2174 prexpr(tn->u.node, fp, 1);
|
|
2175 (void) fprintf(fp, ");\n");
|
|
2176 break;
|
|
2177
|
|
2178 case STASH:
|
|
2179 for (np = tn->u.node; np; np = np->rval)
|
|
2180 (void) fprintf(fp, "\t""ICKSTASH(%s, %lu, %s, %s%s);\n",
|
|
2181 nameof(np->opcode, vartypes),
|
|
2182 np->constant,
|
|
2183 nameof(np->opcode, varstores),
|
|
2184 /* AIS */(opoverused&&(np->opcode==ick_ONESPOT||
|
|
2185 np->opcode==ick_TWOSPOT)?
|
|
2186 "ick_oo_":"0"),
|
|
2187 /* AIS */(opoverused&&(np->opcode==ick_ONESPOT||
|
|
2188 np->opcode==ick_TWOSPOT)?
|
|
2189 nameof(np->opcode, varstoresdem):"0"));
|
|
2190 break;
|
|
2191
|
|
2192 case RETRIEVE:
|
|
2193 for (np = tn->u.node; np; np = np->rval)
|
|
2194 (void) fprintf(fp, "\t""ICKRETRIEVE(%s, %lu, %s, %s, %s%s);\n",
|
|
2195 nameof(np->opcode, varstores), np->constant,
|
|
2196 nameof(np->opcode, vartypes),
|
|
2197 nameof(np->opcode, forgetbits),
|
|
2198 /* AIS */(opoverused&&(np->opcode==ick_ONESPOT||
|
|
2199 np->opcode==ick_TWOSPOT)?
|
|
2200 "ick_oo_":"0"),
|
|
2201 /* AIS */(opoverused&&(np->opcode==ick_ONESPOT||
|
|
2202 np->opcode==ick_TWOSPOT)?
|
|
2203 nameof(np->opcode, varstoresdem):"0"));
|
|
2204
|
|
2205 break;
|
|
2206
|
|
2207 case IGNORE:
|
|
2208 for (np = tn->u.node; np; np = np->rval)
|
|
2209 (void) fprintf(fp,"\t""ICKIGNORE(%s,%lu,%s) = ick_TRUE;\n",
|
|
2210 nameof(np->opcode, forgetbits),
|
|
2211 np->constant,
|
|
2212 nameof(np->opcode, varstores));
|
|
2213 break;
|
|
2214
|
|
2215 case REMEMBER:
|
|
2216 for (np = tn->u.node; np; np = np->rval)
|
|
2217 (void) fprintf(fp,"\t""ICKIGNORE(%s,%lu,%s) = ick_FALSE;\n",
|
|
2218 nameof(np->opcode, forgetbits),
|
|
2219 np->constant,
|
|
2220 nameof(np->opcode, varstores));
|
|
2221 break;
|
|
2222
|
|
2223 /* All abstention code has been edited by AIS to allow for the new
|
|
2224 abstention rules */
|
|
2225 case ABSTAIN:
|
|
2226 /* AIS: In CLC-INTERCAL, you can't abstain a GIVE UP line, so I copied
|
|
2227 a modified version of Joris's REINSTATE patch here as well */
|
|
2228 if (!ick_clcsemantics || (tuples + tn->u.target - 1)->type != GIVE_UP)
|
|
2229 {
|
|
2230 if(!pickcompile)
|
|
2231 (void) fprintf(fp, "\t""if(!ICKABSTAINED(%u)) ICKABSTAINED(%u) = 1;\n", tn->u.target - 1, tn->u.target-1);
|
|
2232 else
|
|
2233 (void) fprintf(fp, "ICKABSTAINED(%u) = 1;\n", tn->u.target-1);
|
|
2234 }
|
|
2235 else
|
|
2236 (void) fprintf(fp, "\t""/* not abstaining from a GIVE UP line */\n");;
|
|
2237 break;
|
|
2238
|
|
2239 case FROM:
|
|
2240 if(pickcompile) ick_lose(IE256, emitlineno, (const char*) NULL);
|
|
2241 (void) fprintf(fp, "\t""ICKABSTAINED(%u)+=", tn->u.target-1);
|
|
2242 tn->u.node->width = 32;
|
|
2243 prexpr(tn->u.node,fp, 1);
|
|
2244 (void) fprintf(fp, ";\n");
|
|
2245 break;
|
|
2246
|
|
2247 case REINSTATE:
|
|
2248 /* (Joris Huizer) ensure it is not an GIVE UP statement */
|
|
2249 if ((tuples + tn->u.target - 1)->type != GIVE_UP)
|
|
2250 {
|
|
2251 if(!pickcompile)
|
|
2252 (void) fprintf(fp, "\t""if(ICKABSTAINED(%u)) ICKABSTAINED(%u)--;\n", tn->u.target - 1, tn->u.target-1);
|
|
2253 else
|
|
2254 (void) fprintf(fp, "\t""ICKABSTAINED(%u)=0;\n", tn->u.target - 1);
|
|
2255 }
|
|
2256 else
|
|
2257 (void) fprintf(fp, "\t""/* not reinstating a GIVE UP line */\n");
|
|
2258 break;
|
|
2259
|
|
2260 case ENABLE:
|
|
2261 case DISABLE:
|
|
2262 case MANYFROM:
|
|
2263 /* AIS: This code has been rewritten to make use of the revlinetype array
|
|
2264 (an optimisation that Joris Huizer came up with; however, I am not
|
|
2265 using his code, but rewriting it, to make use of a single array and an
|
|
2266 index to it, rather than one array for each command type, for
|
|
2267 maintainability reasons. */
|
|
2268 if(pickcompile) ick_lose(IE256, emitlineno, (const char*) NULL);
|
|
2269 (void) fprintf(fp,"\tint i;\n");
|
|
2270 np=tn->u.node;
|
|
2271 if(tn->type==MANYFROM)
|
|
2272 {
|
|
2273 np=np->rval;
|
|
2274 fprintf(fp,"\tint j = ");
|
|
2275 prexpr(tn->u.node->lval, fp, 1);
|
|
2276 fprintf(fp,";\n");
|
|
2277 }
|
|
2278 for(; np; np = np->rval)
|
|
2279 {
|
|
2280 int npc = np->constant;
|
|
2281 anothertype:
|
|
2282 (void) fprintf(fp,"\n\tfor(i=revlineindex[%s];i<revlineindex[%s+1];i++)\n",
|
|
2283 enablers[npc-GETS],enablers[npc-GETS]);
|
|
2284 switch(tn->type)
|
|
2285 {
|
|
2286 case ENABLE: (void) fprintf(fp,"\t if (ick_abstained[revlinetype[i]])"
|
|
2287 "\t\tick_abstained[revlinetype[i]]--;\n"); break;
|
|
2288 case DISABLE: (void) fprintf(fp,"\t if(!ick_abstained[revlinetype[i]])"
|
|
2289 "\t\tick_abstained[revlinetype[i]]=1;\n"); break;
|
|
2290 case MANYFROM:(void) fprintf(fp,"\tick_abstained[revlinetype[i]]+=j;\n"); break;
|
|
2291 default: ick_lose(IE778, emitlineno, (const char *)NULL);
|
|
2292 }
|
|
2293 switch(npc)
|
|
2294 {
|
|
2295 case ABSTAIN: npc=DISABLE; goto anothertype;
|
|
2296 case DISABLE: npc=FROM; goto anothertype;
|
|
2297 case FROM: npc=MANYFROM; goto anothertype;
|
|
2298 case REINSTATE: npc=ENABLE; goto anothertype;
|
|
2299 case COME_FROM: npc=COMPUCOME; goto anothertype;
|
|
2300 case COMPUCOME: npc=GERUCOME; goto anothertype;
|
|
2301 case NEXTFROMLABEL: npc=NEXTFROMEXPR; goto anothertype;
|
|
2302 case NEXTFROMEXPR: npc=NEXTFROMGERUND; goto anothertype;
|
|
2303 default: break;
|
|
2304 }
|
|
2305 }
|
|
2306 break;
|
|
2307
|
|
2308 case NEXTFROMEXPR:
|
|
2309 case NEXTFROMGERUND:
|
|
2310 case GERUCOME:
|
|
2311 case COMPUCOME: /* By AIS. Note that this doesn't even have balanced
|
|
2312 braces; it's designed to work with COMPUCOME's
|
|
2313 crazy guarding arrangements */
|
|
2314 if(pickcompile) ick_lose(IE256, emitlineno, (const char*) NULL); /* AIS */
|
|
2315 if(useickec) /* use ick_ec's features for next from and come from*/
|
|
2316 {
|
|
2317 if(tn->type == COMPUCOME)
|
|
2318 {
|
|
2319 fprintf(fp,"\t""ick_docomefromif(");
|
|
2320 prexpr(tn->u.node, fp, 1);
|
|
2321 fprintf(fp,",ick_lineno,({int i=0;");
|
|
2322 emit_guard(tn,fp); /* re-emit the guard */
|
|
2323 fprintf(fp,"i=1;};i;}));\n");
|
|
2324 break;
|
|
2325 }
|
|
2326 else if(tn->type == NEXTFROMEXPR)
|
|
2327 {
|
|
2328 fprintf(fp,"\t""ick_donextfromif(");
|
|
2329 prexpr(tn->u.node, fp, 1);
|
|
2330 fprintf(fp,",ick_lineno,({int i=0;");
|
|
2331 emit_guard(tn,fp); /* re-emit the guard */
|
|
2332 fprintf(fp,"i=1;};i;}));\n");
|
|
2333 break;
|
|
2334 }
|
|
2335 }
|
|
2336 fprintf(fp,"\t""%s;} else goto CCF%d;\n",
|
|
2337 multithread?"NEXTTHREAD":useprintflow?
|
|
2338 "if(ick_printflow) fprintf(stderr,\"[%d]\",ick_lineno)":"",
|
|
2339 compucomecount);
|
|
2340 break;
|
|
2341
|
|
2342 case GIVE_UP: /* AIS: Edited to allow for yuk */
|
|
2343 if(yukprofile||yukdebug) fprintf(fp, "\t""YUKTERM;\n");
|
|
2344 if(multithread) fprintf(fp, "\t""killthread();\n");
|
|
2345 else
|
|
2346 {
|
|
2347 if(nonespots||opoverused)
|
|
2348 fprintf(fp,"\t""if(ick_onespots) free(ick_onespots);\n");
|
|
2349 if(ntwospots||opoverused)
|
|
2350 fprintf(fp,"\t""if(ick_twospots) free(ick_twospots);\n");
|
|
2351 if(ntails) fprintf(fp,"\t""if(ick_tails) free(ick_tails);\n");
|
|
2352 if(nhybrids) fprintf(fp,"\t""if(ick_hybrids) free(ick_hybrids);\n");
|
|
2353 if(nonespots||opoverused)
|
|
2354 fprintf(fp,"\t""if(ick_oneforget) free(ick_oneforget);\n");
|
|
2355 if(ntwospots||opoverused)
|
|
2356 fprintf(fp,"\t""if(ick_twoforget) free(ick_twoforget);\n");
|
|
2357 if(ntails) fprintf(fp,"\t""if(ick_tailforget) free(ick_tailforget);\n");
|
|
2358 if(nhybrids) fprintf(fp,"\t""if(ick_hyforget) free(ick_hyforget);\n");
|
|
2359 if(opoverused)
|
|
2360 {
|
|
2361 fprintf(fp,"\t""if(ick_oo_onespots) free(ick_oo_onespots);\n");
|
|
2362 fprintf(fp,"\t""if(ick_oo_twospots) free(ick_oo_twospots);\n");
|
|
2363 }
|
|
2364 fprintf(fp,"\t""if(ick_next) free(ick_next);\n");
|
|
2365 if(useickec)
|
|
2366 fprintf(fp,"\t""if(ick_next_jmpbufs) free(ick_next_jmpbufs);\n");
|
|
2367 }
|
|
2368 (void) fprintf(fp, "\t""exit(0);\n");
|
|
2369 break;
|
|
2370
|
|
2371 case TRY_AGAIN: /* By AIS */
|
|
2372 (void) fprintf(fp, "\t""goto ick_restart;\n }\n");
|
|
2373 if(yukprofile||yukdebug) fprintf(fp, " if(yukloop) goto ick_restart;\n");
|
|
2374 if(yukprofile||yukdebug) fprintf(fp, " YUKTERM;\n");
|
|
2375 if(multithread) fprintf(fp, "\t""killthread();\n");
|
|
2376 else
|
|
2377 {
|
|
2378 if(nonespots||opoverused)
|
|
2379 fprintf(fp,"\t""if(ick_onespots) free(ick_onespots);\n");
|
|
2380 if(ntwospots||opoverused)
|
|
2381 fprintf(fp,"\t""if(ick_twospots) free(ick_twospots);\n");
|
|
2382 if(ntails) fprintf(fp,"\t""if(ick_tails) free(ick_tails);\n");
|
|
2383 if(nhybrids) fprintf(fp,"\t""if(ick_hybrids) free(ick_hybrids);\n");
|
|
2384 if(nonespots||opoverused)
|
|
2385 fprintf(fp,"\t""if(ick_oneforget) free(ick_oneforget);\n");
|
|
2386 if(ntwospots||opoverused)
|
|
2387 fprintf(fp,"\t""if(ick_twoforget) free(ick_twoforget);\n");
|
|
2388 if(ntails) fprintf(fp,"\t""if(ick_tailforget) free(ick_tailforget);\n");
|
|
2389 if(nhybrids) fprintf(fp,"\t""if(ick_hyforget) free(ick_hyforget);\n");
|
|
2390 if(opoverused)
|
|
2391 {
|
|
2392 fprintf(fp,"\t""if(ick_oo_onespots) free(ick_oo_onespots);\n");
|
|
2393 fprintf(fp,"\t""if(ick_oo_twospots) free(ick_oo_twospots);\n");
|
|
2394 }
|
|
2395 }
|
|
2396 (void) fprintf(fp, " {\n\treturn(0);\n");
|
|
2397 /* because if TRY AGAIN is the last line, falling off the end isn't an error */
|
|
2398 pasttryagain=1; /* flag an error if we try any more commands */
|
|
2399 break;
|
|
2400
|
|
2401 case WRITE_IN:
|
|
2402 if(pickcompile) ick_lose(IE256, emitlineno, (const char*) NULL); /* AIS */
|
|
2403 for (np = tn->u.node; np; np = np->rval) {
|
|
2404 if (np->lval->opcode == ick_TAIL || np->lval->opcode == ick_HYBRID) {
|
|
2405 (void) fprintf(fp,"\t""ick_binin(");
|
|
2406 prvar(np->lval, fp, 1);
|
|
2407 (void) fprintf(fp, ", %s[%lu]",
|
|
2408 nameof(np->lval->opcode, forgetbits),
|
|
2409 np->lval->constant);
|
|
2410 (void) fprintf(fp,");\n");
|
|
2411 }
|
|
2412 else {
|
|
2413 if (np->lval->opcode != SUB) {
|
|
2414 sp = np->lval;
|
|
2415 (void) fprintf(fp,"\t""(void) ick_assign((char*)&");
|
|
2416 }
|
|
2417 else {
|
|
2418 sp = np->lval->lval;
|
|
2419 (void) fprintf(fp,"\t""(void) ick_assign(");
|
|
2420 }
|
|
2421 prvar(np->lval, fp, 1);
|
|
2422 (void) fprintf(fp,", %s", nameof(sp->opcode, vartypes));
|
|
2423 (void) fprintf(fp,", %s[%lu]", nameof(sp->opcode, forgetbits),
|
|
2424 sp->constant);
|
|
2425 (void) fprintf(fp,", ick_pin());\n");
|
|
2426 }
|
|
2427 }
|
|
2428 break;
|
|
2429
|
|
2430 case READ_OUT:
|
|
2431 if(pickcompile) ick_lose(IE256, emitlineno, (const char*) NULL); /* AIS */
|
|
2432 for (np = tn->u.node; np; np = np->rval)
|
|
2433 {
|
|
2434 if (np->lval->opcode == ick_TAIL || np->lval->opcode == ick_HYBRID) {
|
|
2435 (void) fprintf(fp,"\t""ick_binout(");
|
|
2436 prvar(np->lval, fp, 1);
|
|
2437 (void) fprintf(fp,");\n");
|
|
2438 }
|
|
2439 else {
|
|
2440 (void) fprintf(fp, "\t""ick_pout(");
|
|
2441 prexpr(np->lval, fp, 1);
|
|
2442 (void) fprintf(fp, ");\n");
|
|
2443 }
|
|
2444 }
|
|
2445 break;
|
|
2446
|
|
2447 case PIN: /* AIS, with some code borrowed from the GETS code */
|
|
2448 np = tn->u.node;
|
|
2449 (void) fprintf(fp, "\t""TRISA = seq(~((");
|
|
2450 prexpr(np, fp, 0);
|
|
2451 (void) fprintf(fp, " >> 16) & 255));\n");
|
|
2452 (void) fprintf(fp, "\t""TRISB = seq(~(");
|
|
2453 prexpr(np, fp, 0);
|
|
2454 (void) fprintf(fp, " >> 24));\n");
|
|
2455 (void) fprintf(fp, "\t""PORTA = seq(~(");
|
|
2456 prexpr(np, fp, 0);
|
|
2457 (void) fprintf(fp, " & 255));\n");
|
|
2458 (void) fprintf(fp, "\t""PORTB = seq(~((");
|
|
2459 prexpr(np, fp, 0);
|
|
2460 (void) fprintf(fp, " >> 8) & 255));\n");
|
|
2461 {
|
|
2462 atom* op;
|
|
2463 int ignorable = 1;
|
|
2464 assert(oblist != NULL);
|
|
2465 for(op = oblist; op < obdex; op++)
|
|
2466 {
|
|
2467 if(op->type == np->opcode &&
|
|
2468 (unsigned long)op->intindex == np->constant)
|
|
2469 {
|
|
2470 ignorable &= op->ignorable;
|
|
2471 }
|
|
2472 }
|
|
2473 if(!ignorable)
|
|
2474 { /* Variable can't be ignored, and expression must be in range */
|
|
2475 (void) fprintf(fp,"\t""");
|
|
2476 prexpr(np, fp, 1);
|
|
2477 (void) fprintf(fp, " = ");
|
|
2478 }
|
|
2479 else
|
|
2480 {
|
|
2481 np = tn->u.node;
|
|
2482 (void) fprintf(fp,"\t""if(ignore%s%lu) ",
|
|
2483 nameof(np->opcode,varstores),
|
|
2484 np->constant);
|
|
2485 prexpr(np, fp, 1);
|
|
2486 (void) fprintf(fp, " = ");
|
|
2487 }
|
|
2488 }
|
|
2489 (void) fprintf(fp,"(TRISB<<24) | (TRISA<<16) | (PORTB<<8) | PORTA;\n");
|
|
2490 break;
|
|
2491
|
|
2492 case CREATE: /* By AIS */
|
|
2493 if(createsused == 0) goto splatme;
|
|
2494 (void) fprintf(fp,"\t""ick_registercreation(\"");
|
|
2495 prunknownstr(tn->u.node, fp);
|
|
2496 (void) fprintf(fp,"\",%uU);\n",tn->u.target);
|
|
2497 break;
|
|
2498
|
|
2499 case COMPUCREATE: /* By AIS */
|
|
2500 if(createsused == 0) goto splatme;
|
|
2501 (void) fprintf(fp,"\t""ick_registercreation(\"");
|
|
2502 prunknownstr(tn->u.node->rval, fp);
|
|
2503 (void) fprintf(fp,"\",");
|
|
2504 prexpr(tn->u.node->lval, fp, 1);
|
|
2505 (void) fprintf(fp,");\n");
|
|
2506 free(tn->u.node); /* don't free the rval */
|
|
2507 break;
|
|
2508
|
|
2509 case UNKNOWN: /* By AIS */
|
|
2510 /* We generate a check to see if the unknown statement has gained a
|
|
2511 meaning since it was compiled, or otherwise continue to the splattered
|
|
2512 case. Not for PIC-INTERCAL, though. */
|
|
2513 if(!pickcompile) prunknown(tn->u.node, fp);
|
|
2514 /*@fallthrough@*/
|
|
2515 case SPLATTERED:
|
|
2516 /* AIS: The code previously here could access unallocated memory due to
|
|
2517 a bug if the comment was a COME FROM target. The problem is that
|
|
2518 emitlineno (the line to show an error on) is usually the line after
|
|
2519 this one, but not always, and in this case the line after this one is
|
|
2520 always what we want, so I copied the relevant part of the emitlineno
|
|
2521 logic here to fix the bug. */
|
|
2522 splatme:
|
|
2523 if (tn < tuples + ick_lineno - 1)
|
|
2524 dim = tn[1].ick_lineno - tn->ick_lineno;
|
|
2525 else
|
|
2526 dim = iyylineno - tn->ick_lineno;
|
|
2527 if (tn->sharedline)
|
|
2528 ++dim;
|
|
2529 (void) fprintf(fp, "\t""ick_lose(IE000, %d, \"%s\");\n",
|
|
2530 emitlineno, nice_text(textlines + tn->ick_lineno, dim));
|
|
2531 break;
|
|
2532
|
|
2533 case PREPROC: /* AIS: 'DO NOTHING', but not enterable into a program. This
|
|
2534 is generated by the preprocessor. */
|
|
2535 fprintf(fp,"\t""; /* do nothing */\n");
|
|
2536 break;
|
|
2537
|
|
2538 case COME_FROM:
|
|
2539 case NEXTFROMLABEL: /* AIS */
|
|
2540 if(useickec) /* AIS */
|
|
2541 {
|
|
2542 if(tn->type == COME_FROM)
|
|
2543 {
|
|
2544 fprintf(fp,"\t""ick_docomefromif(%uU,ick_lineno,({int i=0;",
|
|
2545 tn->u.target);
|
|
2546 emit_guard(tn,fp); /* re-emit the guard */
|
|
2547 fprintf(fp,"i=1;};i;}));\n");
|
|
2548 break;
|
|
2549 }
|
|
2550 else /* (tn->type == NEXTFROMLABEL) */
|
|
2551 {
|
|
2552 fprintf(fp,"\t""ick_donextfromif(%uU,ick_lineno,({int i=0;",
|
|
2553 tn->u.target);
|
|
2554 emit_guard(tn,fp); /* re-emit the guard */
|
|
2555 fprintf(fp,"i=1;};i;}));\n");
|
|
2556 break;
|
|
2557 }
|
|
2558 }
|
|
2559 (void) fprintf(fp, "if(0) {C%ld: %s;%s}\n", (long)(tn-tuples+1),
|
|
2560 tn->type==NEXTFROMLABEL ? "ick_pushnext(truelineno+1)":"",
|
|
2561 multithread?" NEXTTHREAD;":!useprintflow?""
|
|
2562 :" if(ick_printflow) "
|
|
2563 "fprintf(stderr,\"[%d]\",ick_lineno);");
|
|
2564 /* AIS: Changed so all COME_FROMs have unique labels even if two
|
|
2565 of them aim at the same line, and added the NEXT FROM case (which
|
|
2566 involves hiding COME FROM labels in an unreachable if()). */
|
|
2567 break;
|
|
2568
|
|
2569 case WHILE: /* AIS: fall through to the error, because this shouldn't
|
|
2570 come up yet. */
|
|
2571 default:
|
|
2572 ick_lose(IE778, emitlineno, (const char *)NULL);
|
|
2573 /*@-unreachable@*/ break; /*@=unreachable@*/
|
|
2574 }
|
|
2575
|
|
2576 if ((tn->type != COME_FROM && tn->type != NEXTFROMLABEL)
|
|
2577 || /*AIS*/ useickec)
|
|
2578 (void) fprintf(fp, " }\n");
|
|
2579
|
|
2580 skipcomment:
|
|
2581
|
|
2582 if ((!useickec && (tn->type == COMPUCOME || tn->type == NEXTFROMEXPR))
|
|
2583 || tn->type == NEXTFROMGERUND || tn->type == GERUCOME )
|
|
2584 { /* By AIS */
|
|
2585 (void) fprintf(fp," else goto CCF%d;\n",compucomecount);
|
|
2586 (void) fprintf(fp," ick_ccfc++;\n");
|
|
2587 /* Note that due to the semantics of setjmp, this has to be written as 2
|
|
2588 separate ifs. The MULTICOME macro expands to a non-multithreaded or
|
|
2589 multithreaded function for handling a COME FROM clash. */
|
|
2590 (void) fprintf(fp," if(ick_ccfc==1||MULTICOME(%d,ick_cjb))\n"
|
|
2591 "\t""if(setjmp(ick_cjb) == 0) goto CCF%d;\n",
|
|
2592 emitlineno, compucomecount);
|
|
2593 /* Of course, emitlineno is unlikely to be helpful! */
|
|
2594 if(tn->type == NEXTFROMEXPR || tn->type == NEXTFROMGERUND)
|
|
2595 {
|
|
2596 /* Stack up the statement we've NEXTed from */
|
|
2597 (void) fprintf(fp," ick_pushnext(truelineno+1);\n");
|
|
2598 }
|
|
2599 (void) fprintf(fp," }\n");
|
|
2600 }
|
|
2601
|
|
2602 /* AIS: Before any COMING FROM this line is done, we need to sort out
|
|
2603 ONCE and AGAIN situations, unless this line was a NEXT or GO_BACK.
|
|
2604 COME FROM is also excluded because it acts at the suckpoint, not
|
|
2605 at the place it's written in the program. */
|
|
2606 if (tn->onceagainflag != onceagain_NORMAL &&
|
|
2607 tn->type != NEXT && tn->type != GO_BACK && tn->type != UNKNOWN &&
|
|
2608 ((tn->type != COME_FROM && tn->type != NEXTFROMLABEL) || useickec))
|
|
2609 {
|
|
2610 /* See my comments against the NEXT code for more information.
|
|
2611 This code is placed here so COME FROM ... ONCE constructs work
|
|
2612 properly (the line is ick_abstained if the COME FROM is reached in
|
|
2613 execution, or its suckpoint is reached in execution). */
|
|
2614 fprintf(fp," ick_oldabstain = ICKABSTAINED(%d);\n", (int)(tn - tuples));
|
|
2615 fprintf(fp," ICKABSTAINED(%d) = %s;\n",
|
|
2616 (int)(tn - tuples),
|
|
2617 tn->onceagainflag==onceagain_ONCE ? "ick_oldabstain ? ick_oldabstain : 1"
|
|
2618 : "0");
|
|
2619 }
|
|
2620
|
|
2621 /* AIS: This is where we start the COME FROM suckpoint code. */
|
|
2622
|
|
2623 /* AIS: The ickec version is very simple! We just finish the labeled
|
|
2624 block started at the start of the command. */
|
|
2625 if(tn->label && useickec)
|
|
2626 (void) fprintf(fp, "});\n");
|
|
2627
|
|
2628 /* AIS: We need to keep track of how many COME FROMs are aiming here
|
|
2629 at runtime, if we don't have the very simple situation of no
|
|
2630 COMPUCOMEs and a single-thread program (in which case the check
|
|
2631 is done at compile-time by codecheck). Even without COMPUCOME,
|
|
2632 this can change in a multithread program due to abstentions. */
|
|
2633 if((tn->ncomefrom && multithread) || (tn->label && compucomesused)
|
|
2634 || gerucomesused)
|
|
2635 (void) fprintf(fp, " ick_ccfc = 0;\n");
|
|
2636 /* AIS: For NEXTING FROM this line */
|
|
2637 if(nextfromsused && tn->ncomefrom)
|
|
2638 {
|
|
2639 (void) fprintf(fp, " truelineno = %d;\n", (int)(tn-tuples));
|
|
2640 }
|
|
2641 /*
|
|
2642 * If the statement that was just degenerated was a COME FROM target,
|
|
2643 * emit the code for the jump to the COME FROM.
|
|
2644 * AIS: Changed most of this to allow for multithreading.
|
|
2645 */
|
|
2646 while(tn->ncomefrom && !useickec) /* acts as an if if singlethreading */
|
|
2647 {
|
|
2648 tuple* cf; /* local to this block */
|
|
2649 if(multithread || compucomesused) generatecfjump = 1;
|
|
2650 cf = tuples+comefromsearch(tn,tn->ncomefrom)-1;
|
|
2651 if (yydebug || compile_only)
|
|
2652 (void) fprintf(fp,
|
|
2653 " /* line %03d is a suck point for the COME FROM "
|
|
2654 "at line %03d */\n", tn->ick_lineno, cf->ick_lineno);
|
|
2655 if (cf->onceagainflag != onceagain_NORMAL)
|
|
2656 { /* Calculate ONCE/AGAIN when the suckpoint is passed */
|
|
2657 fprintf(fp," ick_oldabstain = ICKABSTAINED(%d);\n", (int)(cf - tuples));
|
|
2658 fprintf(fp," ICKABSTAINED(%d) = %s;\n",
|
|
2659 (int)(cf - tuples),
|
|
2660 cf->onceagainflag==onceagain_ONCE ? "ick_oldabstain ? ick_oldabstain : 1"
|
|
2661 : "0");
|
|
2662 }
|
|
2663 emit_guard(cf, fp);
|
|
2664 if(multithread || compucomesused)
|
|
2665 (void) fprintf(fp,
|
|
2666 "\t""ick_ccfc++;\tif(ick_ccfc==1||MULTICOME(%d,ick_cjb)) "
|
|
2667 "if(setjmp(ick_cjb) == 1) goto C%ld;\n }\n",
|
|
2668 emitlineno, (long)(cf-tuples+1));
|
|
2669 else /* optimize for the simple case */
|
|
2670 (void) fprintf(fp, "\t""goto C%ld;\n }\n", (long)(cf-tuples+1));
|
|
2671 tn->ncomefrom--;
|
|
2672 }
|
|
2673
|
|
2674 /* AIS: If the statement has a label, it might be a
|
|
2675 computed COME FROM target. Also check the flag that says this
|
|
2676 code is needed in a multithread non-COMPUCOME program.
|
|
2677 If (at runtime) ick_ccfc is nonzero, we know ick_cjb has already been set;
|
|
2678 otherwise, set it now. In the case of a multithread non-COMPUCOME
|
|
2679 program, the goto will just jump to a longjmp, switching to the
|
|
2680 one and only one COME FROM that hasn't been given its own thread.
|
|
2681 However, skip all the compucomes and gerucomes if preproc is set,
|
|
2682 because COMING FROM a preproc should only ever be done by label. */
|
|
2683 if (((tn->label && compucomesused) || generatecfjump || gerucomesused) &&
|
|
2684 (!tn->preproc || generatecfjump) && (!useickec || gerucomesused))
|
|
2685 {
|
|
2686 if(compucomesused)
|
|
2687 {
|
|
2688 (void) fprintf(fp, " ick_skipto = %u;\n", tn->label);
|
|
2689 }
|
|
2690 if(gerucomesused || nextfromsused)
|
|
2691 {
|
|
2692 (void) fprintf(fp, " truelineno = %d;\n", (int)(tn-tuples));
|
|
2693 }
|
|
2694 if(generatecfjump) (void) fprintf(fp, " if(ick_ccfc) goto CCF%s;\n",
|
|
2695 tn->preproc?"L":"0");
|
|
2696 if((compucomesused || gerucomesused) && !tn->preproc)
|
|
2697 { /* check all the COMPUCOMES */
|
|
2698 (void) fprintf(fp, " %sif(setjmp(ick_cjb) == 0) goto CCF0;\n",
|
|
2699 generatecfjump?"else ":"");
|
|
2700 }
|
|
2701 generatecfjump = 0;
|
|
2702 /* AIS: If NEXT FROM's used, this might be a NEXT return target.
|
|
2703 Don't generate case labels for NEXT, as it has them already. */
|
|
2704 if(nextfromsused && tn->type != NEXT)
|
|
2705 {
|
|
2706 (void) fprintf(fp, " case %u:;\n", (unsigned)(tn-tuples+1));
|
|
2707 }
|
|
2708 }
|
|
2709
|
|
2710 /* AIS: Now we've finished the statement, let's switch to the next
|
|
2711 thread in a multithread program. */
|
|
2712 if(multithread) (void) fputs(" NEXTTHREAD;\n", fp);
|
|
2713 else if(useprintflow)
|
|
2714 (void) fputs(" if(ick_printflow) fprintf(stderr,"
|
|
2715 "\"[%d]\",ick_lineno);\n",fp);
|
|
2716 }
|
|
2717
|
|
2718 /* AIS: Generate prototypes for slat expressions, args to UNKNOWN */
|
|
2719 void emitslatproto(FILE* fp)
|
|
2720 {
|
|
2721 node* np=firstslat;
|
|
2722 const char* t="ick_type32";
|
|
2723 while(np)
|
|
2724 {
|
|
2725 fprintf(fp,"%s ick_og%lx(%s);\nvoid ick_os%lx(%s, void(*)());\n",
|
|
2726 t,(unsigned long)np,t,(unsigned long)np,t);
|
|
2727 np=np->nextslat;
|
|
2728 }
|
|
2729 }
|
|
2730
|
|
2731 /* AIS: Generate bodies for slat expressions, args to UNKNOWN */
|
|
2732 void emitslat(FILE* fp)
|
|
2733 {
|
|
2734 node* np=firstslat;
|
|
2735 node* temp, *temp2;
|
|
2736 const char* t="ick_type32";
|
|
2737 while(np)
|
|
2738 {
|
|
2739 fprintf(fp,
|
|
2740 "void ick_os%lx(%s a, void(*f)())\n{\n static int l=0;\n"
|
|
2741 " if(l)\n {\n if(!f) ick_lose(IE778, ick_lineno, (const char *)NULL);\n"
|
|
2742 " f(a,0);\n return;\n }\n l=1;\n",
|
|
2743 (unsigned long)np,t);
|
|
2744 temp=cons(C_A, 0, 0);
|
|
2745 revprexpr(np, fp, temp); /* revprexpr can't free */
|
|
2746 fprintf(fp," l=0;\n}\n");
|
|
2747 fprintf(fp,"%s ick_og%lx(%s t)\n{\n %s a;\n static int l=0;\n"
|
|
2748 " if(l) return t;\n l=1;\n a=",
|
|
2749 t,(unsigned long)np,t,t);
|
|
2750 prexpr(np, fp, 0);
|
|
2751 fprintf(fp,";\n l=0;\n return a;\n}\n");
|
|
2752 np=np->nextslat;
|
|
2753 }
|
|
2754 np=firstslat;
|
|
2755 /* Note that the order in which the parser assembles nodes means
|
|
2756 that we have to free the nodes in reverse order so we don't
|
|
2757 free child nodes twice. */
|
|
2758 temp2=0;
|
|
2759 while(np)
|
|
2760 {
|
|
2761 temp=np->nextslat;
|
|
2762 np->nextslat=temp2; /* reverse the chain */
|
|
2763 temp2=np;
|
|
2764 np=temp;
|
|
2765 }
|
|
2766 np=temp2;
|
|
2767 while(np)
|
|
2768 {
|
|
2769 temp=np->nextslat;
|
|
2770 nodefree(np);
|
|
2771 np=temp;
|
|
2772 }
|
|
2773 /* JH: clear firstslat */
|
|
2774 firstslat = 0;
|
|
2775 }
|
|
2776
|
|
2777 /* feh.c ends here */
|