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