]> Shamusworld >> Repos - rmac/blob - symbol.c
Fix for bug #71 (thanks to ggn for reporting! :-)
[rmac] / symbol.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // SYMBOL.C - Symbol Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 #include "symbol.h"
10 #include "listing.h"
11 #include "procln.h"
12 #include "error.h"
13
14
15 // Macros
16 #define NBUCKETS 256                                    // Number of hash buckets (power of 2)
17
18 static SYM * symbolTable[NBUCKETS];             // User symbol-table header
19 int curenv;                                                             // Current enviroment number
20 static SYM * sorder;                                    // * -> Symbols, in order of reference
21 static SYM * sordtail;                                  // * -> Last symbol in sorder list
22 static SYM * sdecl;                                             // * -> Symbols, in order of declaration
23 static SYM * sdecltail;                                 // * -> Last symbol in sdecl list
24 static uint32_t currentUID;                             // Symbol UID tracking (done by NewSymbol())
25
26 // Tags for marking symbol spaces
27 // a = absolute
28 // t = text
29 // d = data
30 // ! = "impossible!"
31 // b = BSS
32 static char tdb_text[8] = {
33    'a', 't', 'd', '!', 'b', SPACE, SPACE, SPACE
34 };
35
36
37 //
38 // Initialize symbol table
39 //
40 void InitSymbolTable(void)
41 {
42         int i;                                                                  // Iterator
43
44         for(i=0; i<NBUCKETS; i++)                               // Initialise symbol hash table
45                 symbolTable[i] = NULL;
46
47         curenv = 1;                                                             // Init local symbol enviroment
48         sorder = NULL;                                                  // Init symbol-reference list
49         sordtail = NULL;
50         sdecl = NULL;                                                   // Init symbol-decl list
51         sdecltail = NULL;
52         currentUID = 0;
53 }
54
55
56 //
57 // Hash the print name and enviroment number
58 //
59 int HashSymbol(char * name, int envno)
60 {
61         int sum, k = 0;                                                 // Hash calculation
62
63         for(sum=envno; *name; name++)
64         {
65                 if (k++ == 1)
66                         sum += *name << 2;
67                 else
68                         sum += *name;
69         }
70
71         return sum & (NBUCKETS - 1);
72 }
73
74
75 //
76 // Make a new symbol of type `type' in enviroment `envno'
77 //
78 SYM * NewSymbol(char * name, int type, int envno)
79 {
80         // Allocate the symbol
81         SYM * symbol = malloc(sizeof(SYM));
82
83         if (symbol == NULL)
84         {
85                 printf("NewSymbol: MALLOC ERROR (symbol=\"%s\")\n", name);
86                 return NULL;
87         }
88
89         // Fill-in the symbol
90         symbol->sname  = strdup(name);
91         symbol->stype  = (BYTE)type;
92         symbol->senv   = (WORD)envno;
93         symbol->sattr  = 0;
94         // Don't do this, it could be a forward reference!
95 //      symbol->sattr  = DEFINED;               // We just defined it...
96         // This is a bad assumption. Not every symbol 1st seen in a RISC section is
97         // a RISC symbol!
98 //      symbol->sattre = (rgpu || rdsp ? RISCSYM : 0);
99         symbol->sattre = 0;
100         symbol->svalue = 0;
101         symbol->sorder = NULL;
102         symbol->uid    = currentUID++;
103
104         // Install symbol in symbol table
105         int hash = HashSymbol(name, envno);
106         symbol->snext = symbolTable[hash];
107         symbolTable[hash] = symbol;
108
109         // Append symbol to symbol-order list
110         if (sorder == NULL)
111                 sorder = symbol;                                        // Add first symbol 
112         else
113                 sordtail->sorder = symbol;                      // Or append to tail of list
114
115         sordtail = symbol;
116         return symbol;
117 }
118
119
120 //
121 // Look up the symbol name by its UID and return the pointer to the name.
122 // If it's not found, return NULL.
123 //
124 char * GetSymbolNameByUID(uint32_t uid)
125 {
126         //problem is with string lookup, that's why we're writing this
127         //so once this is written, we can put the uid in the token stream
128
129         // A much better approach to the symbol order list would be to make an
130         // array--that way you can do away with the UIDs and all the rest, and
131         // simply do an array lookup based on position. But meh, let's do this for
132         // now until we can rewrite things so they make sense.
133         SYM * symbol = sorder;
134
135         for(; symbol; symbol=symbol->sorder)
136         {
137                 if (symbol->uid == uid)
138                         return symbol->sname;
139         }
140
141         return NULL;
142 }
143
144
145 //
146 // Lookup the symbol `name', of the specified type, with the specified
147 // enviroment level
148 //
149 SYM * lookup(char * name, int type, int envno)
150 {
151         SYM * symbol = symbolTable[HashSymbol(name, envno)];
152
153         // Do linear-search for symbol in bucket
154         while (symbol != NULL)
155         {
156                 if (symbol->stype == type                       // Type, envno and name must match
157                         && symbol->senv  == envno
158                         && *name == *symbol->sname              // Fast check for first character
159                         && !strcmp(name, symbol->sname))        // More expensive check
160                         break;
161
162                 symbol = symbol->snext;
163         }
164
165         // Return NULL or matching symbol
166         return symbol;
167 }
168
169
170 //
171 // Put symbol on "order-of-declaration" list of symbols
172 //
173 void AddToSymbolDeclarationList(SYM * symbol)
174 {
175         // Don't add if already on list, or it's an equated register/CC
176         if ((symbol->sattr & SDECLLIST)
177                 || (symbol->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)))
178                 return;
179
180         // Mark as "on .sdecl list"
181         symbol->sattr |= SDECLLIST;
182
183         if (sdecl == NULL)
184                 sdecl = symbol;                         // First on decl-list
185         else 
186                 sdecltail->sdecl = symbol;      // Add to end of list
187
188         // Fix up list's tail
189         symbol->sdecl = NULL;
190         sdecltail = symbol;
191 }
192
193
194 //
195 // Make all referenced, undefined symbols global
196 //
197 void ForceUndefinedSymbolsGlobal(void)
198 {
199         SYM * sy;
200
201         DEBUG printf("~ForceUndefinedSymbolsGlobal()\n");
202
203         // Scan through all symbols;
204         // If a symbol is REFERENCED but not DEFINED, then make it global.
205         for(sy=sorder; sy!=NULL; sy=sy->sorder)
206         {
207                 if (sy->stype == LABEL && sy->senv == 0
208                         && ((sy->sattr & (REFERENCED | DEFINED)) == REFERENCED))
209                         sy->sattr |= GLOBAL;
210         }
211 }
212
213
214 //
215 // Convert string to uppercase
216 //
217 int uc_string(char * s)
218 {
219         for(; *s; s++)
220         {
221                 if (*s >= 'a' && *s <= 'z')
222                         *s -= 32;
223         }
224
225         return 0;
226 }
227
228
229 //
230 // Assign numbers to symbols that are to be exported or imported. The symbol
231 // number is put in `.senv'. Return the number of symbols that will be in the
232 // symbol table.
233 //
234 int sy_assign(char * buf, char *(* constr)())
235 {
236         SYM * sy;
237         int scount = 0;
238
239         if (buf == NULL)
240         {
241                 // Append all symbols not appearing on the .sdecl list to the end of
242                 // the .sdecl list
243                 for(sy=sorder; sy!=NULL; sy=sy->sorder)
244                         AddToSymbolDeclarationList(sy);
245         }
246
247         // Run through all symbols (now on the .sdecl list) and assign numbers to
248         // them. We also pick which symbols should be global or not here.
249         for(sy=sdecl; sy!=NULL; sy=sy->sdecl)
250         {
251                 // Don't want register/CC or undefined on our list
252 //these should already be rejected above...
253 //              if (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)))
254 //                      continue;
255
256                 // Export or import external references, and export COMMON blocks.
257                 if ((sy->stype == LABEL)
258                         && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED)
259                         || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED))
260                         || (sy->sattr & COMMON))
261                 {
262                         sy->senv = (WORD)scount++;
263
264                         if (buf != NULL)
265                                 buf = (*constr)(buf, sy, 1);
266                 }
267                 // Export vanilla labels (but don't make them global). An exception is
268                 // made for equates, which are not exported unless they are referenced.
269                 else if (sy->stype == LABEL && lsym_flag
270                         && (sy->sattr & (DEFINED | REFERENCED)) != 0
271                         && (!as68_flag || *sy->sname != 'L'))
272                 {
273                         sy->senv = (WORD)scount++;
274
275                         if (buf != NULL)
276                                 buf = (*constr)(buf, sy, 0);
277                 }
278         }
279
280         return scount;
281 }
282
283
284 //
285 // Generate symbol table for listing file
286 //
287 int symtable(void)
288 {
289         int i;
290         int j;
291         SYM * q = NULL;
292         SYM * p;
293         SYM * r;
294         SYM * k;
295         SYM ** sy;
296         SYM * colptr[4];
297         char ln[150];
298         char ln1[150];
299         char ln2[20];
300         char c, c1;
301         WORD w;
302         int ww;
303         int colhei;
304         extern int pagelen;
305
306         colhei = pagelen - 5;
307
308         // Allocate storage for list headers and partition all labels.  
309         // Throw away macros and macro arguments.
310         sy = (SYM **)malloc(128 * sizeof(LONG));
311
312         for(i=0; i<128; ++i)
313                 sy[i] = NULL;
314
315         for(i=0; i<NBUCKETS; ++i)
316         {
317                 for(p=symbolTable[i]; p!=NULL; p=k)
318                 {
319                         k = p->snext;
320                         j = *p->sname;
321                         r = NULL;
322
323                         // Ignore non-labels
324                         if ((p->stype != LABEL) || (p->sattre & UNDEF_EQUR))
325                                 continue;
326
327                         for(q=sy[j]; q!=NULL; q=q->snext)
328                         {
329                                 if (strcmp(p->sname, q->sname) < 0)
330                                         break;
331
332                                 r = q;
333                         }
334
335                         if (r == NULL)
336                         {
337                                 // Insert at front of list
338                                 p->snext = sy[j];
339                                 sy[j] = p;
340                         }
341                         else
342                         {
343                                 // Insert in middle or append to list
344                                 p->snext = r->snext;
345                                 r->snext = p;
346                         }
347                 }
348         }
349
350         // Link all symbols onto one list again
351         p = NULL;
352
353         for(i=0; i<128; ++i)
354         {
355                 if ((r = sy[i]) != NULL)
356                 {
357                         if (p == NULL)
358                                 q = r;
359                         else
360                                 q->snext = r;
361
362                         while (q->snext != NULL)
363                                 q = q->snext;
364
365                         if (p == NULL)
366                                 p = r;
367                 }
368         }
369
370         eject();
371         strcpy(subttl, "Symbol Table");
372
373         while (p != NULL)
374         {
375                 for(i=0; i<4; ++i)
376                 {
377                         colptr[i] = p;
378
379                         for(j=0; j<colhei; ++j)
380                         {
381                                 if (p == NULL)
382                                         break;
383                                 else
384                                         p = p->snext;
385                         }
386                 }
387
388                 for(i=0; i<colhei; ++i)
389                 {
390                         *ln = EOS;
391
392                         if (colptr[0] == NULL)
393                                 break;
394
395                         for(j=0; j<4; ++j)
396                         {
397                                 if ((q = colptr[j]) == NULL)
398                                         break;
399
400                                 colptr[j] = q->snext;
401                                 w = q->sattr;
402                                 ww = q->sattre;
403                                 // Pick a tag:
404                                 // c    common
405                                 // x    external reference
406                                 // g    global (export)
407                                 // space        nothing special
408                                 c1 = SPACE;
409                                 c = SPACE;
410
411                                 if (w & COMMON)
412                                         c = 'c';
413                                 else if ((w & (DEFINED|GLOBAL)) == GLOBAL)
414                                         c = 'x';
415                                 else if (w & GLOBAL)
416                                         c = 'g';
417
418                                 c1 = tdb_text[w & TDB];
419
420                                 if (c == 'x')
421                                         strcpy(ln2, "external");
422                                 else
423                                 {
424                                         sprintf(ln2, "%08X", q->svalue);
425                                         uc_string(ln2);
426                                 }
427
428                                 sprintf(ln1, "  %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c);
429                                 strcat(ln, ln1);
430                         }
431
432                         ship_ln(ln);
433                 }
434
435                 eject();
436         }
437
438         return 0;
439 }
440