source: trunk/minix/commands/i386/asmconv/parse_gnu.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 20.3 KB
Line 
1/* parse_ack.c - parse GNU assembly Author: R.S. Veldema
2 * <rveldema@cs.vu.nl>
3 * 26 Aug 1996
4 */
5#define nil 0
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <limits.h>
10#include <assert.h>
11#include "asmconv.h"
12#include "token.h"
13#include "asm86.h"
14#include "languages.h"
15
16typedef struct mnemonic { /* GNU as86 mnemonics translation table. */
17 char *name;
18 opcode_t opcode;
19 optype_t optype;
20} mnemonic_t;
21
22static mnemonic_t mnemtab[] = { /* This array is sorted. */
23 { ".align", DOT_ALIGN, PSEUDO },
24 { ".ascii", DOT_ASCII, PSEUDO },
25 { ".asciz", DOT_ASCIZ, PSEUDO },
26 { ".assert", DOT_ASSERT, PSEUDO },
27 { ".base", DOT_BASE, PSEUDO },
28 { ".bss", DOT_BSS, PSEUDO },
29 { ".byte", DOT_DATA1, PSEUDO },
30 { ".comm", DOT_COMM, PSEUDO },
31 { ".data", DOT_DATA, PSEUDO },
32 { ".data1", DOT_DATA1, PSEUDO },
33 { ".data2", DOT_DATA2, PSEUDO },
34 { ".data4", DOT_DATA4, PSEUDO },
35 { ".end", DOT_END, PSEUDO },
36 { ".extern", DOT_EXTERN, PSEUDO },
37 { ".file", DOT_FILE, PSEUDO },
38 { ".globl", DOT_DEFINE, PSEUDO },
39 { ".lcomm", DOT_LCOMM, PSEUDO },
40 { ".line", DOT_LINE, PSEUDO },
41 { ".list", DOT_LIST, PSEUDO },
42 { ".long", DOT_DATA4, PSEUDO },
43 { ".nolist", DOT_NOLIST, PSEUDO },
44 { ".rom", DOT_ROM, PSEUDO },
45 { ".space", DOT_SPACE, PSEUDO },
46 { ".symb", DOT_SYMB, PSEUDO },
47 { ".text", DOT_TEXT, PSEUDO },
48 { ".word", DOT_DATA2, PSEUDO },
49 { "aaa", AAA, WORD },
50 { "aad", AAD, WORD },
51 { "aam", AAM, WORD },
52 { "aas", AAS, WORD },
53 { "adcb", ADC, BYTE },
54 { "adcl", ADC, WORD },
55 { "adcw", ADC, OWORD },
56 { "addb", ADD, BYTE },
57 { "addl", ADD, WORD },
58 { "addw", ADD, OWORD },
59 { "andb", AND, BYTE },
60 { "andl", AND, WORD },
61 { "andw", AND, OWORD },
62 { "arpl", ARPL, WORD },
63 { "bound", BOUND, WORD },
64 { "bsf", BSF, WORD },
65 { "bsr", BSR, WORD },
66 { "bswap", BSWAP, WORD },
67 { "btc", BTC, WORD },
68 { "btl", BT, WORD },
69 { "btr", BTR, WORD },
70 { "bts", BTS, WORD },
71 { "btw", BT, OWORD },
72 { "call", CALL, JUMP },
73 { "callf", CALLF, JUMP },
74 { "cbtw", CBW, OWORD },
75 { "cbw", CBW, WORD },
76 { "cdq", CWD, WORD },
77 { "clc", CLC, WORD },
78 { "cld", CLD, WORD },
79 { "cli", CLI, WORD },
80 { "cltd", CWD, WORD },
81 { "clts", CLTS, WORD },
82 { "cmc", CMC, WORD },
83 { "cmpb", CMP, BYTE },
84 { "cmpl", CMP, WORD },
85 { "cmps", CMPS, WORD },
86 { "cmpsb", CMPS, BYTE },
87 { "cmpw", CMP, OWORD },
88 { "cmpxchg", CMPXCHG, WORD },
89 { "cwd", CWD, WORD },
90 { "cwde", CBW, WORD },
91 { "cwtd", CWD, OWORD },
92 { "cwtl", CBW, WORD },
93 { "daa", DAA, WORD },
94 { "das", DAS, WORD },
95 { "decb", DEC, BYTE },
96 { "decl", DEC, WORD },
97 { "decw", DEC, OWORD },
98 { "divb", DIV, BYTE },
99 { "divl", DIV, WORD },
100 { "divw", DIV, OWORD },
101 { "enter", ENTER, WORD },
102 { "f2xm1", F2XM1, WORD },
103 { "fabs", FABS, WORD },
104 { "fadd", FADD, WORD },
105 { "faddd", FADDD, WORD },
106 { "faddp", FADDP, WORD },
107 { "fadds", FADDS, WORD },
108 { "fbld", FBLD, WORD },
109 { "fbstp", FBSTP, WORD },
110 { "fchs", FCHS, WORD },
111 { "fcomd", FCOMD, WORD },
112 { "fcompd", FCOMPD, WORD },
113 { "fcompp", FCOMPP, WORD },
114 { "fcomps", FCOMPS, WORD },
115 { "fcoms", FCOMS, WORD },
116 { "fcos", FCOS, WORD },
117 { "fdecstp", FDECSTP, WORD },
118 { "fdivd", FDIVD, WORD },
119 { "fdivp", FDIVP, WORD },
120 { "fdivrd", FDIVRD, WORD },
121 { "fdivrp", FDIVRP, WORD },
122 { "fdivrs", FDIVRS, WORD },
123 { "fdivs", FDIVS, WORD },
124 { "ffree", FFREE, WORD },
125 { "fiaddl", FIADDL, WORD },
126 { "fiadds", FIADDS, WORD },
127 { "ficom", FICOM, WORD },
128 { "ficomp", FICOMP, WORD },
129 { "fidivl", FIDIVL, WORD },
130 { "fidivrl", FIDIVRL, WORD },
131 { "fidivrs", FIDIVRS, WORD },
132 { "fidivs", FIDIVS, WORD },
133 { "fildl", FILDL, WORD },
134 { "fildq", FILDQ, WORD },
135 { "filds", FILDS, WORD },
136 { "fimull", FIMULL, WORD },
137 { "fimuls", FIMULS, WORD },
138 { "fincstp", FINCSTP, WORD },
139 { "fistl", FISTL, WORD },
140 { "fistp", FISTP, WORD },
141 { "fists", FISTS, WORD },
142 { "fisubl", FISUBL, WORD },
143 { "fisubrl", FISUBRL, WORD },
144 { "fisubrs", FISUBRS, WORD },
145 { "fisubs", FISUBS, WORD },
146 { "fld1", FLD1, WORD },
147 { "fldcw", FLDCW, WORD },
148 { "fldd", FLDD, WORD },
149 { "fldenv", FLDENV, WORD },
150 { "fldl2e", FLDL2E, WORD },
151 { "fldl2t", FLDL2T, WORD },
152 { "fldlg2", FLDLG2, WORD },
153 { "fldln2", FLDLN2, WORD },
154 { "fldpi", FLDPI, WORD },
155 { "flds", FLDS, WORD },
156 { "fldx", FLDX, WORD },
157 { "fldz", FLDZ, WORD },
158 { "fmuld", FMULD, WORD },
159 { "fmulp", FMULP, WORD },
160 { "fmuls", FMULS, WORD },
161 { "fnclex", FCLEX, WORD },
162 { "fninit", FINIT, WORD },
163 { "fnop", FNOP, WORD },
164 { "fnsave", FSAVE, WORD },
165 { "fnstcw", FSTCW, WORD },
166 { "fnstenv", FSTENV, WORD },
167 { "fpatan", FPATAN, WORD },
168 { "fprem", FPREM, WORD },
169 { "fprem1", FPREM1, WORD },
170 { "fptan", FPTAN, WORD },
171 { "frndint", FRNDINT, WORD },
172 { "frstor", FRSTOR, WORD },
173 { "fscale", FSCALE, WORD },
174 { "fsin", FSIN, WORD },
175 { "fsincos", FSINCOS, WORD },
176 { "fsqrt", FSQRT, WORD },
177 { "fstd", FSTD, WORD },
178 { "fstpd", FSTPD, WORD },
179 { "fstps", FSTPS, WORD },
180 { "fstpx", FSTPX, WORD },
181 { "fsts", FSTS, WORD },
182 { "fstsw", FSTSW, WORD },
183 { "fsubd", FSUBD, WORD },
184 { "fsubp", FSUBP, WORD },
185 { "fsubpr", FSUBPR, WORD },
186 { "fsubrd", FSUBRD, WORD },
187 { "fsubrs", FSUBRS, WORD },
188 { "fsubs", FSUBS, WORD },
189 { "ftst", FTST, WORD },
190 { "fucom", FUCOM, WORD },
191 { "fucomp", FUCOMP, WORD },
192 { "fucompp", FUCOMPP, WORD },
193 { "fxam", FXAM, WORD },
194 { "fxch", FXCH, WORD },
195 { "fxtract", FXTRACT, WORD },
196 { "fyl2x", FYL2X, WORD },
197 { "fyl2xp1", FYL2XP1, WORD },
198 { "hlt", HLT, WORD },
199 { "idivb", IDIV, BYTE },
200 { "idivl", IDIV, WORD },
201 { "idivw", IDIV, OWORD },
202 { "imulb", IMUL, BYTE },
203 { "imull", IMUL, WORD },
204 { "imulw", IMUL, OWORD },
205 { "inb", IN, BYTE },
206 { "incb", INC, BYTE },
207 { "incl", INC, WORD },
208 { "incw", INC, OWORD },
209 { "inl", IN, WORD },
210 { "insb", INS, BYTE },
211 { "insl", INS, WORD },
212 { "insw", INS, OWORD },
213 { "int", INT, WORD },
214 { "into", INTO, JUMP },
215 { "invd", INVD, WORD },
216 { "invlpg", INVLPG, WORD },
217 { "inw", IN, OWORD },
218 { "iret", IRET, JUMP },
219 { "iretd", IRETD, JUMP },
220 { "ja", JA, JUMP },
221 { "jae", JAE, JUMP },
222 { "jb", JB, JUMP },
223 { "jbe", JBE, JUMP },
224 { "jc", JB, JUMP },
225 { "jcxz", JCXZ, JUMP },
226 { "je", JE, JUMP },
227 { "jecxz", JCXZ, JUMP },
228 { "jg", JG, JUMP },
229 { "jge", JGE, JUMP },
230 { "jl", JL, JUMP },
231 { "jle", JLE, JUMP },
232 { "jmp", JMP, JUMP },
233 { "jmpf", JMPF, JUMP },
234 { "jna", JBE, JUMP },
235 { "jnae", JB, JUMP },
236 { "jnb", JAE, JUMP },
237 { "jnbe", JA, JUMP },
238 { "jnc", JAE, JUMP },
239 { "jne", JNE, JUMP },
240 { "jng", JLE, JUMP },
241 { "jnge", JL, JUMP },
242 { "jnl", JGE, JUMP },
243 { "jnle", JG, JUMP },
244 { "jno", JNO, JUMP },
245 { "jnp", JNP, JUMP },
246 { "jns", JNS, JUMP },
247 { "jnz", JNE, JUMP },
248 { "jo", JO, JUMP },
249 { "jp", JP, JUMP },
250 { "js", JS, JUMP },
251 { "jz", JE, JUMP },
252 { "lahf", LAHF, WORD },
253 { "lar", LAR, WORD },
254 { "lds", LDS, WORD },
255 { "leal", LEA, WORD },
256 { "leave", LEAVE, WORD },
257 { "leaw", LEA, OWORD },
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 { "movb", MOV, BYTE },
277 { "movl", MOV, WORD },
278 { "movsb", MOVS, BYTE },
279 { "movsbl", MOVSXB, WORD },
280 { "movsbw", MOVSXB, OWORD },
281 { "movsl", MOVS, WORD },
282 { "movsw", MOVS, OWORD },
283 { "movswl", MOVSX, WORD },
284 { "movw", MOV, OWORD },
285 { "movzbl", MOVZXB, WORD },
286 { "movzbw", MOVZXB, OWORD },
287 { "movzwl", MOVZX, WORD },
288 { "mulb", MUL, BYTE },
289 { "mull", MUL, WORD },
290 { "mulw", MUL, OWORD },
291 { "negb", NEG, BYTE },
292 { "negl", NEG, WORD },
293 { "negw", NEG, OWORD },
294 { "nop", NOP, WORD },
295 { "notb", NOT, BYTE },
296 { "notl", NOT, WORD },
297 { "notw", NOT, OWORD },
298 { "orb", OR, BYTE },
299 { "orl", OR, WORD },
300 { "orw", OR, OWORD },
301 { "outb", OUT, BYTE },
302 { "outl", OUT, WORD },
303 { "outsb", OUTS, BYTE },
304 { "outsl", OUTS, WORD },
305 { "outsw", OUTS, OWORD },
306 { "outw", OUT, OWORD },
307 { "pop", POP, WORD },
308 { "popa", POPA, WORD },
309 { "popad", POPA, WORD },
310 { "popf", POPF, WORD },
311 { "popl", POP, WORD },
312 { "push", PUSH, WORD },
313 { "pusha", PUSHA, WORD },
314 { "pushad", PUSHA, WORD },
315 { "pushf", PUSHF, WORD },
316 { "pushl", PUSH, WORD },
317 { "rclb", RCL, BYTE },
318 { "rcll", RCL, WORD },
319 { "rclw", RCL, OWORD },
320 { "rcrb", RCR, BYTE },
321 { "rcrl", RCR, WORD },
322 { "rcrw", RCR, OWORD },
323 { "ret", RET, JUMP },
324 { "retf", RETF, JUMP },
325 { "rolb", ROL, BYTE },
326 { "roll", ROL, WORD },
327 { "rolw", ROL, OWORD },
328 { "rorb", ROR, BYTE },
329 { "rorl", ROR, WORD },
330 { "rorw", ROR, OWORD },
331 { "sahf", SAHF, WORD },
332 { "salb", SAL, BYTE },
333 { "sall", SAL, WORD },
334 { "salw", SAL, OWORD },
335 { "sarb", SAR, BYTE },
336 { "sarl", SAR, WORD },
337 { "sarw", SAR, OWORD },
338 { "sbbb", SBB, BYTE },
339 { "sbbl", SBB, WORD },
340 { "sbbw", SBB, OWORD },
341 { "scasb", SCAS, BYTE },
342 { "scasl", SCAS, WORD },
343 { "scasw", SCAS, OWORD },
344 { "seta", SETA, BYTE },
345 { "setae", SETAE, BYTE },
346 { "setb", SETB, BYTE },
347 { "setbe", SETBE, BYTE },
348 { "sete", SETE, BYTE },
349 { "setg", SETG, BYTE },
350 { "setge", SETGE, BYTE },
351 { "setl", SETL, BYTE },
352 { "setna", SETBE, BYTE },
353 { "setnae", SETB, BYTE },
354 { "setnb", SETAE, BYTE },
355 { "setnbe", SETA, BYTE },
356 { "setne", SETNE, BYTE },
357 { "setng", SETLE, BYTE },
358 { "setnge", SETL, BYTE },
359 { "setnl", SETGE, BYTE },
360 { "setnle", SETG, BYTE },
361 { "setno", SETNO, BYTE },
362 { "setnp", SETNP, BYTE },
363 { "setns", SETNS, BYTE },
364 { "seto", SETO, BYTE },
365 { "setp", SETP, BYTE },
366 { "sets", SETS, BYTE },
367 { "setz", SETE, BYTE },
368 { "sgdt", SGDT, WORD },
369 { "shlb", SHL, BYTE },
370 { "shldl", SHLD, WORD },
371 { "shll", SHL, WORD },
372 { "shlw", SHL, OWORD },
373 { "shrb", SHR, BYTE },
374 { "shrdl", SHRD, WORD },
375 { "shrl", SHR, WORD },
376 { "shrw", SHR, OWORD },
377 { "sidt", SIDT, WORD },
378 { "sldt", SLDT, WORD },
379 { "smsw", SMSW, WORD },
380 { "stc", STC, WORD },
381 { "std", STD, WORD },
382 { "sti", STI, WORD },
383 { "stosb", STOS, BYTE },
384 { "stosl", STOS, WORD },
385 { "stosw", STOS, OWORD },
386 { "str", STR, WORD },
387 { "subb", SUB, BYTE },
388 { "subl", SUB, WORD },
389 { "subw", SUB, OWORD },
390 { "testb", TEST, BYTE },
391 { "testl", TEST, WORD },
392 { "testw", TEST, OWORD },
393 { "verr", VERR, WORD },
394 { "verw", VERW, WORD },
395 { "wait", WAIT, WORD },
396 { "wbinvd", WBINVD, WORD },
397 { "xadd", XADD, WORD },
398 { "xchgb", XCHG, BYTE },
399 { "xchgl", XCHG, WORD },
400 { "xchgw", XCHG, OWORD },
401 { "xlat", XLAT, WORD },
402 { "xorb", XOR, BYTE },
403 { "xorl", XOR, WORD },
404 { "xorw", XOR, OWORD },
405};
406
407void gnu_parse_init(char *file)
408/* Prepare parsing of an GNU assembly file. */
409{
410 tok_init(file, '#');
411}
412
413static void zap(void)
414/* An error, zap the rest of the line. */
415{
416 token_t *t;
417
418 while ((t= get_token(0))->type != T_EOF && t->symbol != ';')
419 skip_token(1);
420}
421
422static mnemonic_t *search_mnem(char *name)
423/* Binary search for a mnemonic. (That's why the table is sorted.) */
424{
425 int low, mid, high;
426 int cmp;
427 mnemonic_t *m;
428
429 low= 0;
430 high= arraysize(mnemtab)-1;
431 while (low <= high) {
432 mid= (low + high) / 2;
433 m= &mnemtab[mid];
434
435 if ((cmp= strcmp(name, m->name)) == 0) return m;
436
437 if (cmp < 0) high= mid-1; else low= mid+1;
438 }
439 return nil;
440}
441
442static expression_t *gnu_get_C_expression(int *pn)
443/* Read a "C-like" expression. Note that we don't worry about precedence,
444 * the expression is printed later like it is read. If the target language
445 * does not have all the operators (like ~) then this has to be repaired by
446 * changing the source file. (No problem, you still have one source file
447 * to maintain, not two.)
448 */
449{
450 expression_t *e, *a1, *a2;
451 token_t *t;
452
453 if ((t= get_token(*pn))->symbol == '(') {
454 /* ( expr ): grouping. */
455 (*pn)++;
456 if ((a1= gnu_get_C_expression(pn)) == nil) return nil;
457 if (get_token(*pn)->symbol != ')') {
458 parse_err(1, t, "missing )\n");
459 del_expr(a1);
460 return nil;
461 }
462 (*pn)++;
463 e= new_expr();
464 e->operator= '[';
465 e->middle= a1;
466 } else
467 if (t->type == T_WORD || t->type == T_STRING) {
468 /* Label, number, or string. */
469 e= new_expr();
470 e->operator= t->type == T_WORD ? 'W' : 'S';
471 e->name= allocate(nil, (t->len+1) * sizeof(e->name[0]));
472 memcpy(e->name, t->name , t->len+1);
473 e->len= t->len;
474 (*pn)++;
475 } else
476 if (t->symbol == '+' || t->symbol == '-' || t->symbol == '~') {
477 /* Unary operator. */
478 (*pn)++;
479 if ((a1= gnu_get_C_expression(pn)) == nil) return nil;
480 e= new_expr();
481 e->operator= t->symbol;
482 e->middle= a1;
483 } else {
484 parse_err(1, t, "expression syntax error\n");
485 return nil;
486 }
487
488 switch ((t= get_token(*pn))->symbol) {
489 case '%':
490 case '+':
491 case '-':
492 case '*':
493 case '/':
494 case '&':
495 case '|':
496 case '^':
497 case S_LEFTSHIFT:
498 case S_RIGHTSHIFT:
499 (*pn)++;
500 a1= e;
501 if ((a2= gnu_get_C_expression(pn)) == nil) {
502 del_expr(a1);
503 return nil;
504 }
505 e= new_expr();
506 e->operator= t->symbol;
507 e->left= a1;
508 e->right= a2;
509 }
510 return e;
511}
512
513static expression_t *gnu_get_operand(int *pn, int deref)
514/* Get something like: $immed, memory, offset(%base,%index,scale), or simpler. */
515{
516 expression_t *e, *offset, *base, *index;
517 token_t *t;
518 int c;
519
520 if (get_token(*pn)->symbol == '$') {
521 /* An immediate value. */
522 (*pn)++;
523 return gnu_get_C_expression(pn);
524 }
525
526 if (get_token(*pn)->symbol == '*') {
527 /* Indirection. */
528 (*pn)++;
529 if ((offset= gnu_get_operand(pn, deref)) == nil) return nil;
530 e= new_expr();
531 e->operator= '(';
532 e->middle= offset;
533 return e;
534 }
535
536 if ((get_token(*pn)->symbol == '%')
537 && (t= get_token(*pn + 1))->type == T_WORD
538 && isregister(t->name)
539 ) {
540 /* A register operand. */
541 (*pn)+= 2;
542 e= new_expr();
543 e->operator= 'W';
544 e->name= copystr(t->name);
545 return e;
546 }
547
548 /* Offset? */
549 if (get_token(*pn)->symbol != '('
550 || get_token(*pn + 1)->symbol != '%') {
551 /* There is an offset. */
552 if ((offset= gnu_get_C_expression(pn)) == nil) return nil;
553 } else {
554 /* No offset. */
555 offset= nil;
556 }
557
558 /* (%base,%index,scale) ? */
559 base= index= nil;
560 if (get_token(*pn)->symbol == '(') {
561 (*pn)++;
562
563 /* %base ? */
564 if (get_token(*pn)->symbol == '%'
565 && (t= get_token(*pn + 1))->type == T_WORD
566 && isregister(t->name)
567 ) {
568 /* A base register expression. */
569 base= new_expr();
570 base->operator= 'B';
571 base->name= copystr(t->name);
572 (*pn)+= 2;
573 }
574
575 if (get_token(*pn)->symbol == ',') (*pn)++;
576
577 /* %index ? */
578 if (get_token(*pn)->symbol == '%'
579 && (t= get_token(*pn + 1))->type == T_WORD
580 && isregister(t->name)
581 ) {
582 /* A index register expression. */
583 index= new_expr();
584 index->operator= '1'; /* for now */
585 index->name= copystr(t->name);
586 (*pn)+= 2;
587 }
588
589 if (get_token(*pn)->symbol == ',') (*pn)++;
590
591 /* scale ? */
592 if ((base != nil || index != nil)
593 && (t= get_token(*pn))->type == T_WORD
594 && strchr("1248", t->name[0]) != nil
595 && t->name[1] == 0
596 ) {
597 if (index == nil) {
598 /* Base is really an index register. */
599 index= base;
600 base= nil;
601 }
602 index->operator= t->name[0];
603 (*pn)++;
604 }
605
606 if (get_token(*pn)->symbol == ')') {
607 /* Ending paren. */
608 (*pn)++;
609 } else {
610 /* Alas. */
611 parse_err(1, t, "operand syntax error\n");
612 del_expr(offset);
613 del_expr(base);
614 del_expr(index);
615 return nil;
616 }
617 }
618
619 if (base == nil && index == nil) {
620 if (deref) {
621 /* Return a lone offset as (offset). */
622 e= new_expr();
623 e->operator= '(';
624 e->middle= offset;
625 } else {
626 /* Return a lone offset as is. */
627 e= offset;
628 }
629 } else {
630 e= new_expr();
631 e->operator= 'O';
632 e->left= offset;
633
634 e->middle= base;
635 e->right= index;
636 }
637 return e;
638}
639
640static expression_t *gnu_get_oplist(int *pn, int deref)
641/* Get a comma (or colon for jmpf and callf) separated list of instruction
642 * operands.
643 */
644{
645 expression_t *e, *o1, *o2;
646 token_t *t;
647
648 if ((e= gnu_get_operand(pn, deref)) == nil) return nil;
649
650 if ((t= get_token(*pn))->symbol == ',' || t->symbol == ':') {
651 o1= e;
652 (*pn)++;
653 if ((o2= gnu_get_oplist(pn, deref)) == nil) {
654 del_expr(o1);
655 return nil;
656 }
657 e= new_expr();
658 e->operator= ',';
659 e->left= o1;
660 e->right= o2;
661 }
662 return e;
663}
664
665
666static asm86_t *gnu_get_statement(void)
667/* Get a pseudo op or machine instruction with arguments. */
668{
669 token_t *t= get_token(0);
670 asm86_t *a;
671 mnemonic_t *m;
672 int n;
673 int prefix_seen;
674 int deref;
675
676 assert(t->type == T_WORD);
677
678 a= new_asm86();
679
680 /* Process instruction prefixes. */
681 for (prefix_seen= 0;; prefix_seen= 1) {
682 if (strcmp(t->name, "rep") == 0
683 || strcmp(t->name, "repe") == 0
684 || strcmp(t->name, "repne") == 0
685 || strcmp(t->name, "repz") == 0
686 || strcmp(t->name, "repnz") == 0
687 ) {
688 if (a->rep != ONCE) {
689 parse_err(1, t,
690 "can't have more than one rep\n");
691 }
692 switch (t->name[3]) {
693 case 0: a->rep= REP; break;
694 case 'e':
695 case 'z': a->rep= REPE; break;
696 case 'n': a->rep= REPNE; break;
697 }
698 } else
699 if (!prefix_seen) {
700 /* No prefix here, get out! */
701 break;
702 } else {
703 /* No more prefixes, next must be an instruction. */
704 if (t->type != T_WORD
705 || (m= search_mnem(t->name)) == nil
706 || m->optype == PSEUDO
707 ) {
708 parse_err(1, t,
709 "machine instruction expected after instruction prefix\n");
710 del_asm86(a);
711 return nil;
712 }
713 break;
714 }
715
716 /* Skip the prefix and extra newlines. */
717 do {
718 skip_token(1);
719 } while ((t= get_token(0))->symbol == ';');
720 }
721
722 /* All the readahead being done upsets the line counter. */
723 a->line= t->line;
724
725 /* Read a machine instruction or pseudo op. */
726 if ((m= search_mnem(t->name)) == nil) {
727 parse_err(1, t, "unknown instruction '%s'\n", t->name);
728 del_asm86(a);
729 return nil;
730 }
731 a->opcode= m->opcode;
732 a->optype= m->optype;
733 a->oaz= 0;
734 if (a->optype == OWORD) {
735 a->oaz|= OPZ;
736 a->optype= WORD;
737 }
738
739 switch (a->opcode) {
740 case IN:
741 case OUT:
742 case INT:
743 deref= 0;
744 break;
745 default:
746 deref= (a->optype >= BYTE);
747 }
748 n= 1;
749 if (get_token(1)->symbol != ';'
750 && (a->args= gnu_get_oplist(&n, deref)) == nil) {
751 del_asm86(a);
752 return nil;
753 }
754 if (get_token(n)->symbol != ';') {
755 parse_err(1, t, "garbage at end of instruction\n");
756 del_asm86(a);
757 return nil;
758 }
759 if (!is_pseudo(a->opcode)) {
760 /* GNU operand order is the other way around. */
761 expression_t *e, *t;
762
763 e= a->args;
764 while (e != nil && e->operator == ',') {
765 t= e->right; e->right= e->left; e->left= t;
766 e= e->left;
767 }
768 }
769 switch (a->opcode) {
770 case DOT_ALIGN:
771 /* Delete two argument .align, because ACK can't do it.
772 * Raise 2 to the power of .align's argument.
773 */
774 if (a->args == nil || a->args->operator != 'W') {
775 del_asm86(a);
776 return nil;
777 }
778 if (a->args != nil && a->args->operator == 'W'
779 && isanumber(a->args->name)
780 ) {
781 unsigned n;
782 char num[sizeof(int) * CHAR_BIT / 3 + 1];
783
784 n= 1 << strtoul(a->args->name, nil, 0);
785 sprintf(num, "%u", n);
786 deallocate(a->args->name);
787 a->args->name= copystr(num);
788 }
789 break;
790 case JMPF:
791 case CALLF:
792 /*FALL THROUGH*/
793 case JMP:
794 case CALL:
795 break;
796 default:;
797 }
798 skip_token(n+1);
799 return a;
800}
801
802
803asm86_t *gnu_get_instruction(void)
804{
805 asm86_t *a= nil;
806 expression_t *e;
807 token_t *t;
808
809 while ((t= get_token(0))->symbol == ';' || t->symbol == '/') {
810 zap(); /* if a comment started by a '/' */
811 skip_token(1);
812 }
813
814 if (t->type == T_EOF) return nil;
815
816 if (t->symbol == '#') {
817 /* Preprocessor line and file change. */
818
819 if ((t= get_token(1))->type != T_WORD || !isanumber(t->name)
820 || get_token(2)->type != T_STRING
821 ) {
822 parse_err(1, t, "file not preprocessed?\n");
823 zap();
824 } else {
825 set_file(get_token(2)->name,
826 strtol(get_token(1)->name, nil, 0) - 1);
827
828 /* GNU CPP adds extra cruft, simply zap the line. */
829 zap();
830 }
831 a= gnu_get_instruction();
832 } else
833 if (t->type == T_WORD && get_token(1)->symbol == ':') {
834 /* A label definition. */
835
836 a= new_asm86();
837 a->line= t->line;
838 a->opcode= DOT_LABEL;
839 a->optype= PSEUDO;
840 a->args= e= new_expr();
841 e->operator= ':';
842 e->name= copystr(t->name);
843 skip_token(2);
844 } else
845 if (t->type == T_WORD && get_token(1)->symbol == '=') {
846 int n= 2;
847
848 if ((e= gnu_get_C_expression(&n)) == nil) {
849 zap();
850 a= gnu_get_instruction();
851 } else
852 if (get_token(n)->symbol != ';') {
853 parse_err(1, t, "garbage after assignment\n");
854 zap();
855 a= gnu_get_instruction();
856 } else {
857 a= new_asm86();
858 a->line= t->line;
859 a->opcode= DOT_EQU;
860 a->optype= PSEUDO;
861 a->args= new_expr();
862 a->args->operator= '=';
863 a->args->name= copystr(t->name);
864 a->args->middle= e;
865 skip_token(n+1);
866 }
867 } else
868 if (t->type == T_WORD) {
869 if ((a= gnu_get_statement()) == nil) {
870 zap();
871 a= gnu_get_instruction();
872 }
873 } else {
874 parse_err(1, t, "syntax error\n");
875 zap();
876 a= gnu_get_instruction();
877 }
878 return a;
879}
Note: See TracBrowser for help on using the repository browser.