From e410f6f1cd9e8419c57e2e8ad1159b5b16c22b1b Mon Sep 17 00:00:00 2001 From: nanochess Date: Wed, 18 Apr 2018 12:04:51 -0500 Subject: [PATCH] Added support for TMS9900+xas99 (TI-99/4A) --- Makefile | 13 + README | 3 +- pretty6502.c | 1242 ++++++++++++++++++++++++++++---------------------- 3 files changed, 721 insertions(+), 537 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0c0d8ce --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +# Ultra simple makefile for pretty6502 +# by Oscar Toledo G. +# https://github.com/nanochess/pretty6502 +# +build: + @cc pretty6502.c -o pretty6502 + +clean: + @rm pretty6502 + +love: + @echo "...not war" + diff --git a/README b/README index c18bfc0..f477908 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -Pretty6502 v0.4 by Oscar Toledo G. http://nanochess.org/ +Pretty6502 v0.5 by Oscar Toledo G. http://nanochess.org/ Executables provided for Mac OS X and Windows. @@ -20,6 +20,7 @@ Arguments: -p1 Processor 6502 + DASM syntax (default) -p2 Processor Z80 + tniASM syntax -p3 Processor CP1610 + as1600 syntax (Intellivision) + -p4 Processor TMS9900 + xas99 syntax (TI-99/4A) -m8 Start of mnemonic column (default) -o16 Start of operand column (default) diff --git a/pretty6502.c b/pretty6502.c index fdcb40a..bf8c0dd 100644 --- a/pretty6502.c +++ b/pretty6502.c @@ -1,49 +1,62 @@ /* -** Pretty6502 -** -** by Oscar Toledo G. -** -** © Copyright 2017-2018 Oscar Toledo G. -** -** Creation date: Nov/03/2017. -** Revision date: Nov/06/2017. Processor selection. Indents nested IF/ENDIF. -** Tries to preserve vertical structure of comments. -** Allows label in its own line. Allows to change case -** of mnemonics and directives. -** Revision date: Apr/16/2018. Added support for Z80 + tniASM. Solved bug in -** processing of apostrophe in operand. -** Revision date: Apr/17/2018. Added support for CP1610 + as1600 (Intellivision). -** Comments now also include indentation. -*/ + ** Pretty6502 + ** + ** by Oscar Toledo G. + ** + ** © Copyright 2017-2018 Oscar Toledo G. + ** + ** Creation date: Nov/03/2017. + ** Revision date: Nov/06/2017. Processor selection. Indents nested IF/ENDIF. + ** Tries to preserve vertical structure of comments. + ** Allows label in its own line. Allows to change case + ** of mnemonics and directives. + ** Revision date: Apr/16/2018. Added support for Z80 + tniASM. Solved bug in + ** processing of apostrophe in operand. + ** Revision date: Apr/17/2018. Added support for CP1610 + as1600 (Intellivision). + ** Comments now also include indentation. Working in + ** TMS9900 mode. + ** Revision date: Apr/18/2018. Added support for TMS9900 + xas99 (TI-99/4A), also + ** special syntax (comments must be separated by 2 + ** spaces) + */ #include #include #include #include -#define VERSION "v0.4" -int tabs; -int processor; +#define VERSION "v0.5" + +int tabs; /* Size of tabs (0 to use spaces) */ + +enum { + P_UNK, + P_6502, + P_Z80, + P_CP1610, + P_TMS9900, + P_UNSUPPORTED, +} processor; /* Processor/assembler being used (0-4) */ /* -** 6502 mnemonics -*/ + ** 6502 mnemonics + */ char *mnemonics_6502[] = { - "adc", "anc", "and", "ane", "arr", "asl", "asr", "bcc", - "bcs", "beq", "bit", "bmi", "bne", "bpl", "brk", "bvc", - "bvs", "clc", "cld", "cli", "clv", "cmp", "cpx", "cpy", - "dcp", "dec", "dex", "dey", "eor", "inc", "inx", "iny", - "isb", "jmp", "jsr", "las", "lax", "lda", "ldx", "ldy", - "lsr", "lxa", "nop", "ora", "pha", "php", "pla", "plp", - "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", - "sbx", "sec", "sed", "sei", "sha", "shs", "shx", "shy", - "slo", "sre", "sta", "stx", "sty", "tax", "tay", "tsx", - "txa", "txs", "tya", NULL, + "adc", "anc", "and", "ane", "arr", "asl", "asr", "bcc", + "bcs", "beq", "bit", "bmi", "bne", "bpl", "brk", "bvc", + "bvs", "clc", "cld", "cli", "clv", "cmp", "cpx", "cpy", + "dcp", "dec", "dex", "dey", "eor", "inc", "inx", "iny", + "isb", "jmp", "jsr", "las", "lax", "lda", "ldx", "ldy", + "lsr", "lxa", "nop", "ora", "pha", "php", "pla", "plp", + "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", + "sbx", "sec", "sed", "sei", "sha", "shs", "shx", "shy", + "slo", "sre", "sta", "stx", "sty", "tax", "tay", "tsx", + "txa", "txs", "tya", NULL, }; /* -** Z80 mnemonics -*/ + ** Z80 mnemonics + */ char *mnemonics_z80[] = { "adc", "add", "and", "bit", "call", "ccf", "cp", "cpd", "cpdr", "cpi", "cpir", "cpl", "daa", "dec", "di", "djnz", @@ -57,8 +70,8 @@ char *mnemonics_z80[] = { }; /* -** CP1610 mnemonics -*/ + ** CP1610 mnemonics + */ char *mnemonics_cp1610[] = { "adcr", "add", "add@", "addi", "addr", "and", "and@", "andi", "andr", "b", "bc", "beq", "besc", "bext", "bge", "bgt", @@ -73,6 +86,22 @@ char *mnemonics_cp1610[] = { "xor@", "xori", "xorr", NULL, }; +/* + ** TMS9900 mnemonics + */ +char *mnemonics_tms9900[] = { + "a", "ab", "abs", "ai", "andi", "b", "bl", "blwp", + "c", "call", "cb", "ci", "ckof", "ckon", "clr", "coc", + "czc", "dec", "dect", "div", "idle", "inc", "inct", "inv", + "jeq", "jgt", "jh", "jhe", "jl", "jle", "jlt", "jmp", + "jnc", "jne", "jno", "joc", "jop", "ldcr", "li", "limi", + "lrex", "lwpi", "mov", "movb", "mpy", "neg", "nop", "ori", + "pix", "pop", "push", "ret", "rset", "rt", "rtwp", "s", + "sb", "sbo", "sbz", "seto", "sla", "slc", "soc", "socb", + "sra", "src", "srl", "stcr", "stst", "stwp", "swpb", "szc", + "szcb", "tb", "x", "xop", "xor", NULL, +}; + #define DONT_RELOCATE_LABEL 0x01 #define LEVEL_IN 0x02 #define LEVEL_OUT 0x04 @@ -84,52 +113,52 @@ struct directive { }; /* -** DASM directives -*/ + ** DASM directives + */ struct directive directives_dasm[] = { - "=", DONT_RELOCATE_LABEL, - "align", 0, - "byte", 0, - "dc", 0, - "ds", 0, - "dv", 0, - "echo", 0, - "eif", LEVEL_OUT, - "else", LEVEL_MINUS, - "end", 0, - "endif", LEVEL_OUT, - "endm", LEVEL_OUT, - "eqm", DONT_RELOCATE_LABEL, - "equ", DONT_RELOCATE_LABEL, - "err", 0, - "hex", 0, - "if", LEVEL_IN, - "ifconst", LEVEL_IN, - "ifnconst", LEVEL_IN, - "incbin", 0, - "incdir", 0, - "include", 0, - "list", 0, - "long", 0, - "mac", LEVEL_IN, - "mexit", 0, - "org", 0, - "processor", 0, - "rend", 0, - "repeat", LEVEL_IN, - "repend", LEVEL_OUT, - "rorg", 0, - "seg", 0, - "set", DONT_RELOCATE_LABEL, - "subroutine", DONT_RELOCATE_LABEL, - "trace", 0, - "word", 0, - NULL, 0, + "=", DONT_RELOCATE_LABEL, + "align", 0, + "byte", 0, + "dc", 0, + "ds", 0, + "dv", 0, + "echo", 0, + "eif", LEVEL_OUT, + "else", LEVEL_MINUS, + "end", 0, + "endif", LEVEL_OUT, + "endm", LEVEL_OUT, + "eqm", DONT_RELOCATE_LABEL, + "equ", DONT_RELOCATE_LABEL, + "err", 0, + "hex", 0, + "if", LEVEL_IN, + "ifconst", LEVEL_IN, + "ifnconst", LEVEL_IN, + "incbin", 0, + "incdir", 0, + "include", 0, + "list", 0, + "long", 0, + "mac", LEVEL_IN, + "mexit", 0, + "org", 0, + "processor", 0, + "rend", 0, + "repeat", LEVEL_IN, + "repend", LEVEL_OUT, + "rorg", 0, + "seg", 0, + "set", DONT_RELOCATE_LABEL, + "subroutine", DONT_RELOCATE_LABEL, + "trace", 0, + "word", 0, + NULL, 0, }; /* -** tniASM directives -*/ + ** tniASM directives + */ struct directive directives_tniasm[] = { "cpu", 0, "db", 0, @@ -155,7 +184,7 @@ struct directive directives_tniasm[] = { }; /* -** as1600 directives + ** as1600 directives */ struct directive directives_as1600[] = { "begin", 0, @@ -199,28 +228,77 @@ struct directive directives_as1600[] = { }; /* -** Comparison without case -*/ + ** xas99 directives + */ +struct directive directives_xas99[] = { + ".defm", LEVEL_IN, + ".else", LEVEL_MINUS, + ".endif", LEVEL_OUT, + ".endm", LEVEL_OUT, + ".error", 0, + ".ifdef", LEVEL_IN, + ".ifeq", LEVEL_IN, + ".ifge", LEVEL_IN, + ".ifgt", LEVEL_IN, + ".ifndef", LEVEL_IN, + ".ifne", LEVEL_IN, + "aorg", 0, + "bcopy", 0, + "bes", 0, + "bss", 0, + "byte", 0, + "cend", 0, + "copy", 0, + "cseg", 0, + "data", 0, + "def", DONT_RELOCATE_LABEL, + "dend", 0, + "dorg", 0, + "dseg", 0, + "dxop", 0, + "end", 0, + "equ", DONT_RELOCATE_LABEL, + "even", 0, + "idt", 0, + "list", 0, + "load", 0, + "page", 0, + "pend", 0, + "pseg", 0, + "ref", 0, + "rorg", 0, + "save", 0, + "sref", 0, + "text", 0, + "titl", 0, + "unl", 0, + "xorg", 0, + NULL, 0, +}; + +/* + ** Comparison without case + */ int memcmpcase(char *p1, char *p2, int size) { - while (size--) { - if (tolower(*p1) != tolower(*p2)) - return 1; - p1++; - p2++; - } - return 0; + while (size--) { + if (tolower(*p1) != tolower(*p2)) + return 1; + p1++; + p2++; + } + return 0; } /* -** Check for opcode or directive -*/ + ** Check for opcode or directive + */ int check_opcode(char *p1, char *p2) { - int c; - int length; - - if (processor == 1) { /* 6502 + DASM */ + int c; + int length; + + if (processor == P_6502) { /* 6502 + DASM */ for (c = 0; directives_dasm[c].directive != NULL; c++) { length = strlen(directives_dasm[c].directive); if ((*p1 == '.' && length == p2 - p1 - 1 && memcmpcase(p1 + 1, directives_dasm[c].directive, p2 - p1 - 1) == 0) || (length == p2 - p1 && memcmpcase(p1, directives_dasm[c].directive, p2 - p1) == 0)) { @@ -233,7 +311,7 @@ int check_opcode(char *p1, char *p2) return -(c + 1); } } - if (processor == 2) { /* Z80 + tniASM */ + if (processor == P_Z80) { /* Z80 + tniASM */ for (c = 0; directives_tniasm[c].directive != NULL; c++) { length = strlen(directives_tniasm[c].directive); if (length == p2 - p1 && memcmpcase(p1, directives_tniasm[c].directive, p2 - p1) == 0) { @@ -246,7 +324,7 @@ int check_opcode(char *p1, char *p2) return -(c + 1); } } - if (processor == 3) { /* CP1610 + as1600 */ + if (processor == P_CP1610) { /* CP1610 + as1600 */ for (c = 0; directives_as1600[c].directive != NULL; c++) { length = strlen(directives_as1600[c].directive); if (length == p2 - p1 && memcmpcase(p1, directives_as1600[c].directive, p2 - p1) == 0) { @@ -259,485 +337,577 @@ int check_opcode(char *p1, char *p2) return -(c + 1); } } - return 0; + if (processor == P_TMS9900) { /* TMS9900 + xas99 */ + for (c = 0; directives_xas99[c].directive != NULL; c++) { + length = strlen(directives_xas99[c].directive); + if (length == p2 - p1 && memcmpcase(p1, directives_xas99[c].directive, p2 - p1) == 0) { + return c + 1; + } + } + for (c = 0; mnemonics_tms9900[c] != NULL; c++) { + length = strlen(mnemonics_tms9900[c]); + if (length == p2 - p1 && memcmpcase(p1, mnemonics_tms9900[c], p2 - p1) == 0) + return -(c + 1); + } + } + return 0; } /* -** Request space in line -*/ + ** Request space in line + */ void request_space(FILE *output, int *current, int new, int force) { - - /* - ** If already exceeded space... - */ - if (*current >= new) { - if (force) - fputc(' ', output); - (*current)++; - return; - } - - /* - ** Advance one step at a time - */ - while (1) { - if (tabs == 0) { - fprintf(output, "%*s", new - *current, ""); - *current = new; - } else { - fputc('\t', output); - *current = (*current + tabs) / tabs * tabs; - } - if (*current >= new) - return; - } + int base; + int tab; + + /* + ** If already exceeded space... + */ + if (*current >= new) { + if (force == 1) { + fputc(' ', output); + (*current)++; + } else if (force == 2 && *current != 0) { /* TMS9900 */ + fputc(' ', output); + (*current)++; + fputc(' ', output); + (*current)++; + } + return; + } + + /* + ** Advance one step at a time + */ + tab = 0; + base = *current; + while (1) { + if (tabs == 0) { + fprintf(output, "%*s", new - *current, ""); + *current = new; + } else { + fputc('\t', output); + *current = (*current + tabs) / tabs * tabs; + tab = 1; + } + if (*current >= new) { + if (force == 2) { /* TMS9900 */ + if (tab == 0) { + if (*current != 0) { + base = *current - base; + if (base < 1) { + fputc(' ', output); + (*current)++; + } + if (base < 2) { + fputc(' ', output); + (*current)++; + } + } + } + } + return; + } + } } /* -** Main program -*/ + ** Check for comment present + */ +int comment_present(char *start, char *actual, int left_side) +{ + if (processor == P_TMS9900) { + if (actual == start && *actual == '*') + return 1; + if (*actual == '*') { + if (actual == start) + return 1; + if (actual == start + 1 && isspace(actual[-1])) + return 1; + if (actual >= start + 2) { + if (isspace(actual[-2]) && isspace(actual[-1])) + return 1; + } + } + if (isspace(actual[0]) && isspace(actual[1]) && !left_side) + return 1; + if (actual[0] == '\t' && !left_side) + return 1; + } + if (*actual == ';') + return 1; + return 0; +} + +/* + ** Main program + */ int main(int argc, char *argv[]) { - int c; - int style; - int start_mnemonic; - int start_operand; - int start_comment; - int align_comment; - int nesting_space; - int labels_own_line; - FILE *input; - FILE *output; - int allocation; - char *data; - char *p; - char *p1; - char *p2; - char *p3; - int current_column; - int request; - int current_level; - int prev_comment_original_location; - int prev_comment_final_location; - int flags; - int mnemonics_case; - int directives_case; + int c; + int style; + int start_mnemonic; + int start_operand; + int start_comment; + int align_comment; + int nesting_space; + int labels_own_line; + FILE *input; + FILE *output; + int allocation; + char *data; + char *p; + char *p1; + char *p2; + char *p3; + int current_column; + int request; + int current_level; + int prev_comment_original_location; + int prev_comment_final_location; + int flags; + int mnemonics_case; + int directives_case; int indent; int something; - - /* - ** Show usage if less than 3 arguments (program name counts as one) - */ - if (argc < 3) { - fprintf(stderr, "\n"); - fprintf(stderr, "Pretty6502 " VERSION " by Oscar Toledo G. http://nanochess.org/\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Usage:\n"); - fprintf(stderr, " pretty6502 [args] input.asm output.asm\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "It's recommended to not use same output file as input,\n"); - fprintf(stderr, "even if possible because there is a chance (0.0000001%%)\n"); - fprintf(stderr, "that you can DAMAGE YOUR SOURCE if Pretty6502 has\n"); - fprintf(stderr, "undiscovered bugs.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Arguments:\n"); - fprintf(stderr, " -s0 Code in four columns (default)\n"); - fprintf(stderr, " label: mnemonic operand comment\n"); - fprintf(stderr, " -s1 Code in three columns\n"); - fprintf(stderr, " label: mnemonic+operand comment\n"); - fprintf(stderr, " -p0 Processor unknown\n"); + int comment; + + /* + ** Show usage if less than 3 arguments (program name counts as one) + */ + if (argc < 3) { + fprintf(stderr, "\n"); + fprintf(stderr, "Pretty6502 " VERSION " by Oscar Toledo G. http://nanochess.org/\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " pretty6502 [args] input.asm output.asm\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "It's recommended to not use same output file as input,\n"); + fprintf(stderr, "even if possible because there is a chance (0.0000001%%)\n"); + fprintf(stderr, "that you can DAMAGE YOUR SOURCE if Pretty6502 has\n"); + fprintf(stderr, "undiscovered bugs.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Arguments:\n"); + fprintf(stderr, " -s0 Code in four columns (default)\n"); + fprintf(stderr, " label: mnemonic operand comment\n"); + fprintf(stderr, " -s1 Code in three columns\n"); + fprintf(stderr, " label: mnemonic+operand comment\n"); + fprintf(stderr, " -p0 Processor unknown\n"); fprintf(stderr, " -p1 Processor 6502 + DASM syntax (default)\n"); fprintf(stderr, " -p2 Processor Z80 + tniASM syntax\n"); fprintf(stderr, " -p3 Processor CP1610 + as1600 syntax (Intellivision(tm))\n"); - fprintf(stderr, " -m8 Start of mnemonic column (default)\n"); - fprintf(stderr, " -o16 Start of operand column (default)\n"); - fprintf(stderr, " -c32 Start of comment column (default)\n"); - fprintf(stderr, " -t8 Use tabs of size 8 to reach column\n"); - fprintf(stderr, " -t0 Use spaces to align (default)\n"); - fprintf(stderr, " -a0 Align comments to nearest column\n"); - fprintf(stderr, " -a1 Comments at line start are aligned\n"); - fprintf(stderr, " to mnemonic (default)\n"); - fprintf(stderr, " -n4 Nesting spacing (can be any number\n"); - fprintf(stderr, " of spaces or multiple of tab size)\n"); - fprintf(stderr, " -l Puts labels in its own line\n"); - fprintf(stderr, " -dl Change directives to lowercase\n"); - fprintf(stderr, " -du Change directives to uppercase\n"); - fprintf(stderr, " -ml Change mnemonics to lowercase\n"); - fprintf(stderr, " -mu Change mnemonics to uppercase\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Assumes all your labels are at start of line and there is space\n"); - fprintf(stderr, "before mnemonic.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Accepts any assembler file where ; means comment\n"); - fprintf(stderr, "[label] mnemonic [operand] ; comment\n"); - exit(1); - } - - /* - ** Default settings - */ - style = 0; - processor = 1; - start_mnemonic = 8; - start_operand = 16; - start_comment = 32; - tabs = 0; - align_comment = 1; - nesting_space = 4; - labels_own_line = 0; - mnemonics_case = 0; - directives_case = 0; - - /* - ** Process arguments - */ - c = 1; - while (c < argc - 2) { - if (argv[c][0] != '-') { - fprintf(stderr, "Bad argument\n"); - exit(1); - } - switch (tolower(argv[c][1])) { - case 's': /* Style */ - style = atoi(&argv[c][2]); - if (style != 0 && style != 1) { - fprintf(stderr, "Bad style code: %d\n", style); - exit(1); - } - break; - case 'p': /* Processor */ - processor = atoi(&argv[c][2]); - if (processor < 0 || processor > 3) { - fprintf(stderr, "Bad processor code: %d\n", processor); - exit(1); - } - break; - case 'm': /* Mnemonic start */ - if (tolower(argv[c][2]) == 'l') { - mnemonics_case = 1; - } else if (tolower(argv[c][2]) == 'u') { - mnemonics_case = 2; - } else { - start_mnemonic = atoi(&argv[c][2]); - } - break; - case 'o': /* Operand start */ - start_operand = atoi(&argv[c][2]); - break; - case 'c': /* Comment start */ - start_comment = atoi(&argv[c][2]); - break; - case 't': /* Tab size */ - tabs = atoi(&argv[c][2]); - break; - case 'a': /* Comment alignment */ - align_comment = atoi(&argv[c][2]); - if (align_comment != 0 && align_comment != 1) { - fprintf(stderr, "Bad comment alignment: %d\n", align_comment); - exit(1); - } - break; - case 'n': /* Nesting space */ - nesting_space = atoi(&argv[c][2]); - break; - case 'l': /* Labels in own line */ - labels_own_line = 1; - break; - case 'd': /* Directives */ - if (tolower(argv[c][2]) == 'l') { - directives_case = 1; - } else if (tolower(argv[c][2]) == 'u') { - directives_case = 2; - } else { - fprintf(stderr, "Unknown argument: %c%c\n", argv[c][1], argv[c][2]); - } - break; - default: /* Other */ - fprintf(stderr, "Unknown argument: %c\n", argv[c][1]); - exit(1); - } - c++; - } - - /* - ** Validate constraints - */ - if (style == 1) { - if (start_mnemonic > start_comment) { - fprintf(stderr, "Operand error: -m%d > -c%d\n", start_mnemonic, start_comment); - exit(1); - } - start_operand = start_mnemonic; - } else if (style == 0) { - if (start_mnemonic > start_operand) { - fprintf(stderr, "Operand error: -m%d > -o%d\n", start_mnemonic, start_operand); - exit(1); - } - if (start_operand > start_comment) { - fprintf(stderr, "Operand error: -o%d > -c%d\n", start_operand, start_comment); - exit(1); - } - } - if (tabs > 0) { - if (start_mnemonic % tabs) { - fprintf(stderr, "Operand error: -m%d isn't a multiple of %d\n", start_mnemonic, tabs); - exit(1); - } - if (start_operand % tabs) { - fprintf(stderr, "Operand error: -m%d isn't a multiple of %d\n", start_operand, tabs); - exit(1); - } - if (start_comment % tabs) { - fprintf(stderr, "Operand error: -m%d isn't a multiple of %d\n", start_comment, tabs); - exit(1); - } - if (nesting_space % tabs) { - fprintf(stderr, "Operand error: -n%d isn't a multiple of %d\n", nesting_space, tabs); - exit(1); - } - } - - /* - ** Open input file, measure it and read it into buffer - */ - input = fopen(argv[c], "rb"); - if (input == NULL) { - fprintf(stderr, "Unable to open input file: %s\n", argv[c]); - exit(1); - } - fprintf(stderr, "Processing %s...\n", argv[c]); - fseek(input, 0, SEEK_END); - allocation = ftell(input); - data = malloc(allocation + sizeof(char)); - if (data == NULL) { - fprintf(stderr, "Unable to allocate memory\n"); - fclose(input); - exit(1); - } - fseek(input, 0, SEEK_SET); - if (fread(data, sizeof(char), allocation, input) != allocation) { - fprintf(stderr, "Something went wrong reading the input file\n"); - fclose(input); - free(data); - exit(1); - } - fclose(input); - - /* - ** Ease processing of input file - */ - request = 0; - p1 = data; - p2 = data; - while (p1 < data + allocation) { - if (*p1 == '\r') { /* Ignore \r characters */ - p1++; - continue; - } - if (*p1 == '\n') { - p1++; - *p2++ = '\0'; /* Break line */ - request = 1; - continue; - } - *p2++ = *p1++; - request = 0; - } - if (request == 0) - *p2++ = '\0'; /* Force line break */ - allocation = p2 - data; - - /* - ** Now generate output file - */ - c++; - output = fopen(argv[c], "w"); - if (output == NULL) { - fprintf(stderr, "Unable to open output file: %s\n", argv[c]); - exit(1); - } - prev_comment_original_location = 0; - prev_comment_final_location = 0; - current_level = 0; - p = data; - while (p < data + allocation) { + fprintf(stderr, " -p4 Processor TMS9900 + xas99 syntax (TI-99/4A)\n"); + fprintf(stderr, " -m8 Start of mnemonic column (default)\n"); + fprintf(stderr, " -o16 Start of operand column (default)\n"); + fprintf(stderr, " -c32 Start of comment column (default)\n"); + fprintf(stderr, " -t8 Use tabs of size 8 to reach column\n"); + fprintf(stderr, " -t0 Use spaces to align (default)\n"); + fprintf(stderr, " -a0 Align comments to nearest column\n"); + fprintf(stderr, " -a1 Comments at line start are aligned\n"); + fprintf(stderr, " to mnemonic (default)\n"); + fprintf(stderr, " -n4 Nesting spacing (can be any number\n"); + fprintf(stderr, " of spaces or multiple of tab size)\n"); + fprintf(stderr, " -l Puts labels in its own line\n"); + fprintf(stderr, " -dl Change directives to lowercase\n"); + fprintf(stderr, " -du Change directives to uppercase\n"); + fprintf(stderr, " -ml Change mnemonics to lowercase\n"); + fprintf(stderr, " -mu Change mnemonics to uppercase\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Assumes all your labels are at start of line and there is space\n"); + fprintf(stderr, "before mnemonic.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Accepts any assembler file where ; means comment\n"); + fprintf(stderr, "[label] mnemonic [operand] ; comment\n"); + exit(1); + } + + /* + ** Default settings + */ + style = 0; + processor = P_6502; + start_mnemonic = 8; + start_operand = 16; + start_comment = 32; + tabs = 0; + align_comment = 1; + nesting_space = 4; + labels_own_line = 0; + mnemonics_case = 0; + directives_case = 0; + + /* + ** Process arguments + */ + something = 0; + c = 1; + while (c < argc - 2) { + if (argv[c][0] != '-') { + fprintf(stderr, "Bad argument\n"); + exit(1); + } + switch (tolower(argv[c][1])) { + case 's': /* Style */ + style = atoi(&argv[c][2]); + if (style != 0 && style != 1) { + fprintf(stderr, "Bad style code: %d\n", style); + exit(1); + } + break; + case 'p': /* Processor */ + request = atoi(&argv[c][2]); + if (request < 0 || request >= P_UNSUPPORTED) { + fprintf(stderr, "Bad processor code: %d\n", request); + exit(1); + } + processor = request; + break; + case 'm': /* Mnemonic start */ + if (tolower(argv[c][2]) == 'l') { + mnemonics_case = 1; + } else if (tolower(argv[c][2]) == 'u') { + mnemonics_case = 2; + } else { + start_mnemonic = atoi(&argv[c][2]); + } + break; + case 'o': /* Operand start */ + start_operand = atoi(&argv[c][2]); + something = 1; + break; + case 'c': /* Comment start */ + start_comment = atoi(&argv[c][2]); + break; + case 't': /* Tab size */ + tabs = atoi(&argv[c][2]); + break; + case 'a': /* Comment alignment */ + align_comment = atoi(&argv[c][2]); + if (align_comment != 0 && align_comment != 1) { + fprintf(stderr, "Bad comment alignment: %d\n", align_comment); + exit(1); + } + break; + case 'n': /* Nesting space */ + nesting_space = atoi(&argv[c][2]); + break; + case 'l': /* Labels in own line */ + labels_own_line = 1; + break; + case 'd': /* Directives */ + if (tolower(argv[c][2]) == 'l') { + directives_case = 1; + } else if (tolower(argv[c][2]) == 'u') { + directives_case = 2; + } else { + fprintf(stderr, "Unknown argument: %c%c\n", argv[c][1], argv[c][2]); + } + break; + default: /* Other */ + fprintf(stderr, "Unknown argument: %c\n", argv[c][1]); + exit(1); + } + c++; + } + + /* + ** Validate constraints + */ + if (style == 1) { + if (start_mnemonic > start_comment) { + fprintf(stderr, "Operand error: -m%d > -c%d\n", start_mnemonic, start_comment); + exit(1); + } + start_operand = start_mnemonic; + } else if (style == 0) { + if (start_mnemonic > start_operand) { + fprintf(stderr, "Operand error: -m%d > -o%d\n", start_mnemonic, start_operand); + exit(1); + } + if (start_operand > start_comment) { + fprintf(stderr, "Operand error: -o%d > -c%d\n", start_operand, start_comment); + exit(1); + } + } + if (tabs > 0) { + if (start_mnemonic % tabs) { + fprintf(stderr, "Operand error: -m%d isn't a multiple of %d\n", start_mnemonic, tabs); + exit(1); + } + if (start_operand % tabs) { + fprintf(stderr, "Operand error: -m%d isn't a multiple of %d\n", start_operand, tabs); + exit(1); + } + if (start_comment % tabs) { + fprintf(stderr, "Operand error: -m%d isn't a multiple of %d\n", start_comment, tabs); + exit(1); + } + if (nesting_space % tabs) { + fprintf(stderr, "Operand error: -n%d isn't a multiple of %d\n", nesting_space, tabs); + exit(1); + } + } + if (something && processor == P_TMS9900) { + fprintf(stderr, "Warning: ignoring operand column, not possible because assembler syntax in TMS9900 mode\n"); + } + + /* + ** Open input file, measure it and read it into buffer + */ + input = fopen(argv[c], "rb"); + if (input == NULL) { + fprintf(stderr, "Unable to open input file: %s\n", argv[c]); + exit(1); + } + fprintf(stderr, "Processing %s...\n", argv[c]); + fseek(input, 0, SEEK_END); + allocation = ftell(input); + data = malloc(allocation + sizeof(char)); + if (data == NULL) { + fprintf(stderr, "Unable to allocate memory\n"); + fclose(input); + exit(1); + } + fseek(input, 0, SEEK_SET); + if (fread(data, sizeof(char), allocation, input) != allocation) { + fprintf(stderr, "Something went wrong reading the input file\n"); + fclose(input); + free(data); + exit(1); + } + fclose(input); + + /* + ** Ease processing of input file + */ + request = 0; + p1 = data; + p2 = data; + while (p1 < data + allocation) { + if (*p1 == '\r') { /* Ignore \r characters */ + p1++; + continue; + } + if (*p1 == '\n') { + p1++; + + /* Remove trailing spaces */ + while (p2 > data && *(p2 - 1) != '\0' && isspace(*(p2 - 1))) + p2--; + *p2++ = '\0'; /* Break line */ + request = 1; + continue; + } + *p2++ = *p1++; + request = 0; + } + if (request == 0) + *p2++ = '\0'; /* Force line break */ + allocation = p2 - data; + + /* + ** Now generate output file + */ + c++; + output = fopen(argv[c], "w"); + if (output == NULL) { + fprintf(stderr, "Unable to open output file: %s\n", argv[c]); + exit(1); + } + prev_comment_original_location = 0; + prev_comment_final_location = 0; + current_level = 0; + p = data; + while (p < data + allocation) { something = 0; - current_column = 0; - p1 = p; - p2 = p1; - while (*p2 && !isspace(*p2) && *p2 != ';') - p2++; - if (p2 - p1) { /* Label */ + current_column = 0; + p1 = p; + p2 = p1; + + while (*p2 && !isspace(*p2) && !comment_present(p, p2, 1)) { + p2++; + } + if (p2 - p1) { /* Label */ something = 1; - fwrite(p1, sizeof(char), p2 - p1, output); - current_column = p2 - p1; - p1 = p2; - } else { - current_column = 0; - } - while (*p1 && isspace(*p1)) - p1++; + fwrite(p1, sizeof(char), p2 - p1, output); + current_column = p2 - p1; + p1 = p2; + } else { + current_column = 0; + } + while (*p1 && isspace(*p1) && !comment_present(p, p1, 1)) + p1++; indent = current_level * nesting_space; - flags = 0; - if (*p1 && *p1 != ';') { /* Mnemonic */ - p2 = p1; - while (*p2 && !isspace(*p2) && *p2 != ';') - p2++; - if (processor != 0) { - c = check_opcode(p1, p2); - if (c == 0) { - request = start_mnemonic; - } else if (c < 0) { - request = start_mnemonic; - } else { - if (processor == 1) + flags = 0; + if (*p1 && !comment_present(p, p1, 1)) { /* Mnemonic */ + p2 = p1; + while (*p2 && !isspace(*p2) && !comment_present(p, p2, 0)) + p2++; + if (processor != P_UNK) { + c = check_opcode(p1, p2); + if (c == 0) { + request = start_mnemonic; + } else if (c < 0) { + request = start_mnemonic; + } else { + if (processor == P_6502) flags = directives_dasm[c - 1].flags; - else if (processor == 2) + else if (processor == P_Z80) flags = directives_tniasm[c - 1].flags; - else if (processor == 3) + else if (processor == P_CP1610) flags = directives_as1600[c - 1].flags; - if (flags & DONT_RELOCATE_LABEL) - request = start_operand; - else - request = start_mnemonic; - } - } else { - request = start_mnemonic; - c = 0; - } - if (c <= 0) { - if (mnemonics_case == 1) { - p3 = p1; - while (p3 < p2) { - *p3 = tolower(*p3); - p3++; - } - } else if (mnemonics_case == 2) { - p3 = p1; - while (p3 < p2) { - *p3 = toupper(*p3); - p3++; - } - } - } else { - if (directives_case == 1) { - p3 = p1; - while (p3 < p2) { - *p3 = tolower(*p3); - p3++; - } - } else if (directives_case == 2) { - p3 = p1; - while (p3 < p2) { - *p3 = toupper(*p3); - p3++; - } - } - } - - /* - ** Move label to own line - */ - if (current_column != 0 && labels_own_line != 0 && (flags & DONT_RELOCATE_LABEL) == 0) { - fputc('\n', output); - current_column = 0; - } - if (flags & LEVEL_OUT) { + else if (processor == P_TMS9900) + flags = directives_xas99[c - 1].flags; + if (flags & DONT_RELOCATE_LABEL) + request = start_operand; + else + request = start_mnemonic; + } + } else { + request = start_mnemonic; + c = 0; + } + if (c <= 0) { + if (mnemonics_case == 1) { + p3 = p1; + while (p3 < p2) { + *p3 = tolower(*p3); + p3++; + } + } else if (mnemonics_case == 2) { + p3 = p1; + while (p3 < p2) { + *p3 = toupper(*p3); + p3++; + } + } + } else { + if (directives_case == 1) { + p3 = p1; + while (p3 < p2) { + *p3 = tolower(*p3); + p3++; + } + } else if (directives_case == 2) { + p3 = p1; + while (p3 < p2) { + *p3 = toupper(*p3); + p3++; + } + } + } + + /* + ** Move label to own line + */ + if (current_column != 0 && labels_own_line != 0 && (flags & DONT_RELOCATE_LABEL) == 0) { + fputc('\n', output); + current_column = 0; + } + if (flags & LEVEL_OUT) { if (current_level > 0) { - current_level--; + current_level--; indent -= nesting_space; } - } + } if (flags & LEVEL_MINUS) { if (indent >= nesting_space) indent -= nesting_space; else indent = 0; } - request += indent; - request_space(output, ¤t_column, request, 1); + request += indent; + request_space(output, ¤t_column, request, 1); something = 1; - fwrite(p1, sizeof(char), p2 - p1, output); - current_column += p2 - p1; - p1 = p2; - while (*p1 && isspace(*p1)) - p1++; - if (*p1 && *p1 != ';') { /* Operand */ - request = start_operand + indent; - request_space(output, ¤t_column, request, 1); - p2 = p1; - while (*p2 && *p2 != ';') { - if (*p2 == '"') { - p2++; - while (*p2 && *p2 != '"') - p2++; - p2++; - } else if (*p2 == '\'') { - p2++; + fwrite(p1, sizeof(char), p2 - p1, output); + current_column += p2 - p1; + p1 = p2; + while (*p1 && isspace(*p1) && !comment_present(p, p1, 0)) + p1++; + if (*p1 && !comment_present(p, p1, 0)) { /* Operand */ + if (processor == P_TMS9900) + request = current_column + 1; + else + request = start_operand + indent; + request_space(output, ¤t_column, request, 1); + p2 = p1; + while (*p2 && !comment_present(p, p2, 0)) { + if (*p2 == '"') { + p2++; + while (*p2 && *p2 != '"') + p2++; + p2++; + } else if (*p2 == '\'') { + p2++; if (p2 - p1 < 6 || memcmp(p2 - 6, "AF,AF'", 6) != 0) { while (*p2 && *p2 != '\'') p2++; p2++; } - } else { - p2++; - } - } - while (p2 > p1 && isspace(*(p2 - 1))) - p2--; + } else { + p2++; + } + } + while (p2 > p1 && isspace(*(p2 - 1))) + p2--; something = 1; - fwrite(p1, sizeof(char), p2 - p1, output); - current_column += p2 - p1; - p1 = p2; - while (*p1 && isspace(*p1)) - p1++; - } - if (flags & LEVEL_IN) { - current_level++; - } - } - if (*p1 == ';') { /* Comment */ - - /* - ** Try to keep comments aligned vertically (only works - ** if spaces were used in source file) - */ - p2 = p1; - while (p2 - 1 >= p && isspace(*(p2 - 1))) - p2--; - if (p2 == p && p1 - p == prev_comment_original_location) { - request = prev_comment_final_location; - } else { - prev_comment_original_location = p1 - p; - if (current_column == 0) - request = 0; - else if (current_column < start_mnemonic + indent) - request = start_mnemonic + indent; - else - request = start_comment + indent; - if (current_column == 0 && align_comment == 1) - request = start_mnemonic + indent; - prev_comment_final_location = request; - } - request_space(output, ¤t_column, request, 0); - p2 = p1; - while (*p2) - p2++; - while (p2 > p1 && isspace(*(p2 - 1))) - p2--; - fwrite(p1, sizeof(char), p2 - p1, output); - fputc('\n', output); - current_column += p2 - p1; - while (*p++) ; - continue; + fwrite(p1, sizeof(char), p2 - p1, output); + current_column += p2 - p1; + p1 = p2; + while (*p1 && isspace(*p1) && !comment_present(p, p1, 0)) + p1++; + } + if (flags & LEVEL_IN) { + current_level++; + } + } + if (comment_present(p, p1, !something)) { /* Comment */ + if (processor == P_TMS9900) { + while (isspace(*p1)) + p1++; + } + + /* + ** Try to keep comments aligned vertically (only works + ** if spaces were used in source file) + */ + p2 = p1; + while (p2 - 1 >= p && isspace(*(p2 - 1))) + p2--; + if (p2 == p && p1 - p == prev_comment_original_location) { + request = prev_comment_final_location; + } else { + prev_comment_original_location = p1 - p; + if (current_column == 0) + request = 0; + else if (current_column < start_mnemonic + indent) + request = start_mnemonic + indent; + else + request = start_comment + indent; + if (current_column == 0 && align_comment == 1) + request = start_mnemonic + indent; + prev_comment_final_location = request; + } + request_space(output, ¤t_column, request, (*p1 == ';') ? 0 : 2); + p2 = p1; + while (*p2) + p2++; + while (p2 > p1 && isspace(*(p2 - 1))) + p2--; + fwrite(p1, sizeof(char), p2 - p1, output); + fputc('\n', output); + current_column += p2 - p1; + while (*p++) ; + continue; } else if (something == 0) { prev_comment_original_location = 0; + prev_comment_final_location = 0; } - fputc('\n', output); - while (*p++) ; - } - fclose(output); - free(data); - exit(0); + fputc('\n', output); + while (*p++) ; + } + fclose(output); + free(data); + exit(0); }