Pristine Ack-5.5
[Ack-5.5.git] / util / ego / ic / ic_lookup.c
1 /* $Id: ic_lookup.c,v 1.12 1994/06/24 10:24:23 ceriel Exp $ */
2 /*
3  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4  * See the copyright notice in the ACK home directory, in the file "Copyright".
5  */
6 /*  I N T E R M E D I A T E   C O D E
7  *
8  *  I C _ L O O K U P . C
9  */
10
11
12 #include <stdio.h>
13 #include <em_spec.h>
14 #include "../share/types.h"
15 #include "../share/debug.h"
16 #include "../share/map.h"
17 #include "ic.h"
18 #include "ic_lookup.h"
19 #include "../share/alloc.h"
20
21
22 sym_p symhash[NSYMHASH];
23 prc_p prochash[NPROCHASH];
24 num_p numhash[NNUMHASH];
25 char *lastname;
26
27 extern char     *strcpy();
28
29 #define newsym()        (sym_p) newstruct(sym)
30 #define newprc()        (prc_p) newstruct(prc)
31 #define newnum()        (num_p) newstruct(num)
32
33 #define oldsym(x)       oldstruct(sym,x)
34 #define oldprc(x)       oldstruct(prc,x)
35 #define oldnum(x)       oldstruct(num,x)
36
37 #define PF_FILE 2
38 #define DF_FILE 2
39
40 /* instr_lab */
41
42
43
44
45
46 lab_id instr_lab(number)
47         short number;
48 {
49         register num_p *npp, np;
50
51         /* In EM assembly language, a label is an unsigned number,
52          * e.g. 120 in 'BRA *120'. In IC the labels of a procedure
53          * are represented by consecutive integer numbers, called
54          * lab_id. The mapping takes place here.
55          */
56
57
58         npp = &numhash[number%NNUMHASH];
59         while (*npp != (num_p) 0) {
60                 if ((*npp)->n_number == number) {
61                         return(*npp)->n_labid;
62                 } else {
63                         npp = &(*npp)->n_next;
64                 }
65         }
66
67         /* The label was not found in the hashtable, so
68          * create a new entry for it.
69          */
70
71         *npp = np = newnum();
72         np->n_number = number;
73         np->n_labid = ++lastlid;
74         /* Assign a new label identifier to the num struct.
75          * lastlid is reset to 0 at the beginning of
76          * every new EM procedure (by cleaninstrlabs).
77          */
78         return (np->n_labid);
79 }
80
81
82
83 /*  symlookup */
84
85 STATIC unsigned hash(string) char *string; {
86         register char *p;
87         register unsigned i,sum;
88
89         for (sum=i=0,p=string;*p;i += 3)
90                 sum ^= (*p++)<<(i&07);
91         return(sum);
92 }
93
94 dblock_p symlookup(name, status)
95         char *name;
96         int  status;
97 {
98         /* Look up the name of a data block. The name can appear
99          * in either a defining or applied occurrence (status is
100          * DEFINING, OCCURRING resp.), or in a MES ms_ext instruction
101          * as the name of a data block imported by a library module
102          * (status is IMPORTING). Things get complicated,
103          * because a HOL pseudo need not be preceded by a
104          * data label, i.e. a hol block need not have a name.
105          */
106
107
108         register sym_p *spp,  sp;
109         register dblock_p dp;
110
111         if (name == (char *) 0) {
112                 assert(status == DEFINING);
113                 dp = newdblock();
114         } else {
115                 spp = &symhash[hash(name)%NSYMHASH];
116                 while (*spp != (sym_p) 0) {
117                         /* Every hashtable entry points to a list
118                          * of synonyms (i.e. names with the same
119                          * hash values). Try to find 'name' in its
120                          * list.
121                          */
122                         if (strcmp((*spp)->sy_name, name) == 0) {
123                                 dp = (*spp)->sy_dblock;
124                                 if (status != DEFINING ||
125                                     (dp->d_flags1 & DF_EXTERNAL) == 0) {
126                                         dp->d_flags2 |= DF_FILE;
127                                 }
128                                 if (dp->d_flags2 & DF_FILE) {
129                                         lastname = (*spp)->sy_name;
130                                         return dp;
131                                 }
132                                 break;
133                         } else {
134                                 spp = &(*spp)->sy_next;
135                         }
136                 }
137                 /* The name is not found, so create a new entry for it.
138                  * However, if the status is IMPORTING, we just return 0,
139                  * indicating that we don't need this name.
140                  */
141                 if (status == IMPORTING) return (dblock_p) 0;
142                 sp = newsym();
143                 sp->sy_next = *spp;
144                 *spp = sp;
145                 sp->sy_name = (char *) newcore(strlen(name)+1);
146                 strcpy(sp->sy_name, name);
147                 lastname = sp->sy_name;         /* quick hack to get at
148                                                    the name
149                                                 */
150                 dp = sp->sy_dblock = newdblock();
151         }
152         if (fdblock == (dblock_p) 0) {
153                 fdblock = dp;
154                 /* first data block */
155         } else {
156                 ldblock->d_next = dp; /* link to last dblock */
157         }
158         ldblock = dp;
159         dp->d_pseudo    = DUNKNOWN;     /* clear all fields */
160         dp->d_id        = ++lastdid;
161         dp->d_size      = 0;
162         dp->d_objlist   = (obj_p) 0;
163         dp->d_values    = (arg_p) 0;
164         dp->d_next      = (dblock_p) 0;
165         dp->d_flags1    = 0;
166         dp->d_flags2    = 0;
167         if (status == OCCURRING) {
168                 /* This is the first occurrence of the identifier,
169                  * so if it is a used occurrence make the
170                  * identifier externally visible, else make it
171                  * internal.
172                  */
173                 dp->d_flags1 |= DF_EXTERNAL;
174         }
175         dp->d_flags2 |= DF_FILE;
176         return dp;
177 }
178
179
180
181 /* getsym */
182
183 dblock_p getsym(status)
184         int status;
185 {
186         if (table2() != DLBX) {
187                 error("symbol expected");
188         }
189         return(symlookup(string,status));
190 }
191
192
193
194 /* getproc */
195
196 proc_p getproc(status)
197         int status;
198 {
199         if (table2() != sp_pnam) {
200                 error("proc name expected");
201         }
202         return(proclookup(string,status));
203 }
204
205
206
207 /* proclookup */
208
209 proc_p proclookup(name, status)
210         char *name;
211         int  status;
212 {
213         register prc_p *ppp,  pp;
214         register proc_p dp;
215
216         ppp = &prochash[hash(name)%NPROCHASH];
217         while (*ppp != (prc_p) 0) {
218                 /* Every hashtable entry points to a list
219                  * of synonyms (i.e. names with the same
220                  * hash values). Try to find 'name' in its
221                  * list.
222                  */
223                 if (strcmp((*ppp)->pr_name, name) == 0) {
224                         /* found */
225                         dp = (*ppp)->pr_proc;
226                         if (status != DEFINING ||
227                             (dp->p_flags1 & PF_EXTERNAL) == 0) {
228                                 dp->p_flags2 |= PF_FILE;
229                                 return dp;
230                         }
231                         if (dp->p_flags2 & PF_FILE) return dp;
232                         break;
233                 } else {
234                         ppp = &(*ppp)->pr_next;
235                 }
236         }
237         /* The name is not found, so create a new entry for it,
238          * unless the status is IMPORTING, in which case we
239          * return 0, indicating we don't want this proc.
240          */
241         if (status == IMPORTING) return (proc_p) 0;
242         pp = newprc();
243         pp->pr_next = *ppp;
244         *ppp = pp;
245         pp->pr_name = (char *) newcore(strlen(name)+1);
246         strcpy(pp->pr_name, name);
247         dp = pp->pr_proc = newproc();
248         if (fproc == (proc_p) 0) {
249                 fproc = dp;  /* first proc */
250         } else {
251                 lproc->p_next = dp;
252         }
253         lproc = dp;
254         dp->p_id        = ++lastpid;    /* create a unique proc_id */
255         dp->p_next      = (proc_p) 0;
256         dp->p_flags1    = 0;
257         dp->p_flags2    = 0;
258         if (status == OCCURRING) {
259                 /* This is the first occurrence of the identifier,
260                  * so if it is a used occurrence the make the
261                  * identifier externally visible, else make it
262                  * internal.
263                  */
264                 dp->p_flags1 |= PF_EXTERNAL;
265         }
266         dp->p_flags2 |= PF_FILE;
267         return dp;
268 }
269
270
271
272 /* cleaninstrlabs */
273
274 cleaninstrlabs()
275 {
276         register num_p *npp, np, next;
277
278         for (npp = numhash; npp < &numhash[NNUMHASH]; npp++) {
279                 for  (np = *npp; np != (num_p) 0; np = next) {
280                         next = np->n_next;
281                         oldnum(np);
282                 }
283                 *npp = (num_p) 0;
284         }
285         /* Reset last label id (used by instr_lab). */
286         lastlid = (lab_id) 0;
287 }
288
289
290
291 /* dump_procnames */
292
293 dump_procnames(hash,n,f)
294         prc_p  hash[];
295         int    n;
296         FILE   *f;
297 {
298         /* Save the names of the EM procedures in file f.
299          * Note that the Optimizer Intermediate Code does not
300          * use identifiers but proc_ids, object_ids etc.
301          * The names, however, can be used after optimization
302          * is completed, to reconstruct Compact Assembly Language.
303          * The output consists of tuples (proc_id, name).
304          * This routine is called once for every input file.
305          * To prevent names of external procedures being written
306          * more than once, the PF_WRITTEN flag is used.
307          */
308
309         register prc_p *pp, ph;
310         proc_p p;
311
312 #define PF_WRITTEN 01
313
314
315         for (pp = &hash[0]; pp < &hash[n]; pp++) {
316                 /* Traverse the entire hash table */
317                 for (ph = *pp; ph != (prc_p) 0; ph = ph->pr_next) {
318                         /* Traverse the list of synonyms */
319                         p = ph->pr_proc;
320                         if ((p->p_flags2 & PF_WRITTEN) == 0) {
321                                 /* not been written yet */
322                                 fprintf(f,"%d   %s\n",p->p_id, ph->pr_name);
323                                 p->p_flags2 |= PF_WRITTEN;
324                         }
325                 }
326         }
327 }
328
329 /* cleanprocs */
330
331 cleanprocs(hash,n,mask)
332         prc_p hash[];
333         int   n,mask;
334 {
335         /* After an EM input file has been processed, the names
336          * of those procedures that are internal (i.e. not visible
337          * outside the file they are defined in) must be removed
338          * from the procedure hash table. This is accomplished
339          * by removing the 'prc struct' from its synonym list.
340          * After the final input file has been processed, all
341          * remaining prc structs are also removed.
342          */
343
344         register prc_p *pp, ph, x, next;
345
346         for (pp = &hash[0]; pp < &hash[n]; pp++) {
347                 /* Traverse the hash table */
348                 x = (prc_p) 0;
349                 for (ph = *pp; ph != (prc_p) 0; ph = next) {
350                         /* Traverse the synonym list.
351                          * x points to the prc struct just before ph,
352                          * or is 0 if ph is the first struct of
353                          * the list.
354                          */
355                         ph->pr_proc->p_flags2 &= ~PF_FILE;
356                         next = ph->pr_next;
357                         if ((ph->pr_proc->p_flags1 & mask) == 0) {
358                                 if (x == (prc_p) 0) {
359                                         *pp = next;
360                                 } else {
361                                         x->pr_next = next;
362                                 }
363                                 oldprc(ph); /* delete the struct */
364                         } else {
365                                 x = ph;
366                         }
367                 }
368         }
369 }
370
371
372
373 /* dump_dblocknames */
374
375 dump_dblocknames(hash,n,f)
376         sym_p  hash[];
377         int    n;
378         FILE   *f;
379 {
380         /* Save the names of the EM data blocks in file f.
381          * The output consists of tuples (dblock_id, name).
382          * This routine is called once for every input file.
383          */
384
385         register sym_p *sp, sh;
386         dblock_p d;
387
388 #define DF_WRITTEN 01
389
390
391         for (sp = &hash[0]; sp < &hash[n]; sp++) {
392                 /* Traverse the entire hash table */
393                 for (sh = *sp; sh != (sym_p) 0; sh = sh->sy_next) {
394                         /* Traverse the list of synonyms */
395                         d = sh->sy_dblock;
396                         if ((d->d_flags2 & DF_WRITTEN) == 0) {
397                                 /* not been written yet */
398                                 fprintf(f,"%d   %s\n",d->d_id, sh->sy_name);
399                                 d->d_flags2 |= DF_WRITTEN;
400                         }
401                 }
402         }
403 }
404
405 /* cleandblocks */
406
407 cleandblocks(hash,n,mask)
408         sym_p hash[];
409         int   n,mask;
410 {
411         /* After an EM input file has been processed, the names
412          * of those data blocks that are internal must be removed.
413          */
414
415         register sym_p *sp, sh, x, next;
416
417         for (sp = &hash[0]; sp < &hash[n]; sp++) {
418                 x = (sym_p) 0;
419                 for (sh = *sp; sh != (sym_p) 0; sh = next) {
420                         next = sh->sy_next;
421                         sh->sy_dblock->d_flags2 &= ~DF_FILE;
422                         if ((sh->sy_dblock->d_flags1 & mask) == 0) {
423                                 if (x == (sym_p) 0) {
424                                         *sp = next;
425                                 } else {
426                                         x->sy_next = next;
427                                 }
428                                 oldsym(sh); /* delete the struct */
429                         } else {
430                                 x = sh;
431                         }
432                 }
433         }
434 }