| 1 | /*      asmconv 1.11 - convert 80X86 assembly           Author: Kees J. Bot
 | 
|---|
| 2 |  *                                                              24 Dec 1993
 | 
|---|
| 3 |  */
 | 
|---|
| 4 | static char version[] = "1.11";
 | 
|---|
| 5 | 
 | 
|---|
| 6 | #define nil 0
 | 
|---|
| 7 | #include <stdio.h>
 | 
|---|
| 8 | #include <stdarg.h>
 | 
|---|
| 9 | #include <stdlib.h>
 | 
|---|
| 10 | #include <string.h>
 | 
|---|
| 11 | #include <errno.h>
 | 
|---|
| 12 | #include <assert.h>
 | 
|---|
| 13 | #include "asmconv.h"
 | 
|---|
| 14 | #include "asm86.h"
 | 
|---|
| 15 | #include "languages.h"
 | 
|---|
| 16 | 
 | 
|---|
| 17 | void fatal(char *label)
 | 
|---|
| 18 | {
 | 
|---|
| 19 |         fprintf(stderr, "asmconv: %s: %s\n", label, strerror(errno));
 | 
|---|
| 20 |         exit(EXIT_FAILURE);
 | 
|---|
| 21 | }
 | 
|---|
| 22 | 
 | 
|---|
| 23 | void *allocate(void *mem, size_t size)
 | 
|---|
| 24 | /* A checked malloc/realloc().  Yes, I know ISO C allows realloc(NULL, size). */
 | 
|---|
| 25 | {
 | 
|---|
| 26 |         mem= mem == nil ? malloc(size) : realloc(mem, size);
 | 
|---|
| 27 |         if (mem == nil) fatal("malloc()");
 | 
|---|
| 28 |         return mem;
 | 
|---|
| 29 | }
 | 
|---|
| 30 | 
 | 
|---|
| 31 | void deallocate(void *mem)
 | 
|---|
| 32 | /* Free a malloc()d cell.  (Yes I know ISO C allows free(NULL) */
 | 
|---|
| 33 | {
 | 
|---|
| 34 |         if (mem != nil) free(mem);
 | 
|---|
| 35 | }
 | 
|---|
| 36 | 
 | 
|---|
| 37 | char *copystr(const char *s)
 | 
|---|
| 38 | {
 | 
|---|
| 39 |         char *c;
 | 
|---|
| 40 | 
 | 
|---|
| 41 |         c= allocate(nil, (strlen(s) + 1) * sizeof(s[0]));
 | 
|---|
| 42 |         strcpy(c, s);
 | 
|---|
| 43 |         return c;
 | 
|---|
| 44 | }
 | 
|---|
| 45 | 
 | 
|---|
| 46 | int isanumber(const char *s)
 | 
|---|
| 47 | /* True if s can be turned into a number. */
 | 
|---|
| 48 | {
 | 
|---|
| 49 |         char *end;
 | 
|---|
| 50 | 
 | 
|---|
| 51 |         (void) strtol(s, &end, 0);
 | 
|---|
| 52 |         return end != s && *end == 0;
 | 
|---|
| 53 | }
 | 
|---|
| 54 | 
 | 
|---|
| 55 | /* "Invisible" globals. */
 | 
|---|
| 56 | int asm_mode32= (sizeof(int) == 4);
 | 
|---|
| 57 | int err_code= EXIT_SUCCESS;
 | 
|---|
| 58 | 
 | 
|---|
| 59 | int main(int argc, char **argv)
 | 
|---|
| 60 | {
 | 
|---|
| 61 |         void (*parse_init)(char *file);
 | 
|---|
| 62 |         asm86_t *(*get_instruction)(void);
 | 
|---|
| 63 |         void (*emit_init)(char *file, const char *banner);
 | 
|---|
| 64 |         void (*emit_instruction)(asm86_t *instr);
 | 
|---|
| 65 |         char *lang_parse, *lang_emit, *input_file, *output_file;
 | 
|---|
| 66 |         asm86_t *instr;
 | 
|---|
| 67 |         char banner[80];
 | 
|---|
| 68 | 
 | 
|---|
| 69 |         if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'm') {
 | 
|---|
| 70 |                 if (strcmp(argv[1], "-mi86") == 0) {
 | 
|---|
| 71 |                         set_use16();
 | 
|---|
| 72 |                 } else
 | 
|---|
| 73 |                 if (strcmp(argv[1], "-mi386") == 0) {
 | 
|---|
| 74 |                         set_use32();
 | 
|---|
| 75 |                 } else {
 | 
|---|
| 76 |                         fprintf(stderr, "asmconv: '%s': unknown machine\n",
 | 
|---|
| 77 |                                 argv[1]+2);
 | 
|---|
| 78 |                 }
 | 
|---|
| 79 |                 argc--;
 | 
|---|
| 80 |                 argv++;
 | 
|---|
| 81 |         }
 | 
|---|
| 82 | 
 | 
