2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // TOKEN.C - Token Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
15 #define DECL_KW // Declare keyword arrays
16 #define DEF_KW // Declare keyword values
17 #include "kwtab.h" // Incl generated keyword tables & defs
19 int lnsave; // 1; strcpy() text of current line
20 int curlineno; // Current line number
21 int totlines; // Total # of lines
22 int mjump_align = 0; // mjump alignment flag
23 char lntag; // Line tag
24 char * curfname; // Current filename
25 char tolowertab[128]; // Uppercase ==> lowercase
26 char hextab[128]; // Table of hex values
27 char dotxtab[128]; // Table for ".b", ".s", etc.
28 char irbuf[LNSIZ]; // Text for .rept block line
29 char lnbuf[LNSIZ]; // Text of current line
30 WORD filecount; // Unique file number counter
31 WORD cfileno; // Current file number
32 TOKEN * tok; // Ptr to current token
33 TOKEN * etok; // Ptr past last token in tokbuf[]
34 TOKEN tokeol[1] = {EOL}; // Bailout end-of-line token
36 // File record, used to maintain a list of every include file ever visited
37 #define FILEREC struct _filerec
47 INOBJ * cur_inobj; // Ptr current input obj (IFILE/IMACRO)
48 static INOBJ * f_inobj; // Ptr list of free INOBJs
49 static IFILE * f_ifile; // Ptr list of free IFILEs
50 static IMACRO * f_imacro; // Ptr list of free IMACROs
52 static TOKEN tokbuf[TOKBUFSIZE]; // Token buffer (stack-like, all files)
55 ILLEG, ILLEG, ILLEG, ILLEG, // NUL SOH STX ETX
56 ILLEG, ILLEG, ILLEG, ILLEG, // EOT ENQ ACK BEL
57 ILLEG, WHITE, ILLEG, ILLEG, // BS HT LF VT
58 WHITE, ILLEG, ILLEG, ILLEG, // FF CR SO SI
60 ILLEG, ILLEG, ILLEG, ILLEG, // DLE DC1 DC2 DC3
61 ILLEG, ILLEG, ILLEG, ILLEG, // DC4 NAK SYN ETB
62 ILLEG, ILLEG, ILLEG, ILLEG, // CAN EM SUB ESC
63 ILLEG, ILLEG, ILLEG, ILLEG, // FS GS RS US
65 WHITE, MULTX, MULTX, SELF, // SP ! " #
66 MULTX+CTSYM, MULTX, SELF, MULTX, // $ % & '
67 SELF, SELF, SELF, SELF, // ( ) * +
68 SELF, SELF, STSYM, SELF, // , - . /
70 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 0 1
71 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 2 3
72 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 4 5
73 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 6 7
74 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 8 9
76 MULTX, MULTX, MULTX, STSYM+CTSYM, // < = > ?
78 MULTX, STSYM+CTSYM+HDIGIT, // @ A
79 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // B C
80 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // D E
81 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // F G
82 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // H I J K
83 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // L M N O
85 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // P Q R S
86 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // T U V W
87 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // X Y Z [
88 SELF, SELF, MULTX, STSYM+CTSYM, // \ ] ^ _
90 ILLEG, STSYM+CTSYM+HDIGIT, // ` a
91 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // b c
92 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // d e
93 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // f g
94 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // h i j k
95 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // l m n o
97 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // p q r s
98 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // t u v w
99 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // x y z {
100 SELF, SELF, SELF, ILLEG // | } ~ DEL
103 // Names of registers
104 static char * regname[] = {
105 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
106 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
107 "pc", "ssp", "usp", "sr", "ccr"
110 static char * riscregname[] = {
111 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
112 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
113 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
114 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
119 // Make `fnum' the Current `curfname'
121 void setfnum(WORD fnum)
125 for(fr=filerec; fr!=NULL && fnum--; fr=fr->frec_next);
128 curfname = "(*top*)";
130 curfname = fr->frec_name;
135 // Allocate an IFILE or IMACRO
137 INOBJ * a_inobj(int typ)
143 // Allocate and initialize INOBJ first
145 inobj = (INOBJ *)amem((LONG)sizeof(INOBJ));
149 f_inobj = f_inobj->in_link;
154 case SRC_IFILE: // Alloc and init an IFILE
156 ifile = (IFILE *)amem((LONG)sizeof(IFILE));
160 f_ifile = f_ifile->if_link;
163 inobj->inobj.ifile = ifile;
165 case SRC_IMACRO: // Alloc and init an IMACRO
166 if (f_imacro == NULL)
167 imacro = (IMACRO *)amem((LONG)sizeof(IMACRO));
171 f_imacro = f_imacro->im_link;
174 inobj->inobj.imacro = imacro;
176 case SRC_IREPT: // Alloc and init an IREPT
177 inobj->inobj.irept = (IREPT *)amem((LONG)sizeof(IREPT));
178 DEBUG printf("alloc IREPT\n");
182 // Install INOBJ on top of input stack
183 inobj->in_ifent = ifent; // Record .if context on entry
184 inobj->in_type = (WORD)typ;
185 inobj->in_otok = tok;
186 inobj->in_etok = etok;
187 inobj->in_link = cur_inobj;
195 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
196 // A macro reference is in one of two forms:
197 // \name <non-name-character>
199 // A doubled backslash (\\) is compressed to a single backslash (\).
200 // Argument definitions have been pre-tokenized, so we have to turn them back
201 // into text. This means that numbers, in particular, become hex, regardless of
202 // their representation when the macro was invoked. This is a hack.
203 // A label may appear at the beginning of the line:
204 // :<name><whitespace>
205 // (the colon must be in the first column). These labels are stripped before
206 // macro expansion takes place.
208 int mexpand(char * src, char * dest, int destsiz)
212 char * dst; // Next dest slot
213 char * edst; // End+1 of dest buffer
215 int questmark; // \? for testing argument existence
217 char mname[128]; // Assume max size of a formal arg name
221 char numbuf[20]; // Buffer for text of CONSTs
223 imacro = cur_inobj->inobj.imacro;
224 macnum = (int)(imacro->im_macro->sattr);
228 edst = dest + destsiz;
230 // Check for (and skip over) any "label" on the line
234 while (*s != EOS && !(chrtab[*s] & WHITE))
238 ++s; // Skip first whitespace
241 // Expand the rest of the line
245 { // Copy single character
252 { // Do macro expansion
258 case '\\': // \\, \ (collapse to single backslash)
264 case '?': // \? <macro> set `questmark' flag
268 case '#': // \#, number of arguments
269 sprintf(numbuf, "%d", (int)imacro->im_nargs);
271 case '!': // \! size suffix supplied on invocation
272 switch ((int)imacro->im_siz)
274 case SIZN: d = ""; break;
275 case SIZB: d = ".b"; break;
276 case SIZW: d = ".w"; break;
277 case SIZL: d = ".l"; break;
281 case '~': // ==> unique label string Mnnnn...
282 sprintf(numbuf, "M%ud", curuniq);
298 return error("missing argument name");
301 // \n ==> argument number 'n', 0..9
302 if (chrtab[*s] & DIGIT)
312 // Get argument name: \name, \{name}
320 while (chrtab[*s] & CTSYM);
324 for(++s; *s != EOS && *s != '}';)
328 return error("missing '}'");
335 // Lookup the argument and copy its (string) value into the destination string
336 DEBUG printf("mname='%s'\n", mname);
338 if ((arg = lookup(mname, MACARG, macnum)) == NULL)
339 return errors("undefined argument: '%s'", mname);
342 // Convert a string of tokens (terminated with EOL) back into text. If an argument
343 // is out of range (not specified in the macro invocation) then it is ignored.
344 i = (int)arg->svalue;
346 DEBUG printf("~argnumber=%d\n", i);
350 if (i < imacro->im_nargs)
354 // 0 if the argument is empty or non-existant,
355 // 1 if the argument is not empty
358 if (tk == NULL || *tk == EOL)
364 *dst++ = (char)(questmark + '0');
368 if (tk != NULL) // arg# is in range, so expand it
372 // Reverse-translation from a token number to a string. This is a hack.
373 // It might be better table-driven.
376 if ((*tk >= KW_D0) && !rdsp && !rgpu)
378 d = regname[(int)*tk++ - KW_D0];
381 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
383 d = riscregname[(int)*tk++ - KW_R0];
415 // Shamus: Changing the format specifier from %lx to %ux caused
416 // the assembler to choke on legitimate code... Need to investigate
417 // this further before changing anything else here!
419 sprintf(numbuf, "$%lx", (LONG)*tk++);
480 *dst++ = (char)*(tk-1);
485 // If 'd' != NULL, copy string to destination
489 DEBUG printf("d='%s'\n", d);
510 return fatal("line too long as a result of macro expansion");
515 // Get Next Line of Text from a Macro
521 unsigned source_addr;
523 imacro = cur_inobj->inobj.imacro;
524 strp = imacro->im_nextln;
526 if (strp == NULL) // End-of-macro
529 imacro->im_nextln = (LONG *)*strp;
530 mexpand((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
532 if (!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align)
534 // if we need to adjust the alignment of the jump source address to meet the rules of
535 // gpu main execution we need to skip the first nop of the macro. This is simpler than
536 // trying to insert nop's mid macro.
537 source_addr = (orgactive) ? orgaddr : sloc;
542 strp = imacro->im_nextln;
547 imacro->im_nextln = (LONG *)*strp;
548 mexpand((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
554 return imacro->im_lnbuf;
559 // Get Next Line of Text from a Repeat Block
566 irept = cur_inobj->inobj.irept;
567 strp = irept->ir_nextln; // initial null
569 // Do repeat at end of .rept block's string list
572 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
573 irept->ir_nextln = irept->ir_firstln; // copy first line
575 if (irept->ir_count-- == 0)
577 DEBUG printf("end-repeat-block\n");
581 strp = irept->ir_nextln; //strp
584 strcpy(irbuf, (char*)(irept->ir_nextln + 1));
586 DEBUG printf("repeat line='%s'\n", irbuf);
587 irept->ir_nextln = (LONG *)*strp;
594 // Include a Source File used at the Root, and for ".include" Files
596 int include(int handle, char * fname)
603 printf("[Including: %s]\n", fname); // Verbose mode
605 // Alloc and initialize include-descriptors
606 inobj = a_inobj(SRC_IFILE);
607 ifile = inobj->inobj.ifile;
609 ifile->ifhandle = handle; // Setup file handle
610 ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
611 ifile->ifoldlineno = curlineno; // Save old line number
612 ifile->ifoldfname = curfname; // Save old filename
613 ifile->ifno = cfileno; // Save old file number
614 cfileno = ++filecount; // Compute new file number
615 curfname = nstring(fname); // Set current filename (alloc storage)
616 curlineno = 0; // Start on line zero
618 // Add another file to the file-record
619 fr = (FILEREC *)amem((LONG)sizeof(FILEREC));
620 fr->frec_next = NULL;
621 fr->frec_name = curfname;
624 filerec = fr; // Add first filerec
626 last_fr->frec_next = fr; // Append to list of filerecs
635 // Initialize Tokenizer
637 void init_token(void)
640 char * htab = "0123456789abcdefABCDEF"; // Hex character table
642 lnsave = 0; // Don't save lines
643 curfname = ""; // No file, empty filename
644 filecount = (WORD)-1;
645 cfileno = (WORD)-1; // cfileno gets bumped to 0
657 // Initialize hex, "dot" and tolower tables
662 tolowertab[i] = (char)i;
665 for(i=0; htab[i]!=EOS; ++i)
666 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
668 for(i='A'; i<='Z'; ++i)
669 tolowertab[i] |= 0x20;
671 // These characters are legal immediately after a period
672 dotxtab['b'] = DOTB; // .b .B .s .S
676 dotxtab['w'] = DOTW; // .w .W
678 dotxtab['l'] = DOTL; // .l .L
680 dotxtab['I'] = DOTI; // .l .L
686 // Pop the Current Input Level
699 // Pop IFENT levels until we reach the conditional assembly context we were at when the
700 // input object was entered.
701 while (ifent != inobj->in_ifent)
704 tok = inobj->in_otok; // Restore tok and otok
705 etok = inobj->in_etok;
707 switch (inobj->in_type)
709 case SRC_IFILE: // Pop and release an IFILE
711 printf("[Leaving: %s]\n", curfname);
713 ifile = inobj->inobj.ifile;
714 ifile->if_link = f_ifile;
716 close(ifile->ifhandle); // Close source file
717 curfname = ifile->ifoldfname; // Set current filename
718 curlineno = ifile->ifoldlineno; // Set current line#
719 DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
720 cfileno = ifile->ifno; // Restore current file number
722 case SRC_IMACRO: // Pop and release an IMACRO
723 imacro = inobj->inobj.imacro;
724 imacro->im_link = f_imacro;
727 case SRC_IREPT: // Pop and release an IREPT
728 DEBUG printf("dealloc IREPT\n");
729 p = inobj->inobj.irept->ir_firstln;
740 cur_inobj = inobj->in_link;
741 inobj->in_link = f_inobj;
750 // Get line from file into buf, return NULL on EOF or ptr to the start of a
760 readamt = -1; // 0 if last read() yeilded 0 bytes
761 fl = cur_inobj->inobj.ifile;
765 // Scan for next end-of-line; handle stupid text formats by treating \r\n the same as \n.
766 // (lone '\r' at end of buffer means we have to check for '\n').
769 d = &fl->ifbuf[fl->ifind];
771 for(p=d; i<j; ++i, ++p)
773 if (*p == '\r' || *p == '\n')
781 break; // Look for '\n' to eat
783 else if (p[1] == '\n')
797 // Handle hanging lines by ignoring them (Input file is exhausted, no \r or \n on last line)
798 if (!readamt && fl->ifcnt)
805 // Truncate and return absurdly long lines.
806 if (fl->ifcnt >= QUANTUM)
808 fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
810 return &fl->ifbuf[fl->ifind];
813 // Relocate what's left of a line to the beginning of the buffer, and read some more of the
814 // file in; return NULL if the buffer's empty and on EOF.
817 p = &fl->ifbuf[fl->ifind];
818 d = &fl->ifbuf[fl->ifcnt & 1];
820 for(i = 0; i < fl->ifcnt; ++i)
823 fl->ifind = fl->ifcnt & 1;
826 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
829 if ((fl->ifcnt += readamt) == 0)
840 char * ln = NULL; // Ptr to current position in line
841 char * p; // Random character ptr
842 TOKEN *tk; // Token-deposit ptr
843 int state = 0; // State for keyword detector
844 int j = 0; // Var for keyword detector
845 char c; // Random char
846 VALUE v; // Random value
847 char * nullspot = NULL; // Spot to clobber for SYMBOL terminatn
848 int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
853 if (cur_inobj == NULL) // Return EOF if input stack is empty
856 // Get another line of input from the current input source: a file, a macro, or a repeat-block
857 switch (cur_inobj->in_type)
861 // o bump source line number;
862 // o tag the listing-line with a space;
863 // o kludge lines generated by Alcyon C.
865 if ((ln = getln()) == NULL)
867 fpop(); // Pop input level
868 goto retry; // Try for more lines
871 ++curlineno; // Bump line number
876 // AS68 compatibility, throw away all lines starting with back-quotes, tildes, or '*'
877 // On other lines, turn the first '*' into a semi-colon.
878 if (*ln == '`' || *ln == '~' || *ln == '*')
882 for(p=ln; *p!=EOS; ++p)
895 // o Handle end-of-macro;
896 // o tag the listing-line with an at (@) sign.
898 if ((ln = getmln()) == NULL)
900 exitmac(); // Exit macro (pop args, do fpop(), etc)
901 goto retry; // Try for more lines...
907 // o Handle end-of-repeat-block;
908 // o tag the listing-line with a pound (#) sign.
910 if ((ln = getrln()) == NULL)
920 // Save text of the line. We only do this during listings and within macro-type blocks,
921 // since it is expensive to unconditionally copy every line.
925 // General house-keeping
926 tok = tokeol; // Set "tok" to EOL in case of error
927 tk = etok; // Reset token ptr
928 stuffnull = 0; // Don't stuff nulls
929 ++totlines; // Bump total #lines assembled
931 // See if the entire line is a comment. This is a win if the programmer puts in lots of comments
932 if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln+1) == '/')))
935 // Main tokenization loop;
936 // o skip whitespace;
937 // o handle end-of-line;
939 // o handle single-character tokens (operators, etc.);
940 // o handle multiple-character tokens (constants, strings, etc.).
943 // Skip whitespace, handle EOL
944 while ((int)chrtab[*ln] & WHITE)
947 // Handle EOL, comment with ';'
948 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln+1) == '/')))
951 // Handle start of symbol. Symbols are null-terminated in place. The termination is
952 // always one symbol behind, since there may be no place for a null in the case that
953 // an operator immediately follows the name.
958 if (stuffnull) // Terminate old symbol
961 v = 0; // Assume no DOT attrib follows symbol
963 p = nullspot = ln++; // Nullspot -> start of this symbol
965 // Find end of symbol (and compute its length)
966 for(j=1; (int)chrtab[*ln]&CTSYM; ++j)
969 // Handle "DOT" special forms (like ".b") that follow a normal symbol or keyword:
972 *ln++ = EOS; // Terminate symbol
973 stuffnull = 0; // And never try it again
975 // Character following the `.' must have a DOT attribute, and the chararacter after
976 // THAT one must not have a start-symbol attribute (to prevent symbols that look
977 // like, for example, "zingo.barf", which might be a good idea anyway....)
978 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
979 return error("[bwsl] must follow `.' in symbol");
981 v = (VALUE)dotxtab[*ln++];
983 if ((int)chrtab[*ln] & CTSYM)
984 return error("misuse of `.', not allowed in symbols");
987 // If the symbol is small, check to see if it's really the name of a register.
990 for(state=0; state>=0;)
992 j = (int)tolowertab[*p++];
995 if (kwcheck[j] != state)
1001 if (*p == EOS || p == ln)
1015 //make j = -1 if time, date etc with no preceeding ^^
1016 //defined, referenced, streq, macdef, date and time
1019 case 112: // defined
1020 case 113: // referenced
1029 if (j < 0 || state < 0)
1032 *tk++ = (TOKEN)nullspot;
1040 if (v) // Record attribute token (if any)
1043 if (stuffnull) // Arrange for string termination
1049 // Handle identity tokens
1056 // Handle multiple-character tokens
1061 case '!': // ! or !=
1071 case '\'': // 'string'
1072 case '\"': // "string"
1077 for(p=ln; *ln!=EOS && *ln!=c1;)
1086 return(error("unterminated string"));
1115 warn("bad backslash code in string");
1125 return error("unterminated string");
1129 case '$': // $, hex constant
1130 if ((int)chrtab[*ln] & HDIGIT)
1134 while ((int)hextab[*ln] >= 0)
1135 v = (v << 4) + (int)hextab[*ln++];
1139 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1145 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1151 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1164 case '<': // < or << or <> or <=
1183 case ':': // : or ::
1193 case '=': // = or ==
1203 case '>': // > or >> or >=
1218 case '%': // % or binary constant
1219 if (*ln < '0' || *ln > '1')
1227 while (*ln >= '0' && *ln <= '1')
1228 v = (v << 1) + *ln++ - '0';
1232 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1238 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1244 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1253 case '@': // @ or octal constant
1254 if (*ln < '0' || *ln > '7')
1262 while (*ln >= '0' && *ln <= '7')
1263 v = (v << 3) + *ln++ - '0';
1267 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1273 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1279 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1288 case '^': // ^ or ^^ <operator-name>
1295 if (((int)chrtab[*++ln] & STSYM) == 0)
1297 error("invalid symbol following ^^");
1303 while ((int)chrtab[*ln] & CTSYM)
1306 for(state=0; state>=0;)
1308 // Get char, convert to lowercase
1311 if (j >= 'A' && j <= 'Z')
1316 if (kwcheck[j] != state)
1322 if (*p == EOS || p == ln)
1331 if (j < 0 || state < 0)
1333 error("unknown symbol following ^^");
1340 interror(2); // Bad MULTX entry in chrtab
1345 // Handle decimal constant
1350 while ((int)chrtab[*ln] & DIGIT)
1351 v = (v * 10) + *ln++ - '0';
1355 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1361 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1367 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1378 // Handle illegal character
1379 return error("illegal character");
1382 // Terminate line of tokens and return "success."
1385 tok = etok; // Set tok to beginning of line
1387 if (stuffnull) // Terminate last SYMBOL
1397 // .GOTO <label> goto directive
1399 // The label is searched for starting from the first line of the current,
1400 // enclosing macro definition. If no enclosing macro exists, an error is
1403 // A label is of the form:
1405 // :<name><whitespace>
1407 // The colon must appear in column 1. The label is stripped prior to macro
1408 // expansion, and is NOT subject to macro expansion. The whitespace may also
1411 //int d_goto(WORD siz) {
1414 char * sym; // Label to search for
1415 LONG * defln; // Macro definition strings
1416 char * s1; // Temps for string comparison
1418 IMACRO * imacro; // Macro invocation block
1420 // Setup for the search
1422 return error("missing label");
1424 sym = (char *)tok[1];
1427 if (cur_inobj->in_type != SRC_IMACRO)
1428 return error("goto not in macro");
1430 imacro = cur_inobj->inobj.imacro;
1431 defln = (LONG *)imacro->im_macro->svalue;
1433 // Find the label, starting with the first line.
1434 for(; defln!=NULL; defln=(LONG *)*defln)
1436 if (*(char *)(defln + 1) == ':')
1438 // Compare names (sleazo string compare)
1440 s2 = (char *)(defln + 1) + 1;
1453 // Found the label, set new macro next-line and return.
1454 if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1456 imacro->im_nextln = defln;
1462 return error("goto label not found");