├── .gitignore ├── Makefile ├── LICENSE ├── README └── pretty6502.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.o 3 | Aa* 4 | aa* 5 | dasm 6 | pretty6502 7 | pretty6502.exe 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Ultra simple makefile for pretty6502 2 | # by Oscar Toledo G. 3 | # https://github.com/nanochess/pretty6502 4 | # 5 | build: 6 | @cc pretty6502.c -o pretty6502 7 | 8 | clean: 9 | @rm pretty6502 10 | 11 | love: 12 | @echo "...not war" 13 | 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Oscar Toledo G. http://nanochess.org/ 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Pretty6502 v0.8 by Oscar Toledo G. http://nanochess.org/ 2 | 3 | Usage: 4 | pretty6502 [args] input.asm output.asm 5 | 6 | It's recommended to not use same output file as input, 7 | even if possible because there is a chance (0.0000001%) 8 | that you can DAMAGE YOUR SOURCE if Pretty6502 has 9 | undiscovered bugs. 10 | 11 | Arguments: 12 | -s0 Code in four columns (default) 13 | label: mnemonic operand comment 14 | -s1 Code in three columns 15 | label: mnemonic+operand comment 16 | 17 | -p0 Processor unknown. 18 | -p1 Processor 6502 + DASM syntax (default) 19 | -p2 Processor Z80 + tniASM syntax 20 | -p3 Processor CP1610 + as1600 syntax (Intellivision) 21 | -p4 Processor TMS9900 + xas99 syntax (TI-99/4A) 22 | -p5 Processor 8086 + nasm syntax 23 | -p6 Processor 65c02 + ca65 syntax 24 | -p7 Processor 6502 + gasm80 syntax 25 | -p8 Processor Z80 + gasm80 syntax 26 | 27 | -n4 Nesting spacing (can be any number 28 | of spaces or multiple of tab size) 29 | 30 | -m8 Start of mnemonic column (default) 31 | -o16 Start of operand column (default) 32 | -c32 Start of comment column (default) 33 | 34 | -t0 Use spaces to align (default) 35 | -t8 Use tabs to reach column (size 8) 36 | Options -m, -o, -c, and -n must be multiples of this value. 37 | 38 | -a0 Align comments to nearest column 39 | -a1 Comments at line start are aligned 40 | to mnemonic (default) 41 | 42 | -l Put labels in its own line 43 | 44 | -dl Change directives to lowercase 45 | -du Change directives to uppercase 46 | -ml Change mnemonics to lowercase 47 | -mu Change mnemonics to uppercase 48 | 49 | Assumes all your labels are at start of line and there is space 50 | before mnemonic. 51 | 52 | Accepts any assembler file where ; means comment 53 | [label] mnemonic [operand] ; comment 54 | 55 | 56 | >> ATTENTION << 57 | 58 | Do you would like to learn to program 6502 assembler and 59 | creating Atari 2600 games? It is possible with my newest book 60 | Programming Games for Atari 2600. 61 | 62 | Now available from Lulu: 63 | 64 | Paperback 65 | https://www.lulu.com/shop/oscar-toledo-gutierrez/programming-games-for-atari-2600/paperback/product-pq9dg4.html 66 | 67 | Hardcover 68 | https://www.lulu.com/shop/oscar-toledo-gutierrez/programming-games-for-atari-2600/hardcover/product-n8z9r6.html 69 | 70 | eBook 71 | https://nanochess.org/store.html 72 | 73 | These are some of the example programs documented profusely 74 | in the book: 75 | 76 | * Game of Ball. 77 | * Wall Breaker. 78 | * Invaders. 79 | * The Lost Kingdom. 80 | * Diamond Craze. 81 | -------------------------------------------------------------------------------- /pretty6502.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Pretty6502 3 | ** 4 | ** by Oscar Toledo G. 5 | ** 6 | ** © Copyright 2017-2025 Oscar Toledo G. 7 | ** 8 | ** Creation date: Nov/03/2017. 9 | ** Revision date: Nov/06/2017. Processor selection. Indents nested IF/ENDIF. 10 | ** Tries to preserve vertical structure of comments. 11 | ** Allows label in its own line. Allows to change case 12 | ** of mnemonics and directives. 13 | ** Revision date: Apr/16/2018. Added support for Z80 + tniASM. Solved bug in 14 | ** processing of apostrophe in operand. 15 | ** Revision date: Apr/17/2018. Added support for CP1610 + as1600 (Intellivision). 16 | ** Comments now also include indentation. Working in 17 | ** TMS9900 mode. 18 | ** Revision date: Apr/18/2018. Added support for TMS9900 + xas99 (TI-99/4A), also 19 | ** special syntax (comments must be separated by 2 20 | ** spaces). 21 | ** Revision date: May/04/2020. Adjusted CP1610 for indenting REPEAT directive. 22 | ** Revision date: Apr/12/2021. Added support for 8086 + nasm. 23 | ** Revision date: Feb/03/2025. Added support for 6502+Z80 / gasm80. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define VERSION "v0.9" 32 | 33 | int tabs; /* Size of tabs (0 to use spaces) */ 34 | 35 | enum { 36 | P_UNK, 37 | P_6502, 38 | P_Z80, 39 | P_CP1610, 40 | P_TMS9900, 41 | P_8086, 42 | P_65C02, 43 | P_6502_GASM80, 44 | P_Z80_GASM80, 45 | P_UNSUPPORTED, 46 | } processor; /* Processor/assembler being used (0-4) */ 47 | 48 | /* 49 | ** 65C02 mnemonics 50 | */ 51 | char *mnemonics_65C02[] = { 52 | "adc" ,"and" ,"asl" ,"bbr0","bbr1","bbr2","bbr3","bbr4", 53 | "bbr5","bbr6","bbr7","bbs0","bbs1","bbs2","bbs3","bbs4", 54 | "bbs5","bbs6","bbs7","bcc" ,"bcs" ,"beq" ,"bit" ,"bmi" , 55 | "bne" ,"bpl" ,"bra" ,"brk" ,"bvc" ,"bvs" ,"clc" ,"cld" , 56 | "cli" ,"clv" ,"cmp" ,"cpx" ,"cpy" ,"dea" ,"dec" ,"dex" , 57 | "dey" ,"eor" ,"ina" ,"inc" ,"inx" ,"iny" ,"jmp" ,"jsr" , 58 | "lda" ,"ldx" ,"ldy" ,"lsr" ,"nop" ,"ora" ,"pha" ,"php" , 59 | "phx" ,"phy" ,"pla" ,"plp" ,"plx" ,"ply" ,"rmb0","rmb1", 60 | "rmb2","rmb3","rmb4","rmb5","rmb6","rmb7","rol" ,"ror" , 61 | "rti" ,"rts" ,"sbc" ,"sec" ,"sed" ,"sei" ,"smb0","smb1", 62 | "smb2","smb3","smb4","smb5","smb6","smb7","sta" ,"stp" , 63 | "stx" ,"sty" ,"stz" ,"tax" ,"tay" ,"trb" ,"tsb" ,"tsx", 64 | "txa" ,"txs" ,"tya" ,"wai" , NULL, 65 | }; 66 | 67 | /* 68 | ** 65C02 mnemonics 69 | */ 70 | char *mnemonics_6502[] = { 71 | "adc", "anc", "and", "ane", "arr", "asl", "asr", "bcc", 72 | "bcs", "beq", "bit", "bmi", "bne", "bpl", "brk", "bvc", 73 | "bvs", "clc", "cld", "cli", "clv", "cmp", "cpx", "cpy", 74 | "dcp", "dec", "dex", "dey", "eor", "inc", "inx", "iny", 75 | "isb", "jmp", "jsr", "las", "lax", "lda", "ldx", "ldy", 76 | "lsr", "lxa", "nop", "ora", "pha", "php", "pla", "plp", 77 | "rla", "rol", "ror", "rra", "rti", "rts", "sax", "sbc", 78 | "sbx", "sec", "sed", "sei", "sha", "shs", "shx", "shy", 79 | "slo", "sre", "sta", "stx", "sty", "tax", "tay", "tsx", 80 | "txa", "txs", "tya", NULL, 81 | }; 82 | 83 | /* 84 | ** Z80 mnemonics 85 | */ 86 | char *mnemonics_z80[] = { 87 | "adc", "add", "and", "bit", "call", "ccf", "cp", "cpd", 88 | "cpdr", "cpi", "cpir", "cpl", "daa", "dec", "di", "djnz", 89 | "ei", "ex", "exx", "halt", "im", "in", "inc", "ind", 90 | "indr", "ini", "inir", "jp", "jr", "ld", "ldd", "lddr", 91 | "ldi", "ldir", "neg", "nop", "or", "otdr", "otir", "out", 92 | "outd", "outi", "pop", "push", "res", "ret", "reti", "retn", 93 | "rl", "rla", "rlc", "rlca", "rld", "rr", "rra", "rrc", 94 | "rrca", "rrd", "rst", "sbc", "scf", "set", "sla", "sra", 95 | "srl", "sub", "xor", NULL, 96 | }; 97 | 98 | /* 99 | ** CP1610 mnemonics 100 | */ 101 | char *mnemonics_cp1610[] = { 102 | "adcr", "add", "add@", "addi", "addr", "and", "and@", "andi", 103 | "andr", "b", "bc", "beq", "besc", "bext", "bge", "bgt", 104 | "ble", "blge", "bllt", "blt", "bmi", "bnc", "bneq", "bnov", 105 | "bnze", "bov", "bpl", "busc", "bze", "clrc", "clrr", "cmp", 106 | "cmp@", "cmpi", "cmpr", "comr", "decr", "dis", "eis", "gswd", 107 | "hlt", "incr", "j", "jd", "je", "jr", "jsr", "jsrd", 108 | "jsre", "movr", "mvi", "mvi@", "mvii", "mvo", "mvo@", "mvoi", 109 | "negr", "nop", "nopp", "pshr", "pulr", "rlc", "rrc", "rswd", 110 | "sar", "sarc", "sdbd", "setc", "sin", "sll", "sllc", "slr", 111 | "sub", "sub@", "subi", "subr", "swap", "tci", "tstr", "xor", 112 | "xor@", "xori", "xorr", NULL, 113 | }; 114 | 115 | /* 116 | ** TMS9900 mnemonics 117 | */ 118 | char *mnemonics_tms9900[] = { 119 | "a", "ab", "abs", "ai", "andi", "b", "bl", "blwp", 120 | "c", "call", "cb", "ci", "ckof", "ckon", "clr", "coc", 121 | "czc", "dec", "dect", "div", "idle", "inc", "inct", "inv", 122 | "jeq", "jgt", "jh", "jhe", "jl", "jle", "jlt", "jmp", 123 | "jnc", "jne", "jno", "joc", "jop", "ldcr", "li", "limi", 124 | "lrex", "lwpi", "mov", "movb", "mpy", "neg", "nop", "ori", 125 | "pix", "pop", "push", "ret", "rset", "rt", "rtwp", "s", 126 | "sb", "sbo", "sbz", "seto", "sla", "slc", "soc", "socb", 127 | "sra", "src", "srl", "stcr", "stst", "stwp", "swpb", "szc", 128 | "szcb", "tb", "x", "xop", "xor", NULL, 129 | }; 130 | 131 | /* 132 | ** 8086 mnemonics 133 | */ 134 | char *mnemonics_8086[] = { 135 | "aaa", "aad", "aam", "aas", "adc", "add", "and", "call", 136 | "cbw", "clc", "cld", "cli", "cmc", "cmp", "cmps", "cmpsb", 137 | "cmpsw","cs", "cwd", "daa", "das", "dec", "div", "ds", 138 | "es", "hlt", "idiv", "imul", "in", "inc", "int", "int3", 139 | "into", "iret", "ja", "jb", "jbe", "jcxz", "jg", "jge", 140 | "jl", "jle", "jmp", "jnb", "jno", "jns", "jnz", "jo", 141 | "jpe", "jpo", "js", "jz", "lahf", "lds", "lea", "les", 142 | "lock", "lods", "lodsb","lodsw","loop", "loopnz","loopz","mov", 143 | "movs", "movsb","movsw","mul", "neg", "nop", "not", "or", 144 | "out", "pop", "popf", "push", "pushf","rcl", "rcr", "rep", 145 | "repnz","repz", "ret", "retf", "rol", "ror", "sahf", "sar", 146 | "sbb", "scas", "scasb","scasw","shl", "shr", "ss", "stc", 147 | "std", "sti", "stos", "stosb","stosw","sub", "test", "wait", 148 | "xchg", "xlat", "xor", NULL, 149 | }; 150 | 151 | #define DONT_RELOCATE_LABEL 0x01 152 | #define LEVEL_IN 0x02 153 | #define LEVEL_OUT 0x04 154 | #define LEVEL_MINUS 0x08 155 | 156 | struct directive { 157 | char *directive; 158 | int flags; 159 | }; 160 | 161 | /* 162 | ** DASM directives 163 | */ 164 | struct directive directives_dasm[] = { 165 | "=", DONT_RELOCATE_LABEL, 166 | "align", 0, 167 | "byte", 0, 168 | "dc", 0, 169 | "ds", 0, 170 | "dv", 0, 171 | "echo", 0, 172 | "eif", LEVEL_OUT, 173 | "else", LEVEL_MINUS, 174 | "end", 0, 175 | "endif", LEVEL_OUT, 176 | "endm", LEVEL_OUT, 177 | "eqm", DONT_RELOCATE_LABEL, 178 | "equ", DONT_RELOCATE_LABEL, 179 | "err", 0, 180 | "hex", 0, 181 | "if", LEVEL_IN, 182 | "ifconst", LEVEL_IN, 183 | "ifnconst", LEVEL_IN, 184 | "incbin", 0, 185 | "incdir", 0, 186 | "include", 0, 187 | "list", 0, 188 | "long", 0, 189 | "mac", LEVEL_IN, 190 | "mexit", 0, 191 | "org", 0, 192 | "processor", 0, 193 | "rend", 0, 194 | "repeat", LEVEL_IN, 195 | "repend", LEVEL_OUT, 196 | "rorg", 0, 197 | "seg", 0, 198 | "set", DONT_RELOCATE_LABEL, 199 | "subroutine", DONT_RELOCATE_LABEL, 200 | "trace", 0, 201 | "word", 0, 202 | NULL, 0, 203 | }; 204 | 205 | /* 206 | ** CA65 (https://cc65.github.io/doc/ca65.html) directives 207 | */ 208 | struct directive directives_ca65[] = { 209 | "*", DONT_RELOCATE_LABEL, 210 | ".asize", 0, 211 | ".cpu", 0, 212 | ".isize", 0, 213 | ".paramcount", 0, 214 | ".time", 0, 215 | ".version", 0, 216 | ".addrsize", 0, 217 | ".bank", 0, 218 | ".bankbyte", 0, 219 | ".blank", 0, 220 | ".concat", 0, 221 | ".const", 0, 222 | ".def", LEVEL_IN, 223 | ".definedmacro",0, 224 | ".defined", 0, 225 | ".hibyte", 0, 226 | ".hiword", 0, 227 | ".ident", 0, 228 | ".ismnem", 0, 229 | ".ismnemonic", 0, 230 | ".left", 0, 231 | ".lobyte", 0, 232 | ".loword", 0, 233 | ".match", 0, 234 | ".max", 0, 235 | ".mid", 0, 236 | ".min", 0, 237 | ".ref", 0, 238 | ".referenced", 0, 239 | ".right", 0, 240 | ".sizeof", 0, 241 | ".sprintf", 0, 242 | ".strat", 0, 243 | ".string", 0, 244 | ".strlen", 0, 245 | ".tcount", 0, 246 | ".xmatch", 0, 247 | ".a16", 0, 248 | ".a8", 0, 249 | ".addr", 0, 250 | ".align", 0, 251 | ".asciiz", 0, 252 | ".assert", 0, 253 | ".autoimport", 0, 254 | ".bankbytes", 0, 255 | ".bss", 0, 256 | ".byt", 0, 257 | ".byte", 0, 258 | ".case", 0, 259 | ".charmap", 0, 260 | ".code", 0, 261 | ".condes", 0, 262 | ".constructor", 0, 263 | ".data", 0, 264 | ".dbyt", 0, 265 | ".debuginfo", 0, 266 | ".define", 0, 267 | ".delmac", 0, 268 | ".delmacro", 0, 269 | ".destructor", 0, 270 | ".dword", 0, 271 | ".else", 0, 272 | ".elseif", 0, 273 | ".end", LEVEL_OUT, 274 | ".endenum", LEVEL_OUT, 275 | ".endif", LEVEL_OUT, 276 | ".endmac", LEVEL_OUT, 277 | ".endmacro", LEVEL_OUT, 278 | ".endproc", LEVEL_OUT, 279 | ".endrep", LEVEL_OUT, 280 | ".endrepeat", LEVEL_OUT, 281 | ".endscope", LEVEL_OUT, 282 | ".endstruct", LEVEL_OUT, 283 | ".endunion", LEVEL_OUT, 284 | ".enum", 0, 285 | ".error", 0, 286 | ".exitmac", LEVEL_OUT, 287 | ".exitmacro", LEVEL_OUT, 288 | ".export", 0, 289 | ".exportzp", 0, 290 | ".faraddr", 0, 291 | ".fatal", 0, 292 | ".feature", 0, 293 | ".fileopt", 0, 294 | ".fopt", 0, 295 | ".forceimport", 0, 296 | ".global", 0, 297 | ".globalzp", 0, 298 | ".hibytes", 0, 299 | ".i16", 0, 300 | ".i8", 0, 301 | ".if", LEVEL_IN, 302 | ".ifblank", LEVEL_IN, 303 | ".ifconst", LEVEL_IN, 304 | ".ifdef", LEVEL_IN, 305 | ".ifnblank", LEVEL_IN, 306 | ".ifndef", LEVEL_IN, 307 | ".ifnref", LEVEL_IN, 308 | ".ifp02", LEVEL_IN, 309 | ".ifp4510", LEVEL_IN, 310 | ".ifp816", LEVEL_IN, 311 | ".ifpc02", LEVEL_IN, 312 | ".ifpdtv", LEVEL_IN, 313 | ".ifpsc02", LEVEL_IN, 314 | ".ifref", LEVEL_IN, 315 | ".import", 0, 316 | ".importzp", 0, 317 | ".incbin", 0, 318 | ".include", 0, 319 | ".interruptor", 0, 320 | ".linecont", 0, 321 | ".list", 0, 322 | ".listbytes", 0, 323 | ".literal", 0, 324 | ".lobytes", 0, 325 | ".local", 0, 326 | ".localchar", 0, 327 | ".macpack", 0, 328 | ".mac", LEVEL_IN, 329 | ".macro", LEVEL_IN, 330 | ".org", 0, 331 | ".out", 0, 332 | ".p02", 0, 333 | ".p4510", 0, 334 | ".p816", 0, 335 | ".pagelen", 0, 336 | ".pagelength", 0, 337 | ".pc02", 0, 338 | ".pdtv", 0, 339 | ".popcharmap", 0, 340 | ".popcpu", 0, 341 | ".popseg", 0, 342 | ".proc", 0, 343 | ".psc02", 0, 344 | ".pushcharmap", 0, 345 | ".pushcpu", 0, 346 | ".pushseg", 0, 347 | ".refto", 0, 348 | ".referto", 0, 349 | ".reloc", 0, 350 | ".repeat", LEVEL_IN, 351 | ".res", 0, 352 | ".rodata", 0, 353 | ".scope", 0, 354 | ".segment", 0, 355 | ".set", 0, 356 | ".setcpu", 0, 357 | ".smart", 0, 358 | ".struct", 0, 359 | ".tag", 0, 360 | ".undef", 0, 361 | ".undefine", 0, 362 | ".union", 0, 363 | ".warning", 0, 364 | ".word", 0, 365 | ".zeropage", 0, 366 | ".macpack", 0, 367 | ".tag", 0, 368 | ".org", 0, 369 | "=", DONT_RELOCATE_LABEL, 370 | NULL, 0, 371 | }; 372 | 373 | /* 374 | ** tniASM directives 375 | */ 376 | struct directive directives_tniasm[] = { 377 | "cpu", 0, 378 | "db", 0, 379 | "dc", 0, 380 | "ds", 0, 381 | "dw", 0, 382 | "dephase", 0, 383 | "else", LEVEL_MINUS, 384 | "endif", LEVEL_OUT, 385 | "equ", DONT_RELOCATE_LABEL, 386 | "fname", 0, 387 | "forg", 0, 388 | "if", LEVEL_IN, 389 | "ifdef", LEVEL_IN, 390 | "ifexist", LEVEL_IN, 391 | "incbin", 0, 392 | "include", 0, 393 | "org", 0, 394 | "phase", 0, 395 | "rb", 0, 396 | "rw", 0, 397 | NULL, 0, 398 | }; 399 | 400 | /* 401 | ** as1600 directives 402 | */ 403 | struct directive directives_as1600[] = { 404 | "begin", 0, 405 | "bidecle", 0, 406 | "byte", 0, 407 | "cfgvar", 0, 408 | "cmsg", 0, 409 | "dcw", 0, 410 | "decle", 0, 411 | "else", LEVEL_MINUS, 412 | "endi", LEVEL_OUT, 413 | "endm", LEVEL_OUT, 414 | "endp", 0, 415 | "endr", LEVEL_OUT, 416 | "ends", LEVEL_OUT, 417 | "err", 0, 418 | "if", LEVEL_IN, 419 | "listing", 0, 420 | "macro", LEVEL_IN, 421 | "memattr", 0, 422 | "org", DONT_RELOCATE_LABEL, 423 | "proc", DONT_RELOCATE_LABEL, 424 | "qequ", DONT_RELOCATE_LABEL, 425 | "qset", DONT_RELOCATE_LABEL, 426 | "repeat", LEVEL_IN, 427 | "res", 0, 428 | "reserve", 0, 429 | "return", 0, 430 | "rmb", 0, 431 | "romw", 0, 432 | "romwidth", 0, 433 | "rpt", 0, 434 | "set", DONT_RELOCATE_LABEL, 435 | "smsg", 0, 436 | "srcfile", 0, 437 | "string", 0, 438 | "struct", DONT_RELOCATE_LABEL | LEVEL_IN, 439 | "wmsg", 0, 440 | "word", 0, 441 | NULL, 0, 442 | }; 443 | 444 | /* 445 | ** xas99 directives 446 | */ 447 | struct directive directives_xas99[] = { 448 | ".defm", LEVEL_IN, 449 | ".else", LEVEL_MINUS, 450 | ".endif", LEVEL_OUT, 451 | ".endm", LEVEL_OUT, 452 | ".error", 0, 453 | ".ifdef", LEVEL_IN, 454 | ".ifeq", LEVEL_IN, 455 | ".ifge", LEVEL_IN, 456 | ".ifgt", LEVEL_IN, 457 | ".ifndef", LEVEL_IN, 458 | ".ifne", LEVEL_IN, 459 | "aorg", 0, 460 | "bcopy", 0, 461 | "bes", 0, 462 | "bss", 0, 463 | "byte", 0, 464 | "cend", 0, 465 | "copy", 0, 466 | "cseg", 0, 467 | "data", 0, 468 | "def", DONT_RELOCATE_LABEL, 469 | "dend", 0, 470 | "dorg", 0, 471 | "dseg", 0, 472 | "dxop", 0, 473 | "end", 0, 474 | "equ", DONT_RELOCATE_LABEL, 475 | "even", 0, 476 | "idt", 0, 477 | "list", 0, 478 | "load", 0, 479 | "page", 0, 480 | "pend", 0, 481 | "pseg", 0, 482 | "ref", 0, 483 | "rorg", 0, 484 | "save", 0, 485 | "sref", 0, 486 | "text", 0, 487 | "titl", 0, 488 | "unl", 0, 489 | "xorg", 0, 490 | NULL, 0, 491 | }; 492 | 493 | /* 494 | ** nasm directives 495 | */ 496 | struct directive directives_nasm[] = { 497 | "%arg", 0, 498 | "%assign", 0, 499 | "%define", 0, 500 | "%defstr", 0, 501 | "%deftok", 0, 502 | "%depend", 0, 503 | "%elif", LEVEL_MINUS, 504 | "%elifdef", LEVEL_MINUS, 505 | "%elifn", LEVEL_MINUS, 506 | "%elifndef",LEVEL_MINUS, 507 | "%else", LEVEL_MINUS, 508 | "%endif", LEVEL_OUT, 509 | "%endmacro",LEVEL_OUT, 510 | "%endrep", LEVEL_OUT, 511 | "%error", 0, 512 | "%fatal", 0, 513 | "%if", LEVEL_IN, 514 | "%ifdef", LEVEL_IN, 515 | "%ifmacro", LEVEL_IN, 516 | "%ifn", LEVEL_IN, 517 | "%ifndef", LEVEL_IN, 518 | "%include", 0, 519 | "%line", 0, 520 | "%local", 0, 521 | "%macro", LEVEL_IN, 522 | "%pathsearch", 0, 523 | "%pragma", 0, 524 | "%pop", 0, 525 | "%push", 0, 526 | "%rep", LEVEL_IN, 527 | "%rotate", 0, 528 | "%stacksize",0, 529 | "%strcat", 0, 530 | "%strlen", 0, 531 | "%substr", 0, 532 | "%unmacro", 0, 533 | "%use", 0, 534 | "%warning", 0, 535 | "__sect__", 0, 536 | "absolute", 0, 537 | "align", 0, 538 | "alignb", 0, 539 | "bits", 0, 540 | "common", 0, 541 | "cpu", 0, 542 | "db", 0, 543 | "dd", 0, 544 | "default", 0, 545 | "do", 0, 546 | "dq", 0, 547 | "dt", 0, 548 | "dw", 0, 549 | "dy", 0, 550 | "dz", 0, 551 | "equ", DONT_RELOCATE_LABEL, 552 | "export", 0, 553 | "extern", 0, 554 | "float", 0, 555 | "global", 0, 556 | "import", 0, 557 | "incbin", 0, 558 | "library", 0, 559 | "module", 0, 560 | "resb", 0, 561 | "resd", 0, 562 | "reso", 0, 563 | "resq", 0, 564 | "rest", 0, 565 | "resw", 0, 566 | "resy", 0, 567 | "resz", 0, 568 | "sectalign",0, 569 | "section", 0, 570 | "segment", 0, 571 | "use16", 0, 572 | "use32", 0, 573 | "[warning", 0, 574 | NULL, 0, 575 | }; 576 | 577 | /* 578 | ** gasm80 directives 579 | */ 580 | struct directive directives_gasm80[] = { 581 | "align", 0, 582 | "cpu", 0, 583 | "db", 0, 584 | "dw", 0, 585 | "else", LEVEL_MINUS, 586 | "endif", LEVEL_OUT, 587 | "equ", DONT_RELOCATE_LABEL, 588 | "forg", 0, 589 | "if", LEVEL_IN, 590 | "ifdef", LEVEL_IN, 591 | "ifndef", LEVEL_IN, 592 | "incbin", 0, 593 | "include", 0, 594 | "org", 0, 595 | "rb", 0, 596 | "times", 0, 597 | NULL, 0, 598 | }; 599 | 600 | /* 601 | ** Comparison without case 602 | */ 603 | int memcmpcase(char *p1, char *p2, int size) 604 | { 605 | while (size--) { 606 | if (tolower(*p1) != tolower(*p2)) 607 | return 1; 608 | p1++; 609 | p2++; 610 | } 611 | return 0; 612 | } 613 | 614 | /* 615 | ** Check for opcode or directive 616 | */ 617 | int check_opcode(char *p1, char *p2) 618 | { 619 | int c; 620 | int length; 621 | 622 | if (processor == P_6502) { /* 6502 + DASM */ 623 | for (c = 0; directives_dasm[c].directive != NULL; c++) { 624 | length = strlen(directives_dasm[c].directive); 625 | 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)) { 626 | return c + 1; 627 | } 628 | } 629 | for (c = 0; mnemonics_6502[c] != NULL; c++) { 630 | length = strlen(mnemonics_6502[c]); 631 | if (length == p2 - p1 && memcmpcase(p1, mnemonics_6502[c], p2 - p1) == 0) 632 | return -(c + 1); 633 | } 634 | } 635 | if (processor == P_65C02) { /* 65C02 + ca65 */ 636 | for (c = 0; directives_ca65[c].directive != NULL; c++) { 637 | length = strlen(directives_ca65[c].directive); 638 | if ((*p1 == '.' && length == p2 - p1 - 1 && memcmpcase(p1 + 1, directives_ca65[c].directive, p2 - p1 - 1) == 0) || (length == p2 - p1 && memcmpcase(p1, directives_ca65[c].directive, p2 - p1) == 0)) { 639 | return c + 1; 640 | } 641 | } 642 | for (c = 0; mnemonics_65C02[c] != NULL; c++) { 643 | length = strlen(mnemonics_65C02[c]); 644 | if (length == p2 - p1 && memcmpcase(p1, mnemonics_65C02[c], p2 - p1) == 0) 645 | return -(c + 1); 646 | } 647 | } 648 | if (processor == P_Z80) { /* Z80 + tniASM */ 649 | for (c = 0; directives_tniasm[c].directive != NULL; c++) { 650 | length = strlen(directives_tniasm[c].directive); 651 | if (length == p2 - p1 && memcmpcase(p1, directives_tniasm[c].directive, p2 - p1) == 0) { 652 | return c + 1; 653 | } 654 | } 655 | for (c = 0; mnemonics_z80[c] != NULL; c++) { 656 | length = strlen(mnemonics_z80[c]); 657 | if (length == p2 - p1 && memcmpcase(p1, mnemonics_z80[c], p2 - p1) == 0) 658 | return -(c + 1); 659 | } 660 | } 661 | if (processor == P_CP1610) { /* CP1610 + as1600 */ 662 | for (c = 0; directives_as1600[c].directive != NULL; c++) { 663 | length = strlen(directives_as1600[c].directive); 664 | if (length == p2 - p1 && memcmpcase(p1, directives_as1600[c].directive, p2 - p1) == 0) { 665 | return c + 1; 666 | } 667 | } 668 | for (c = 0; mnemonics_cp1610[c] != NULL; c++) { 669 | length = strlen(mnemonics_cp1610[c]); 670 | if (length == p2 - p1 && memcmpcase(p1, mnemonics_cp1610[c], p2 - p1) == 0) 671 | return -(c + 1); 672 | } 673 | } 674 | if (processor == P_TMS9900) { /* TMS9900 + xas99 */ 675 | for (c = 0; directives_xas99[c].directive != NULL; c++) { 676 | length = strlen(directives_xas99[c].directive); 677 | if (length == p2 - p1 && memcmpcase(p1, directives_xas99[c].directive, p2 - p1) == 0) { 678 | return c + 1; 679 | } 680 | } 681 | for (c = 0; mnemonics_tms9900[c] != NULL; c++) { 682 | length = strlen(mnemonics_tms9900[c]); 683 | if (length == p2 - p1 && memcmpcase(p1, mnemonics_tms9900[c], p2 - p1) == 0) 684 | return -(c + 1); 685 | } 686 | } 687 | if (processor == P_8086) { /* 8086 + nasm */ 688 | for (c = 0; directives_nasm[c].directive != NULL; c++) { 689 | length = strlen(directives_nasm[c].directive); 690 | if (length == p2 - p1 && memcmpcase(p1, directives_nasm[c].directive, p2 - p1) == 0) { 691 | return c + 1; 692 | } 693 | } 694 | for (c = 0; mnemonics_8086[c] != NULL; c++) { 695 | length = strlen(mnemonics_8086[c]); 696 | if (length == p2 - p1 && memcmpcase(p1, mnemonics_8086[c], p2 - p1) == 0) 697 | return -(c + 1); 698 | } 699 | } 700 | if (processor == P_6502_GASM80) { /* 6502 + GASM80 */ 701 | for (c = 0; directives_gasm80[c].directive != NULL; c++) { 702 | length = strlen(directives_gasm80[c].directive); 703 | if (length == p2 - p1 && memcmpcase(p1, directives_gasm80[c].directive, p2 - p1) == 0) { 704 | return c + 1; 705 | } 706 | } 707 | for (c = 0; mnemonics_6502[c] != NULL; c++) { 708 | length = strlen(mnemonics_6502[c]); 709 | if (length == p2 - p1 && memcmpcase(p1, mnemonics_6502[c], p2 - p1) == 0) 710 | return -(c + 1); 711 | } 712 | } 713 | if (processor == P_Z80_GASM80) { /* Z80 + GASM80 */ 714 | for (c = 0; directives_gasm80[c].directive != NULL; c++) { 715 | length = strlen(directives_gasm80[c].directive); 716 | if (length == p2 - p1 && memcmpcase(p1, directives_gasm80[c].directive, p2 - p1) == 0) { 717 | return c + 1; 718 | } 719 | } 720 | for (c = 0; mnemonics_z80[c] != NULL; c++) { 721 | length = strlen(mnemonics_z80[c]); 722 | if (length == p2 - p1 && memcmpcase(p1, mnemonics_z80[c], p2 - p1) == 0) 723 | return -(c + 1); 724 | } 725 | } 726 | return 0; 727 | } 728 | 729 | /* 730 | ** Request space in line 731 | */ 732 | void request_space(FILE *output, int *current, int new, int force) 733 | { 734 | int base; 735 | int tab; 736 | 737 | /* 738 | ** If already exceeded space... 739 | */ 740 | if (*current >= new) { 741 | if (force == 1) { 742 | fputc(' ', output); 743 | (*current)++; 744 | } else if (force == 2 && *current != 0) { /* TMS9900 */ 745 | fputc(' ', output); 746 | (*current)++; 747 | fputc(' ', output); 748 | (*current)++; 749 | } 750 | return; 751 | } 752 | 753 | /* 754 | ** Advance one step at a time 755 | */ 756 | tab = 0; 757 | base = *current; 758 | while (1) { 759 | if (tabs == 0) { 760 | fprintf(output, "%*s", new - *current, ""); 761 | *current = new; 762 | } else { 763 | fputc('\t', output); 764 | *current = (*current + tabs) / tabs * tabs; 765 | tab = 1; 766 | } 767 | if (*current >= new) { 768 | if (force == 2) { /* TMS9900 */ 769 | if (tab == 0) { 770 | if (*current != 0) { 771 | base = *current - base; 772 | if (base < 1) { 773 | fputc(' ', output); 774 | (*current)++; 775 | } 776 | if (base < 2) { 777 | fputc(' ', output); 778 | (*current)++; 779 | } 780 | } 781 | } 782 | } 783 | return; 784 | } 785 | } 786 | } 787 | 788 | /* 789 | ** Check for comment present 790 | */ 791 | int comment_present(char *start, char *actual, int left_side) 792 | { 793 | if (processor == P_TMS9900) { 794 | if (actual == start && *actual == '*') 795 | return 1; 796 | if (*actual == '*') { 797 | if (actual == start) 798 | return 1; 799 | if (actual == start + 1 && isspace(actual[-1])) 800 | return 1; 801 | if (actual >= start + 2) { 802 | if (isspace(actual[-2]) && isspace(actual[-1])) 803 | return 1; 804 | } 805 | } 806 | if (isspace(actual[0]) && isspace(actual[1]) && !left_side) 807 | return 1; 808 | if (actual[0] == '\t' && !left_side) 809 | return 1; 810 | } 811 | if (*actual == ';') 812 | return 1; 813 | return 0; 814 | } 815 | 816 | /* 817 | ** Main program 818 | */ 819 | int main(int argc, char *argv[]) 820 | { 821 | int c; 822 | int style; 823 | int start_mnemonic; 824 | int start_operand; 825 | int start_comment; 826 | int align_comment; 827 | int nesting_space; 828 | int labels_own_line; 829 | FILE *input; 830 | FILE *output; 831 | int allocation; 832 | char *data; 833 | char *p; 834 | char *p1; 835 | char *p2; 836 | char *p3; 837 | int current_column; 838 | int request; 839 | int current_level; 840 | int prev_comment_original_location; 841 | int prev_comment_final_location; 842 | int flags; 843 | int mnemonics_case; 844 | int directives_case; 845 | int indent; 846 | int something; 847 | int comment; 848 | 849 | /* 850 | ** Show usage if less than 3 arguments (program name counts as one) 851 | */ 852 | if (argc < 3) { 853 | fprintf(stderr, "\n"); 854 | fprintf(stderr, "Pretty6502 " VERSION " by Oscar Toledo G. http://nanochess.org/\n"); 855 | fprintf(stderr, "\n"); 856 | fprintf(stderr, "Usage:\n"); 857 | fprintf(stderr, " pretty6502 [args] input.asm output.asm\n"); 858 | fprintf(stderr, "\n"); 859 | fprintf(stderr, "It's recommended to not use same output file as input,\n"); 860 | fprintf(stderr, "even if possible because there is a chance (0.0000001%%)\n"); 861 | fprintf(stderr, "that you can DAMAGE YOUR SOURCE if Pretty6502 has\n"); 862 | fprintf(stderr, "undiscovered bugs.\n"); 863 | fprintf(stderr, "\n"); 864 | fprintf(stderr, "Arguments:\n"); 865 | fprintf(stderr, " -s0 Code in four columns (default)\n"); 866 | fprintf(stderr, " label: mnemonic operand comment\n"); 867 | fprintf(stderr, " -s1 Code in three columns\n"); 868 | fprintf(stderr, " label: mnemonic+operand comment\n"); 869 | fprintf(stderr, " -p0 Processor unknown\n"); 870 | fprintf(stderr, " -p1 Processor 6502 + DASM syntax (default)\n"); 871 | fprintf(stderr, " -p2 Processor Z80 + tniASM syntax\n"); 872 | fprintf(stderr, " -p3 Processor CP1610 + as1600 syntax (Intellivision(tm))\n"); 873 | fprintf(stderr, " -p4 Processor TMS9900 + xas99 syntax (TI-99/4A)\n"); 874 | fprintf(stderr, " -p5 Processor 8086 + nasm syntax\n"); 875 | fprintf(stderr, " -p6 Processor 65c02 + ca65 syntax\n"); 876 | fprintf(stderr, " -p7 Processor 6502 + gasm80 syntax\n"); 877 | fprintf(stderr, " -p8 Processor Z80 + gasm80 syntax\n"); 878 | fprintf(stderr, " -n4 Nesting spacing (can be any number\n"); 879 | fprintf(stderr, " of spaces or multiple of tab size)\n"); 880 | fprintf(stderr, " -m8 Start of mnemonic column (default)\n"); 881 | fprintf(stderr, " -o16 Start of operand column (default)\n"); 882 | fprintf(stderr, " -c32 Start of comment column (default)\n"); 883 | fprintf(stderr, " -t0 Use spaces to align (default)\n"); 884 | fprintf(stderr, " -t8 Use tabs to reach column (size 8)\n"); 885 | fprintf(stderr, " Options -m, -o, -c, and -n must be multiples of this value.\n"); 886 | fprintf(stderr, " -a0 Align comments to nearest column\n"); 887 | fprintf(stderr, " -a1 Comments at line start are aligned\n"); 888 | fprintf(stderr, " to mnemonic (default)\n"); 889 | fprintf(stderr, " -l Puts labels in its own line\n"); 890 | fprintf(stderr, " -dl Change directives to lowercase\n"); 891 | fprintf(stderr, " -du Change directives to uppercase\n"); 892 | fprintf(stderr, " -ml Change mnemonics to lowercase\n"); 893 | fprintf(stderr, " -mu Change mnemonics to uppercase\n"); 894 | fprintf(stderr, "\n"); 895 | fprintf(stderr, "Assumes all your labels are at start of line and there is space\n"); 896 | fprintf(stderr, "before mnemonic.\n"); 897 | fprintf(stderr, "\n"); 898 | fprintf(stderr, "Accepts any assembler file where ; means comment\n"); 899 | fprintf(stderr, "[label] mnemonic [operand] ; comment\n"); 900 | exit(1); 901 | } 902 | 903 | /* 904 | ** Default settings 905 | */ 906 | style = 0; 907 | processor = P_6502; 908 | start_mnemonic = 8; 909 | start_operand = 16; 910 | start_comment = 32; 911 | tabs = 0; 912 | align_comment = 1; 913 | nesting_space = 4; 914 | labels_own_line = 0; 915 | mnemonics_case = 0; 916 | directives_case = 0; 917 | 918 | /* 919 | ** Process arguments 920 | */ 921 | something = 0; 922 | c = 1; 923 | while (c < argc - 2) { 924 | if (argv[c][0] != '-') { 925 | fprintf(stderr, "Bad argument\n"); 926 | exit(1); 927 | } 928 | switch (tolower(argv[c][1])) { 929 | case 's': /* Style */ 930 | style = atoi(&argv[c][2]); 931 | if (style != 0 && style != 1) { 932 | fprintf(stderr, "Bad style code: %d\n", style); 933 | exit(1); 934 | } 935 | break; 936 | case 'p': /* Processor */ 937 | request = atoi(&argv[c][2]); 938 | if (request < 0 || request >= P_UNSUPPORTED) { 939 | fprintf(stderr, "Bad processor code: %d\n", request); 940 | exit(1); 941 | } 942 | processor = request; 943 | break; 944 | case 'm': /* Mnemonic start */ 945 | if (tolower(argv[c][2]) == 'l') { 946 | mnemonics_case = 1; 947 | } else if (tolower(argv[c][2]) == 'u') { 948 | mnemonics_case = 2; 949 | } else { 950 | start_mnemonic = atoi(&argv[c][2]); 951 | } 952 | break; 953 | case 'o': /* Operand start */ 954 | start_operand = atoi(&argv[c][2]); 955 | something = 1; 956 | break; 957 | case 'c': /* Comment start */ 958 | start_comment = atoi(&argv[c][2]); 959 | break; 960 | case 't': /* Tab size */ 961 | tabs = atoi(&argv[c][2]); 962 | break; 963 | case 'a': /* Comment alignment */ 964 | align_comment = atoi(&argv[c][2]); 965 | if (align_comment != 0 && align_comment != 1) { 966 | fprintf(stderr, "Bad comment alignment: %d\n", align_comment); 967 | exit(1); 968 | } 969 | break; 970 | case 'n': /* Nesting space */ 971 | nesting_space = atoi(&argv[c][2]); 972 | break; 973 | case 'l': /* Labels in own line */ 974 | labels_own_line = 1; 975 | break; 976 | case 'd': /* Directives */ 977 | if (tolower(argv[c][2]) == 'l') { 978 | directives_case = 1; 979 | } else if (tolower(argv[c][2]) == 'u') { 980 | directives_case = 2; 981 | } else { 982 | fprintf(stderr, "Unknown argument: %c%c\n", argv[c][1], argv[c][2]); 983 | } 984 | break; 985 | default: /* Other */ 986 | fprintf(stderr, "Unknown argument: %c\n", argv[c][1]); 987 | exit(1); 988 | } 989 | c++; 990 | } 991 | 992 | /* 993 | ** Validate constraints 994 | */ 995 | if (style == 1) { 996 | if (start_mnemonic > start_comment) { 997 | fprintf(stderr, "Operand error: -m%d > -c%d\n", start_mnemonic, start_comment); 998 | exit(1); 999 | } 1000 | start_operand = start_mnemonic; 1001 | } else if (style == 0) { 1002 | if (start_mnemonic > start_operand) { 1003 | fprintf(stderr, "Operand error: -m%d > -o%d\n", start_mnemonic, start_operand); 1004 | exit(1); 1005 | } 1006 | if (start_operand > start_comment) { 1007 | fprintf(stderr, "Operand error: -o%d > -c%d\n", start_operand, start_comment); 1008 | exit(1); 1009 | } 1010 | } 1011 | if (tabs > 0) { 1012 | if (start_mnemonic % tabs) { 1013 | fprintf(stderr, "Operand error: -m%d isn't a multiple of -t%d\n", start_mnemonic, tabs); 1014 | exit(1); 1015 | } 1016 | if (start_operand % tabs) { 1017 | fprintf(stderr, "Operand error: -m%d isn't a multiple of -t%d\n", start_operand, tabs); 1018 | exit(1); 1019 | } 1020 | if (start_comment % tabs) { 1021 | fprintf(stderr, "Operand error: -m%d isn't a multiple of -t%d\n", start_comment, tabs); 1022 | exit(1); 1023 | } 1024 | if (nesting_space % tabs) { 1025 | fprintf(stderr, "Operand error: -n%d isn't a multiple of -t%d\n", nesting_space, tabs); 1026 | exit(1); 1027 | } 1028 | } 1029 | if (something && processor == P_TMS9900) { 1030 | fprintf(stderr, "Warning: ignoring operand column, not possible because you selected TMS9900 mode\n"); 1031 | } 1032 | 1033 | /* 1034 | ** Open input file, measure it and read it into buffer 1035 | */ 1036 | input = fopen(argv[c], "rb"); 1037 | if (input == NULL) { 1038 | fprintf(stderr, "Unable to open input file: %s\n", argv[c]); 1039 | exit(1); 1040 | } 1041 | fprintf(stderr, "Processing %s...\n", argv[c]); 1042 | fseek(input, 0, SEEK_END); 1043 | allocation = ftell(input); 1044 | data = malloc(allocation + sizeof(char)); 1045 | if (data == NULL) { 1046 | fprintf(stderr, "Unable to allocate memory\n"); 1047 | fclose(input); 1048 | exit(1); 1049 | } 1050 | fseek(input, 0, SEEK_SET); 1051 | if (fread(data, sizeof(char), allocation, input) != allocation) { 1052 | fprintf(stderr, "Something went wrong reading the input file\n"); 1053 | fclose(input); 1054 | free(data); 1055 | exit(1); 1056 | } 1057 | fclose(input); 1058 | 1059 | /* 1060 | ** Ease processing of input file 1061 | */ 1062 | request = 0; 1063 | p1 = data; 1064 | p2 = data; 1065 | while (p1 < data + allocation) { 1066 | if (*p1 == '\r') { /* Ignore \r characters */ 1067 | p1++; 1068 | continue; 1069 | } 1070 | if (*p1 == '\n') { 1071 | p1++; 1072 | 1073 | /* Remove trailing spaces */ 1074 | while (p2 > data && *(p2 - 1) != '\0' && isspace(*(p2 - 1))) 1075 | p2--; 1076 | *p2++ = '\0'; /* Break line */ 1077 | request = 1; 1078 | continue; 1079 | } 1080 | *p2++ = *p1++; 1081 | request = 0; 1082 | } 1083 | if (request == 0) 1084 | *p2++ = '\0'; /* Force line break */ 1085 | allocation = p2 - data; 1086 | 1087 | /* 1088 | ** Now generate output file 1089 | */ 1090 | c++; 1091 | output = fopen(argv[c], "w"); 1092 | if (output == NULL) { 1093 | fprintf(stderr, "Unable to open output file: %s\n", argv[c]); 1094 | exit(1); 1095 | } 1096 | prev_comment_original_location = 0; 1097 | prev_comment_final_location = 0; 1098 | current_level = 0; 1099 | p = data; 1100 | while (p < data + allocation) { 1101 | something = 0; 1102 | current_column = 0; 1103 | p1 = p; 1104 | p2 = p1; 1105 | 1106 | while (*p2 && !isspace(*p2) && !comment_present(p, p2, 1)) { 1107 | p2++; 1108 | } 1109 | if (p2 - p1) { /* Label */ 1110 | something = 1; 1111 | fwrite(p1, sizeof(char), p2 - p1, output); 1112 | current_column = p2 - p1; 1113 | p1 = p2; 1114 | } else { 1115 | current_column = 0; 1116 | } 1117 | while (*p1 && isspace(*p1) && !comment_present(p, p1, 1)) 1118 | p1++; 1119 | indent = current_level * nesting_space; 1120 | flags = 0; 1121 | if (*p1 && !comment_present(p, p1, 1)) { /* Mnemonic */ 1122 | p2 = p1; 1123 | while (*p2 && !isspace(*p2) && !comment_present(p, p2, 0)) 1124 | p2++; 1125 | if (processor != P_UNK) { /* The processor is defined */ 1126 | c = check_opcode(p1, p2); 1127 | if (c == 0) { /* No match */ 1128 | request = start_mnemonic; 1129 | } else if (c < 0) { /* Mnemonic */ 1130 | request = start_mnemonic; 1131 | } else { /* Directive */ 1132 | if (processor == P_6502) 1133 | flags = directives_dasm[c - 1].flags; 1134 | else if (processor == P_Z80) 1135 | flags = directives_tniasm[c - 1].flags; 1136 | else if (processor == P_CP1610) 1137 | flags = directives_as1600[c - 1].flags; 1138 | else if (processor == P_TMS9900) 1139 | flags = directives_xas99[c - 1].flags; 1140 | else if (processor == P_8086) 1141 | flags = directives_nasm[c - 1].flags; 1142 | else if (processor == P_65C02) 1143 | flags = directives_ca65[c - 1].flags; 1144 | else if (processor == P_6502_GASM80) 1145 | flags = directives_gasm80[c - 1].flags; 1146 | else if (processor == P_Z80_GASM80) 1147 | flags = directives_gasm80[c - 1].flags; 1148 | if (flags & DONT_RELOCATE_LABEL) 1149 | request = start_operand; 1150 | else 1151 | request = start_mnemonic; 1152 | } 1153 | } else { 1154 | request = start_mnemonic; 1155 | c = 0; 1156 | } 1157 | if (c <= 0) { /* Mnemonic or unknown */ 1158 | if (mnemonics_case == 1) { 1159 | p3 = p1; 1160 | while (p3 < p2) { 1161 | *p3 = tolower(*p3); 1162 | p3++; 1163 | } 1164 | } else if (mnemonics_case == 2) { 1165 | p3 = p1; 1166 | while (p3 < p2) { 1167 | *p3 = toupper(*p3); 1168 | p3++; 1169 | } 1170 | } 1171 | } else { /* Directive */ 1172 | if (directives_case == 1) { 1173 | p3 = p1; 1174 | while (p3 < p2) { 1175 | *p3 = tolower(*p3); 1176 | p3++; 1177 | } 1178 | } else if (directives_case == 2) { 1179 | p3 = p1; 1180 | while (p3 < p2) { 1181 | *p3 = toupper(*p3); 1182 | p3++; 1183 | } 1184 | } 1185 | } 1186 | 1187 | /* 1188 | ** Move label to own line 1189 | */ 1190 | if (current_column != 0 && labels_own_line != 0 && (flags & DONT_RELOCATE_LABEL) == 0) { 1191 | fputc('\n', output); 1192 | current_column = 0; 1193 | } 1194 | if (flags & LEVEL_OUT) { /* Directive, exits nested level */ 1195 | if (current_level > 0) { 1196 | current_level--; 1197 | indent -= nesting_space; 1198 | } 1199 | } 1200 | if (flags & LEVEL_MINUS) { /* Directive, enters nested level */ 1201 | if (indent >= nesting_space) 1202 | indent -= nesting_space; 1203 | else 1204 | indent = 0; 1205 | } 1206 | request += indent; 1207 | request_space(output, ¤t_column, request, 1); 1208 | something = 1; 1209 | fwrite(p1, sizeof(char), p2 - p1, output); 1210 | current_column += p2 - p1; 1211 | p1 = p2; 1212 | while (*p1 && isspace(*p1) && !comment_present(p, p1, 0)) 1213 | p1++; 1214 | if (*p1 && !comment_present(p, p1, 0)) { /* Operand */ 1215 | if (processor == P_TMS9900) 1216 | request = current_column + 1; 1217 | else 1218 | request = start_operand + indent; 1219 | request_space(output, ¤t_column, request, 1); 1220 | p2 = p1; 1221 | while (*p2 && !comment_present(p, p2, 0)) { 1222 | if (*p2 == '"') { 1223 | p2++; 1224 | while (*p2 && *p2 != '"') { 1225 | if (*p2 == '\\' && *(p2 + 1) == '"') 1226 | p2++; 1227 | p2++; 1228 | } 1229 | p2++; 1230 | } else if (*p2 == '\'') { 1231 | p2++; 1232 | if (p2 - p1 < 6 || memcmp(p2 - 6, "AF,AF'", 6) != 0) { 1233 | while (*p2 && *p2 != '\'') { 1234 | if (*p2 == '\\' && *(p2 + 1) == '\'') 1235 | p2++; 1236 | p2++; 1237 | } 1238 | p2++; 1239 | } 1240 | } else { 1241 | p2++; 1242 | } 1243 | } 1244 | while (p2 > p1 && isspace(*(p2 - 1))) 1245 | p2--; 1246 | something = 1; 1247 | fwrite(p1, sizeof(char), p2 - p1, output); 1248 | current_column += p2 - p1; 1249 | p1 = p2; 1250 | while (*p1 && isspace(*p1) && !comment_present(p, p1, 0)) 1251 | p1++; 1252 | } 1253 | if (flags & LEVEL_IN) { 1254 | current_level++; 1255 | } 1256 | } 1257 | if (comment_present(p, p1, !something)) { /* Comment */ 1258 | if (processor == P_TMS9900) { 1259 | while (isspace(*p1)) 1260 | p1++; 1261 | } 1262 | 1263 | /* 1264 | ** Try to keep comments aligned vertically (only works 1265 | ** if spaces were used in source file) 1266 | */ 1267 | p2 = p1; 1268 | while (p2 - 1 >= p && isspace(*(p2 - 1))) 1269 | p2--; 1270 | if (processor == P_TMS9900 && p2 == p && *p1 == '*') { 1271 | request = 0; /* Cannot be other */ 1272 | } else if (p2 == p && p1 - p == prev_comment_original_location) { 1273 | request = prev_comment_final_location; 1274 | } else { 1275 | prev_comment_original_location = p1 - p; 1276 | if (current_column == 0) 1277 | request = 0; 1278 | else if (current_column < start_mnemonic + indent) 1279 | request = start_mnemonic + indent; 1280 | else 1281 | request = start_comment + indent; 1282 | if (current_column == 0 && align_comment == 1) 1283 | request = start_mnemonic + indent; 1284 | prev_comment_final_location = request; 1285 | } 1286 | request_space(output, ¤t_column, request, (*p1 == ';') ? 0 : 2); 1287 | p2 = p1; 1288 | while (*p2) 1289 | p2++; 1290 | while (p2 > p1 && isspace(*(p2 - 1))) 1291 | p2--; 1292 | fwrite(p1, sizeof(char), p2 - p1, output); 1293 | current_column += p2 - p1; 1294 | } else if (something == 0) { 1295 | prev_comment_original_location = 0; 1296 | prev_comment_final_location = 0; 1297 | } 1298 | fputc('\n', output); 1299 | while (*p++) ; 1300 | } 1301 | fclose(output); 1302 | free(data); 1303 | exit(0); 1304 | } 1305 | --------------------------------------------------------------------------------