1 /* ccg.c -- preprocessor for dynamic assemblers
2 *
3 * Copyright (C) 1999, 2000 Ian Piumarta <ian.piumarta@inria.fr>
4 *
5 * This file is part of CCG.
6 *
7 * CCG is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * CCG is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * See the file COPYING for more details.
17 *
18 * Last edited: Thu Jan 13 12:02:56 2000 by piumarta (Ian Piumarta) on pingu
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <ctype.h>
25 #include <string.h>
26
27 #ifdef __STRICT_ANSI__
28 /* a BSD function not declared in ANSI string.h */
29 extern int strcasecmp();
30 #endif
31
32 #if defined(sun) && defined(__sparc__)
33 # include <errno.h>
34 # if !defined(ECHRNG)
35 /* Poor old SunOS needs a little coaxing along */
36 extern int vfprintf();
37 extern int bcopy();
38 extern int strcasecmp();
39 # define memmove(d,s,l) bcopy(s,d,l)
40 # endif
41 #endif
42
43 #define REWRITE_PSEUDO_ARGS
44
45 #define HEADER_PREFIX "ccg/asm-"
46 #define LABEL_CHARS "_A-Za-z0-9"
47
48 #define ASM_1_OPEN "#["
49 #define ASM_1_CLOSE "]#"
50 #define ASM_2_OPEN "#{"
51 #define ASM_2_CLOSE "}#"
52
53 #define REG_OPEN "#("
54 #define REG_CLOSE ")#"
55
56 char commentChar= '#';
57 char escapeChar= '!';
58
59 #define ASM_1_BEGIN "_ASM_APP_1"
60 #define ASM_1_END "_ASM_NOAPP_1"
61 #define ASM_2_BEGIN "_ASM_APP_2"
62 #define ASM_2_END "_ASM_NOAPP_2"
63
64 #define ASM_ORG "_ASM_ORG"
65 #define ASM_LBL "_ASM_LBL"
66 #define ASM_DEF "_ASM_DEF"
67
68 char *fileName= 0;
69 int lineNo= 0;
70 char line[256];
71
72 int quiet= 0;
73 int dodot= 1;
74 int check_insns= 1;
75
76 int asmFwdWarned= 0;
77
78 char **insn_tab= 0;
79
80 typedef char *(*rewriter)(int code);
81
82 extern rewriter rewrite;
83
warning(char * fmt,...)84 void warning(char *fmt, ...)
85 {
86 if (!quiet) {
87 va_list ap;
88 if (fileName) fprintf(stderr, "%s:%d: warning: ", fileName, lineNo);
89 va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
90 fprintf(stderr, "\n");
91 if (fileName) fprintf(stderr, "%s:%d: %s\n", fileName, lineNo, line);
92 }
93 }
94
error(char * fmt,...)95 void error(char *fmt, ...)
96 {
97 va_list ap;
98 if (fileName) fprintf(stderr, "%s:%d: error: ", fileName, lineNo);
99 va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap);
100 fprintf(stderr, "\n");
101 if (fileName) fprintf(stderr, "%s:%d: %s\n", fileName, lineNo, line);
102 exit(1);
103 }
104
usage(char * progName)105 void usage(char *progName)
106 {
107 fprintf(stderr,
108 CCGVERSION" Copyright (C) 1999, 2000 Ian Piumarta <ian.piumarta@inria.fr>\n"
109 "Usage: %s [<option>* fileName]+\n"
110 "where <option> is one of:\n"
111 " -c <char> change the comment delimiter from the default `%c'\n"
112 " -e <char> change the escape character from the default `%c'\n"
113 " -n disable opcode/operand validation\n"
114 " -o <fileName> start a new output file (`-' means stdout)\n"
115 " -q quiet (suppress forward reference warning messages)\n"
116 "Multiple input files are concatenated onto the current output file unless\n"
117 "redirected with -o. The initial output file is stdout.\n",
118 progName, commentChar, escapeChar);
119 exit(1);
120 }
121
122 int inAsm= 0;
123
124 char lb[256];
125 char op[256];
126 char ox[256], *oxp;
127 char a1[256];
128 char a2[256];
129 char a3[256];
130 char a4[256];
131 char a5[256]; /* PowerPC requires up to 5 operands */
132
133 /*
134 * rewriting -- support
135 */
136
check_insn(char * insn)137 void check_insn(char *insn)
138 {
139 char **i;
140 for (i= insn_tab; *i != (char *)0; ++i)
141 if (!strcmp(*i, insn)) return;
142 error("unrecognised instruction: %s", insn);
143 }
144
upcase(char * ptr,int n)145 void upcase(char *ptr, int n)
146 {
147 while (n--) {
148 *ptr= toupper(*ptr);
149 ++ptr;
150 }
151 }
152
insert(char * dest,char * src)153 char *insert(char *dest, char *src)
154 {
155 int destLen= strlen(dest);
156 int srcLen= strlen(src);
157 memmove(dest + srcLen, dest, destLen + 1);
158 memcpy(dest, src, srcLen);
159 return dest + srcLen;
160 }
161
delete(char * dest,int n)162 void delete(char *dest, int n)
163 {
164 memcpy(dest, dest + n, strlen(dest) - n + 1);
165 }
166
skipParens(char * arg)167 char *skipParens(char *arg)
168 {
169 int nest= 0;
170 for (;;) {
171 int c= *arg++;
172 if (c == 0) {
173 if (nest > 0) error("mismatched parentheses");
174 return arg - 1;
175 }
176 if ((c == '(') || (c == '['))
177 ++nest;
178 else
179 if ((c == ')') || (c == ']')) {
180 if (nest == 0)
181 return arg - 1;
182 else
183 if (--nest == 0)
184 return arg;
185 }
186 }
187 return arg;
188 }
189
skipDigits(char * arg)190 char *skipDigits(char *arg)
191 {
192 while (isdigit(*arg)) ++arg;
193 return arg;
194 }
195
is_alnum(char c)196 int is_alnum(char c) { return isalnum(c) || c == '_'; }
isopchar(char c)197 int isopchar(char c) { return is_alnum(c) || c == ',' || c == '.'; }
198
199 /*
200 * rewriting -- Intel
201 *
202 * OPCODE + i = immediate operand
203 * + r = register operand
204 * + m = memory operand (rewrite to: disp,base,index,scale)
205 */
206
rewrite_i386_reg(char * arg)207 char *rewrite_i386_reg(char *arg)
208 {
209 if (*arg == '(') return skipParens(arg);
210
211 /* in approximate order of likely usage */
212
213 /* 32-bit registers */
214 if (!strncmp(arg, "eax", 3)) { delete(arg, 3); arg= insert(arg, "_EAX"); }
215 else if (!strncmp(arg, "ecx", 3)) { delete(arg, 3); arg= insert(arg, "_ECX"); }
216 else if (!strncmp(arg, "edx", 3)) { delete(arg, 3); arg= insert(arg, "_EDX"); }
217 else if (!strncmp(arg, "ebx", 3)) { delete(arg, 3); arg= insert(arg, "_EBX"); }
218 else if (!strncmp(arg, "esp", 3)) { delete(arg, 3); arg= insert(arg, "_ESP"); }
219 else if (!strncmp(arg, "ebp", 3)) { delete(arg, 3); arg= insert(arg, "_EBP"); }
220 else if (!strncmp(arg, "esi", 3)) { delete(arg, 3); arg= insert(arg, "_ESI"); }
221 else if (!strncmp(arg, "edi", 3)) { delete(arg, 3); arg= insert(arg, "_EDI"); }
222 /* 8-bit registers */
223 else if (!strncmp(arg, "al", 2)) { delete(arg, 2); arg= insert(arg, "_AL"); }
224 else if (!strncmp(arg, "cl", 2)) { delete(arg, 2); arg= insert(arg, "_CL"); }
225 else if (!strncmp(arg, "dl", 2)) { delete(arg, 2); arg= insert(arg, "_DL"); }
226 else if (!strncmp(arg, "bl", 2)) { delete(arg, 2); arg= insert(arg, "_BL"); }
227 else if (!strncmp(arg, "ah", 2)) { delete(arg, 2); arg= insert(arg, "_AH"); }
228 else if (!strncmp(arg, "ch", 2)) { delete(arg, 2); arg= insert(arg, "_CH"); }
229 else if (!strncmp(arg, "dh", 2)) { delete(arg, 2); arg= insert(arg, "_DH"); }
230 else if (!strncmp(arg, "bh", 2)) { delete(arg, 2); arg= insert(arg, "_BH"); }
231 /* 16-bit registers */
232 else if (!strncmp(arg, "ax", 2)) { delete(arg, 2); arg= insert(arg, "_AX"); }
233 else if (!strncmp(arg, "cx", 2)) { delete(arg, 2); arg= insert(arg, "_CX"); }
234 else if (!strncmp(arg, "dx", 2)) { delete(arg, 2); arg= insert(arg, "_DX"); }
235 else if (!strncmp(arg, "bx", 2)) { delete(arg, 2); arg= insert(arg, "_BX"); }
236 else if (!strncmp(arg, "sp", 2)) { delete(arg, 2); arg= insert(arg, "_SP"); }
237 else if (!strncmp(arg, "bp", 2)) { delete(arg, 2); arg= insert(arg, "_BP"); }
238 else if (!strncmp(arg, "si", 2)) { delete(arg, 2); arg= insert(arg, "_SI"); }
239 else if (!strncmp(arg, "di", 2)) { delete(arg, 2); arg= insert(arg, "_DI"); }
240 /* special registers would go here... */
241 else
242 error("unknown register name: %s", arg);
243 return arg;
244 }
245
rewrite_i386_mem(char * arg)246 char *rewrite_i386_mem(char *arg)
247 {
248 /* deference */
249 if (arg[0] == '*') {
250 if (arg[1] != '%') error("bad register in *%%reg");
251 *arg++= '0'; /* disp */
252 *arg++= ',';
253 arg= rewrite_i386_reg(arg); /* base */
254 if (*arg != '\0') error("junk after *%%reg");
255 return insert(arg, ",0,0"); /* index, scale */
256 }
257 /* displacement */
258 if (*arg == '(') {
259 if (arg[1] == '%') {
260 /* (base...) */
261 arg= insert(arg, "0");
262 } else {
263 /* (disp)... */
264 arg= skipParens(arg);
265 }
266 } else {
267 /* disp... */
268 while (*arg != '\0' && *arg != '(') ++arg;
269 }
270 if (*arg == '\0') {
271 /* absolute address */
272 return insert(arg, ",0,0,0");
273 }
274 if (*arg != '(') error("junk after absolute address");
275 delete(arg, 1); /* '(' */
276 arg= insert(arg, ",");
277 if (*arg != '%') {
278 while (*arg != '\0' && *arg != ',' && *arg != ')') ++arg;
279 } else {
280 delete(arg, 1);
281 arg= rewrite_i386_reg(arg);
282 }
283 if (*arg == '\0') error("missing close parenthesis in disp(base))");
284 if (*arg == ')') {
285 delete(arg, 1);
286 if (*arg != '\0') error("junk after disp(base)");
287 return insert(arg, ",0,0");
288 }
289 if (*arg != ',') error("missing comma in disp(base,index)");
290 ++arg;
291 if (*arg == '\0') error("missing index in disp(base,index)");
292 if (*arg != '%') {
293 while (*arg != '\0' && *arg != ',' && *arg != ')') ++arg;
294 } else {
295 delete(arg, 1);
296 arg= rewrite_i386_reg(arg);
297 }
298 if (*arg == '\0') error("missing close parenthesis in disp(base,index)");
299 if (*arg == ')') {
300 delete(arg, 1);
301 if (*arg != '\0') error("junk after disp(base)");
302 return insert(arg, ",1");
303 }
304 if (*arg != ',') error("missing comma in disp(base,index,scale)");
305 ++arg;
306 if (*arg == '\0') error("missing scale in disp(base,index,scale)");
307 if (*arg != '%') {
308 while (*arg != '\0' && *arg != ',' && *arg != ')') ++arg;
309 } else {
310 delete(arg, 1);
311 arg= rewrite_i386_reg(arg);
312 }
313 if (*arg != ')') error("missing close parenthesis in disp(base,index,scale)");
314 delete(arg, 1);
315 return arg;
316 }
317
rewrite_i386_arg(char * arg,int argind)318 char *rewrite_i386_arg(char *arg, int argind)
319 {
320 if (*arg == '\0') return arg;
321 /* immediate */
322 if (arg[0] == '$') {
323 oxp+= sprintf(oxp, "i");
324 delete(arg, 1);
325 return arg;
326 }
327 /* register */
328 if (arg[0] == '%') {
329 oxp+= sprintf(oxp, "r");
330 delete(arg, 1);
331 rewrite_i386_reg(arg);
332 return arg;
333 }
334 /* memory */
335 oxp+= sprintf(oxp, "m");
336 rewrite_i386_mem(arg);
337 return arg;
338 }
339
340 char *(i386_insns[])= {
341 #include "insns-i386.h"
342 (char *)0
343 };
344
rewrite_i386(int code)345 char *rewrite_i386(int code)
346 {
347 if (code == 0) {
348 insn_tab= i386_insns;
349 return "i386";
350 }
351 if (code == 1) {
352 if (a1[0] != '%') error("malformed register expression");
353 delete(a1, 1);
354 return rewrite_i386_reg(a1);
355 }
356 rewrite_i386_arg(a1, 1);
357 rewrite_i386_arg(a2, 2);
358 rewrite_i386_arg(a3, 3);
359 return 0;
360 }
361
362 /*
363 * rewriting -- PowerPC
364 *
365 * <imm> = [0-9]+ | (.+) -> i(imm)
366 * <imm> = <imm>@FN -> i(_FN(imm)) // for varName@ha, etc...
367 * <reg> = r<imm> -> r(imm)
368 * <mem> = <imm>(<reg>) -> m(imm,reg)
369 * <idx> = <reg>(<reg>) -> x(reg,reg)
370 *
371 */
372
is_ppc_reg(char * arg)373 int is_ppc_reg(char *arg)
374 {
375 return ((arg[0] == 'r') && ((arg[1] == '(') || isdigit(arg[1])));
376 }
377
rewrite_ppc_imm(char * arg,int argind)378 char *rewrite_ppc_imm(char *arg, int argind)
379 {
380 int c= *arg;
381 if (isdigit(c) || (c == '-' && isdigit(arg[1]))) {
382 /* numeric */
383 while (isdigit(*++arg));
384 } else if (isalpha(c) || (c == '_')) {
385 /* macro */
386 while (isalnum(*arg) || (*arg == '_')) ++arg;
387 if (*arg == '(') {
388 if (is_ppc_reg(arg + 1)) return arg; /* done imm part of mem */
389 /* macro(arg) */
390 arg= skipParens(arg);
391 }
392 } else if (*arg == '(') {
393 /* expression */
394 arg= skipParens(arg);
395 } else {
396 error("unrecognised operand, position %d", argind);
397 }
398 return arg;
399 }
400
rewrite_ppc_reg(char * arg,int argind)401 char *rewrite_ppc_reg(char *arg, int argind)
402 {
403 if (!is_ppc_reg(arg)) error("malformed register operand, position %d", argind);
404 delete(arg, 1);
405 return rewrite_ppc_imm(arg, argind);
406 }
407
rewrite_ppc_arg(char * arg,int argind)408 char *rewrite_ppc_arg(char *arg, int argind)
409 {
410 int immediate= 0;
411 if (*arg == '\0') return arg;
412 if (is_ppc_reg(arg)) {
413 /* register */
414 arg= rewrite_ppc_reg(arg, argind);
415 } else {
416 /* immediate */
417 char *base= arg;
418 immediate= 1;
419 arg= rewrite_ppc_imm(arg, argind);
420 while (*arg == '@') {
421 char fnName[64];
422 char *in= arg + 1, *out= fnName;
423 *out++= '_'; /* prefix FN with '_' (replaces '@' from arg) */
424 while (isalpha(*in) || *in == '_')
425 *out++= toupper(*in++);
426 *out= '\0';
427 {
428 int len= out - fnName;
429 if (len < 2) /* only got the _ */
430 error("malformed immediate modifier, position %d", argind);
431 delete(arg, len); /* drop '@' + FN */
432 insert(base, "(");
433 arg+= 1;
434 insert(base, fnName);
435 arg+= len;
436 arg= insert(arg, ")");
437 }
438 }
439 }
440 if (*arg != '(') {
441 /* non-memory */
442 if (*arg != '\0') {
443 error("junk after %s operand, position %d",
444 (immediate ? "immediate" : "register"), argind);
445 }
446 if (immediate) {
447 oxp+= sprintf(oxp, "i");
448 return arg;
449 }
450 oxp+= sprintf(oxp, "r");
451 return arg;
452 }
453 /* memory */
454 *arg++= ',';
455 arg= rewrite_ppc_reg(arg, argind);
456 if (*arg != ')') error("junk after index register, position %d", argind);
457 delete(arg, 1);
458 if (*arg != '\0') error("junk after memory operand, position %d", argind);
459 if (immediate) {
460 oxp+= sprintf(oxp, "m");
461 } else {
462 oxp+= sprintf(oxp, "x");
463 }
464 return arg;
465 }
466
467 char *(ppc_insns[])= {
468 #include "insns-ppc.h"
469 (char *)0
470 };
471
rewrite_ppc(int code)472 char *rewrite_ppc(int code)
473 {
474 if (code == 0) {
475 insn_tab= ppc_insns;
476 return "ppc";
477 }
478 if (code == 1) {
479 return rewrite_ppc_reg(a1, 1);
480 }
481 rewrite_ppc_arg(a1, 1);
482 rewrite_ppc_arg(a2, 2);
483 rewrite_ppc_arg(a3, 3);
484 rewrite_ppc_arg(a4, 4);
485 rewrite_ppc_arg(a5, 5);
486 return 0;
487 }
488
489 /*
490 * rewriting -- Sparc
491 *
492 * %reg -> r(R)
493 * imm -> i(I)
494 * [%reg+%reg] -> x(R,R)
495 * [%reg+/-imm] -> m(R,I)
496 *
497 */
498
is_sparc_r(char c)499 int is_sparc_r(char c)
500 {
501 return c == 'r' || c == 'g' || c == 'o' || c == 'l' || c == 'i';
502 }
503
rewrite_sparc_reg(char * arg)504 char *rewrite_sparc_reg(char *arg)
505 {
506 if (!strncmp(arg, "fp",2)) { /* %i6 == %30 */
507 delete(arg, 2);
508 return insert(arg, "30");
509 }
510 if (!strncmp(arg, "sp",2)) { /* %o6 == %14 */
511 delete(arg, 2);
512 return insert(arg, "14");
513 }
514 if (is_sparc_r(arg[0]) && (((arg[1] >= '0') && (arg[1] <= '7')) || (arg[1] == '('))) {
515 switch (*arg) {
516 case 'r': delete(arg, 1); arg= insert(arg, "0+"); break;
517 case 'g': delete(arg, 1); arg= insert(arg, "0+"); break;
518 case 'o': delete(arg, 1); arg= insert(arg, "8+"); break;
519 case 'l': delete(arg, 1); arg= insert(arg, "16+"); break;
520 case 'i': delete(arg, 1); arg= insert(arg, "24+"); break;
521 default:
522 error("THIS CANNOT HAPPEN");
523 }
524 }
525 if (*arg == '(') return skipParens(arg);
526 while (isdigit(*arg)) ++arg;
527 return arg;
528 }
529
rewrite_sparc_mem(char * arg)530 char *rewrite_sparc_mem(char *arg)
531 {
532 /* need to suffix op with m (immediate index) or x (register index) */
533 /* return arg -> ']' */
534 if (arg[0] != '%') error("missing base register in memory operand");
535 delete(arg, 1);
536 arg= rewrite_sparc_reg(arg);
537 if (*arg == ']') {
538 /* no index: use immediate zero */
539 oxp+= sprintf(oxp, "m");
540 arg= insert(arg, ",0");
541 return arg;
542 }
543 if (*arg == '+' && arg[1] == '%') {
544 /* [%reg+%reg] */
545 oxp+= sprintf(oxp, "x");
546 *arg++= ',';
547 delete(arg, 1); /* % */
548 return rewrite_sparc_reg(arg);
549 }
550 if (*arg == '+' || *arg == '-') {
551 /* [%reg+/-offset] */
552 oxp+= sprintf(oxp, "m");
553 arg= insert(arg, ",");
554 return skipParens(arg);
555 }
556 return arg;
557 }
558
rewrite_sparc_arg(char * arg)559 char *rewrite_sparc_arg(char *arg)
560 {
561 if (*arg == '\0') return arg;
562 /* pseudo-ops %hi() and %lo() */
563 if (!strncmp(arg, "%hi(", 4)) {
564 *arg++= '_';
565 *arg++= 'H';
566 *arg++= 'I';
567 goto immediate;
568 }
569 if (!strncmp(arg, "%lo(", 4)) {
570 *arg++= '_';
571 *arg++= 'L';
572 *arg++= 'O';
573 goto immediate;
574 }
575 /* register */
576 if (*arg == '%') {
577 oxp+= sprintf(oxp, "r");
578 delete(arg, 1);
579 arg= rewrite_sparc_reg(arg);
580 if (*arg != '\0') error("junk after register operand");
581 return arg;
582 }
583 /* memory */
584 if (*arg == '[') {
585 delete(arg, 1);
586 arg= rewrite_sparc_mem(arg);
587 if (*arg != ']') error("malformed memory operand");
588 delete(arg, 1);
589 if (*arg != '\0') error("junk after memory operand");
590 return arg;
591 }
592 /* immediate */
593 immediate:
594 oxp+= sprintf(oxp, "i");
595 while (*arg != '\0') ++arg;
596 return arg;
597 }
598
599 char *(sparc_insns[])= {
600 #include "insns-sparc.h"
601 (char *)0
602 };
603
rewrite_sparc(int code)604 char *rewrite_sparc(int code)
605 {
606 if (code == 0) {
607 insn_tab= sparc_insns;
608 return "sparc";
609 }
610 if (code == 1) {
611 if (a1[0] != '%') error("malformed register expression");
612 delete(a1, 1);
613 return rewrite_sparc_reg(a1);
614 }
615 rewrite_sparc_arg(a1);
616 rewrite_sparc_arg(a2);
617 rewrite_sparc_arg(a3);
618 return 0;
619 }
620
621 /*
622 * rewriting -- Others (as yet unimplemented)
623 */
624
rewrite_null(int code)625 char *rewrite_null(int code)
626 {
627 error("missing #cpu declaration");
628 return 0;
629 }
630
631 rewriter rewrite_alpha= rewrite_null;
632 rewriter rewrite_hppa= rewrite_null;
633 rewriter rewrite_mips= rewrite_null;
634 rewriter rewrite_m68k= rewrite_null;
635
636 rewriter rewrite= rewrite_null;
637
638 #if defined(PPC) || defined(_POWER) || defined(_IBMR2)
639 # define localRewrite rewrite_ppc
640 #elif defined(__sparc__)
641 # define localRewrite rewrite_sparc
642 #elif defined(__alpha__)
643 # define localRewrite rewrite_alpha
644 #elif defined(__hppa__)
645 # define localRewrite rewrite_hppa
646 #elif defined(__mips__)
647 # define localRewrite rewrite_mips
648 #elif defined(__mc68000__)
649 # define localRewrite rewrite_m68k
650 #elif defined(__i386__)
651 # define localRewrite rewrite_i386
652 #else
653 # define localRewrite rewrite_null
654 #endif
655
656
657 /*
658 * assembler statement parsing
659 */
660
eatSpaces(char * in)661 char *eatSpaces(char *in)
662 {
663 while (isspace(*in)) ++in;
664 if (*in == commentChar) {
665 if (!isspace(in[1]))
666 warning("POSSIBLE UNINTENTIONAL COMMENT"); /* sometimes serious if not caught */
667 *in= '\0';
668 }
669 return in;
670 }
671
eatOpcode(char * in,char * opp)672 char *eatOpcode(char *in, char *opp)
673 {
674 int c;
675 in= eatSpaces(in);
676 while (isopchar(c= *in++)) {
677 if (c == ',') c= '_'; /* sparc */
678 if (c == '.') c= '_'; /* ppc and pseudo */
679 *opp++= c;
680 }
681 --in;
682 upcase(op, opp - op);
683 *opp= '\0';
684 return eatSpaces(in);
685 }
686
eatArg(char * in,char * out)687 char *eatArg(char *in, char *out)
688 {
689 int nest= 0;
690 int inString= 0;
691 in= eatSpaces(in);
692 for (;;) {
693 char c= *in++;
694 if (c == 0 || c == '\n') { --in; break; }
695 else if (c == commentChar && nest == 0) { --in; break; }
696 else if (c <= ' ' && !inString) continue;
697 else if (c == '\"') inString= !inString;
698 else if (c == '(' || c == '[') ++nest;
699 else if (c == ')' || c == ']') --nest;
700 else if (c == ',' && nest == 0) break;
701 if (c == '.' && dodot)
702 out+= sprintf(out, "asm_pc");
703 else
704 *out++= c;
705 }
706 if (nest != 0) error("mismatched parentheses");
707 *out= '\0';
708 return eatSpaces(in);
709 }
710
assemble(char * line)711 char *assemble(char *line)
712 {
713 static char buf[256];
714 static char arg[256];
715 static char tmp[256];
716 char *out= buf;
717 int width= 0;
718 int continued= 0;
719
720 if (strlen(line) == 0) return line;
721 line= eatSpaces(line);
722 if (*line == escapeChar) {
723 return line + 1;
724 }
725 if (line[strlen(line) - 1] == '\\') {
726 continued= 1;
727 line[strlen(line) - 1]= '\0';
728 }
729 line= eatSpaces(line);
730 *out= '\0';
731 if (line[0] == '\0') return (continued ? "\\" : "");
732 while (2 == sscanf(line, "%["LABEL_CHARS"]%[:]%n", arg, tmp, &width)) {
733 out+= sprintf(out, " "ASM_DEF"(%s);", arg);
734 line= eatSpaces(line + width);
735 }
736 /* pseudo-ops: .org and .label are intrinsic, all others are platdep */
737 if ((!strncmp(line, ".org", 4)) && isspace(line[4])) {
738 line= eatArg(line + 5, a1);
739 if (*line != '\0') error("junk after origin expression");
740 out+= sprintf(out, " "ASM_ORG"(%s);", a1);
741 if (continued) out+= sprintf(out, "\\");
742 return buf;
743 } else
744 if ((!strncmp(line, ".label", 6)) && isspace(line[6])) {
745 line= eatSpaces(line + 7);
746 if (*line == '\0') error("missing label list");
747 while ((*arg= '\0'),
748 sscanf(line, "%["LABEL_CHARS"]%n", arg, &width),
749 (*arg != '\0')) {
750 out+= sprintf(out, " "ASM_LBL"(%s);", arg);
751 line= eatSpaces(line + width);
752 if (*line == '\0') {
753 if (continued) out+= sprintf(out, "\\");
754 return buf;
755 }
756 if (*line != ',') error("junk in label list");
757 line= eatSpaces(line + 1);
758 }
759 error("illegal label name");
760 }
761 /* opcode [operands...] */
762 line= eatOpcode(line, op);
763 line= eatArg(line, a1);
764 line= eatArg(line, a2);
765 line= eatArg(line, a3);
766 line= eatArg(line, a4);
767 line= eatArg(line, a5);
768 if (op[0]) {
769 *(oxp= ox)= '\0';
770 #ifdef REWRITE_PSEUDO_ARGS
771 rewrite(2);
772 #else
773 /* don't rewrite pseudo-ops */
774 if (op[0] == '_') {
775 if (a1[0]) *oxp++= 'o';
776 if (a2[0]) *oxp++= 'o';
777 if (a3[0]) *oxp++= 'o';
778 if (a4[0]) *oxp++= 'o';
779 if (a5[0]) *oxp++= 'o';
780 } else {
781 rewrite(2);
782 }
783 #endif
784 strcat(op, ox);
785 if (check_insns && op[0] != '_') check_insn(op);
786 out+= sprintf(out, "\t%s", op);
787 out+= sprintf(out, "\t(");
788 if (a1[0]) out+= sprintf(out, "%s", a1);
789 if (a2[0]) out+= sprintf(out, ", %s", a2);
790 if (a3[0]) out+= sprintf(out, ", %s", a3);
791 if (a4[0]) out+= sprintf(out, ", %s", a4);
792 if (a5[0]) out+= sprintf(out, ", %s", a5);
793 out+= sprintf(out, "); ");
794 }
795 if (continued) out+= sprintf(out, "\\");
796 return buf;
797 }
798
799 /*
800 * shell
801 */
802
selectCPU(char * arch,rewriter rw)803 void selectCPU(char *arch, rewriter rw)
804 {
805 if (rw == rewrite_null) error("%s is not supported", arch);
806 if (rewrite != rewrite_null && rewrite != rw)
807 error("conflicting #cpu declarations");
808 if (rw != localRewrite)
809 warning("foreign cpu type selected");
810 rewrite= rw;
811 }
812
chooseCPU(char * arg)813 void chooseCPU(char *arg)
814 {
815 if
816 (!strcasecmp(arg, "default")) selectCPU("default", localRewrite);
817 else if
818 (!strcasecmp(arg, "ppc") ||
819 !strcasecmp(arg, "power") ||
820 !strcasecmp(arg, "powerpc") ||
821 !strcasecmp(arg, "rs6000")) selectCPU("PowerPC", rewrite_ppc);
822 else if
823 (!strcasecmp(arg, "sparc")) selectCPU("Sparc", rewrite_sparc);
824 else if
825 (!strcasecmp(arg, "alpha") ||
826 !strcasecmp(arg, "axp")) selectCPU("Alpha", rewrite_alpha);
827 else if
828 (!strcasecmp(arg, "hppa")) selectCPU("HP-PA", rewrite_hppa);
829 else if
830 (!strcasecmp(arg, "mips")) selectCPU("MIPS", rewrite_mips);
831 else if
832 (!strcasecmp(arg, "68k") ||
833 !strcasecmp(arg, "m68k") ||
834 !strcasecmp(arg, "mc68k") ||
835 !strcasecmp(arg, "68000") ||
836 !strcasecmp(arg, "m68000") ||
837 !strcasecmp(arg, "mc68000")) selectCPU("M68K", rewrite_m68k);
838 else if
839 (!strcasecmp(arg, "i386") || !strcasecmp(arg, "386") ||
840 !strcasecmp(arg, "i486") || !strcasecmp(arg, "486") ||
841 !strcasecmp(arg, "i586") || !strcasecmp(arg, "586") ||
842 !strcasecmp(arg, "pentium") ||
843 !strcasecmp(arg, "intel") ||
844 !strcasecmp(arg, "ia32")) selectCPU("i386", rewrite_i386);
845 else
846 error("unknown architecture");
847 }
848
process(char * line,FILE * out)849 void process(char *line, FILE *out)
850 {
851 char arg[256];
852 if (*line == '\0') return;
853 if (*line == '\n') {
854 fprintf(out, line);
855 return;
856 }
857 line[strlen(line) - 1]= '\0'; /* zap newline */
858 if (!inAsm && (line[0] == '#')) {
859 if (!strncmp(line, "#cpu", 4)) {
860 if (sscanf(line, "#cpu %s", arg) != 1)
861 error("missing architecture name");
862 chooseCPU(arg);
863 fprintf(out, "#include \""HEADER_PREFIX"%s.h\" /* #cpu %s */\n",
864 rewrite(0), arg);
865 return;
866 }
867 if (!strncmp(line, "#quiet", 6)) {
868 if (inAsm) quiet= 2; else quiet= 1;
869 fprintf(out, "/* #quiet */\n");
870 return;
871 }
872 if (!strncmp(line, "#nodot", 6)) {
873 dodot= 0;
874 fprintf(out, "/* #nodot */\n");
875 return;
876 }
877 if (!strncmp(line, "#localpc", 8)) {
878 fprintf(out, "#define _ASM_LOCALPC /* #localpc */\n");
879 return;
880 }
881 if (sscanf(line, "#comment %s", arg)) {
882 commentChar= *arg;
883 fprintf(out, "/* #comment %c */\n", commentChar);
884 return;
885 }
886 if (sscanf(line, "#escape %s", arg)) {
887 escapeChar= *arg;
888 fprintf(out, "/* #escape %c */\n", escapeChar);
889 return;
890 }
891 }
892 for (;;) {
893 if (!inAsm) {
894 char *delim= 0, save= 0;
895 if ((delim= strstr(line, REG_OPEN)) != 0) {
896 char *delim2= 0;
897 save= *delim;
898 *delim= '\0';
899 fprintf(out, "%s", line);
900 *delim= save;
901 line= delim + strlen(REG_OPEN);
902 if ((delim2= strstr(line, REG_CLOSE)) == 0)
903 error("missing closing delimiter in register expression");
904 save= *delim2;
905 *delim2= '\0';
906 line= eatArg(line, a1);
907 *delim2= save;
908 oxp= op;
909 rewrite(1);
910 fprintf(out, "(%s)", a1);
911 if (line != strstr(line, REG_CLOSE)) error("bad register expression");
912 line+= strlen(REG_CLOSE);
913 continue;
914 }
915 if ((delim= strstr(line, ASM_1_OPEN)) != 0) {
916 inAsm= 1;
917 } else {
918 if ((delim= strstr(line, ASM_2_OPEN)) != 0) {
919 inAsm= 2;
920 } else {
921 fprintf(out, "%s\n", line);
922 return;
923 }
924 }
925 save= *delim;
926 *delim= '\0';
927 fprintf(out, "%s %s ", line,
928 ((inAsm == 2) ? ASM_2_BEGIN : ASM_1_BEGIN));
929 asmFwdWarned= 0;
930 line= delim + 2;
931 *delim= save;
932 }
933 /* assembling */
934 {
935 char *delim= 0, save= 0;
936 if ((delim= strstr(line, ASM_1_CLOSE)) != 0) {
937 if (inAsm != 1) error("mismatched assembler delimiters");
938 } else {
939 if ((delim= strstr(line, ASM_2_CLOSE)) != 0) {
940 if (inAsm != 2) error("mismatched assembler delimiters");
941 } else {
942 fprintf(out, "%s\n", assemble(line));
943 return;
944 }
945 }
946 save= *delim;
947 *delim= '\0';
948 fprintf(out, " %s%s", assemble(line),
949 ((inAsm == 1) ? ASM_1_END : ASM_2_END));
950 line= delim+2;
951 *delim= save;
952 inAsm= 0;
953 }
954 }
955 }
956
newOutput(FILE * out)957 void newOutput(FILE *out)
958 {
959 #if 0
960 fprintf(out,
961 "/****************************************************************************\n"
962 " THIS FILE WAS GENERATED AUTOMATICALLY -- DO NOT EDIT IT!\n"
963 "****************************************************************************/\n");
964 #endif
965 }
966
967 /*
968 * driver
969 */
970
main(int argc,char ** argv)971 int main(int argc, char **argv)
972 {
973 char *progName= *argv++;
974 FILE *in= 0, *out= 0;
975
976 {
977 char *ptr= progName;
978 do
979 if (*ptr++ == '/') progName= ptr;
980 while (*ptr);
981 }
982
983 if (argc < 2) usage(progName);
984
985 while (--argc) {
986 lineNo= 0;
987 fileName= 0;
988
989 if (!strcmp(*argv, "-o")) {
990 char *outFile;
991 if (out) fclose(out);
992 if (!argc--) error("file name missing after \"-o\"");
993 outFile= *++argv;
994 if (!strcmp(outFile, "-"))
995 out= 0;
996 else {
997 out= fopen(outFile, "w");
998 if (!out) error("can't open output file: %s", outFile);
999 newOutput(out);
1000 }
1001 ++argv;
1002 continue;
1003 }
1004
1005 if (!strcmp(*argv, "-c")) {
1006 if (!argc--) error("character missing after \"-c\"");
1007 commentChar= **++argv;
1008 ++argv;
1009 continue;
1010 }
1011
1012 if (!strcmp(*argv, "-e")) {
1013 if (!argc--) error("character missing after \"-v\"");
1014 escapeChar= **++argv;
1015 ++argv;
1016 continue;
1017 }
1018
1019 if (!strcmp(*argv, "-q")) {
1020 quiet= 1;
1021 ++argv;
1022 continue;
1023 }
1024
1025 if (!strcmp(*argv, "-n")) {
1026 check_insns= 0;
1027 ++argv;
1028 continue;
1029 }
1030
1031 if (**argv == '-') usage(progName);
1032
1033 fileName= *argv++;
1034 in= fopen(fileName, "r");
1035 if (in == 0) {
1036 fprintf(stderr, "%s: file not found: %s\n", progName, fileName);
1037 exit(1);
1038 }
1039 if (out == 0) {
1040 out= stdout;
1041 newOutput(out);
1042 }
1043 #if 0
1044 fprintf(out, "# \"%s\" %d\n", fileName, 1);
1045 #endif
1046 while (!feof(in)) {
1047 if (0 == fgets(line, sizeof(line) - 1, in)) break;
1048 ++lineNo;
1049 process(line, out);
1050 }
1051 fclose(in);
1052 }
1053
1054 return 0;
1055 }
1056