/* * Z80 - Assembler * Copyright (C) 1987-1992 by Udo Munk * * History: * 17-SEP-1987 Development under Digital Research CP/M 2.2 * 28-JUN-1988 Switched to Unix System V.3 */ #include #include #include "z80a.h" #include "z80aglb.h" static char *errmsg[] = { /* Fehlermeldungen fuer fatal() */ "out of memory: %s", /* 0 */ "usage: z80asm -ofile -f[b|m|h] -l[file] -s[n|a] -v -dsymbol ... file ...", "Assembly halted", /* 2 */ "can't open file %s", /* 3 */ "internal error: %s" /* 4 */ }; main(argc, argv) int argc; char *argv[]; { int len; init(); options(argc, argv); printf("Z80 - Assembler Release %s, %s\n", REL, COPYR); pass1(); pass2(); if (list_flag) { switch (sym_flag) { case 0: /* keine Symboltabelle */ break; case 1: /* unsortierte Symboltabelle */ lst_sym(); break; case 2: /* nach Namen sortierte Symboltabelle */ len = copy_sym(); n_sort_sym(len); lst_sort_sym(len); break; case 3: /* nach Adressen sortierte Symboltabelle */ len = copy_sym(); a_sort_sym(len); lst_sort_sym(len); break; default: break; } fclose(lstfp); } return(errors); } /* * Initialisierung */ init() { errfp = stdout; } /* * Diese Funktion bearbeitet die beim Aufruf angegebenen Options. * Die uebergebenen Dateinamen werden in die entsprechenden * Strings uebernommen. */ options(argc, argv) int argc; char *argv[]; { register char *s, *t; register int i; char *malloc(); while (--argc > 0 && (*++argv)[0] == '-') for (s = argv[0]+1; *s != '\0'; s++) switch (*s) { case 'o': case 'O': if (*++s == '\0') { puts("name missing in option -o"); usage(); } get_fn(objfn, s, OBJEXT); s += (strlen(s) - 1); break; case 'l': case 'L': if (*(s + 1) != '\0') { get_fn(lstfn, ++s, LSTEXT); s += (strlen(s) - 1); } list_flag = 1; break; case 's': case 'S': if (*(s + 1) == '\0') sym_flag = 1; else if ((*(s + 1) == 'n') || (*(s + 1) == 'N')) sym_flag = 2; else if ((*(s + 1) == 'a') || (*(s + 1) == 'A')) sym_flag = 3; else { printf("unknown option -%s\n", s); usage(); } s += (strlen(s) - 1); break; case 'f': case 'F': if ((*(s + 1) == 'b') || (*(s + 1) == 'B')) out_form = OUTBIN; else if ((*(s + 1) == 'm') || (*(s + 1) == 'M')) out_form = OUTMOS; else if ((*(s + 1) == 'h') || (*(s + 1) == 'H')) out_form = OUTHEX; else { printf("unknown option -%s\n", s); usage(); } s += (strlen(s) - 1); break; case 'd': case 'D': if (*++s == '\0') { puts("name missing in option -d"); usage(); } t = tmp; while (*s) *t++ = islower(*s) ? toupper(*s++) : *s++; s--; *t = '\0'; if (put_sym(tmp, 0)) fatal(F_OUTMEM, "symbols"); break; case 'v': case 'V': ver_flag = 1; break; default : printf("unknown option %c\n", *s); usage(); } i = 0; while ((argc--) && (i < MAXFN)) { if ((infiles[i] = malloc(LENFN + 1)) == NULL) fatal(F_OUTMEM, "filenames"); get_fn(infiles[i], *argv++, SRCEXT); i++; } if (i == 0) { printf("no input file given\n"); usage(); } } /* * An den Argumenten in der Befehlszeile ist was falsch, * Gebrauchsanleitung ausgeben und abbrechen. */ usage() { fatal(F_USAGE, NULL); } /* * Fehlermeldung ausgeben und abbrechen */ fatal(i, arg) register int i; register char *arg; { void exit(); printf(errmsg[i], arg); putchar('\n'); exit(1); } /* * Pass 1: * - Lauf ueber alle Quelldateien */ pass1() { register int fi; pass = 1; pc = 0; fi = 0; if (!ver_flag) puts("Pass 1"); open_o_files(infiles[fi]); while (infiles[fi] != NULL) { if (!ver_flag) printf(" Read %s\n", infiles[fi]); p1_file(infiles[fi]); fi++; } if (errors) { fclose(objfp); unlink(objfn); printf("%d error(s)\n", errors); fatal(F_HALT, NULL); } } /* * Pass 1: * - Lauf ueber eine Quelldatei * * Input: Name der zu bearbeitenden Quelldatei */ p1_file(fn) char *fn; { c_line = 0; srcfn = fn; if ((srcfp = fopen(fn, READA)) == NULL) fatal(F_FOPEN, fn); while (p1_line()) ; fclose(srcfp); if (iflevel) asmerr(E_MISEIF); } /* * Pass 1: * - Eine Zeile Quelle verarbeiten * * Output: 1 Zeile verarbeitet * 0 EOF erreicht */ p1_line() { register char *p; register int i; register struct opc *op; char *get_label(), *get_opcode(), *get_arg(); struct opc *search_op(); if ((p = fgets(line, MAXLINE, srcfp)) == NULL) return(0); c_line++; p = get_label(label, p); p = get_opcode(opcode, p); p = get_arg(operand, p); if (strcmp(opcode, ENDFILE) == 0) return(0); if (*opcode) { if ((op = search_op(opcode)) != NULL) { i = (*op->op_fun)(op->op_c1, op->op_c2); if (gencode) pc += i; } else asmerr(E_ILLOPC); } else if (*label) put_label(); return(1); } /* * Pass 2: * - Lauf ueber alle Quelldateien */ pass2() { register int fi; pass = 2; pc = 0; fi = 0; if (!ver_flag) puts("Pass 2"); obj_header(); while (infiles[fi] != NULL) { if (!ver_flag) printf(" Read %s\n", infiles[fi]); p2_file(infiles[fi]); fi++; } obj_end(); fclose(objfp); printf("%d error(s)\n", errors); } /* * Pass 2: * - Lauf ueber eine Quelldatei * * Input: Name der zu bearbeitenden Quelldatei */ p2_file(fn) char *fn; { c_line = 0; srcfn = fn; if ((srcfp = fopen(fn, READA)) == NULL) fatal(F_FOPEN, fn); while (p2_line()) ; fclose(srcfp); } /* * Pass 2: * - Eine Zeile Quelle verarbeiten * * Output: 1 Zeile verarbeitet * 0 EOF erreicht */ p2_line() { register char *p; register int op_count; register struct opc *op; char *get_label(), *get_opcode(), *get_arg(); struct opc *search_op(); if ((p = fgets(line, MAXLINE, srcfp)) == NULL) return(0); c_line++; s_line++; p = get_label(label, p); p = get_opcode(opcode, p); p = get_arg(operand, p); if (strcmp(opcode, ENDFILE) == 0) { lst_line(pc, 0); return(0); } if (*opcode) { op = search_op(opcode); op_count = (*op->op_fun)(op->op_c1, op->op_c2); if (gencode) { lst_line(pc, op_count); obj_writeb(op_count); pc += op_count; } else { sd_flag = 2; lst_line(0, 0); } } else { sd_flag = 2; lst_line(0, 0); } return(1); } /* * Oeffnen der Ausgabedateien: Objectdatei und bei Option * -l der Listdatei. Der Dateiname der Quelldatei wird * uebergeben. Die Dateinamen der Object- und Listdatei * werden, wenn nicht hinter den Optionen -l und -o angegeben, * aus dem Quelldateinamen erzeugt. */ open_o_files(source) register char *source; { char *strcpy(), *strcat(), *strrchr(); register char *p; if (*objfn == '\0') strcpy(objfn, source); if ((p = strrchr(objfn, '.')) != NULL) strcpy(p, OBJEXT); else strcat(objfn, OBJEXT); if (out_form == OUTHEX) objfp = fopen(objfn, WRITEA); else objfp = fopen(objfn, WRITEB); if (objfp == NULL) fatal(F_FOPEN, objfn); if (list_flag) { if (*lstfn == '\0') strcpy(lstfn, source); if ((p = strrchr(lstfn, '.')) != NULL) strcpy(p, LSTEXT); else strcat(lstfn, LSTEXT); if ((lstfp = fopen(lstfn, WRITEA)) == NULL) fatal(F_FOPEN, lstfn); errfp = lstfp; } } /* * Einen Dateinamen in "dest" aus "src" und "ext" zusammenbauen */ get_fn(dest, src, ext) char *dest, *src, *ext; { char *strrchr(), *strcat(); register int i; register char *sp, *dp; i = 0; sp = src; dp = dest; while ((i++ < LENFN) && (*sp != '\0')) *dp++ = *sp++; *dp = '\0'; if ((strrchr(dest,'.') == NULL) && (strlen(dest) <= (LENFN-strlen(ext)))) strcat(dest, ext); } /* * Extrahieren der Labels, Konstanten und Variablen aus * einer Zeile Quelltext mit Umwandlung in Grosschrift * und Begrenzung der Laenge. */ char *get_label(s, l) register char *s, *l; { register int i; i = 0; if (*l == LINCOM) goto comment; while (!isspace(*l) && *l != COMMENT && *l != LABSEP && i < SYMSIZE) { *s++ = islower(*l) ? toupper(*l++) : *l++; i++; } comment: *s = '\0'; return(l); } /* * Extrahieren des Op-Codes aus einer Zeile Quelltext ab der * uebergebenen Position. Der String wird bei der Uebertragung * in Grosschrift umgewandelt. */ char *get_opcode(s, l) register char *s, *l; { if (*l == LINCOM) goto comment; while (!isspace(*l) && *l != COMMENT && *l != LABSEP) l++; if (*l == LABSEP) l++; while (*l == ' ' || *l == '\t') l++; while (!isspace(*l) && *l != COMMENT) *s++ = islower(*l) ? toupper(*l++) : *l++; comment: *s = '\0'; return(l); } /* * Extrahieren des Operanden aus einer Zeile Quelltext ab der * uebergebenen Position. Der String wird bei der Uebertragung * in Grosschrift umgewandelt und Blanks sowie Tabs werden * ueberlesen. Strings, die in ' eingeschlossen sind, werden * ohne Aenderung kopiert. */ char *get_arg(s, l) register char *s, *l; { if (*l == LINCOM) goto comment; while (*l == ' ' || *l == '\t') l++; while (*l != '\n' && *l != COMMENT) { if (isspace(*l)) { l++; continue; } if (*l != STRSEP) { *s++ = islower(*l) ? toupper(*l) : *l; l++; continue; } *s++ = *l++; if (*(s - 2) == 'F') /* EX AF,AF' !!!!! */ continue; while (*l != STRSEP) { if (*l == '\n' || *l == '\0' || *l == COMMENT) goto comment; *s++ = *l++; } *s++ = *l++; } comment: *s = '\0'; return(l); }