1 /* parse_bas.c - parse BCC AS assembly Author: Kees J. Bot
12 #include "languages.h"
14 typedef struct mnemonic
{ /* BAS mnemonics translation table. */
20 static mnemonic_t mnemtab
[] = { /* This array is sorted. */
21 { ".align", DOT_ALIGN
, PSEUDO
},
22 { ".ascii", DOT_ASCII
, PSEUDO
},
23 { ".asciz", DOT_ASCIZ
, PSEUDO
},
24 { ".assert", DOT_ASSERT
, PSEUDO
},
25 { ".base", DOT_BASE
, PSEUDO
},
26 { ".blkb", DOT_SPACE
, PSEUDO
},
27 { ".bss", DOT_BSS
, PSEUDO
},
28 { ".byte", DOT_DATA1
, PSEUDO
},
29 { ".comm", DOT_COMM
, PSEUDO
},
30 { ".data", DOT_DATA
, PSEUDO
},
31 { ".define", DOT_DEFINE
, PSEUDO
},
32 { ".end", DOT_END
, PSEUDO
},
33 { ".even", DOT_ALIGN
, PSEUDO
},
34 { ".extern", DOT_EXTERN
, PSEUDO
},
35 { ".file", DOT_FILE
, PSEUDO
},
36 { ".globl", DOT_DEFINE
, PSEUDO
},
37 { ".lcomm", DOT_LCOMM
, PSEUDO
},
38 { ".line", DOT_LINE
, PSEUDO
},
39 { ".list", DOT_LIST
, PSEUDO
},
40 { ".long", DOT_DATA4
, PSEUDO
},
41 { ".nolist", DOT_NOLIST
, PSEUDO
},
42 { ".rom", DOT_ROM
, PSEUDO
},
43 { ".space", DOT_SPACE
, PSEUDO
},
44 { ".symb", DOT_SYMB
, PSEUDO
},
45 { ".text", DOT_TEXT
, PSEUDO
},
46 { ".use16", DOT_USE16
, PSEUDO
},
47 { ".use32", DOT_USE32
, PSEUDO
},
48 { ".word", DOT_DATA2
, PSEUDO
},
49 { ".zerob", DOT_SPACE
, PSEUDO
},
50 { ".zerow", DOT_SPACE
, PSEUDO
},
58 { "arpl", ARPL
, WORD
},
64 { "bhis", JAE
, JUMP
},
67 { "blos", JBE
, JUMP
},
71 { "bound", BOUND
, WORD
},
75 { "bswap", BSWAP
, WORD
},
81 { "call", CALL
, JUMP
},
82 { "callf", CALLF
, JUMP
},
88 { "clts", CLTS
, WORD
},
91 { "cmps", CMPS
, WORD
},
92 { "cmpsb", CMPS
, BYTE
},
93 { "cmpxchg", CMPXCHG
, WORD
},
95 { "cwde", CBW
, WORD
},
98 { "dd", DOT_DATA4
, PSEUDO
},
100 { "div", DIV
, WORD
},
101 { "enter", ENTER
, WORD
},
102 { "export", DOT_DEFINE
, PSEUDO
},
103 { "f2xm1", F2XM1
, WORD
},
104 { "fabs", FABS
, WORD
},
105 { "fadd", FADD
, WORD
},
106 { "faddd", FADDD
, WORD
},
107 { "faddp", FADDP
, WORD
},
108 { "fadds", FADDS
, WORD
},
109 { "fbld", FBLD
, WORD
},
110 { "fbstp", FBSTP
, WORD
},
111 { "fchs", FCHS
, WORD
},
112 { "fclex", FCLEX
, WORD
},
113 { "fcomd", FCOMD
, WORD
},
114 { "fcompd", FCOMPD
, WORD
},
115 { "fcompp", FCOMPP
, WORD
},
116 { "fcomps", FCOMPS
, WORD
},
117 { "fcoms", FCOMS
, WORD
},
118 { "fcos", FCOS
, WORD
},
119 { "fdecstp", FDECSTP
, WORD
},
120 { "fdivd", FDIVD
, WORD
},
121 { "fdivp", FDIVP
, WORD
},
122 { "fdivrd", FDIVRD
, WORD
},
123 { "fdivrp", FDIVRP
, WORD
},
124 { "fdivrs", FDIVRS
, WORD
},
125 { "fdivs", FDIVS
, WORD
},
126 { "ffree", FFREE
, WORD
},
127 { "fiaddl", FIADDL
, WORD
},
128 { "fiadds", FIADDS
, WORD
},
129 { "ficom", FICOM
, WORD
},
130 { "ficomp", FICOMP
, WORD
},
131 { "fidivl", FIDIVL
, WORD
},
132 { "fidivrl", FIDIVRL
, WORD
},
133 { "fidivrs", FIDIVRS
, WORD
},
134 { "fidivs", FIDIVS
, WORD
},
135 { "fildl", FILDL
, WORD
},
136 { "fildq", FILDQ
, WORD
},
137 { "filds", FILDS
, WORD
},
138 { "fimull", FIMULL
, WORD
},
139 { "fimuls", FIMULS
, WORD
},
140 { "fincstp", FINCSTP
, WORD
},
141 { "finit", FINIT
, WORD
},
142 { "fistl", FISTL
, WORD
},
143 { "fistp", FISTP
, WORD
},
144 { "fists", FISTS
, WORD
},
145 { "fisubl", FISUBL
, WORD
},
146 { "fisubrl", FISUBRL
, WORD
},
147 { "fisubrs", FISUBRS
, WORD
},
148 { "fisubs", FISUBS
, WORD
},
149 { "fld1", FLD1
, WORD
},
150 { "fldcw", FLDCW
, WORD
},
151 { "fldd", FLDD
, WORD
},
152 { "fldenv", FLDENV
, WORD
},
153 { "fldl2e", FLDL2E
, WORD
},
154 { "fldl2t", FLDL2T
, WORD
},
155 { "fldlg2", FLDLG2
, WORD
},
156 { "fldln2", FLDLN2
, WORD
},
157 { "fldpi", FLDPI
, WORD
},
158 { "flds", FLDS
, WORD
},
159 { "fldx", FLDX
, WORD
},
160 { "fldz", FLDZ
, WORD
},
161 { "fmuld", FMULD
, WORD
},
162 { "fmulp", FMULP
, WORD
},
163 { "fmuls", FMULS
, WORD
},
164 { "fnop", FNOP
, WORD
},
165 { "fpatan", FPATAN
, WORD
},
166 { "fprem", FPREM
, WORD
},
167 { "fprem1", FPREM1
, WORD
},
168 { "fptan", FPTAN
, WORD
},
169 { "frndint", FRNDINT
, WORD
},
170 { "frstor", FRSTOR
, WORD
},
171 { "fsave", FSAVE
, WORD
},
172 { "fscale", FSCALE
, WORD
},
173 { "fsin", FSIN
, WORD
},
174 { "fsincos", FSINCOS
, WORD
},
175 { "fsqrt", FSQRT
, WORD
},
176 { "fstcw", FSTCW
, WORD
},
177 { "fstd", FSTD
, WORD
},
178 { "fstenv", FSTENV
, WORD
},
179 { "fstpd", FSTPD
, WORD
},
180 { "fstps", FSTPS
, WORD
},
181 { "fstpx", FSTPX
, WORD
},
182 { "fsts", FSTS
, WORD
},
183 { "fstsw", FSTSW
, WORD
},
184 { "fsubd", FSUBD
, WORD
},
185 { "fsubp", FSUBP
, WORD
},
186 { "fsubpr", FSUBPR
, WORD
},
187 { "fsubrd", FSUBRD
, WORD
},
188 { "fsubrs", FSUBRS
, WORD
},
189 { "fsubs", FSUBS
, WORD
},
190 { "ftst", FTST
, WORD
},
191 { "fucom", FUCOM
, WORD
},
192 { "fucomp", FUCOMP
, WORD
},
193 { "fucompp", FUCOMPP
, WORD
},
194 { "fxam", FXAM
, WORD
},
195 { "fxch", FXCH
, WORD
},
196 { "fxtract", FXTRACT
, WORD
},
197 { "fyl2x", FYL2X
, WORD
},
198 { "fyl2xp1", FYL2XP1
, WORD
},
199 { "hlt", HLT
, WORD
},
200 { "idiv", IDIV
, WORD
},
201 { "imul", IMUL
, WORD
},
204 { "inc", INC
, WORD
},
205 { "ins", INS
, WORD
},
206 { "insb", INS
, BYTE
},
207 { "int", INT
, WORD
},
208 { "into", INTO
, JUMP
},
209 { "invd", INVD
, WORD
},
210 { "invlpg", INVLPG
, WORD
},
211 { "iret", IRET
, JUMP
},
212 { "iretd", IRETD
, JUMP
},
215 { "jae", JAE
, JUMP
},
217 { "jbe", JBE
, JUMP
},
219 { "jcxz", JCXZ
, JUMP
},
221 { "jecxz", JCXZ
, JUMP
},
224 { "jge", JGE
, JUMP
},
227 { "jhis", JAE
, JUMP
},
229 { "jle", JLE
, JUMP
},
231 { "jlos", JBE
, JUMP
},
233 { "jmp", JMP
, JUMP
},
234 { "jmpf", JMPF
, JUMP
},
235 { "jna", JBE
, JUMP
},
236 { "jnae", JB
, JUMP
},
237 { "jnb", JAE
, JUMP
},
238 { "jnbe", JA
, JUMP
},
239 { "jnc", JAE
, JUMP
},
240 { "jne", JNE
, JUMP
},
241 { "jng", JLE
, JUMP
},
242 { "jnge", JL
, JUMP
},
243 { "jnl", JGE
, JUMP
},
244 { "jnle", JG
, JUMP
},
245 { "jno", JNO
, JUMP
},
246 { "jnp", JNP
, JUMP
},
247 { "jns", JNS
, JUMP
},
248 { "jnz", JNE
, JUMP
},
253 { "lahf", LAHF
, WORD
},
254 { "lar", LAR
, WORD
},
255 { "lds", LDS
, WORD
},
256 { "lea", LEA
, WORD
},
257 { "leave", LEAVE
, WORD
},
258 { "les", LES
, WORD
},
259 { "lfs", LFS
, WORD
},
260 { "lgdt", LGDT
, WORD
},
261 { "lgs", LGS
, WORD
},
262 { "lidt", LIDT
, WORD
},
263 { "lldt", LLDT
, WORD
},
264 { "lmsw", LMSW
, WORD
},
265 { "lock", LOCK
, WORD
},
266 { "lods", LODS
, WORD
},
267 { "lodsb", LODS
, BYTE
},
268 { "loop", LOOP
, JUMP
},
269 { "loope", LOOPE
, JUMP
},
270 { "loopne", LOOPNE
, JUMP
},
271 { "loopnz", LOOPNE
, JUMP
},
272 { "loopz", LOOPE
, JUMP
},
273 { "lsl", LSL
, WORD
},
274 { "lss", LSS
, WORD
},
275 { "ltr", LTR
, WORD
},
276 { "mov", MOV
, WORD
},
277 { "movs", MOVS
, WORD
},
278 { "movsb", MOVS
, BYTE
},
279 { "movsx", MOVSX
, WORD
},
280 { "movzx", MOVZX
, WORD
},
281 { "mul", MUL
, WORD
},
282 { "neg", NEG
, WORD
},
283 { "nop", NOP
, WORD
},
284 { "not", NOT
, WORD
},
286 { "out", OUT
, WORD
},
287 { "outb", OUT
, BYTE
},
288 { "outs", OUTS
, WORD
},
289 { "outsb", OUTS
, BYTE
},
290 { "pop", POP
, WORD
},
291 { "popa", POPA
, WORD
},
292 { "popad", POPA
, WORD
},
293 { "popf", POPF
, WORD
},
294 { "popfd", POPF
, WORD
},
295 { "push", PUSH
, WORD
},
296 { "pusha", PUSHA
, WORD
},
297 { "pushad", PUSHA
, WORD
},
298 { "pushf", PUSHF
, WORD
},
299 { "pushfd", PUSHF
, WORD
},
300 { "rcl", RCL
, WORD
},
301 { "rcr", RCR
, WORD
},
302 { "ret", RET
, JUMP
},
303 { "retf", RETF
, JUMP
},
304 { "rol", ROL
, WORD
},
305 { "ror", ROR
, WORD
},
306 { "sahf", SAHF
, WORD
},
307 { "sal", SAL
, WORD
},
308 { "sar", SAR
, WORD
},
309 { "sbb", SBB
, WORD
},
310 { "scas", SCAS
, WORD
},
311 { "seta", SETA
, BYTE
},
312 { "setae", SETAE
, BYTE
},
313 { "setb", SETB
, BYTE
},
314 { "setbe", SETBE
, BYTE
},
315 { "sete", SETE
, BYTE
},
316 { "setg", SETG
, BYTE
},
317 { "setge", SETGE
, BYTE
},
318 { "setl", SETL
, BYTE
},
319 { "setna", SETBE
, BYTE
},
320 { "setnae", SETB
, BYTE
},
321 { "setnb", SETAE
, BYTE
},
322 { "setnbe", SETA
, BYTE
},
323 { "setne", SETNE
, BYTE
},
324 { "setng", SETLE
, BYTE
},
325 { "setnge", SETL
, BYTE
},
326 { "setnl", SETGE
, BYTE
},
327 { "setnle", SETG
, BYTE
},
328 { "setno", SETNO
, BYTE
},
329 { "setnp", SETNP
, BYTE
},
330 { "setns", SETNS
, BYTE
},
331 { "seto", SETO
, BYTE
},
332 { "setp", SETP
, BYTE
},
333 { "sets", SETS
, BYTE
},
334 { "setz", SETE
, BYTE
},
335 { "sgdt", SGDT
, WORD
},
336 { "shl", SHL
, WORD
},
337 { "shld", SHLD
, WORD
},
338 { "shr", SHR
, WORD
},
339 { "shrd", SHRD
, WORD
},
340 { "sidt", SIDT
, WORD
},
341 { "sldt", SLDT
, WORD
},
342 { "smsw", SMSW
, WORD
},
343 { "stc", STC
, WORD
},
344 { "std", STD
, WORD
},
345 { "sti", STI
, WORD
},
346 { "stos", STOS
, WORD
},
347 { "stosb", STOS
, BYTE
},
348 { "str", STR
, WORD
},
349 { "sub", SUB
, WORD
},
350 { "test", TEST
, WORD
},
351 { "verr", VERR
, WORD
},
352 { "verw", VERW
, WORD
},
353 { "wait", WAIT
, WORD
},
354 { "wbinvd", WBINVD
, WORD
},
355 { "xadd", XADD
, WORD
},
356 { "xchg", XCHG
, WORD
},
357 { "xlat", XLAT
, WORD
},
358 { "xor", XOR
, WORD
},
361 void bas_parse_init(char *file
)
362 /* Prepare parsing of an BAS assembly file. */
367 static void zap(void)
368 /* An error, zap the rest of the line. */
372 while ((t
= get_token(0))->type
!= T_EOF
&& t
->symbol
!= ';')
376 static mnemonic_t
*search_mnem(char *name
)
377 /* Binary search for a mnemonic. (That's why the table is sorted.) */
384 high
= arraysize(mnemtab
)-1;
385 while (low
<= high
) {
386 mid
= (low
+ high
) / 2;
389 if ((cmp
= strcmp(name
, m
->name
)) == 0) return m
;
391 if (cmp
< 0) high
= mid
-1; else low
= mid
+1;
396 static expression_t
*bas_get_C_expression(int *pn
)
397 /* Read a "C-like" expression. Note that we don't worry about precedence,
398 * the expression is printed later like it is read. If the target language
399 * does not have all the operators (like ~) then this has to be repaired by
400 * changing the source file. (No problem, you still have one source file
401 * to maintain, not two.)
404 expression_t
*e
, *a1
, *a2
;
407 if ((t
= get_token(*pn
))->symbol
== '(') {
408 /* ( expr ): grouping. */
410 if ((a1
= bas_get_C_expression(pn
)) == nil
) return nil
;
411 if (get_token(*pn
)->symbol
!= ')') {
412 parse_err(1, t
, "missing )\n");
421 if (t
->type
== T_WORD
|| t
->type
== T_STRING
) {
422 /* Label, number, or string. */
424 e
->operator= t
->type
== T_WORD
? 'W' : 'S';
425 e
->name
= allocate(nil
, (t
->len
+1) * sizeof(e
->name
[0]));
426 memcpy(e
->name
, t
->name
, t
->len
+1);
430 if (t
->symbol
== '+' || t
->symbol
== '-' || t
->symbol
== '~') {
431 /* Unary operator. */
433 if ((a1
= bas_get_C_expression(pn
)) == nil
) return nil
;
435 e
->operator= t
->symbol
;
438 if (t
->symbol
== '$' && get_token(*pn
+ 1)->type
== T_WORD
) {
439 /* A hexadecimal number. */
440 t
= get_token(*pn
+ 1);
443 e
->name
= allocate(nil
, (t
->len
+3) * sizeof(e
->name
[0]));
444 strcpy(e
->name
, "0x");
445 memcpy(e
->name
+2, t
->name
, t
->len
+1);
449 parse_err(1, t
, "expression syntax error\n");
453 switch ((t
= get_token(*pn
))->symbol
) {
466 if ((a2
= bas_get_C_expression(pn
)) == nil
) {
471 e
->operator= t
->symbol
;
478 /* We want to know the sizes of the first two operands. */
479 static optype_t optypes
[2];
482 static expression_t
*bas_get_operand(int *pn
)
483 /* Get something like: [memory], offset[base+index*scale], or simpler. */
485 expression_t
*e
, *offset
, *base
, *index
;
490 /* Prefixed by 'byte', 'word' or 'dword'? */
491 if ((t
= get_token(*pn
))->type
== T_WORD
&& (
492 strcmp(t
->name
, "byte") == 0
493 || strcmp(t
->name
, "word") == 0
494 || strcmp(t
->name
, "dword") == 0)
496 switch (t
->name
[0]) {
497 case 'b': optype
= BYTE
; break;
498 case 'w': optype
= use16() ? WORD
: OWORD
; break;
499 case 'd': optype
= use32() ? WORD
: OWORD
; break;
501 if (op_idx
< arraysize(optypes
)) optypes
[op_idx
++]= optype
;
504 /* It may even be "byte ptr"... */
505 if ((t
= get_token(*pn
))->type
== T_WORD
506 && strcmp(t
->name
, "ptr") == 0) {
511 /* Is it [memory]? */
512 if (get_token(*pn
)->symbol
== '['
513 && ((t
= get_token(*pn
+ 1))->type
!= T_WORD
514 || !isregister(t
->name
))
516 /* A memory dereference. */
518 if ((offset
= bas_get_C_expression(pn
)) == nil
) return nil
;
519 if (get_token(*pn
)->symbol
!= ']') {
520 parse_err(1, t
, "operand syntax error\n");
531 /* #something? *something? */
532 if ((c
= get_token(*pn
)->symbol
) == '#' || c
== '*') {
533 /* '#' and '*' are often used to introduce some constant. */
538 if (get_token(*pn
)->symbol
!= '[') {
539 /* There is an offset. */
540 if ((offset
= bas_get_C_expression(pn
)) == nil
) return nil
;
546 /* [base]? [base+? base-? */
548 if (get_token(*pn
)->symbol
== '['
549 && (t
= get_token(*pn
+ 1))->type
== T_WORD
550 && isregister(t
->name
)
551 && ((c
= get_token(*pn
+ 2)->symbol
) == ']' || c
=='+' || c
=='-')
553 /* A base register expression. */
556 base
->name
= copystr(t
->name
);
557 (*pn
)+= c
== ']' ? 3 : 2;
559 /* No base register expression. */
563 /* +offset]? -offset]? */
565 && (c
== '+' || c
== '-')
566 && (t
= get_token(*pn
+ 1))->type
== T_WORD
567 && !isregister(t
->name
)
570 if ((offset
= bas_get_C_expression(pn
)) == nil
) return nil
;
571 if (get_token(*pn
)->symbol
!= ']') {
572 parse_err(1, t
, "operand syntax error\n");
581 /* [index*scale]? +index*scale]? */
582 if (c
== '+' || get_token(*pn
)->symbol
== '[') {
583 /* An index most likely. */
586 if (!( /* This must be true: */
587 (t
= get_token(*pn
+ 1))->type
== T_WORD
588 && isregister(t
->name
)
589 && (get_token(*pn
+ 2)->symbol
== ']' || (
590 get_token(*pn
+ 2)->symbol
== '*'
591 && (m
= get_token(*pn
+ 3))->type
== T_WORD
592 && strchr("1248", m
->name
[0]) != nil
594 && get_token(*pn
+ 4)->symbol
== ']'
598 parse_err(1, t
, "operand syntax error\n");
603 /* Found an index. */
605 index
->operator= m
== nil
? '1' : m
->name
[0];
606 index
->name
= copystr(t
->name
);
607 (*pn
)+= (m
== nil
? 3 : 5);
613 if (base
== nil
&& index
== nil
) {
614 /* Return a lone offset as is. */
617 /* Lone registers tell operand size. */
618 if (offset
->operator == 'W' && isregister(offset
->name
)) {
619 switch (isregister(offset
->name
)) {
620 case 1: optype
= BYTE
; break;
621 case 2: optype
= use16() ? WORD
: OWORD
; break;
622 case 4: optype
= use32() ? WORD
: OWORD
; break;
624 if (op_idx
< arraysize(optypes
))
625 optypes
[op_idx
++]= optype
;
637 static expression_t
*bas_get_oplist(int *pn
)
638 /* Get a comma (or colon for jmpf and callf) separated list of instruction
642 expression_t
*e
, *o1
, *o2
;
645 if ((e
= bas_get_operand(pn
)) == nil
) return nil
;
647 if ((t
= get_token(*pn
))->symbol
== ',' || t
->symbol
== ':') {
650 if ((o2
= bas_get_oplist(pn
)) == nil
) {
662 static asm86_t
*bas_get_statement(void)
663 /* Get a pseudo op or machine instruction with arguments. */
665 token_t
*t
= get_token(0);
672 assert(t
->type
== T_WORD
);
674 if (strcmp(t
->name
, ".sect") == 0) {
675 /* .sect .text etc. Accept only four segment names. */
678 if (t
->type
!= T_WORD
|| (
679 strcmp(t
->name
, ".text") != 0
680 && strcmp(t
->name
, ".rom") != 0
681 && strcmp(t
->name
, ".data") != 0
682 && strcmp(t
->name
, ".bss") != 0
683 && strcmp(t
->name
, ".end") != 0
685 parse_err(1, t
, "weird section name to .sect\n");
691 /* Process instruction prefixes. */
692 for (prefix_seen
= 0;; prefix_seen
= 1) {
693 if (strcmp(t
->name
, "rep") == 0
694 || strcmp(t
->name
, "repe") == 0
695 || strcmp(t
->name
, "repne") == 0
696 || strcmp(t
->name
, "repz") == 0
697 || strcmp(t
->name
, "repnz") == 0
699 if (a
->rep
!= ONCE
) {
701 "can't have more than one rep\n");
703 switch (t
->name
[3]) {
704 case 0: a
->rep
= REP
; break;
706 case 'z': a
->rep
= REPE
; break;
707 case 'n': a
->rep
= REPNE
; break;
710 if (strcmp(t
->name
, "seg") == 0
711 && get_token(1)->type
== T_WORD
) {
712 if (a
->seg
!= DEFSEG
) {
714 "can't have more than one segment prefix\n");
716 switch (get_token(1)->name
[0]) {
717 case 'c': a
->seg
= CSEG
; break;
718 case 'd': a
->seg
= DSEG
; break;
719 case 'e': a
->seg
= ESEG
; break;
720 case 'f': a
->seg
= FSEG
; break;
721 case 'g': a
->seg
= GSEG
; break;
722 case 's': a
->seg
= SSEG
; break;
727 /* No prefix here, get out! */
730 /* No more prefixes, next must be an instruction. */
731 if (t
->type
!= T_WORD
732 || (m
= search_mnem(t
->name
)) == nil
733 || m
->optype
== PSEUDO
736 "machine instruction expected after instruction prefix\n");
743 /* Skip the prefix and extra newlines. */
746 } while ((t
= get_token(0))->symbol
== ';');
749 /* All the readahead being done upsets the line counter. */
752 /* Read a machine instruction or pseudo op. */
753 if ((m
= search_mnem(t
->name
)) == nil
) {
754 parse_err(1, t
, "unknown instruction '%s'\n", t
->name
);
758 a
->opcode
= m
->opcode
;
759 a
->optype
= m
->optype
;
760 if (a
->opcode
== CBW
|| a
->opcode
== CWD
) {
761 a
->optype
= (strcmp(t
->name
, "cbw") == 0
762 || strcmp(t
->name
, "cwd") == 0) == use16() ? WORD
: OWORD
;
764 for (op_idx
= 0; op_idx
< arraysize(optypes
); op_idx
++)
765 optypes
[op_idx
]= m
->optype
;
769 if (get_token(1)->symbol
!= ';'
770 && (a
->args
= bas_get_oplist(&n
)) == nil
) {
775 if (m
->optype
== WORD
) {
776 /* Does one of the operands overide the optype? */
777 for (op_idx
= 0; op_idx
< arraysize(optypes
); op_idx
++) {
778 if (optypes
[op_idx
] != m
->optype
)
779 a
->optype
= optypes
[op_idx
];
783 if (get_token(n
)->symbol
!= ';') {
784 parse_err(1, t
, "garbage at end of instruction\n");
790 /* Restrict .align to have a single numeric argument, some
791 * assemblers think of the argument as a power of two, so
792 * we need to be able to change the value.
794 if (strcmp(t
->name
, ".even") == 0 && a
->args
== nil
) {
795 /* .even becomes .align 2. */
797 a
->args
= e
= new_expr();
799 e
->name
= copystr("2");
802 if (a
->args
== nil
|| a
->args
->operator != 'W'
803 || !isanumber(a
->args
->name
)) {
805 ".align is restricted to one numeric argument\n");
812 /* Types of both operands tell the instruction type. */
813 a
->optype
= optypes
[0];
814 if (optypes
[1] == BYTE
) {
815 a
->opcode
= a
->opcode
== MOVSX
? MOVSXB
: MOVZXB
;
826 /* Only the first operand tells the operand size. */
827 a
->optype
= optypes
[0];
835 asm86_t
*bas_get_instruction(void)
841 while ((t
= get_token(0))->symbol
== ';')
844 if (t
->type
== T_EOF
) return nil
;
846 if (t
->symbol
== '#') {
847 /* Preprocessor line and file change. */
849 if ((t
= get_token(1))->type
!= T_WORD
|| !isanumber(t
->name
)
850 || get_token(2)->type
!= T_STRING
852 parse_err(1, t
, "file not preprocessed?\n");
855 set_file(get_token(2)->name
,
856 strtol(get_token(1)->name
, nil
, 0) - 1);
858 /* GNU CPP adds extra cruft, simply zap the line. */
861 a
= bas_get_instruction();
863 if (t
->type
== T_WORD
&& get_token(1)->symbol
== ':') {
864 /* A label definition. */
867 a
->opcode
= DOT_LABEL
;
869 a
->args
= e
= new_expr();
871 e
->name
= copystr(t
->name
);
874 if (t
->type
== T_WORD
&& get_token(1)->symbol
== '=') {
877 if ((e
= bas_get_C_expression(&n
)) == nil
) {
879 a
= bas_get_instruction();
881 if (get_token(n
)->symbol
!= ';') {
882 parse_err(1, t
, "garbage after assignment\n");
884 a
= bas_get_instruction();
891 a
->args
->operator= '=';
892 a
->args
->name
= copystr(t
->name
);
897 if (t
->type
== T_WORD
&& get_token(1)->type
== T_WORD
898 && strcmp(get_token(1)->name
, "lcomm") == 0) {
899 /* Local common block definition. */
902 if ((e
= bas_get_C_expression(&n
)) == nil
) {
904 a
= bas_get_instruction();
906 if (get_token(n
)->symbol
!= ';') {
907 parse_err(1, t
, "garbage after lcomm\n");
909 a
= bas_get_instruction();
913 a
->opcode
= DOT_LCOMM
;
916 a
->args
->operator= ',';
918 a
->args
->left
= e
= new_expr();
920 e
->name
= copystr(t
->name
);
921 e
->len
= strlen(e
->name
)+1;
925 if (t
->type
== T_WORD
) {
926 if ((a
= bas_get_statement()) == nil
) {
928 a
= bas_get_instruction();
931 parse_err(1, t
, "syntax error\n");
933 a
= bas_get_instruction();
935 if (a
->optype
== OWORD
) {