65d7580b7a14a013fefae620dfa243275f292dc0
[rmac] / procln.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // PROCLN.C - Line Processing
4 // Copyright (C) 199x Landon Dyer, 2017 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 "procln.h"
10 #include "6502.h"
11 #include "amode.h"
12 #include "direct.h"
13 #include "error.h"
14 #include "expr.h"
15 #include "listing.h"
16 #include "mach.h"
17 #include "macro.h"
18 #include "riscasm.h"
19 #include "sect.h"
20 #include "symbol.h"
21
22 #define DEF_KW                                  // Declare keyword values
23 #include "kwtab.h"                              // Incl generated keyword tables & defs
24
25 #define DEF_MN                                  // Incl 68k keyword definitions
26 #define DECL_MN                                 // Incl 68k keyword state machine tables
27 #include "mntab.h"
28
29 #define DEF_MR
30 #define DECL_MR
31 #include "risckw.h"
32
33 #define DEF_MP                                  // Include 6502 keyword definitions
34 #define DECL_MP                                 // Include 6502 keyword state machine tables
35 #include "6502kw.h"
36
37 IFENT * ifent;                                  // Current ifent
38 static IFENT ifent0;                    // Root ifent
39 static IFENT * f_ifent;                 // Freelist of ifents
40 static int disabled;                    // Assembly conditionally disabled
41 int just_bss;                                   // 1, ds.b in microprocessor mode
42 VALUE pcloc;                                    // Value of "PC" at beginning of line
43 SYM * lab_sym;                                  // Label on line (or NULL)
44 int bfparam1;                                   // bfxxx instruction parameters
45 int bfparam2;                                   // bfxxx instruction parameters
46
47 const char extra_stuff[] = "extra (unexpected) text found after addressing mode";
48 const char comma_error[] = "missing comma";
49 const char syntax_error[] = "syntax error";
50 const char locgl_error[] = "cannot GLOBL local symbol";
51 const char lab_ignored[] = "label ignored";
52
53 // Table to convert an addressing-mode number to a bitmask.
54 LONG amsktab[0124] = {
55         M_DREG, M_DREG, M_DREG, M_DREG,
56         M_DREG, M_DREG, M_DREG, M_DREG,
57
58         M_AREG, M_AREG, M_AREG, M_AREG,
59         M_AREG, M_AREG, M_AREG, M_AREG,
60
61         M_AIND, M_AIND, M_AIND, M_AIND,
62         M_AIND, M_AIND, M_AIND, M_AIND,
63
64         M_APOSTINC, M_APOSTINC, M_APOSTINC, M_APOSTINC,
65         M_APOSTINC, M_APOSTINC, M_APOSTINC, M_APOSTINC,
66
67         M_APREDEC, M_APREDEC, M_APREDEC, M_APREDEC,
68         M_APREDEC, M_APREDEC, M_APREDEC, M_APREDEC,
69
70         M_ADISP, M_ADISP, M_ADISP, M_ADISP,
71         M_ADISP, M_ADISP, M_ADISP, M_ADISP,
72
73         M_AINDEXED, M_AINDEXED, M_AINDEXED, M_AINDEXED,
74         M_AINDEXED, M_AINDEXED, M_AINDEXED, M_AINDEXED,
75
76         M_ABSW,                                                                                 // 070
77         M_ABSL,                                                                                 // 071
78         M_PCDISP,                                                                               // 072
79         M_PCINDEXED,                                                                    // 073
80         M_IMMED,                                                                                // 074
81         0L,                                                                                             // 075
82         0L,                                                                                             // 076
83         0L,                                                                                             // 077
84         M_ABASE,                                                                                // 0100
85         M_MEMPOST,                                                                              // 0101
86         M_MEMPRE,                                                                               // 0102
87         M_PCBASE,                                                                               // 0103
88         M_PCMPOST,                                                                              // 0104
89         M_PCMPRE,                                                                               // 0105
90         M_AM_USP,                                                                               // 0106
91         M_AM_SR,                                                                                // 0107
92         M_AM_CCR,                                                                               // 0110
93         M_AM_NONE,                                                                              // 0111 
94         0x30,                                                                                   // 0112 
95         0x30,                                                                                   // 0113
96         0L,                                                                                         // 0114
97         0L,                                                                                         // 0115
98         0L,                                                                                         // 0116
99         0L,                                                                                         // 0117
100         M_CREG,                                                                             // 0120 (caches - TODO: is this correct or does it need its own bitfield?)
101         M_CREG,                                                                             // 0121
102         M_FREG,                                         // 0122
103         M_FPSCR                                         // 0123
104 };                                                                                                      // 0123 length
105
106
107 // Function prototypes
108 int HandleLabel(char *, int);
109
110
111 //
112 // Initialize line processor
113 //
114 void InitLineProcessor(void)
115 {
116         disabled = 0;
117         ifent = &ifent0;
118         f_ifent = ifent0.if_prev = NULL;
119         ifent0.if_state = 0;
120 }
121
122
123 //
124 // Line processor
125 //
126 void Assemble(void)
127 {
128         int state;                                      // Keyword machine state (output)
129         int j;                                          // Random int, must be fast
130         char * p;                                       // Random char ptr, must be fast
131         TOKEN * tk;                                     // First token in line
132         char * label;                           // Symbol (or NULL)
133         char * equate;                          // Symbol (or NULL)
134         int labtyp = 0;                         // Label type (':', DCOLON)
135         int equtyp = 0;                         // Equ type ('=', DEQUALS)
136         VALUE eval;                                     // Expression value
137         WORD eattr;                                     // Expression attributes
138         SYM * esym;                                     // External symbol involved in expr.
139         WORD siz = 0;                           // Size suffix to mnem/diretve/macro
140         LONG amsk0, amsk1;                      // Address-type masks for ea0, ea1
141         MNTAB * m;                                      // Code generation table pointer
142         SYM * sy, * sy2;                        // Symbol (temp usage)
143         char * opname = NULL;           // Name of dirctve/mnemonic/macro
144         int listflag;                           // 0: Don't call listeol()
145         WORD rmask;                                     // Register list, for REG
146         int registerbank;                       // RISC register bank
147         int riscreg;                            // RISC register
148         listflag = 0;                           // Initialise listing flag
149
150 loop:                                                   // Line processing loop label
151
152         // Get another line of tokens
153         if (TokenizeLine() == TKEOF)
154         {
155 if (debug) printf("Assemble: Found TKEOF flag...\n");
156                 if (list_flag && listflag)                      // Flush last line of source
157                         listeol();
158
159                 if (ifent->if_prev != NULL)                     // Check conditional token
160                         error("hit EOF without finding matching .endif");
161
162                 return;
163         }
164
165         DEBUG DumpTokenBuffer();
166
167         if (list_flag)
168         {
169                 if (listflag && listing > 0)
170                         listeol();                                              // Tell listing generator about EOL
171
172                 lstout((char)(disabled ? '-' : lntag)); // Prepare new line for listing
173                 listflag = 1;                                           // OK to call `listeol' now
174                 just_bss = 0;                                           // Reset just_bss mode
175         }
176
177         state = -3;                                                             // No keyword (just EOL)
178         label = NULL;                                                   // No label
179         lab_sym = NULL;                                                 // No (exported) label
180         equate = NULL;                                                  // No equate
181         tk = tok;                                                               // Save first token in line
182         pcloc = (VALUE)sloc;                                    // Set beginning-of-line PC
183
184 loop1:                                                                          // Internal line processing loop
185
186         if (*tok == EOL)                                                // Restart loop if end-of-line
187                 goto loop;
188
189         // First token MUST be a symbol (Shamus: not sure why :-/)
190         if (*tok != SYMBOL)
191         {
192         if (*tok>=KW_D0 && *tok<=KW_R31)
193             error("cannot use reserved keyword as label name or .equ");
194         else
195                 error("syntax error; expected symbol");
196                 goto loop;
197         }
198
199         j = (int)tok[2];                                                // Skip equates (normal statements)
200
201         if (j == '=' || j == DEQUALS || j == SET || j == REG || j == EQUREG || j == CCDEF)
202         {
203                 equate = string[tok[1]];
204                 equtyp = j;
205                 tok += 3;
206                 goto normal;
207         }
208
209         // Skip past label (but record it)
210         if (j == ':' || j == DCOLON)
211         {
212 as68label:
213                 label = string[tok[1]];                         // Get label name
214                 labtyp = tok[2];                                        // Get label type
215                 tok += 3;                                                       // Go to next line token
216
217                 // AS68 MODE:
218                 // Looks like another label follows the previous one, so handle
219                 // the previous one until there aren't any more
220                 if (as68_flag && (*tok == SYMBOL && tok[2] == ':'))
221                 {
222                         if (HandleLabel(label, labtyp) != 0)
223                                 goto loop;
224
225                         goto as68label;
226                 }
227         }
228
229         // EOL is legal here...
230         if (*tok == EOL)
231                 goto normal;
232
233         // Next token MUST be a symbol
234         if (*tok++ != SYMBOL)
235         {
236                 error("syntax error; expected symbol");
237                 goto loop;
238         }
239
240         opname = p = string[*tok++];
241
242         // Check to see if the SYMBOL is a keyword (a mnemonic or directive).
243         // On output, `state' will have one of the values:
244         //    -3          there was no symbol (EOL)
245         //    -2..-1      the symbol didn't match any keyword
246         //    0..499      vanilla directives (dc, ds, etc.)
247         //    500..999    electric directives (macro, rept, etc.)
248         //    1000..+     mnemonics (move, lsr, etc.)
249         for(state=0; state>=0;)
250         {
251                 j = mnbase[state] + (int)tolowertab[*p];
252
253                 // Reject, character doesn't match
254                 if (mncheck[j] != state)
255                 {
256                         state = -1;                                             // No match
257                         break;
258                 }
259
260                 // Must accept or reject at EOS
261                 if (!*++p)
262                 {
263                         state = mnaccept[j];                    // (-1 on no terminal match)
264                         break;
265                 }
266
267                 state = mntab[j];
268         }
269
270         // Check for ".b" ".w" ".l" after directive, macro or mnemonic.
271         siz = SIZN;
272
273         if (*tok == DOTW)
274                 siz = SIZW, tok++;
275         else if (*tok == DOTL)
276                 siz = SIZL, tok++;
277         else if (*tok == DOTB)
278                 siz = SIZB, tok++;
279         else if(*tok == DOTD)
280                 siz = SIZD, tok++;
281         else if(*tok == DOTP)
282                 siz = SIZP, tok++;
283         else if(*tok == DOTQ)
284                 siz = SIZQ, tok++;
285         else if(*tok == DOTS)
286                 siz = SIZS, tok++;
287         else if(*tok == DOTX)
288                 siz = SIZX, tok++;
289
290
291         // Do special directives (500..999) (These must be handled in "real time")
292         if (state >= 500 && state < 1000)
293         {
294                 switch (state)
295                 {
296                 case MN_IF:
297                         d_if();
298                 goto loop;
299                 case MN_ELSE:
300                         d_else();
301                         goto loop;
302                 case MN_ENDIF:
303                         d_endif();
304                         goto loop;
305                 case MN_IIF:                                            // .iif --- immediate if
306                         if (disabled || expr(exprbuf, &eval, &eattr, &esym) != OK)
307                                 goto loop;
308
309                         if (!(eattr & DEFINED))
310                         {
311                                 error(undef_error);
312                                 goto loop;
313                         }
314
315                         if (*tok++ != ',')
316                         {
317                                 error(comma_error);
318                                 goto loop;
319                         }
320
321                         if (eval == 0)
322                                 goto loop;
323
324                         goto loop1;
325                 case MN_MACRO:                                          // .macro --- macro definition
326                         if (!disabled)
327                         {
328                                 // Label on a macro definition is bad mojo... Warn the user
329                                 if (label != NULL)
330                                         warn(lab_ignored);
331
332                                 DefineMacro();
333                         }
334
335                         goto loop;
336                 case MN_EXITM:                                          // .exitm --- exit macro
337                 case MN_ENDM:                                           // .endm --- same as .exitm
338                         if (!disabled)
339                         {
340                                 if (label != NULL)
341                                         warn(lab_ignored);
342
343                                 ExitMacro();
344                         }
345
346                         goto loop;
347                 case MN_REPT:
348                         if (!disabled)
349                         {
350                                 // Handle labels on REPT directive lines...
351                                 if (label)
352                                 {
353                                         if (HandleLabel(label, labtyp) != 0)
354                                                 goto loop;
355                                 }
356
357                                 defrept();
358                         }
359
360                         goto loop;
361                 case MN_ENDR:
362                         if (!disabled)
363                                 error("mis-nested .endr");
364
365                         goto loop;
366                 }
367         }
368
369 normal:
370         if (disabled)                                                   // Conditionally disabled code
371                 goto loop;
372
373         // Do equates
374         if (equate != NULL)
375         {
376                 // Pick global or local symbol enviroment
377                 j = (*equate == '.' ? curenv : 0);
378                 sy = lookup(equate, LABEL, j);
379
380                 if (sy == NULL)
381                 {
382                         sy = NewSymbol(equate, LABEL, j);
383                         sy->sattr = 0;
384
385                         if (equtyp == DEQUALS)
386                         {
387                                 // Can't GLOBAL a local symbol
388                                 if (j)
389                                 {
390                                         error(locgl_error);
391                                         goto loop;
392                                 }
393
394                                 sy->sattr = GLOBAL;
395                         }
396                 }
397                 else if ((sy->sattr & DEFINED) && equtyp != SET)
398                 {
399                         if ((equtyp == EQUREG) && (sy->sattre & UNDEF_EQUR))
400                         {
401 //REALLY?                               sy->sattre |= ~UNDEF_EQUR;
402                                 sy->sattre &= ~UNDEF_EQUR;
403                                 sy->svalue = 0;
404                         }
405                         else if ((equtyp == CCDEF) && (sy->sattre & UNDEF_CC))
406                         {
407 //REALLY?                               sy->sattre |= ~UNDEF_CC;
408                                 sy->sattre &= ~UNDEF_CC;
409                                 sy->svalue = 0;
410                         }
411                         else
412                         {
413                                 errors("multiple equate to '%s'", sy->sname);
414                                 goto loop;
415                         }
416                 }
417
418                 // Put symbol in "order of definition" list if it's not already there
419                 AddToSymbolDeclarationList(sy);
420
421                 // Parse value to equate symbol to;
422                 // o  .equr
423                 // o  .reg
424                 // o  everything else
425                 if (equtyp == EQUREG)
426                 {
427 //Linko's request to issue a warning on labels that equated to the same
428 //register would go here. Not sure how to implement it though. :-/
429 /*
430 Maybe like this way:
431 have an array of bools with 64 entries. Whenever a register is equated, set the
432 corresponding register bool to true. Whenever it's undef'ed, set it to false.
433 When checking to see if it's already been equated, issue a warning.
434 */
435                         // Check that we are in a RISC section
436                         if (!rgpu && !rdsp)
437                         {
438                                 error(".equr/.regequ must be defined in .gpu/.dsp section");
439                                 goto loop;
440                         }
441
442                         // Check for register to equate to
443                         if ((*tok >= KW_R0) && (*tok <= KW_R31))
444                         {
445 //                              sy->sattre  = EQUATEDREG | RISCSYM;     // Mark as equated register
446                                 sy->sattre  = EQUATEDREG;       // Mark as equated register
447                                 riscreg = (*tok - KW_R0);
448 //is there any reason to do this, since we're putting this in svalue?
449 //i'm thinking, no. Let's test that out! :-D
450 //                              sy->sattre |= (riscreg << 8);           // Store register number
451 //everything seems to build fine without it... We'll leave it here Just In Case(tm)
452
453 #define DEBODGE_REGBANK
454 #ifdef DEBODGE_REGBANK
455                                 // Default is current state of "regbank"
456                                 registerbank = regbank;
457 #else
458                                 // Default is no register bank specified
459                                 registerbank = BANK_N;
460 #endif
461
462                                 // Check for ",<bank #>" override notation
463                                 if ((tok[1] == ',') && (tok[2] == CONST))
464                                 {
465                                         // Advance token pointer to the constant
466                                         tok += 3;
467
468                                         // Anything other than a 0 or a 1 will result in "No Bank"
469                                         if (*tok == 0)
470                                                 registerbank = BANK_0;
471                                         else if (*tok == 1)
472                                                 registerbank = BANK_1;
473                                 }
474
475 #ifdef DEBODGE_REGBANK
476                                 sy->sattre |= registerbank;     // Store register bank
477 #else
478 // What needs to happen here is to prime registerbank with regbank, then use
479 // registerbank down below for the bank marking.
480 #warning "!!! regbank <-> registerbank confusion here !!!"
481 // The question here is why, if we're allowed to override the ".regbankN" rules
482 // above, then why is it using the one set by the directive in the extended
483 // attributes and not in what ends up in symbol->svalue?
484 // ".regbankN" is not an original Madmac directive, so it's suspect
485                                 sy->sattre |= regbank;          // Store register bank
486 #endif
487                                 eattr = ABS | DEFINED | GLOBAL;
488 // & what does this $80000080 constant mean???
489 //                              eval = 0x80000080 + (riscreg) + (registerbank << 8);
490                                 eval = riscreg;
491                                 tok++;
492                         }
493                         // Checking for a register symbol
494                         else if (tok[0] == SYMBOL)
495                         {
496                                 sy2 = lookup(string[tok[1]], LABEL, j);
497
498                                 // Make sure symbol is a valid equreg
499                                 if (!sy2 || !(sy2->sattre & EQUATEDREG))
500                                 {
501                                         error("invalid GPU/DSP .equr/.regequ definition");
502                                         goto loop;
503                                 }
504                                 else
505                                 {
506                                         eattr = ABS | DEFINED | GLOBAL; // Copy symbols attributes
507                                         sy->sattre = sy2->sattre;
508                                         eval = (sy2->svalue & 0xFFFFF0FF);
509                                         tok += 2;
510                                 }
511                         }
512                         else
513                         {
514                                 error("invalid GPU/DSP .equr/.regequ definition");
515                                 goto loop;
516                         }
517                 }
518                 else if (equtyp == REG)
519                 {
520                         if (reglist(&rmask) < 0)
521                                 goto loop;
522
523                         eval = (VALUE)rmask;
524                         eattr = ABS | DEFINED;
525                 }
526                 else if (equtyp == CCDEF)
527                 {
528                         sy->sattre |= EQUATEDCC;
529                         eattr = ABS | DEFINED | GLOBAL;
530
531                         if (tok[0] == SYMBOL)
532                         {
533                                 sy2 = lookup(string[tok[1]], LABEL, j);
534
535                                 if (!sy2 || !(sy2->sattre & EQUATEDCC))
536                                 {
537                                         error("invalid gpu/dsp .ccdef definition");
538                                         goto loop;
539                                 }
540                                 else
541                                 {
542                                         eattr = ABS | DEFINED | GLOBAL;
543                                         sy->sattre = sy2->sattre;
544                                         eval = sy2->svalue;
545                                         tok += 2;
546                                 }
547                         }
548                         else if (expr(exprbuf, &eval, &eattr, &esym) != OK)
549                                 goto loop;
550                 }
551                 //equ a equr
552                 else if (*tok == SYMBOL)
553                 {
554                         sy2 = lookup(string[tok[1]], LABEL, j);
555
556                         if (sy2 && (sy2->sattre & EQUATEDREG))
557                         {
558                                 sy->stype = sy2->stype;
559                                 sy->sattr = sy2->sattr;
560                                 sy->sattre = sy2->sattre;
561 //ICK                           sy->svalue = (sy2->svalue & 0xFFFFF0FF);
562                                 sy->svalue = sy2->svalue;
563                                 goto loop;
564                         }
565                         else if (expr(exprbuf, &eval, &eattr, &esym) != OK)
566                                 goto loop;
567                 }
568                 else if (expr(exprbuf, &eval, &eattr, &esym) != OK)
569                         goto loop;
570
571                 if (!(eattr & DEFINED))
572                 {
573                         error(undef_error);
574                         goto loop;
575                 }
576
577                 sy->sattr |= eattr | EQUATED;   // Symbol inherits value and attributes
578                 sy->svalue = eval;
579
580                 if (list_flag)                                  // Put value in listing
581                         listvalue(eval);
582
583                 at_eol();                                               // Must be at EOL now
584                 goto loop;
585         }
586
587         // Do labels
588         if (label != NULL)
589         {
590                 // Non-zero == error occurred
591                 if (HandleLabel(label, labtyp) != 0)
592                         goto loop;
593         }
594
595         // Punt on EOL
596         if (state == -3)
597                 goto loop;
598
599         // If we're in 6502 mode and are still in need of a mnemonic, then search
600         // for valid 6502 mnemonic.
601         if (m6502 && (state < 0 || state >= 1000))
602         {
603 #ifdef ST
604                 state = kmatch(opname, mpbase, mpcheck, mptab, mpaccept);
605 #else
606                 for(state=0, p=opname; state>= 0; )
607                 {
608                         j = mpbase[state] + tolowertab[*p];
609
610                         if (mpcheck[j] != state)        // Reject, character doesn't match
611                         {
612                                 state = -1;             // No match
613                                 break;
614                         }
615
616                         if (!*++p)
617                         {                       // Must accept or reject at EOS
618                                 state = mpaccept[j];    // (-1 on no terminal match)
619                                 break;
620                         }
621
622                         state = mptab[j];
623                 }
624 #endif
625
626                 // Call 6502 code generator if we found a mnemonic
627                 if (state >= 2000)
628                 {
629                         m6502cg(state - 2000);
630                         goto loop;
631                 }
632         }
633
634         // If we are in GPU or DSP mode and still in need of a mnemonic then search
635         // for one
636         if ((rgpu || rdsp) && (state < 0 || state >= 1000))
637         {
638                 for(state=0, p=opname; state>=0;)
639                 {
640                         j = mrbase[state] + (int)tolowertab[*p];
641
642                         // Reject, character doesn't match
643                         if (mrcheck[j] != state)
644                         {
645                                 state = -1;                                     // No match
646                                 break;
647                         }
648
649                         // Must accept or reject at EOS
650                         if (!*++p)
651                         {
652                                 state = mraccept[j];            // (-1 on no terminal match)
653                                 break;
654                         }
655
656                         state = mrtab[j];
657                 }
658
659                 // Call RISC code generator if we found a mnemonic
660                 if (state >= 3000)
661                 {
662                         GenerateRISCCode(state);
663                         goto loop;
664                 }
665         }
666
667         // Invoke macro or complain about bad mnemonic
668         if (state < 0)
669         {
670                 if ((sy = lookup(opname, MACRO, 0)) != NULL)
671                         InvokeMacro(sy, siz);
672                 else
673                         errors("unknown op '%s'", opname);
674
675                 goto loop;
676         }
677
678         // Call directive handlers
679         if (state < 500)
680         {
681                 (*dirtab[state])(siz);
682                 goto loop;
683         }
684
685         // Do mnemonics
686         // o  can't deposit instrs in BSS or ABS
687         // o  do automatic .EVEN for instrs
688         // o  allocate space for largest possible instr
689         // o  can't do ".b" operations with an address register
690         if (scattr & SBSS)
691         {
692                 error("cannot initialize non-storage (BSS) section");
693                 goto loop;
694         }
695
696         if (sloc & 1)                                   // Automatic .even
697                 auto_even();
698
699         if (challoc - ch_size < 18)             // Make sure have space in current chunk
700                 chcheck(0);
701
702         m = &machtab[state - 1000];
703
704         // Call special-mode handler
705         if (m->mnattr & CGSPECIAL)
706         {
707                 (*m->mnfunc)(m->mninst, siz);
708                 goto loop;
709         }
710
711         if (amode(1) < 0)                               // Parse 0, 1 or 2 addr modes
712                 goto loop;
713
714         if (*tok != EOL)
715                 error(extra_stuff);
716
717         amsk0 = amsktab[am0];
718         amsk1 = amsktab[am1];
719
720         // Catch attempts to use ".B" with an address register (yes, this check
721         // does work at this level)
722         if (siz == SIZB && (am0 == AREG || am1 == AREG))
723         {
724                 error("cannot use '.b' with an address register");
725                 goto loop;
726         }
727
728         // Keep a backup of chptr (used for optimisations during codegen)
729         chptr_opcode = chptr;
730
731         for(;;)
732         {
733                 if ((m->mnattr & siz) && (amsk0 & m->mn0) != 0 && (amsk1 & m->mn1) != 0)
734                 {
735                         (*m->mnfunc)(m->mninst, siz);
736                         goto loop;
737                 }
738
739                 m = &machtab[m->mncont];
740         }
741 }
742
743
744 //
745 // Handle the creation of labels
746 //
747 int HandleLabel(char * label, int labelType)
748 {
749         // Check for dot in front of label; means this is a local label if present
750         int environment = (*label == '.' ? curenv : 0);
751         SYM * symbol = lookup(label, LABEL, environment);
752
753         if (symbol == NULL)
754         {
755                 symbol = NewSymbol(label, LABEL, environment);
756                 symbol->sattr = 0;
757 //              symbol->sattre = RISCSYM;
758                 symbol->sattre = 0;
759         }
760         else if (symbol->sattr & DEFINED)
761                 return errors("multiply-defined label '%s'", label);
762
763         // Put symbol in "order of definition" list if it's not already in it
764         AddToSymbolDeclarationList(symbol);
765
766         if (orgactive)
767         {
768                 symbol->svalue = orgaddr;
769                 symbol->sattr |= ABS | DEFINED | EQUATED;
770         }
771         else
772         {
773                 symbol->svalue = sloc;
774                 symbol->sattr |= DEFINED | cursect;
775         }
776
777         lab_sym = symbol;
778
779         if (0 == environment)
780                 curenv++;
781
782         // Make label global if it has a double colon
783         if (labelType == DCOLON)
784         {
785                 if (environment != 0)
786                         return error(locgl_error);
787
788                 symbol->sattr |= GLOBAL;
789         }
790
791         return 0;
792 }
793
794
795 //
796 // .if, Start conditional assembly
797 //
798 int d_if(void)
799 {
800         IFENT * rif;
801         WORD eattr;
802         VALUE eval;
803         SYM * esym;
804
805         // Alloc an IFENTRY
806         if ((rif = f_ifent) == NULL)
807                 rif = (IFENT *)malloc(sizeof(IFENT));
808         else
809                 f_ifent = rif->if_prev;
810
811         rif->if_prev = ifent;
812         ifent = rif;
813
814         if (!disabled)
815         {
816                 if (expr(exprbuf, &eval, &eattr, &esym) != OK)
817                         return 0;
818
819                 if ((eattr & DEFINED) == 0)
820                         return error(undef_error);
821
822                 disabled = !eval;
823         }
824
825         rif->if_state = (WORD)disabled;
826         return 0;
827 }
828
829
830 //
831 // .else, Do alternate case for .if
832 //
833 int d_else(void)
834 {
835         IFENT * rif = ifent;
836
837         if (rif->if_prev == NULL)
838                 return error("mismatched .else");
839
840         if (disabled)
841                 disabled = rif->if_prev->if_state;
842         else
843                 disabled = 1;
844
845         rif->if_state = (WORD)disabled;
846         return 0;
847 }
848
849
850 //
851 // .endif, End of conditional assembly block
852 // This is also called by fpop() to pop levels of IFENTs in case a macro or
853 // include file exits early with `exitm' or `end'.
854 //
855 int d_endif (void)
856 {
857         IFENT * rif = ifent;
858
859         if (rif->if_prev == NULL)
860                 return error("mismatched .endif");
861
862         ifent = rif->if_prev;
863         disabled = rif->if_prev->if_state;
864         rif->if_prev = f_ifent;
865         f_ifent = rif;
866         return 0;
867 }
868