Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / cemcom.ansi / stack.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 /* $Id: stack.c,v 1.10 1994/06/27 08:02:30 ceriel Exp $ */
6 /*      S T A C K / U N S T A C K  R O U T I N E S      */
7
8 #include        "lint.h"
9 #include        <system.h>
10 #ifndef LINT
11 #include        <em.h>
12 #else
13 #include        "l_em.h"
14 #endif  /* LINT */
15 #include        "debug.h"
16 #include        "botch_free.h"
17 #include        <alloc.h>
18 #include        "Lpars.h"
19 #include        "arith.h"
20 #include        "stack.h"
21 #include        "type.h"
22 #include        "idf.h"
23 #include        "def.h"
24 #include        "struct.h"
25 #include        "level.h"
26 #include        "mes.h"
27
28 /* #include     <em_reg.h> */
29
30 extern char options[];
31
32 static struct stack_level UniversalLevel;
33 struct stack_level *local_level = &UniversalLevel;
34 /*      The main reason for having this secondary stacking
35         mechanism besides the linked lists pointed to by the idf's
36         is efficiency.
37         To remove the idf's of a given level, one could scan the
38         hash table and chase down the idf chains; with a hash
39         table size of 100 this is feasible, but with a size of say
40         100000 this becomes painful. Therefore all idf's are also
41         kept in a stack of sets, one set for each level.
42 */
43
44 int level;      /* Always equal to local_level->sl_level. */
45
46 stack_level()   {
47         /*      A new level is added on top of the identifier stack.
48         */
49         register struct stack_level *stl = new_stack_level();
50         register struct stack_level *loclev = local_level;
51         
52         loclev->sl_next = stl;
53         stl->sl_previous = loclev;
54         stl->sl_level = ++level;
55         stl->sl_max_block = loclev->sl_max_block;
56         local_level = stl;
57 #ifdef  LINT
58         lint_start_local();
59 #endif  /* LINT */
60 }
61
62 stack_idf(idf, stl)
63         struct idf *idf;
64         register struct stack_level *stl;
65 {
66         /*      The identifier idf is inserted in the stack on level stl,
67                 but only if it is not already present at this level.
68         */
69         register struct stack_entry *se;
70         
71         se = stl->sl_entry;
72         while (se) {
73                 if (se->se_idf == idf) return;
74                 se = se->next;
75         }
76
77         se = new_stack_entry();
78
79         /* link it into the stack level */
80         se->next = stl->sl_entry;
81         se->se_idf = idf;
82         stl->sl_entry = se;
83 }
84
85 struct stack_level *
86 stack_level_of(lvl)
87 {
88         /*      The stack_level corresponding to level lvl is returned.
89                 The stack should probably be an array, to be extended with
90                 realloc where needed.
91         */
92         register struct stack_level *stl;
93
94         if (lvl == level)
95                 return local_level;
96         stl = &UniversalLevel;
97                 
98         while (stl->sl_level != lvl) {
99                 stl = stl->sl_next;
100         }
101         return stl;
102 }
103
104 unstack_level()
105 {
106         /*      The top level of the identifier stack is removed.
107         */
108         struct stack_level *lastlvl;
109
110 #ifdef  DEBUG
111         if (options['t'])
112                 dumpidftab("before unstackidfs", 0);
113 #endif  /* DEBUG */
114
115 #ifdef  LINT
116         lint_end_local(local_level);
117 #endif  /* LINT */
118
119         /*      The implementation below is more careful than strictly
120                 necessary. Optimists may optimize it afterwards.
121         */
122         while (local_level->sl_entry)   {
123                 register struct stack_entry *se = local_level->sl_entry;
124                 register struct idf *idf = se->se_idf;
125                 register struct def *def;
126                 register struct sdef *sdef;
127                 register struct tag *tag;
128
129                 /* unlink it from the local stack level */
130                 local_level->sl_entry = se->next;
131                 free_stack_entry(se);
132
133                 if (level == L_LOCAL && (def = idf->id_label)) {
134                         unstack_label(idf);
135                         free_def(def);
136                         idf->id_label = 0;
137                 }
138                 while ((def = idf->id_def) && def->df_level >= level)   {
139                         /* unlink it from the def list under the idf block */
140                         if (def->df_sc == REGISTER || def->df_sc == AUTO)
141                                 FreeLocal(def->df_address);
142                         idf->id_def = def->next;
143                         free_def(def);
144                         update_ahead(idf);
145                 }
146                 while ( (sdef = idf->id_sdef)
147                 &&      sdef->sd_level >= level
148                 )       {
149                         /* unlink it from the sdef list under the idf block */
150                         idf->id_sdef = sdef->next;
151                         free_sdef(sdef);
152                 }
153                 while ( (tag = idf->id_tag)
154                 &&      tag->tg_level >= level
155                 )       {
156                         /* unlink it from the struct list under the idf block */
157                         idf->id_tag = tag->next;
158                         free_tag(tag);
159                 }
160         }
161         /*      Unlink the local stack level from the stack.
162         */
163         lastlvl = local_level;
164         local_level = local_level->sl_previous;
165         if (level >= L_LOCAL)   {
166                 local_level->sl_max_block = lastlvl->sl_max_block;
167         }
168         free_stack_level(lastlvl);
169         local_level->sl_next = (struct stack_level *) 0;
170         level = local_level->sl_level;
171
172 #ifdef  DEBUG
173         if (options['t'])
174                 dumpidftab("after unstackidfs", 0);
175 #endif  /* DEBUG */
176 }
177
178 unstack_world()
179 {
180         /*      The global level of identifiers is scanned, and final
181                 decisions are taken about such issues as
182                 extern/static/global and un/initialized.
183                 Effects on the code generator: initialised variables
184                 have already been encoded while the uninitialised ones
185                 are not and have to be encoded at this moment.
186         */
187         register struct stack_entry *se = local_level->sl_entry;
188
189 #ifdef  LINT
190         lint_end_global(local_level);
191 #endif  /* LINT */
192
193 #ifdef GEN_NM_LIST
194         open_name_list();
195 #endif /* GEN_NM_LIST */
196
197         while (se)      {
198                 register struct idf *idf = se->se_idf;
199                 register struct def *def = idf->id_def;
200                 
201                 if (!def)       {
202                         /* global selectors, etc. */
203                         se = se->next;
204                         continue;
205                 }
206                 
207 #ifdef DEBUG
208                 if (options['a']) {
209                         char *symbol2str();
210
211                         print("\"%s\", %s, %s, %s, %s\n",
212                                 idf->id_text,
213                                 (def->df_alloc == 0) ? "no alloc" :
214                                 (def->df_alloc == ALLOC_SEEN) ? "alloc seen" :
215                                 (def->df_alloc == ALLOC_DONE) ? "alloc done" :
216                                 "illegal alloc info",
217                                 symbol2str(def->df_sc),
218                                 def->df_initialized ? "init" : "no init",
219                                 def->df_used ? "used" : "not used");
220                 }
221 #endif /* DEBUG */
222                 if (def->df_sc == STATIC
223                     && def->df_type->tp_fund == FUNCTION
224                     && !def->df_initialized) {
225                         /* orphaned static function */
226                         warning("static function %s never defined, %s"
227                                     , idf->id_text
228                                     , "changed to extern");
229                         def->df_sc = EXTERN;
230                 }
231                 
232                 if (def->df_alloc == ALLOC_SEEN
233                     && !def->df_initialized) {
234                         /* space must be allocated */
235                         bss(idf);
236 #ifdef GEN_NM_LIST
237                         if (def->df_sc != STATIC)
238                                 namelist(idf->id_text); /* may be common */
239 #endif /* GEN_NM_LIST */
240                         def->df_alloc = ALLOC_DONE;     /* see Note below */
241                 }
242                 se = se->next;
243         }
244         /*      Note:
245                 df_alloc must be set to ALLOC_DONE because the idf entry
246                 may occur several times in the list.
247                 The reason for this is that the same name may be used
248                 for different purposes on the same level, e.g.
249                         struct s {int s;} s;
250                 is a legal definition and contains 3 defining occurrences
251                 of s.
252                 Each definition has been entered into the identifier stack.
253                 Although only one of them concerns a variable, we meet the
254                 s 3 times when scanning the identifier stack.
255         */
256 }
257
258 #ifdef GEN_NM_LIST
259 /*      A list of potential common names is kept, to be fed to
260         an understanding loader.  The list is written to a file
261         the name of which is nmlist.  If nmlist == NULL, no name
262         list is generated.
263 */
264 extern char *nmlist;    /* BAH! -- main.c       */
265 static File *nfp = 0;
266
267 open_name_list()
268 {
269         if (nmlist && sys_open(nmlist, OP_WRITE, &nfp) == 0)
270                 fatal("cannot create namelist %s", nmlist);
271 }
272
273 namelist(nm)
274         char *nm;
275 {
276         if (nmlist)     {
277                 sys_write(nfp, nm, strlen(nm));
278                 sys_write(nfp, "\n", 1);
279         }
280 }
281 #endif /* GEN_NM_LIST */