|
|
@@ -8,9 +8,23 @@ function ToHexString(v, l){ |
|
|
|
return r; |
|
|
|
} |
|
|
|
|
|
|
|
function GetStrings(s, rc){ |
|
|
|
s = (typeof(s) === 'string') ? [s] : s; |
|
|
|
var m = s[0].match(/"((?:\\.|[^"\\])*)"/); |
|
|
|
if (m && m.length > 0){ |
|
|
|
let i = s[0].indexOf(m[0]); |
|
|
|
if (i > 0){ |
|
|
|
s[0] = s[0].substr(0, i) + rc + s[0].substr(i + m[0].length); |
|
|
|
s.push(m[0]); |
|
|
|
return GetStrings(s, rc); |
|
|
|
} |
|
|
|
} |
|
|
|
return s; |
|
|
|
} |
|
|
|
|
|
|
|
function Tokenize(l){ |
|
|
|
var m = l.match(/([^()]+)|([()])/g); |
|
|
|
var ip = false; |
|
|
|
var ip = false; |
|
|
|
var t = []; |
|
|
|
m.forEach((mi)=>{ |
|
|
|
if (mi === "("){ |
|
|
@@ -24,9 +38,15 @@ function Tokenize(l){ |
|
|
|
t.push("+" + i); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
mi.split(/[\s,]+/).forEach((i)=>{ |
|
|
|
if (i !== "") |
|
|
|
var strs = GetStrings(mi, "*"); |
|
|
|
var stri = 1; |
|
|
|
strs[0].split(/[\s,]+/).forEach((i)=>{ |
|
|
|
if (i === "*" && stri < strs.length){ |
|
|
|
t.push(strs[stri].substr(1, strs[stri].length - 2)); |
|
|
|
stri += 1; |
|
|
|
} else if (i !== ""){ |
|
|
|
t.push(i); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
@@ -280,6 +300,35 @@ function StoreOp(data, cmp, codes, mint, maxt, zpm){ |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------- |
|
|
|
// -------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
function directive_DEFINE(data, cmp){ |
|
|
|
// Variable label!! |
|
|
|
StoreVarLabel(data, cmp.tokens[1], cmp.tokens[2]); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function directive_BYTES(data, cmp){ |
|
|
|
// Compiler directive. Treat all proceeding tokens as values and store them raw. |
|
|
|
for(let i=1; i < cmp.tokens.length; i++){ |
|
|
|
let v = Number.NaN; |
|
|
|
if (cmp.tokens[i].startsWith("$")){ |
|
|
|
v = parseInt(cmp.tokens[i].substr(1), 16); |
|
|
|
} else if (cmp.tokens[i].startsWith("b")){ |
|
|
|
v = parseInt(cmp.tokens[i].substr(1), 2); |
|
|
|
} else { |
|
|
|
v = parseInt(cmp.tokens[i]); |
|
|
|
} |
|
|
|
if (isNaN(v) || v < 0 || v >= 256) |
|
|
|
throw new Error("Byte list value is malformed or out of bounds at program address " + ToHexString(data.PC)); |
|
|
|
cmp.op.push(v); |
|
|
|
data.PC += 1; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------- |
|
|
|
// -------------------------------------------------------------------------------------------- |
|
|
@@ -300,6 +349,12 @@ class Assembler{ |
|
|
|
// Currently compiled code. |
|
|
|
result: [] |
|
|
|
}; |
|
|
|
this.__directives = { |
|
|
|
".bytes":directive_BYTES, |
|
|
|
".byt":directive_BYTES, |
|
|
|
".define":directive_DEFINE, |
|
|
|
".def":directive_DEFINE |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
get PC(){return this.__data.PC;} |
|
|
@@ -336,7 +391,7 @@ class Assembler{ |
|
|
|
let s = line.split(":"); |
|
|
|
let lbl = s[0].trim(); |
|
|
|
if (lbl.length <= 0) |
|
|
|
throw new Error("Malformatted jump label at program address " + toHexString(this.__PC)); |
|
|
|
throw new Error("Malformatted jump label at program address " + ToHexString(this.__data.PC)); |
|
|
|
StoreJmpLabel(this.__data, lbl); |
|
|
|
line = s[1].trim(); |
|
|
|
if (line.length <= 0){return this;} // Nothing left to process. |
|
|
@@ -344,64 +399,23 @@ class Assembler{ |
|
|
|
// Finally... tokenize the main command. |
|
|
|
cmp.tokens = Tokenize(line); |
|
|
|
|
|
|
|
if (cmp.tokens[0].toLowerCase() === '.define'){ |
|
|
|
// Variable label!! |
|
|
|
StoreVarLabel(this.__data, cmp.tokens[1], cmp.tokens[2]); |
|
|
|
} else if (cmp.tokens[0].toLowerCase() === '.bytes'){ |
|
|
|
// Compiler directive. Treat all proceeding tokens as values and store them raw. |
|
|
|
for(let i=1; i < cmp.tokens.length; i++){ |
|
|
|
let v = Number.NaN; |
|
|
|
if (cmp.tokens[i].startsWith("$")){ |
|
|
|
v = parseInt(cmp.tokens[i].substr(1), 16); |
|
|
|
} else if (cmp.tokens[i].startsWith("b")){ |
|
|
|
v = parseInt(cmp.tokens[i].substr(1), 2); |
|
|
|
} else { |
|
|
|
v = parseInt(cmp.tokens[i]); |
|
|
|
} |
|
|
|
if (isNaN(v) || v < 0 || v >= 256) |
|
|
|
throw new Error("Byte list value is malformed or out of bounds at program address " + toHexString(this.__PC)); |
|
|
|
cmp.op.push(v); |
|
|
|
this.__data.PC += 1; |
|
|
|
}; |
|
|
|
} else if (cmp.tokens[0].length === 3){ |
|
|
|
var directivesHandled = false; |
|
|
|
if (cmp.tokens[0].startsWith(".")){ |
|
|
|
let d = cmp.tokens[0].toLowerCase(); |
|
|
|
if (d in this.__directives){ |
|
|
|
this.__directives[d](this.__data, cmp); |
|
|
|
directivesHandled = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!directivesHandled && cmp.tokens[0].length === 3){ |
|
|
|
let procFailed = false; |
|
|
|
let mv = null; |
|
|
|
// Possible op code. |
|
|
|
switch(cmp.tokens[0].toLowerCase()){ |
|
|
|
// --- ADC |
|
|
|
case 'adc': |
|
|
|
procFailed = StoreOp(this.__data, cmp, [0x69, 0x65, 0x75, 0x6D, 0x7D, 0x79, 0x61, 0x71], 2, 3); |
|
|
|
/* |
|
|
|
if (tokens.length >= 2 && tokens.length <= 3){ |
|
|
|
mv = addrModeVal(tokens[1], (tokens.length === 3) ? tokens[2].toUpperCase(), null); |
|
|
|
this.__PC += 2; |
|
|
|
switch(mv[0]){ |
|
|
|
case "i": |
|
|
|
op.push(0x69); |
|
|
|
op.push(mv[1]); |
|
|
|
break; |
|
|
|
case "z": |
|
|
|
case "zX": |
|
|
|
op.push((mv[0] === "z") ? 0x65 : 0x75); |
|
|
|
op.push(mv[1]); |
|
|
|
break; |
|
|
|
case "a": |
|
|
|
case "aX": |
|
|
|
case "aY": |
|
|
|
op.push((mv[0] === "a") ? 0x6D : ((mv[0] === "aX") ? 0x7D : 0x79)); |
|
|
|
op.push(mv[1] & 0x000000FF); |
|
|
|
op.push((mv[1] & 0x0000FF00) >> 8); |
|
|
|
this.__PC += 1; |
|
|
|
break; |
|
|
|
case "nX": |
|
|
|
case "nY": |
|
|
|
op.push((mv[0] === "nX") ? 0x61 : 0x71); |
|
|
|
op.push(mv[1]); |
|
|
|
break; |
|
|
|
} |
|
|
|
} else { procFailed = true; } |
|
|
|
*/ |
|
|
|
break; |
|
|
|
procFailed = StoreOp(this.__data, cmp, [0x69, 0x65, 0x75, 0x6D, 0x7D, 0x79, 0x61, 0x71], 2, 3); break; |
|
|
|
// --- AND |
|
|
|
case 'and': |
|
|
|
procFailed = StoreOp(this.__data, cmp, [0x29, 0x25, 0x35, 0x2D, 0x3D, 0x39, 0x21, 0x31], 2, 3); |
|
|
@@ -652,7 +666,8 @@ class Assembler{ |
|
|
|
if (procFailed) |
|
|
|
throw new Error("Malformed op-code on program address " + ToHexString(this.__data.PC)); |
|
|
|
} else { |
|
|
|
throw new Error("Failed to compile line '" + line + "' at program address " + ToHexString(this.__data.PC)); |
|
|
|
if (!directivesHandled) |
|
|
|
throw new Error("Failed to compile line '" + line + "' at program address " + ToHexString(this.__data.PC)); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |