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