mirror of
https://github.com/pfusik/xasm.git
synced 2024-06-15 18:29:31 +00:00
Upgraded to DMD 2.051.
This commit is contained in:
parent
034b95ea83
commit
6992795f55
326
xasm.d
326
xasm.d
|
@ -1,6 +1,6 @@
|
||||||
// xasm 3.0.2 by Piotr Fusik <fox@scene.pl>
|
// xasm 3.0.2 by Piotr Fusik <fox@scene.pl>
|
||||||
// http://xasm.atari.org
|
// http://xasm.atari.org
|
||||||
// Can be compiled with DMD v1.030.
|
// Can be compiled with DMD v2.051.
|
||||||
|
|
||||||
// Poetic License:
|
// Poetic License:
|
||||||
//
|
//
|
||||||
|
@ -16,10 +16,11 @@
|
||||||
// free or for profit.
|
// free or for profit.
|
||||||
// These rights, on this notice, rely.
|
// These rights, on this notice, rely.
|
||||||
|
|
||||||
|
import std.stdio;
|
||||||
import std.math;
|
import std.math;
|
||||||
import std.stream;
|
import std.stream;
|
||||||
import std.cstream;
|
|
||||||
import std.string;
|
import std.string;
|
||||||
|
import std.conv;
|
||||||
|
|
||||||
version (Windows) {
|
version (Windows) {
|
||||||
import std.c.windows.windows;
|
import std.c.windows.windows;
|
||||||
|
@ -52,31 +53,31 @@ const char[] TITLE = "xasm 3.0.2";
|
||||||
|
|
||||||
char[] sourceFilename = null;
|
char[] sourceFilename = null;
|
||||||
|
|
||||||
bit[26] options;
|
bool[26] options;
|
||||||
|
|
||||||
char[][26] optionParameters;
|
char[][26] optionParameters;
|
||||||
|
|
||||||
char[][] commandLineDefinitions = null;
|
char[][] commandLineDefinitions = null;
|
||||||
|
|
||||||
char[] makeTarget = null;
|
char[] makeTarget;
|
||||||
|
|
||||||
char[] makeSources = "";
|
char[] makeSources;
|
||||||
|
|
||||||
int exitCode = 0;
|
int exitCode;
|
||||||
|
|
||||||
int totalLines;
|
int totalLines;
|
||||||
|
|
||||||
bit pass2 = false;
|
bool pass2;
|
||||||
|
|
||||||
bit optionFill; // opt f
|
bool optionFill; // opt f
|
||||||
|
|
||||||
bit option5200; // opt g
|
bool option5200; // opt g
|
||||||
|
|
||||||
bit optionHeaders; // opt h
|
bool optionHeaders; // opt h
|
||||||
|
|
||||||
bit optionListing; // opt l
|
bool optionListing; // opt l
|
||||||
|
|
||||||
bit optionObject; // opt o
|
bool optionObject; // opt o
|
||||||
|
|
||||||
char[] line;
|
char[] line;
|
||||||
|
|
||||||
|
@ -84,11 +85,11 @@ int column;
|
||||||
|
|
||||||
class Location {
|
class Location {
|
||||||
|
|
||||||
char[] filename;
|
string filename;
|
||||||
|
|
||||||
int lineNo = 0;
|
int lineNo = 0;
|
||||||
|
|
||||||
this(char[] filename) {
|
this(string filename) {
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,11 +98,15 @@ Location[] locations;
|
||||||
|
|
||||||
Location currentLocation;
|
Location currentLocation;
|
||||||
|
|
||||||
bit foundEnd;
|
bool foundEnd;
|
||||||
|
|
||||||
class AssemblyError : Exception {
|
class AssemblyError : Exception {
|
||||||
|
|
||||||
this(char[] msg) {
|
this(in char[] msg) {
|
||||||
|
super(msg.idup);
|
||||||
|
}
|
||||||
|
|
||||||
|
this(string msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,24 +115,24 @@ class Label {
|
||||||
|
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
bit unused = true;
|
bool unused = true;
|
||||||
|
|
||||||
bit unknownInPass1 = false;
|
bool unknownInPass1 = false;
|
||||||
|
|
||||||
bit passed = false;
|
bool passed = false;
|
||||||
|
|
||||||
this(int value) {
|
this(int value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label[char[]] labelTable;
|
Label[string] labelTable;
|
||||||
|
|
||||||
Label currentLabel;
|
Label currentLabel;
|
||||||
|
|
||||||
typedef int function(int a, int b) OperatorFunction;
|
typedef int function(int a, int b) OperatorFunction;
|
||||||
|
|
||||||
bit inOpcode = false;
|
bool inOpcode = false;
|
||||||
|
|
||||||
struct ValOp {
|
struct ValOp {
|
||||||
|
|
||||||
|
@ -142,7 +147,7 @@ ValOp[] valOpStack;
|
||||||
|
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
bit unknownInPass1;
|
bool unknownInPass1;
|
||||||
|
|
||||||
enum AddrMode {
|
enum AddrMode {
|
||||||
ACCUMULATOR = 0,
|
ACCUMULATOR = 0,
|
||||||
|
@ -175,17 +180,17 @@ ushort[] blockEnds;
|
||||||
|
|
||||||
int blockIndex;
|
int blockIndex;
|
||||||
|
|
||||||
bit repeating; // line
|
bool repeating; // line
|
||||||
|
|
||||||
int repeatCounter; // line
|
int repeatCounter; // line
|
||||||
|
|
||||||
bit instructionBegin;
|
bool instructionBegin;
|
||||||
|
|
||||||
bit pairing;
|
bool pairing;
|
||||||
|
|
||||||
bit willSkip;
|
bool willSkip;
|
||||||
|
|
||||||
bit skipping;
|
bool skipping;
|
||||||
|
|
||||||
ushort[] skipOffsets;
|
ushort[] skipOffsets;
|
||||||
|
|
||||||
|
@ -193,7 +198,7 @@ int skipOffsetsIndex = 0;
|
||||||
|
|
||||||
int repeatOffset; // instruction repeat
|
int repeatOffset; // instruction repeat
|
||||||
|
|
||||||
bit wereManyInstructions;
|
bool wereManyInstructions;
|
||||||
|
|
||||||
typedef void function(int move) MoveFunction;
|
typedef void function(int move) MoveFunction;
|
||||||
|
|
||||||
|
@ -207,11 +212,11 @@ AddrMode addrMode2;
|
||||||
|
|
||||||
struct IfContext {
|
struct IfContext {
|
||||||
|
|
||||||
bit condition;
|
bool condition;
|
||||||
|
|
||||||
bit wasElse;
|
bool wasElse;
|
||||||
|
|
||||||
bit aConditionMatched;
|
bool aConditionMatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
IfContext[] ifContexts;
|
IfContext[] ifContexts;
|
||||||
|
@ -222,37 +227,35 @@ char[32] listingLine;
|
||||||
|
|
||||||
int listingColumn;
|
int listingColumn;
|
||||||
|
|
||||||
char[] lastListedFilename = null;
|
string lastListedFilename;
|
||||||
|
|
||||||
Stream objectStream = null;
|
Stream objectStream;
|
||||||
|
|
||||||
int objectBytes = 0;
|
int objectBytes = 0;
|
||||||
|
|
||||||
bit getOption(char letter) {
|
bool getOption(char letter) {
|
||||||
assert(letter >= 'a' && letter <= 'z');
|
assert(letter >= 'a' && letter <= 'z');
|
||||||
return options[letter - 'a'];
|
return options[letter - 'a'];
|
||||||
}
|
}
|
||||||
|
|
||||||
void warning(char[] msg, bool error = false) {
|
void warning(in char[] msg, bool error = false) {
|
||||||
dout.flush();
|
stdout.flush();
|
||||||
version (Windows) {
|
version (Windows) {
|
||||||
HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
|
HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
GetConsoleScreenBufferInfo(h, &csbi);
|
GetConsoleScreenBufferInfo(h, &csbi);
|
||||||
SetConsoleTextAttribute(h, (csbi.wAttributes & ~0xf) | (error ? 12 : 14));
|
SetConsoleTextAttribute(h, (csbi.wAttributes & ~0xf) | (error ? 12 : 14));
|
||||||
|
scope (exit) SetConsoleTextAttribute(h, csbi.wAttributes);
|
||||||
}
|
}
|
||||||
if (line !is null) {
|
if (line !is null) {
|
||||||
derr.printf("%.*s\n", line);
|
stderr.writeln(line);
|
||||||
}
|
}
|
||||||
derr.printf("%.*s (%d) %.*s: %.*s\n",
|
stderr.writefln("%s (%d) %s: %s",
|
||||||
currentLocation.filename,
|
currentLocation.filename,
|
||||||
currentLocation.lineNo,
|
currentLocation.lineNo,
|
||||||
error ? "ERROR" : "WARNING",
|
error ? "ERROR" : "WARNING",
|
||||||
msg
|
msg
|
||||||
);
|
);
|
||||||
version (Windows) {
|
|
||||||
SetConsoleTextAttribute(h, csbi.wAttributes);
|
|
||||||
}
|
|
||||||
exitCode = 1;
|
exitCode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +263,7 @@ void illegalCharacter() {
|
||||||
throw new AssemblyError("Illegal character");
|
throw new AssemblyError("Illegal character");
|
||||||
}
|
}
|
||||||
|
|
||||||
bit eol() {
|
bool eol() {
|
||||||
return column >= line.length;
|
return column >= line.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,7 +330,7 @@ void readSpaces() {
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] readLabel() {
|
char[] readLabel() {
|
||||||
char[] label = "";
|
char[] label;
|
||||||
while (!eol()) {
|
while (!eol()) {
|
||||||
char c = line[column++];
|
char c = line[column++];
|
||||||
if (c >= '0' && c <= '9' || c == '_') {
|
if (c >= '0' && c <= '9' || c == '_') {
|
||||||
|
@ -352,7 +355,7 @@ void readComma() {
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] readInstruction() {
|
char[] readInstruction() {
|
||||||
char[] r = "";
|
char[] r;
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
char c = readChar() & 0xdf;
|
char c = readChar() & 0xdf;
|
||||||
if (c < 'A' || c > 'Z') {
|
if (c < 'A' || c > 'Z') {
|
||||||
|
@ -364,12 +367,12 @@ char[] readInstruction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] readFunction() {
|
char[] readFunction() {
|
||||||
if (column + 5 >= line.length) return "";
|
if (column + 5 >= line.length) return null;
|
||||||
if (line[column + 3] != '(') return "";
|
if (line[column + 3] != '(') return null;
|
||||||
char[] r = "";
|
char[] r;
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
char c = line[column + i] & 0xdf;
|
char c = line[column + i] & 0xdf;
|
||||||
if (c < 'A' || c > 'Z') return "";
|
if (c < 'A' || c > 'Z') return null;
|
||||||
r ~= c;
|
r ~= c;
|
||||||
}
|
}
|
||||||
column += 4;
|
column += 4;
|
||||||
|
@ -377,7 +380,7 @@ char[] readFunction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] readFilename() {
|
char[] readFilename() {
|
||||||
char[] filename = "";
|
char[] filename;
|
||||||
readSpaces();
|
readSpaces();
|
||||||
char delimiter = readChar();
|
char delimiter = readChar();
|
||||||
switch (delimiter) {
|
switch (delimiter) {
|
||||||
|
@ -391,6 +394,7 @@ char[] readFilename() {
|
||||||
default:
|
default:
|
||||||
illegalCharacter();
|
illegalCharacter();
|
||||||
}
|
}
|
||||||
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void readStringChar(char c) {
|
void readStringChar(char c) {
|
||||||
|
@ -413,7 +417,7 @@ ubyte[] readString() {
|
||||||
if (line[column] != delimiter) {
|
if (line[column] != delimiter) {
|
||||||
if (line[column] == '*') {
|
if (line[column] == '*') {
|
||||||
column++;
|
column++;
|
||||||
foreach (inout ubyte b; r) {
|
foreach (ref b; r) {
|
||||||
b ^= 0x80;
|
b ^= 0x80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -548,7 +552,7 @@ int operatorShiftLeft(int a, int b) {
|
||||||
if (b < 0) {
|
if (b < 0) {
|
||||||
return operatorShiftRight(a, -b);
|
return operatorShiftRight(a, -b);
|
||||||
}
|
}
|
||||||
if (a != 0 & b >= 32) {
|
if (a != 0 && b >= 32) {
|
||||||
throw new AssemblyError("Arithmetic overflow");
|
throw new AssemblyError("Arithmetic overflow");
|
||||||
}
|
}
|
||||||
long r = cast(long) a << b;
|
long r = cast(long) a << b;
|
||||||
|
@ -672,8 +676,8 @@ void readValue() {
|
||||||
}
|
}
|
||||||
ValOp[] savedValOpStack = valOpStack;
|
ValOp[] savedValOpStack = valOpStack;
|
||||||
AddrMode savedAddrMode = addrMode;
|
AddrMode savedAddrMode = addrMode;
|
||||||
bit savedUnknownInPass1 = unknownInPass1;
|
bool savedUnknownInPass1 = unknownInPass1;
|
||||||
bit savedInstructionBegin = instructionBegin;
|
bool savedInstructionBegin = instructionBegin;
|
||||||
valOpStack.length = 0;
|
valOpStack.length = 0;
|
||||||
inOpcode = true;
|
inOpcode = true;
|
||||||
assemblyInstruction(readInstruction());
|
assemblyInstruction(readInstruction());
|
||||||
|
@ -863,11 +867,11 @@ void readValue() {
|
||||||
valOpStack.length = 0;
|
valOpStack.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug int testValue(char[] l) {
|
debug int testValue(in char[] l) {
|
||||||
line = l;
|
line = l.dup;
|
||||||
column = 0;
|
column = 0;
|
||||||
readValue();
|
readValue();
|
||||||
dout.printf("Value of %.*s is %x\n", line, value);
|
writefln("Value of %s is %x", line, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1139,11 +1143,11 @@ void readAbsoluteAddrMode() {
|
||||||
addrMode = AddrMode.ABSOLUTE;
|
addrMode = AddrMode.ABSOLUTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug AddrMode testAddrMode(char[] l) {
|
debug AddrMode testAddrMode(in char[] l) {
|
||||||
line = l;
|
line = l.dup;
|
||||||
column = 0;
|
column = 0;
|
||||||
readAddrMode();
|
readAddrMode();
|
||||||
dout.printf("Addressing mode of \"%.*s\" is %x\n", line, addrMode);
|
writefln("Addressing mode of \"%s\" is %x", line, addrMode);
|
||||||
return addrMode;
|
return addrMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1166,14 +1170,14 @@ unittest {
|
||||||
inOpcode = false;
|
inOpcode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit inFalseCondition() {
|
bool inFalseCondition() {
|
||||||
foreach (IfContext ic; ifContexts) {
|
foreach (IfContext ic; ifContexts) {
|
||||||
if (!ic.condition) return true;
|
if (!ic.condition) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int filenameExt(char[] filename) {
|
int filenameExt(in char[] filename) {
|
||||||
int i = filename.length;
|
int i = filename.length;
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
switch (filename[i]) {
|
switch (filename[i]) {
|
||||||
|
@ -1197,19 +1201,19 @@ unittest {
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] makeEscape(char[] s) {
|
char[] makeEscape(char[] s) {
|
||||||
return replace(s, "$", "$$");
|
return replace(s.idup, "$", "$$").dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream openInputFile(char[] filename) {
|
Stream openInputFile(char[] filename) {
|
||||||
makeSources ~= ' ' ~ makeEscape(filename);
|
makeSources ~= ' ' ~ makeEscape(filename);
|
||||||
try {
|
try {
|
||||||
return new BufferedFile(filename, FileMode.In);
|
return new BufferedFile(filename.idup, FileMode.In);
|
||||||
} catch (OpenException e) {
|
} catch (OpenException e) {
|
||||||
throw new AssemblyError(e.toString());
|
throw new AssemblyError(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream openOutputFile(char letter, char[] defaultExt) {
|
Stream openOutputFile(char letter, string defaultExt) {
|
||||||
char[] filename;
|
char[] filename;
|
||||||
if (optionParameters[letter - 'a'] is null) {
|
if (optionParameters[letter - 'a'] is null) {
|
||||||
filename = sourceFilename;
|
filename = sourceFilename;
|
||||||
|
@ -1225,24 +1229,24 @@ Stream openOutputFile(char letter, char[] defaultExt) {
|
||||||
makeTarget = makeEscape(filename);
|
makeTarget = makeEscape(filename);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new BufferedFile(filename, FileMode.OutNew);
|
return new BufferedFile(filename.idup, FileMode.OutNew);
|
||||||
} catch (OpenException e) {
|
} catch (OpenException e) {
|
||||||
throw new AssemblyError(e.toString());
|
throw new AssemblyError(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ensureListingFileOpen(char letter, char[] msg) {
|
void ensureListingFileOpen(char letter, in char[] msg) {
|
||||||
if (listingStream is null) {
|
if (listingStream is null) {
|
||||||
listingStream = openOutputFile(letter, ".lst");
|
listingStream = openOutputFile(letter, ".lst");
|
||||||
if (!getOption('q')) {
|
if (!getOption('q')) {
|
||||||
dout.printf(msg);
|
write(msg);
|
||||||
}
|
}
|
||||||
listingStream.printf(TITLE ~ "\r\n");
|
listingStream.writeLine(TITLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void listNibble(int x) {
|
void listNibble(int x) {
|
||||||
listingLine[listingColumn++] = x <= 9 ? x + '0' : x + ('A' - 10);
|
listingLine[listingColumn++] = cast(char) (x <= 9 ? x + '0' : x + ('A' - 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
void listByte(ubyte x) {
|
void listByte(ubyte x) {
|
||||||
|
@ -1268,13 +1272,13 @@ void listLine() {
|
||||||
}
|
}
|
||||||
ensureListingFileOpen('l', "Writing listing file...\n");
|
ensureListingFileOpen('l', "Writing listing file...\n");
|
||||||
if (currentLocation.filename != lastListedFilename) {
|
if (currentLocation.filename != lastListedFilename) {
|
||||||
listingStream.printf("Source: %.*s\n", currentLocation.filename);
|
listingStream.writefln("Source: %s", currentLocation.filename);
|
||||||
lastListedFilename = currentLocation.filename;
|
lastListedFilename = currentLocation.filename;
|
||||||
}
|
}
|
||||||
int i = 4;
|
int i = 4;
|
||||||
int x = currentLocation.lineNo;
|
int x = currentLocation.lineNo;
|
||||||
while (x > 0 && i >= 0) {
|
while (x > 0 && i >= 0) {
|
||||||
listingLine[i--] = '0' + x % 10;
|
listingLine[i--] = cast(char) ('0' + x % 10);
|
||||||
x /= 10;
|
x /= 10;
|
||||||
}
|
}
|
||||||
while (i >= 0) {
|
while (i >= 0) {
|
||||||
|
@ -1284,7 +1288,7 @@ void listLine() {
|
||||||
while (listingColumn < 32) {
|
while (listingColumn < 32) {
|
||||||
listingLine[listingColumn++] = ' ';
|
listingLine[listingColumn++] = ' ';
|
||||||
}
|
}
|
||||||
listingStream.printf("%.32s%.*s\r\n", cast(char*) listingLine, line);
|
listingStream.writefln("%.32s%s", listingLine, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void listCommentLine() {
|
void listCommentLine() {
|
||||||
|
@ -1303,8 +1307,8 @@ void listLabelTable() {
|
||||||
listingStream = null;
|
listingStream = null;
|
||||||
}
|
}
|
||||||
ensureListingFileOpen('t', "Writing label table...\n");
|
ensureListingFileOpen('t', "Writing label table...\n");
|
||||||
listingStream.printf("Label table:\r\n");
|
listingStream.writefln("Label table:");
|
||||||
foreach (char[] name; labelTable.keys.sort) {
|
foreach (name; labelTable.keys.sort) {
|
||||||
Label l = labelTable[name];
|
Label l = labelTable[name];
|
||||||
listingStream.write(l.unused ? 'n' : ' ');
|
listingStream.write(l.unused ? 'n' : ' ');
|
||||||
listingStream.write(l.unknownInPass1 ? '2' : ' ');
|
listingStream.write(l.unknownInPass1 ? '2' : ' ');
|
||||||
|
@ -1314,8 +1318,8 @@ void listLabelTable() {
|
||||||
sign = '-';
|
sign = '-';
|
||||||
value = -value;
|
value = -value;
|
||||||
}
|
}
|
||||||
listingStream.printf(
|
listingStream.writefln(
|
||||||
(l.value & 0xffff0000) != 0 ? " %c%08X %.*s\r\n" : " %c%04X %.*s\r\n",
|
(l.value & 0xffff0000) != 0 ? " %s%08X %s" : " %s%04X %s",
|
||||||
sign, value, name
|
sign, value, name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1332,7 +1336,7 @@ void objectByte(ubyte b) {
|
||||||
if (objectStream is null) {
|
if (objectStream is null) {
|
||||||
objectStream = openOutputFile('o', ".obx");
|
objectStream = openOutputFile('o', ".obx");
|
||||||
if (!getOption('q')) {
|
if (!getOption('q')) {
|
||||||
dout.printf("Writing object file...\n");
|
writeln("Writing object file...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -1438,7 +1442,7 @@ void putCommand(ubyte b) {
|
||||||
case AddrMode.ABSOLUTE_X:
|
case AddrMode.ABSOLUTE_X:
|
||||||
case AddrMode.ABSOLUTE_Y:
|
case AddrMode.ABSOLUTE_Y:
|
||||||
case AddrMode.INDIRECT:
|
case AddrMode.INDIRECT:
|
||||||
putWord(value);
|
putWord(cast(ushort) value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (addrMode) {
|
switch (addrMode) {
|
||||||
|
@ -1525,37 +1529,37 @@ void assemblyAccumulator(ubyte b, ubyte prefix, int move) {
|
||||||
// STA #
|
// STA #
|
||||||
illegalAddrMode();
|
illegalAddrMode();
|
||||||
}
|
}
|
||||||
putCommand(b + 9);
|
putCommand(cast(ubyte) (b + 9));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ABSOLUTE:
|
case AddrMode.ABSOLUTE:
|
||||||
putCommand(b + 0xd);
|
putCommand(cast(ubyte) (b + 0xd));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ZEROPAGE:
|
case AddrMode.ZEROPAGE:
|
||||||
putCommand(b + 5);
|
putCommand(cast(ubyte) (b + 5));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ABSOLUTE_X:
|
case AddrMode.ABSOLUTE_X:
|
||||||
putCommand(b + 0x1d);
|
putCommand(cast(ubyte) (b + 0x1d));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ZEROPAGE_X:
|
case AddrMode.ZEROPAGE_X:
|
||||||
putCommand(b + 0x15);
|
putCommand(cast(ubyte) (b + 0x15));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ZEROPAGE_Y:
|
case AddrMode.ZEROPAGE_Y:
|
||||||
addrMode -= 1;
|
addrMode -= 1;
|
||||||
goto case AddrMode.ABSOLUTE_Y;
|
goto case AddrMode.ABSOLUTE_Y;
|
||||||
case AddrMode.ABSOLUTE_Y:
|
case AddrMode.ABSOLUTE_Y:
|
||||||
putCommand(b + 0x19);
|
putCommand(cast(ubyte) (b + 0x19));
|
||||||
break;
|
break;
|
||||||
case AddrMode.INDIRECT_X:
|
case AddrMode.INDIRECT_X:
|
||||||
if ((addrMode & AddrMode.ZERO) != 0) {
|
if ((addrMode & AddrMode.ZERO) != 0) {
|
||||||
putWord(0x00a2);
|
putWord(0x00a2);
|
||||||
}
|
}
|
||||||
putCommand(b + 1);
|
putCommand(cast(ubyte) (b + 1));
|
||||||
break;
|
break;
|
||||||
case AddrMode.INDIRECT_Y:
|
case AddrMode.INDIRECT_Y:
|
||||||
if ((addrMode & AddrMode.ZERO) != 0) {
|
if ((addrMode & AddrMode.ZERO) != 0) {
|
||||||
putWord(0x00a0);
|
putWord(0x00a0);
|
||||||
}
|
}
|
||||||
putCommand(b + 0x11);
|
putCommand(cast(ubyte) (b + 0x11));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1568,19 +1572,19 @@ void assemblyShift(ubyte b) {
|
||||||
// INC @, DEC @
|
// INC @, DEC @
|
||||||
illegalAddrMode();
|
illegalAddrMode();
|
||||||
}
|
}
|
||||||
putByte(b + 0xa);
|
putByte(cast(ubyte) (b + 0xa));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ABSOLUTE:
|
case AddrMode.ABSOLUTE:
|
||||||
putCommand(b + 0xe);
|
putCommand(cast(ubyte) (b + 0xe));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ZEROPAGE:
|
case AddrMode.ZEROPAGE:
|
||||||
putCommand(b + 6);
|
putCommand(cast(ubyte) (b + 6));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ABSOLUTE_X:
|
case AddrMode.ABSOLUTE_X:
|
||||||
putCommand(b + 0x1e);
|
putCommand(cast(ubyte) (b + 0x1e));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ZEROPAGE_X:
|
case AddrMode.ZEROPAGE_X:
|
||||||
putCommand(b + 0x16);
|
putCommand(cast(ubyte) (b + 0x16));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
illegalAddrMode();
|
illegalAddrMode();
|
||||||
|
@ -1594,10 +1598,10 @@ void assemblyCompareIndex(ubyte b) {
|
||||||
putCommand(b);
|
putCommand(b);
|
||||||
break;
|
break;
|
||||||
case AddrMode.ABSOLUTE:
|
case AddrMode.ABSOLUTE:
|
||||||
putCommand(b + 0xc);
|
putCommand(cast(ubyte) (b + 0xc));
|
||||||
break;
|
break;
|
||||||
case AddrMode.ZEROPAGE:
|
case AddrMode.ZEROPAGE:
|
||||||
putCommand(b + 4);
|
putCommand(cast(ubyte) (b + 4));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
illegalAddrMode();
|
illegalAddrMode();
|
||||||
|
@ -1761,7 +1765,7 @@ ubyte calculateBranch(int offset) {
|
||||||
} else {
|
} else {
|
||||||
dist = offset - 0x7f;
|
dist = offset - 0x7f;
|
||||||
}
|
}
|
||||||
throw new AssemblyError("Branch out of range by " ~ toString(dist) ~ " bytes");
|
throw new AssemblyError("Branch out of range by " ~ to!string(dist) ~ " bytes");
|
||||||
}
|
}
|
||||||
return cast(ubyte) offset;
|
return cast(ubyte) offset;
|
||||||
}
|
}
|
||||||
|
@ -1844,7 +1848,7 @@ void assemblyMove() {
|
||||||
readAddrMode();
|
readAddrMode();
|
||||||
value1 = value;
|
value1 = value;
|
||||||
addrMode1 = addrMode;
|
addrMode1 = addrMode;
|
||||||
bit unknown1 = unknownInPass1;
|
bool unknown1 = unknownInPass1;
|
||||||
readAddrMode();
|
readAddrMode();
|
||||||
value2 = value;
|
value2 = value;
|
||||||
addrMode2 = addrMode;
|
addrMode2 = addrMode;
|
||||||
|
@ -1971,7 +1975,7 @@ void assemblyDtaInteger(char letter) {
|
||||||
storeDtaNumber(value, letter);
|
storeDtaNumber(value, letter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bit realSign;
|
bool realSign;
|
||||||
|
|
||||||
int realExponent;
|
int realExponent;
|
||||||
|
|
||||||
|
@ -2009,7 +2013,7 @@ void putReal() {
|
||||||
putByte(cast(ubyte) realMantissa);
|
putByte(cast(ubyte) realMantissa);
|
||||||
}
|
}
|
||||||
|
|
||||||
bit readSign() {
|
bool readSign() {
|
||||||
switch (readChar()) {
|
switch (readChar()) {
|
||||||
case '+':
|
case '+':
|
||||||
return false;
|
return false;
|
||||||
|
@ -2022,7 +2026,7 @@ bit readSign() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void readExponent() {
|
void readExponent() {
|
||||||
bit sign = readSign();
|
bool sign = readSign();
|
||||||
char c = readChar();
|
char c = readChar();
|
||||||
if (c < '0' || c > '9') {
|
if (c < '0' || c > '9') {
|
||||||
illegalCharacter();
|
illegalCharacter();
|
||||||
|
@ -2165,11 +2169,11 @@ void assemblyDta() {
|
||||||
foreach (ubyte b; s) {
|
foreach (ubyte b; s) {
|
||||||
switch (b & 0x60) {
|
switch (b & 0x60) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
putByte(b + 0x40);
|
putByte(cast(ubyte) (b + 0x40));
|
||||||
break;
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
case 0x40:
|
case 0x40:
|
||||||
putByte(b - 0x20);
|
putByte(cast(ubyte) (b - 0x20));
|
||||||
break;
|
break;
|
||||||
case 0x60:
|
case 0x60:
|
||||||
putByte(b);
|
putByte(b);
|
||||||
|
@ -2307,7 +2311,7 @@ void assemblyErt() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bit readOption() {
|
bool readOption() {
|
||||||
switch (readChar()) {
|
switch (readChar()) {
|
||||||
case '-':
|
case '-':
|
||||||
return false;
|
return false;
|
||||||
|
@ -2316,6 +2320,7 @@ bit readOption() {
|
||||||
default:
|
default:
|
||||||
illegalCharacter();
|
illegalCharacter();
|
||||||
}
|
}
|
||||||
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assemblyOpt() {
|
void assemblyOpt() {
|
||||||
|
@ -2356,7 +2361,7 @@ void originWord(ushort value, char listingChar) {
|
||||||
listingLine[listingColumn++] = listingChar;
|
listingLine[listingColumn++] = listingChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOrigin(int addr, bit requestedHeader, bit requestedFFFF) {
|
void setOrigin(int addr, bool requestedHeader, bool requestedFFFF) {
|
||||||
origin = loadOrigin = addr;
|
origin = loadOrigin = addr;
|
||||||
if (requestedHeader || loadingOrigin < 0 || (addr != loadingOrigin && !optionFill)) {
|
if (requestedHeader || loadingOrigin < 0 || (addr != loadingOrigin && !optionFill)) {
|
||||||
blockIndex++;
|
blockIndex++;
|
||||||
|
@ -2395,8 +2400,8 @@ void checkHeadersOn() {
|
||||||
void assemblyOrg() {
|
void assemblyOrg() {
|
||||||
noRepeatSkipDirective();
|
noRepeatSkipDirective();
|
||||||
readSpaces();
|
readSpaces();
|
||||||
bit requestedFFFF = false;
|
bool requestedFFFF = false;
|
||||||
bit requestedHeader = false;
|
bool requestedHeader = false;
|
||||||
if (column + 2 < line.length && line[column + 1] == ':') {
|
if (column + 2 < line.length && line[column + 1] == ':') {
|
||||||
switch (line[column]) {
|
switch (line[column]) {
|
||||||
case 'F':
|
case 'F':
|
||||||
|
@ -2433,7 +2438,7 @@ void assemblyRunIni(ushort addr) {
|
||||||
setOrigin(addr, false, false);
|
setOrigin(addr, false, false);
|
||||||
readSpaces();
|
readSpaces();
|
||||||
readUnsignedWord();
|
readUnsignedWord();
|
||||||
putWord(value);
|
putWord(cast(ushort) (value));
|
||||||
loadingOrigin = -1; // don't fill
|
loadingOrigin = -1; // don't fill
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2463,6 +2468,7 @@ void assemblyIns() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stream stream = openInputFile(filename);
|
Stream stream = openInputFile(filename);
|
||||||
|
scope (exit) stream.close();
|
||||||
try {
|
try {
|
||||||
stream.seek(offset, offset >= 0 ? SeekPos.Set : SeekPos.End);
|
stream.seek(offset, offset >= 0 ? SeekPos.Set : SeekPos.End);
|
||||||
} catch (SeekException e) {
|
} catch (SeekException e) {
|
||||||
|
@ -2481,7 +2487,6 @@ void assemblyIns() {
|
||||||
putByte(b);
|
putByte(b);
|
||||||
if (length > 0) length--;
|
if (length > 0) length--;
|
||||||
}
|
}
|
||||||
// stream.close(); bug in Phobos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void assemblyInstruction(char[] instruction) {
|
void assemblyInstruction(char[] instruction) {
|
||||||
|
@ -2805,16 +2810,16 @@ void assemblyInstruction(char[] instruction) {
|
||||||
skipping = false;
|
skipping = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug ubyte[] testInstruction(char[] l) {
|
debug ubyte[] testInstruction(in char[] l) {
|
||||||
objectBuffer.length = 0;
|
objectBuffer.length = 0;
|
||||||
line = l;
|
line = l.dup;
|
||||||
column = 0;
|
column = 0;
|
||||||
assemblyInstruction(readInstruction());
|
assemblyInstruction(readInstruction());
|
||||||
dout.printf("%.*s assembles to", line);
|
write(line, " assembles to");
|
||||||
foreach (ubyte b; objectBuffer) {
|
foreach (ubyte b; objectBuffer) {
|
||||||
dout.printf(" %02x", b);
|
writef(" %02x", b);
|
||||||
}
|
}
|
||||||
dout.printf("\n");
|
writeln();
|
||||||
return objectBuffer;
|
return objectBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2853,14 +2858,14 @@ void assemblyPair() {
|
||||||
|
|
||||||
void assemblyLine() {
|
void assemblyLine() {
|
||||||
debug {
|
debug {
|
||||||
dout.printf("%.*s\n", line);
|
writeln(line);
|
||||||
}
|
}
|
||||||
currentLocation.lineNo++;
|
currentLocation.lineNo++;
|
||||||
totalLines++;
|
totalLines++;
|
||||||
column = 0;
|
column = 0;
|
||||||
listingColumn = 6;
|
listingColumn = 6;
|
||||||
if (origin >= 0) {
|
if (origin >= 0) {
|
||||||
listWord(origin);
|
listWord(cast(ushort) origin);
|
||||||
listingLine[listingColumn++] = ' ';
|
listingLine[listingColumn++] = ' ';
|
||||||
}
|
}
|
||||||
char[] label = readLabel();
|
char[] label = readLabel();
|
||||||
|
@ -2872,7 +2877,7 @@ void assemblyLine() {
|
||||||
throw new AssemblyError("Label declared twice");
|
throw new AssemblyError("Label declared twice");
|
||||||
}
|
}
|
||||||
currentLabel = new Label(origin);
|
currentLabel = new Label(origin);
|
||||||
labelTable[label] = currentLabel;
|
labelTable[label.idup] = currentLabel;
|
||||||
} else {
|
} else {
|
||||||
assert(label in labelTable);
|
assert(label in labelTable);
|
||||||
currentLabel = labelTable[label];
|
currentLabel = labelTable[label];
|
||||||
|
@ -2978,48 +2983,45 @@ void assemblyFile(char[] filename) {
|
||||||
if (getOption('p')) {
|
if (getOption('p')) {
|
||||||
filename = getFullPath(filename);
|
filename = getFullPath(filename);
|
||||||
}
|
}
|
||||||
currentLocation = new Location(filename);
|
currentLocation = new Location(filename.idup);
|
||||||
foundEnd = false;
|
foundEnd = false;
|
||||||
Stream stream = openInputFile(filename);
|
Stream stream = openInputFile(filename);
|
||||||
line = "";
|
scope (exit) stream.close();
|
||||||
try {
|
line = null;
|
||||||
readChar: while (!foundEnd) {
|
readChar: while (!foundEnd) {
|
||||||
ubyte c;
|
ubyte c;
|
||||||
|
try {
|
||||||
|
stream.read(c);
|
||||||
|
} catch (ReadException e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case '\r':
|
||||||
|
assemblyLine();
|
||||||
|
line = null;
|
||||||
try {
|
try {
|
||||||
stream.read(c);
|
stream.read(c);
|
||||||
} catch (ReadException e) {
|
} catch (ReadException e) {
|
||||||
break;
|
break readChar;
|
||||||
}
|
}
|
||||||
switch (c) {
|
if (c != '\n') {
|
||||||
case '\r':
|
|
||||||
assemblyLine();
|
|
||||||
line = "";
|
|
||||||
try {
|
|
||||||
stream.read(c);
|
|
||||||
} catch (ReadException e) {
|
|
||||||
break readChar;
|
|
||||||
}
|
|
||||||
if (c != '\n') {
|
|
||||||
line ~= cast(char) c;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
case '\x9b':
|
|
||||||
assemblyLine();
|
|
||||||
line = "";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
line ~= cast(char) c;
|
line ~= cast(char) c;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
if (!foundEnd) {
|
case '\n':
|
||||||
|
case '\x9b':
|
||||||
assemblyLine();
|
assemblyLine();
|
||||||
|
line = null;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
line ~= cast(char) c;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
foundEnd = false;
|
|
||||||
} finally {
|
|
||||||
// stream.close(); // bug in Phobos
|
|
||||||
}
|
}
|
||||||
|
if (!foundEnd) {
|
||||||
|
assemblyLine();
|
||||||
|
}
|
||||||
|
foundEnd = false;
|
||||||
if (locations.length > 0) {
|
if (locations.length > 0) {
|
||||||
currentLocation = locations[locations.length - 1];
|
currentLocation = locations[locations.length - 1];
|
||||||
locations.length = locations.length - 1;
|
locations.length = locations.length - 1;
|
||||||
|
@ -3042,8 +3044,8 @@ void assemblyPass() {
|
||||||
wereManyInstructions = false;
|
wereManyInstructions = false;
|
||||||
if (commandLineDefinitions.length > 0) {
|
if (commandLineDefinitions.length > 0) {
|
||||||
currentLocation = new Location("command line");
|
currentLocation = new Location("command line");
|
||||||
foreach (char[] definition; commandLineDefinitions) {
|
foreach (definition; commandLineDefinitions) {
|
||||||
int i = find(definition, '=');
|
int i = indexOf(definition, '=');
|
||||||
assert(i >= 0);
|
assert(i >= 0);
|
||||||
line = definition[0 .. i] ~ " equ " ~ definition[i + 1 .. definition.length];
|
line = definition[0 .. i] ~ " equ " ~ definition[i + 1 .. definition.length];
|
||||||
assemblyLine();
|
assemblyLine();
|
||||||
|
@ -3061,7 +3063,7 @@ void assemblyPass() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bit isOption(char[] arg) {
|
bool isOption(char[] arg) {
|
||||||
if (arg.length < 2) return false;
|
if (arg.length < 2) return false;
|
||||||
if (arg[0] == '-') return true;
|
if (arg[0] == '-') return true;
|
||||||
if (arg[0] != '/') return false;
|
if (arg[0] != '/') return false;
|
||||||
|
@ -3102,12 +3104,12 @@ int main(char[][] args) {
|
||||||
char[] definition = null;
|
char[] definition = null;
|
||||||
if (arg[0] == '/') {
|
if (arg[0] == '/') {
|
||||||
if (arg.length >= 3 && arg[2] == ':') {
|
if (arg.length >= 3 && arg[2] == ':') {
|
||||||
definition = arg[3..arg.length];
|
definition = arg[3 .. arg.length];
|
||||||
}
|
}
|
||||||
} else if (i + 1 < args.length && !isOption(args[i + 1])) {
|
} else if (i + 1 < args.length && !isOption(args[i + 1])) {
|
||||||
definition = args[++i];
|
definition = args[++i];
|
||||||
}
|
}
|
||||||
if (definition is null || find(definition, '=') < 0) {
|
if (definition is null || indexOf(definition, '=') < 0) {
|
||||||
exitCode = 3;
|
exitCode = 3;
|
||||||
}
|
}
|
||||||
commandLineDefinitions ~= definition;
|
commandLineDefinitions ~= definition;
|
||||||
|
@ -3119,7 +3121,7 @@ int main(char[][] args) {
|
||||||
char[] filename = null;
|
char[] filename = null;
|
||||||
if (arg[0] == '/') {
|
if (arg[0] == '/') {
|
||||||
if (arg.length >= 3 && arg[2] == ':') {
|
if (arg.length >= 3 && arg[2] == ':') {
|
||||||
filename = arg[3..arg.length];
|
filename = arg[3 .. arg.length];
|
||||||
}
|
}
|
||||||
} else if (i + 1 < args.length && !isOption(args[i + 1])) {
|
} else if (i + 1 < args.length && !isOption(args[i + 1])) {
|
||||||
filename = args[++i];
|
filename = args[++i];
|
||||||
|
@ -3144,10 +3146,10 @@ int main(char[][] args) {
|
||||||
exitCode = 3;
|
exitCode = 3;
|
||||||
}
|
}
|
||||||
if (!getOption('q')) {
|
if (!getOption('q')) {
|
||||||
dout.printf(TITLE ~ "\n");
|
writeln(TITLE);
|
||||||
}
|
}
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
dout.printf(
|
write(
|
||||||
"Syntax: xasm source [options]\n"
|
"Syntax: xasm source [options]\n"
|
||||||
"/c Include false conditionals in listing\n"
|
"/c Include false conditionals in listing\n"
|
||||||
"/d:label=value Define a label\n"
|
"/d:label=value Define a label\n"
|
||||||
|
@ -3181,13 +3183,13 @@ int main(char[][] args) {
|
||||||
}
|
}
|
||||||
if (exitCode <= 1) {
|
if (exitCode <= 1) {
|
||||||
if (!getOption('q')) {
|
if (!getOption('q')) {
|
||||||
dout.printf("%d lines of source assembled\n", totalLines);
|
writefln("%d lines of source assembled", totalLines);
|
||||||
if (objectBytes > 0) {
|
if (objectBytes > 0) {
|
||||||
dout.printf("%d bytes written to the object file\n", objectBytes);
|
writefln("%d bytes written to the object file", objectBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getOption('m')) {
|
if (getOption('m')) {
|
||||||
dout.printf("%.*s:%.*s\n\txasm", makeTarget, makeSources);
|
writef("%s:%s\n\txasm", makeTarget, makeSources);
|
||||||
for (int i = 1; i < args.length; i++) {
|
for (int i = 1; i < args.length; i++) {
|
||||||
char[] arg = args[i];
|
char[] arg = args[i];
|
||||||
if (isOption(arg)) {
|
if (isOption(arg)) {
|
||||||
|
@ -3199,9 +3201,9 @@ int main(char[][] args) {
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
if (arg[0] == '/') {
|
if (arg[0] == '/') {
|
||||||
dout.printf(" /%c:$@", arg[1]);
|
writef(" /%c:$@", arg[1]);
|
||||||
} else {
|
} else {
|
||||||
dout.printf(" -%c $@", arg[1]);
|
writef(" -%c $@", arg[1]);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3209,18 +3211,18 @@ int main(char[][] args) {
|
||||||
if (arg[0] == '-'
|
if (arg[0] == '-'
|
||||||
&& (letter == 'd' || letter == 'l' || letter == 't')
|
&& (letter == 'd' || letter == 'l' || letter == 't')
|
||||||
&& i + 1 < args.length && !isOption(args[i + 1])) {
|
&& i + 1 < args.length && !isOption(args[i + 1])) {
|
||||||
dout.printf(" %.*s %.*s", arg, makeEscape(args[++i]));
|
writef(" %s %s", arg, makeEscape(args[++i]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dout.printf(" %.*s", makeEscape(arg));
|
writef(" %s", makeEscape(arg));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dout.printf(" $<");
|
writef(" $<");
|
||||||
}
|
}
|
||||||
dout.printf("\n");
|
writeln();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return exitCode;
|
return exitCode;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user