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