]> Shamusworld >> Repos - rmac/blob - expr.c
Added new .cstruct construct. Thanks to GroovyBee for the suggestion!
[rmac] / expr.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011 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 "expr.h"
10 #include "direct.h"
11 #include "error.h"
12 #include "listing.h"
13 #include "mach.h"
14 #include "procln.h"
15 #include "risca.h"
16 #include "sect.h"
17 #include "symbol.h"
18 #include "token.h"
19
20 #define DEF_KW                                                  // Declare keyword values 
21 #include "kwtab.h"                                              // Incl generated keyword tables & defs
22
23 static char tokcl[128];                                 // Generated table of token classes
24 static VALUE evstk[EVSTACKSIZE];                // Evaluator value stack
25 static WORD evattr[EVSTACKSIZE];                // Evaluator attribute stack
26
27 // Token-class initialization list
28 char itokcl[] = {
29         0,                                                                      // END
30         CONST, SYMBOL, 0,                                       // ID 
31         '(', '[', '{', 0,                                       // OPAR
32         ')', ']', '}', 0,                                       // CPAR 
33         CR_DEFINED, CR_REFERENCED,                      // SUNARY (special unary)
34         CR_STREQ, CR_MACDEF,
35         CR_DATE, CR_TIME, 0,
36         '!', '~', UNMINUS, 0,                           // UNARY
37         '*', '/', '%', 0,                                       // MULT 
38         '+', '-', 0,                                            // ADD 
39         SHL, SHR, 0,                                            // SHIFT 
40         LE, GE, '<', '>', NE, '=', 0,           // REL 
41         '&', 0,                                                         // AND 
42         '^', 0,                                                         // XOR 
43         '|', 0,                                                         // OR 
44         1                                                                       // (the end) 
45 };
46
47 const char missym_error[] = "missing symbol";
48 const char str_error[] = "missing symbol or string";
49
50 // Convert expression to postfix
51 static TOKEN * tk;                                              // Deposit tokens here (this is really a
52                                                                                 // pointer to exprbuf from direct.c)
53 static symbolNum;                                               // Pointer to the entry in symbolPtr[]
54
55
56 //
57 // Obtain a String Value
58 //
59 static VALUE str_value(char * p)
60 {
61         VALUE v;
62
63         for(v=0; *p; p++)
64                 v = (v << 8) | (*p & 0xFF);
65
66         return v;
67 }
68
69
70 //
71 // Initialize Expression Analyzer
72 //
73 void init_expr(void)
74 {
75         int i;                                                                  // Iterator
76         char * p;                                                               // Token pointer
77
78         // Initialize token-class table
79         for(i=0; i<128; i++)                                    // Mark all entries END
80                 tokcl[i] = END;
81
82         for(i=0, p=itokcl; *p!=1; p++)
83         {
84                 if (*p == 0)
85                         i++;
86                 else 
87                         tokcl[(int)(*p)] = (char)i;
88         }
89
90         symbolNum = 0;
91 }
92
93
94 //
95 // Binary operators (all the same precedence)
96 //
97 int expr0(void)
98 {
99         TOKEN t;
100
101         if (expr1() != OK)
102                 return ERROR;
103         
104         while (tokcl[*tok] >= MULT)
105         {
106                 t = *tok++;
107
108                 if (expr1() != OK)
109                         return ERROR;
110
111                 *tk++ = t;
112         }
113
114         return OK;
115 }
116
117
118 //
119 // Unary operators (detect unary '-')
120 //
121 int expr1(void)
122 {
123         int class;
124         TOKEN t;
125         SYM * sy;
126         char * p, * p2;
127         WORD w;
128         int j;
129
130         class = tokcl[*tok];
131
132         if (*tok == '-' || class == UNARY)
133         {
134                 t = *tok++;
135
136                 if (expr2() != OK)
137                         return ERROR;
138
139                 if (t == '-')
140                         t = UNMINUS;
141
142                 *tk++ = t;
143         }
144         else if (class == SUNARY)
145         {
146                 switch ((int)*tok++)
147                 {
148                 case CR_TIME:
149                         *tk++ = CONST;
150                         *tk++ = dos_time();
151                         break;
152                 case CR_DATE:
153                         *tk++ = CONST;
154                         *tk++ = dos_date();
155                         break;
156                 case CR_MACDEF:                                    // ^^macdef <macro-name>
157                         if (*tok++ != SYMBOL)
158                                 return error(missym_error);
159
160 #if 0
161                         p = (char *)*tok++;
162 #else
163                         p = string[*tok++];
164 #endif
165                         w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
166                         *tk++ = CONST;
167                         *tk++ = (TOKEN)w;
168                         break;
169                 case CR_DEFINED:
170                         w = DEFINED;
171                         goto getsym;
172                 case CR_REFERENCED:
173                         w = REFERENCED;
174 getsym:
175                         if (*tok++ != SYMBOL)
176                                 return error(missym_error);
177
178 #if 0
179                         p = (char *)*tok++;
180 #else
181                         p = string[*tok++];
182 #endif
183                         j = 0;
184
185                         if (*p == '.')
186                                 j = curenv;
187
188                         w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
189                         *tk++ = CONST;
190                         *tk++ = (TOKEN)w;
191                         break;
192                 case CR_STREQ:
193                         if (*tok != SYMBOL && *tok != STRING)
194                                 return error(str_error);
195
196 #if 0
197                         p = (char *)tok[1];
198 #else
199                         p = string[tok[1]];
200 #endif
201                         tok +=2;
202
203                         if (*tok++ != ',')
204                                 return error(comma_error);
205
206                         if (*tok != SYMBOL && *tok != STRING)
207                                 return error(str_error);
208
209 #if 0
210                         p2 = (char *)tok[1];
211 #else
212                         p = string[tok[1]];
213 #endif
214                         tok += 2;
215
216                         w = (WORD)(!strcmp(p, p2));
217                         *tk++ = CONST;
218                         *tk++ = (TOKEN)w;
219                         break;
220                 }
221         }
222         else 
223                 return expr2();
224
225         return OK;
226 }
227
228
229 //
230 // Terminals (CONSTs) and parenthesis grouping
231 //
232 int expr2(void)
233 {
234         char * p;
235         SYM * sy;
236         int j;
237
238         switch ((int)*tok++)
239         {
240         case CONST:
241                 *tk++ = CONST;
242                 *tk++ = *tok++;
243                 break;
244         case SYMBOL:
245 #if 0
246                 p = (char *)*tok++;
247 #else
248                 p = string[*tok++];
249 #endif
250                 j = 0;
251
252                 if (*p == '.')
253                         j = curenv;
254
255                 sy = lookup(p, LABEL, j);
256
257                 if (sy == NULL)
258                         sy = NewSymbol(p, LABEL, j);
259
260                 // Check register bank usage
261                 if (sy->sattre & EQUATEDREG)
262                 {
263                         if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
264                                 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
265
266                         if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
267                                 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
268                 }
269
270                 *tk++ = SYMBOL;
271 #if 0
272                 *tk++ = (TOKEN)sy;
273 #else
274                 *tk++ = symbolNum;
275                 symbolPtr[symbolNum] = sy;
276                 symbolNum++;
277 #endif
278                 break;
279         case STRING:
280                 *tk++ = CONST;
281 #if 0
282                 *tk++ = str_value((char *)*tok++);
283 #else
284                 *tk++ = str_value(string[*tok++]);
285 #endif
286                 break;
287         case '(':
288                 if (expr0() != OK)
289                         return ERROR;
290
291                 if (*tok++ != ')')
292                         return error("missing close parenthesis ')'");
293
294                 break;
295         case '[':
296                 if (expr0() != OK)
297                         return ERROR;
298
299                 if (*tok++ != ']')
300                         return error("missing close parenthesis ']'");
301
302                 break;
303         case '$':
304                 *tk++ = ACONST;                                    // Attributed const
305                 *tk++ = sloc;                                      // Current location
306                 *tk++ = cursect | DEFINED;                         // Store attribs
307                 break;
308         case '*':
309                 *tk++ = ACONST;                                    // Attributed const
310
311                 if (orgactive)
312                         *tk++ = orgaddr;
313                 else
314                         *tk++ = pcloc;                                  // Location at start of line
315
316                 *tk++ = ABS | DEFINED;                             // Store attribs
317                 break;
318         default:
319                 return error("bad expression");
320         }
321
322         return OK;
323 }
324
325
326 //
327 // Recursive-descent expression analyzer (with some simple speed hacks)
328 //
329 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
330 {
331         // Passed in values (once derefenced, that is) can all be zero. They are
332         // there so that the expression analyzer can fill them in as needed. The
333         // expression analyzer gets its input from "tok", and not from anything
334         // passed in by the user.
335         SYM * sy;
336         char * p;
337         int j;
338
339         tk = otk;                       // Set token pointer to 'exprbuf' (direct.c)
340                                                 // Also set in various other places too (risca.c, e.g.)
341 //      symbolNum = 0;          // Set symbol number in symbolPtr[] to 0
342
343         // Optimize for single constant or single symbol.
344         if ((tok[1] == EOL)
345                 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
346                 && (tokcl[tok[2]] < UNARY)))
347         {
348                 if (*tok >= KW_R0 && *tok <= KW_R31)
349                 {
350                         *tk++ = CONST;
351                         *tk++ = *a_value = (*tok - KW_R0);
352                         *a_attr = ABS | DEFINED;
353
354                         if (a_esym != NULL)
355                                 *a_esym = NULL;
356
357                         tok++;
358                         *tk++ = ENDEXPR;
359                         return OK;
360                 }
361                 else if (*tok == CONST)
362                 {
363                         *tk++ = CONST;
364                         *tk++ = *a_value = tok[1];
365                         *a_attr = ABS | DEFINED;
366
367                         if (a_esym != NULL)
368                                 *a_esym = NULL;
369                 }
370                 else if (*tok == '*')
371                 {
372                         *tk++ = CONST;
373
374                         if (orgactive)
375                                 *tk++ = *a_value = orgaddr;
376                         else
377                                 *tk++ = *a_value = pcloc;
378
379                         *a_attr = ABS | DEFINED;
380                         //*tk++ = 
381
382                         if (a_esym != NULL)
383                                 *a_esym = NULL;
384
385                         tok--;
386                 }
387                 else
388                 {
389 #if 0
390                         p = (char *)tok[1];
391 #else
392                         p = string[tok[1]];
393 #endif
394                         j = 0;
395
396                         if (*p == '.')
397                                 j = curenv;
398
399                         sy = lookup(p, LABEL, j);
400
401                         if (sy == NULL)
402                                 sy = NewSymbol(p, LABEL, j);
403
404                         sy->sattr |= REFERENCED;
405
406                         // Check register bank usage
407                         if (sy->sattre & EQUATEDREG)
408                         {
409                                 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
410                                         warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
411
412                                 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
413                                         warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
414                         }
415
416                         *tk++ = SYMBOL;
417 #if 0
418                         *tk++ = (TOKEN)sy;
419 #else
420                         *tk++ = symbolNum;
421                         symbolPtr[symbolNum] = sy;
422                         symbolNum++;
423 #endif
424
425                         if (sy->sattr & DEFINED)
426                                 *a_value = sy->svalue;
427                         else
428                                 *a_value = 0;
429
430                         if (sy->sattre & EQUATEDREG) 
431                                 *a_value &= 0x1F;
432
433                         *a_attr = (WORD)(sy->sattr & ~GLOBAL);
434
435                         if ((sy->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
436                                 *a_esym = sy;
437                 }
438
439                 tok += 2;
440                 *tk++ = ENDEXPR;
441                 return OK;
442         }
443
444         if (expr0() != OK)
445                 return ERROR;
446
447         *tk++ = ENDEXPR;
448         return evexpr(otk, a_value, a_attr, a_esym);
449 }
450
451
452 //
453 // Evaluate expression.
454 // If the expression involves only ONE external symbol, the expression is
455 // UNDEFINED, but it's value includes everything but the symbol value, and
456 // `a_esym' is set to the external symbol.
457 //
458 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
459 {
460         WORD * sattr;
461         VALUE * sval;
462         WORD attr;
463         SYM * sy;
464         SYM * esym;
465         WORD sym_seg;
466
467         sval = evstk;                                                   // (Empty) initial stack
468         sattr = evattr;
469         esym = NULL;                                                    // No external symbol involved
470         sym_seg = 0;
471
472         while (*tk != ENDEXPR)
473         {
474                 switch ((int)*tk++)
475                 {
476                 case SYMBOL:
477 //                      sy = (SYM *)*tk++;
478                         sy = symbolPtr[*tk++];
479                         sy->sattr |= REFERENCED;                // Set "referenced" bit 
480
481                         if (!(sy->sattr & DEFINED))
482                         {
483                                 // Reference to undefined symbol
484                                 if (!(sy->sattr & GLOBAL))
485                                 {
486                                         *a_attr = 0;
487                                         *a_value = 0;
488                                         return OK;
489                                 }
490
491                                 if (esym != NULL)                       // Check for multiple externals
492                                         return error(seg_error);
493
494                                 esym = sy;
495                         }
496
497                         if (sy->sattr & DEFINED)
498                         {
499                                 *++sval = sy->svalue;           // Push symbol's value
500                         }
501                         else
502                         {
503                                 *++sval = 0;                            // 0 for undefined symbols 
504                         }
505
506                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
507                         sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
508                         break;
509                 case CONST:
510                         *++sval = *tk++;                                // Push value
511                         *++sattr = ABS | DEFINED;               // Push simple attribs
512                         break;
513                 case ACONST:
514                         *++sval = *tk++;                                // Push value
515                         *++sattr = (WORD)*tk++;                 // Push attribs
516                         break;
517
518                         // Binary "+" and "-" matrix:
519                         // 
520                         //                ABS    Sect     Other
521                         //     ----------------------------
522                         //   ABS     |  ABS   |  Sect  |  Other |
523                         //   Sect    |  Sect  |  [1]   |  Error |
524                         //   Other   |  Other |  Error |  [1]   |
525                         //      ----------------------------
526                         // 
527                         //   [1] + : Error
528                         //       - : ABS
529                 case '+':
530                         --sval;                                                 // Pop value
531                         --sattr;                                                // Pop attrib 
532                         *sval += sval[1];                               // Compute value
533
534                         if (!(*sattr & (TEXT | DATA | BSS)))
535                                 *sattr = sattr[1];
536                         else if (sattr[1] & (TEXT | DATA | BSS))
537                                 return error(seg_error);
538
539                         break;
540                 case '-':
541                         --sval;                                                 // Pop value
542                         --sattr;                                                // Pop attrib 
543                         *sval -= sval[1];                               // Compute value
544
545                         attr = (WORD)(*sattr & (TEXT | DATA | BSS));
546
547                         if (!attr)
548                                 *sattr = sattr[1];
549                         else if (sattr[1] & (TEXT | DATA | BSS))
550                         {
551                                 if (!(attr & sattr[1]))
552                                         return error(seg_error);
553                                 else
554                                         *sattr &= ~(TEXT | DATA | BSS);
555                         }
556
557                         break;
558                 // Unary operators only work on ABS items
559                 case UNMINUS:
560                         if (*sattr & (TEXT | DATA | BSS))
561                                 error(seg_error);
562
563                         *sval = -(int)*sval;
564                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
565                         break;
566                 case '!':
567                         if (*sattr & (TEXT | DATA | BSS))
568                                 error(seg_error);
569
570                         *sval = !*sval;
571                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
572                         break;
573                 case '~':
574                         if (*sattr & (TEXT | DATA | BSS))
575                                 error(seg_error);
576
577                         *sval = ~*sval;
578                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
579                         break;
580                 // Comparison operators must have two values that
581                 // are in the same segment, but that's the only requirement.
582                 case LE:
583                         --sattr;
584                         --sval;
585
586                         if ((*sattr & TDB) != (sattr[1] & TDB))
587                                 error(seg_error);
588
589                         *sattr = ABS | DEFINED;
590                         *sval = *sval <= sval[1];
591                         break;
592                 case GE:
593                         --sattr;
594                         --sval;
595
596                         if ((*sattr & TDB) != (sattr[1] & TDB))
597                                 error(seg_error);
598
599                         *sattr = ABS | DEFINED;
600                         *sval = *sval >= sval[1];
601                         break;
602                 case '>':
603                         --sattr;
604                         --sval;
605
606                         if ((*sattr & TDB) != (sattr[1] & TDB))
607                                 error(seg_error);
608
609                         *sattr = ABS | DEFINED;
610                         *sval = *sval > sval[1];
611                         break;
612                 case '<':
613                         --sattr;
614                         --sval;
615
616                         if ((*sattr & TDB) != (sattr[1] & TDB))
617                                 error(seg_error);
618
619                         *sattr = ABS | DEFINED;
620                         *sval = *sval < sval[1];
621                         break;
622                 case NE:
623                         --sattr;
624                         --sval;
625
626                         if ((*sattr & TDB) != (sattr[1] & TDB))
627                                 error(seg_error);
628
629                         *sattr = ABS | DEFINED;
630                         *sval = *sval != sval[1];
631                         break;
632                 case '=':
633                         --sattr;
634                         --sval;
635
636                         if ((*sattr & TDB) != (sattr[1] & TDB))
637                                 error(seg_error);
638
639                         *sattr = ABS | DEFINED;
640                         *sval = *sval == sval[1];
641                         break;
642                 // All other binary operators must have two ABS items
643                 // to work with.  They all produce an ABS value.
644                 default:
645                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
646                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
647                         //error(seg_error);
648                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
649
650                         switch ((int)tk[-1])
651                         {
652                         case '*':
653                                 --sval;
654                                 --sattr;                                        // Pop attrib 
655                                 *sval *= sval[1];
656                                 break;
657                         case '/':
658                                 --sval;
659                                 --sattr;                                        // Pop attrib 
660
661                                 if (sval[1] == 0)
662                                         return error("divide by zero");
663
664                                 *sval /= sval[1];
665                                 break;
666                         case '%':
667                                 --sval;
668                                 --sattr;                                        // Pop attrib 
669
670                                 if (sval[1] == 0)
671                                         return error("mod (%) by zero");
672
673                                 *sval %= sval[1];
674                                 break;
675                         case SHL:
676                                 --sval;
677                                 --sattr;                                        // Pop attrib 
678                                 *sval <<= sval[1];
679                                 break;
680                         case SHR:
681                                 --sval;
682                                 --sattr;                                        // Pop attrib 
683                                 *sval >>= sval[1];
684                                 break;
685                         case '&':
686                                 --sval;
687                                 --sattr;                                        // Pop attrib 
688                                 *sval &= sval[1];
689                                 break;
690                         case '^':
691                                 --sval;
692                                 --sattr;                                        // Pop attrib 
693                                 *sval ^= sval[1];
694                                 break;
695                         case '|':
696                                 --sval;
697                                 --sattr;                                        // Pop attrib 
698                                 *sval |= sval[1];
699                                 break;
700                         default:
701                                 interror(5);                            // Bad operator in expression stream
702                         }
703                 }
704         }
705
706         if (esym != NULL)
707                 *sattr &= ~DEFINED;
708
709         if (a_esym != NULL)
710                 *a_esym = esym;
711
712         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
713         // expressions where absolute values also existed. The absolutes were
714         // overiding the symbol segments and not being included :(
715         //*a_attr = *sattr | sym_seg;                                        // Copy value + attrib
716
717         *a_attr = *sattr;                                               // Copy value + attrib
718         *a_value = *sval;
719
720         return OK;
721 }