|---|
| 83 |         if (argc < 3 || argc > 5) {
 | 
|---|
| 84 |                 fprintf(stderr,
 | 
|---|
| 85 | "Usage: asmconv <input-type> <output-type> [input-file [output-file]]\n");
 | 
|---|
| 86 |                 exit(EXIT_FAILURE);
 | 
|---|
| 87 |         }
 | 
|---|
| 88 | 
 | 
|---|
| 89 |         lang_parse= argv[1];
 | 
|---|
| 90 |         lang_emit= argv[2];
 | 
|---|
| 91 |         input_file= argc < 4 ? nil : argv[3];
 | 
|---|
| 92 |         output_file= argc < 5 ? nil : argv[4];
 | 
|---|
| 93 | 
 | 
|---|
| 94 |         /* Choose the parsing routines. */
 | 
|---|
| 95 |         if (strcmp(lang_parse, "ack") == 0) {
 | 
|---|
| 96 |                 /* Standard ACK. */
 | 
|---|
| 97 |                 parse_init= ack_parse_init;
 | 
|---|
| 98 |                 get_instruction= ack_get_instruction;
 | 
|---|
| 99 |         } else
 | 
|---|
| 100 |         if (strcmp(lang_parse, "ncc") == 0) {
 | 
|---|
| 101 |                 /* ACK Xenix assembly, a black sheep among ACK assemblies. */
 | 
|---|
| 102 |                 parse_init= ncc_parse_init;
 | 
|---|
| 103 |                 get_instruction= ncc_get_instruction;
 | 
|---|
| 104 |         } else
 | 
|---|
| 105 |         if (strcmp(lang_parse, "gnu") == 0) {
 | 
|---|
| 106 |                 /* GNU assembly.  Parser by R.S. Veldema. */
 | 
|---|
| 107 |                 parse_init= gnu_parse_init;
 | 
|---|
| 108 |                 get_instruction= gnu_get_instruction;
 | 
|---|
| 109 |         } else
 | 
|---|
| 110 |         if (strcmp(lang_parse, "bas") == 0) {
 | 
|---|
| 111 |                 /* Bruce Evans' assembler. */
 | 
|---|
| 112 |                 parse_init= bas_parse_init;
 | 
|---|
| 113 |                 get_instruction= bas_get_instruction;
 | 
|---|
| 114 |         } else {
 | 
|---|
| 115 |                 fprintf(stderr, "asmconv: '%s': unknown input language\n",
 | 
|---|
| 116 |                         lang_parse);
 | 
|---|
| 117 |                 exit(EXIT_FAILURE);
 | 
|---|
| 118 |         }
 | 
|---|
| 119 | 
 | 
|---|
| 120 |         /* Choose the output language. */
 | 
|---|
| 121 |         if (strcmp(lang_emit, "ack") == 0) {
 | 
|---|
| 122 |                 /* Standard ACK. */
 | 
|---|
| 123 |                 emit_init= ack_emit_init;
 | 
|---|
| 124 |                 emit_instruction= ack_emit_instruction;
 | 
|---|
| 125 |         } else
 | 
|---|
| 126 |         if (strcmp(lang_emit, "ncc") == 0) {
 | 
|---|
| 127 |                 /* ACK Xenix assembly, can be read by BAS and the 8086 ACK
 | 
|---|
| 128 |                  * ANSI C compiler.  (Allows us to compile the Boot Monitor.)
 | 
|---|
| 129 |                  */
 | 
|---|
| 130 |                 emit_init= ncc_emit_init;
 | 
|---|
| 131 |                 emit_instruction= ncc_emit_instruction;
 | 
|---|
| 132 |         } else
 | 
|---|
| 133 |         if (strcmp(lang_emit, "gnu") == 0) {
 | 
|---|
| 134 |                 /* GNU assembler.  So we can assemble the ACK stuff among the
 | 
|---|
| 135 |                  * kernel sources and in the library.
 | 
|---|
| 136 |                  */
 | 
|---|
| 137 |                 emit_init= gnu_emit_init;
 | 
|---|
| 138 |                 emit_instruction= gnu_emit_instruction;
 | 
|---|
| 139 |         } else {
 | 
|---|
| 140 |                 fprintf(stderr, "asmconv: '%s': unknown output language\n",
 | 
|---|
| 141 |                         lang_emit);
 | 
|---|
| 142 |                 exit(EXIT_FAILURE);
 | 
|---|
| 143 |         }
 | 
|---|
| 144 | 
 | 
|---|
| 145 |         sprintf(banner, "Translated from %s to %s by asmconv %s",
 | 
|---|
| 146 |                                         lang_parse, lang_emit, version);
 | 
|---|
| 147 | 
 | 
|---|
| 148 |         (*parse_init)(input_file);
 | 
|---|
| 149 |         (*emit_init)(output_file, banner);
 | 
|---|
| 150 |         for (;;) {
 | 
|---|
| 151 |                 instr= (*get_instruction)();
 | 
|---|
| 152 |                 (*emit_instruction)(instr);
 | 
|---|
| 153 |                 if (instr == nil) break;
 | 
|---|
| 154 |                 del_asm86(instr);
 | 
|---|
| 155 |         }
 | 
|---|
| 156 |         exit(err_code);
 | 
|---|
| 157 | }
 | 
|---|