raspberry-pi-pico-machine-c.../compiler/tools/lispToAs.js

684 lines
16 KiB
JavaScript
Raw Normal View History

2022-05-15 22:32:35 +02:00
import * as fs from "fs";
var path = process.argv[2];
var pathout = process.argv[3];
if(!path||!pathout){
console.log("PLease this Schema: node ToAs.js [path] [pathout]");
process.exit();
}
var file = fs.readFileSync(path).toString();
function error(msg,l=null,c=null){
var out = "Error"
if(l!=null&&c!=null)out+=` in line ${l} and character ${c}`;
out+=": "+msg;
console.log("\x1b[31m",out,"\x1b[0m");
process.exit(1);
}
function cutCmd(code,line,chars){
if(!code.startsWith("("))return ["",error("Compiler Error",line,chars)];
if(!code.endsWith(")"))return ["",error("Compiler Error",line,chars)];
code = code.substring(1,code.length-1);
var countLinesBegin = line;
var countCharsBegin = chars;
var countLines = line;
var countChars = chars;
var inC = 0;
var wasinC = false;
var inStr = 0;
var buffer = "";
var i = 0;
var out = [];
function finishBuff(){
out.push(
wasinC?
new LISPcmd(buffer.trim(),countLinesBegin,countCharsBegin)
:
new LISPstring(buffer.trim(),countLinesBegin,countCharsBegin)
);
countLinesBegin = countLines;
countCharsBegin = countChars;
buffer = "";
wasinC = false;
}
for (var i = 0; i < code.length; i++) {
countChars++;
//console.log(code,countLines,countChars);
let c = code[i];
if(!inC&&!inStr){
countLinesBegin = countLines;
countCharsBegin = countChars;
}
if(c=="\\"){
buffer+=code[++i];
continue;
}
if(inStr){
if(c=="\n"){
countLines++;
countChars = 0;
}else if(c=='"'){
if(!inC)finishBuff();
inStr = false;
}else{
buffer+=c;
}
continue;
}
if(c=='"'){
inStr = true;
continue;
}
if(c==";"&&!inC){
while(code[++i]!="\n"){}
countLines++;
countChars = 0;
continue;
}
if(c=="\n"){
countLines++;
countChars = 0;
}
if((c == " "||c=="\n")&&!inC){
if(buffer.trim()!=""){
finishBuff();
}
continue;
}
if(c == "("){
if(!inC&&buffer.trim()!=""){
finishBuff();
}
inC++;
wasinC = true;
}
if(c == ")"){
inC--;
if(inC<0)error("Closing braket to much!",countLines,countChars);
if(!inC){
buffer+=c;
finishBuff();
continue;
}
}
buffer+=c;
}
if(inStr)error("Missing closing quotation mark!",countLines,countChars);
if(inC)error("Missing closing braket!",countLines,countChars);
if(buffer.trim()!="")finishBuff();
return out;
}
class LISPstring extends String {
#l;
#c;
constructor(string,line,char) {
super(string);
this.#l = line;
this.#c = char;
}
get lineCount(){
return this.#l;
}
get charCount(){
return this.#l;
}
get pos(){
return [this.#l,this.#c];
}
}
class LISPcmd extends Array {
#l;
#c;
constructor(code,line,char) {
var childs = cutCmd(code,line,char);
super(...childs);
this.#l = line;
this.#c = char;
}
get lineCount(){
return this.#l;
}
get charCount(){
return this.#l;
}
get pos(){
return [this.#l,this.#c];
}
}
var data = new LISPcmd("(\n"+file+"\n)",0,0);
//console.log(JSON.stringify(data));
function getType(data){
/*if(data=="empty"){
return ["emp", ""];
}*/
if(data=="true"){
return ["bool", 1];
}
if(data=="false"){
return ["bool", 0];
}
if(data=="NaN"){
return ["num", NaN];
}
/*if(typeof data == "string"&&data.startsWith('"') && data.endsWith('"')){
return ["str", data.slice(1,-1)];
}*/
if((data instanceof LISPstring)&&!isNaN(data)/*!data.match(new RegExp("[^0-9.-e+]","g"))*/){
return ["num", Number(data)];
}
if(data instanceof LISPcmd/*Array.isArray(data)*/){
return ["code", data];
}
return ["var",data];
}
var nid = 0;
var dataTypes = {
uint32: {ptype:0, length:4, mask:null },
uint16: {ptype:0, length:2, mask:0xffff },
uint8: {ptype:0, length:1, mask:0xff },
int32: {ptype:1, length:4, mask:null },
int16: {ptype:1, length:2, mask:0xffff },
int8: {ptype:1, length:1, mask:0xff },
float: {ptype:2, length:4, mask:null },
bool: {ptype:0, length:1, mask:1 },
};
var dataTypesReversed = {
0:"uint/bool",
1:"int",
2:"float"
}
/*var numTypes = ["uint32", "uint16","uint8","int32","int16","int8","float","bool"];*/
function last(d){
return d[d.length-1];
}
function find(d,n){
for (var i = d.length-1; i >= 0 ; i--) {
if(typeof d[i][n] == "object")return d[i][n];
}
return null;
}
function createVars(c){
var l = 0;
return [Object.entries(c).map(d=>{
var out = `${d[1].id} = ${l};${dataTypes[d[1].type].length}`;
if(d[1].used==0) return ";"+out;
l+=dataTypes[d[1].type].length;
return out;
}).join("\n"),l];
}
var extrafuns = {
};
function execute(data,expect,context,local){
var code = "";
var ptype = 0;
var doconv = true;
let [type,d] = getType(data);
if(type == "code"){
if(data[0]=="defvar"){
var ctx = last(context);
var [vname,vtype] = data[1].split(":");
if(ctx[vname])error(`Can not redefine: ${cname}! It is already defined!`,...data.pos);
if(!dataTypes[vtype])error(`Unknown Datatype: ${vtype}`,...data.pos);
let mvar = {type:vtype,used:0,id:"v"+nid++,local:local};
ctx["v"+vname] = mvar;
let [c,etype] = execute(data[2],mvar.type,context,local);
code+= `
;defvar: executing value:
${c}
;defvar: Store Value
STA ${dataTypes[mvar.type].length|(mvar.local?0x10:0)} ${mvar.id}
`;
ptype = dataTypes[mvar.type].ptype;
}else if(data[0]=="defun"){
var [fname,ftype] = (data[1]??"").split(":");
if(local)error(`Nested functions are currently not supported: ${fname}`,...data.pos);
if(extrafuns[fname])error(`You can not declare functions double: ${fname}`,...data.pos);
if(!dataTypes[ftype])error(`Unknown Datatype: ${ftype}`,...data.pos);
var ctx = last(context);
var funsCtx = {};
var args = [];
var lcode = "";
data[2].forEach(v=>{
var [vname,vtype] = v.split(":");
if(funsCtx[vname])error(`You declared the Argument ${vname} in function",fname,"twice!`,...data.pos);
if(!dataTypes[vtype])error(`Unknown Datatype: ${vtype}`,...data.pos);
var mvarg = {type:vtype,used:1,id:"arg"+nid++,local:false};
var mvarl = {type:vtype,used:1,id:"arg"+nid++,local:true};
funsCtx["v"+vname] = mvarl;
args.push(mvarg);
ctx["arg_"+vname] = mvarg;
lcode+=`
;function copy args
LDA ${dataTypes[mvarg.type].length} ${mvarg.id}
STA ${dataTypes[mvarl.type].length|0x10} ${mvarl.id}
`
});
var mvar = {type:ftype,used:1,id:"return"+nid++,local:false};
var fun = {
type:ftype,
code:"",
args,
return:mvar
};
extrafuns[fname] = fun;
//execute lcode
lcode+="\n;function code:\n";
for (var i = 3; i < data.length; i++) {
let [c,t] = execute(data[i],data.length-1==i?ftype:"any",[...context,funsCtx],true);
lcode+=c;
}
ctx["return_"+fname] = mvar;
lcode+= `
;return from subrutine
STA ${dataTypes[mvar.type].length} ${mvar.id}
RSR
`;
let [localvars,localL] = createVars(funsCtx);
lcode = `
;function reserve Stackspace
${(new Array(Math.floor(localL/255))).fill("PSH 255").join("\n ")}
${(localL%255>0?`PSH ${localL%255}`:'')}
;function place variable pointers
${localvars}
${lcode}
`;
fun.code = lcode;
code=`
LIA .${fname}
`;
ptype=0;
}else if(data[0]=="let"){
var mvar = find(context,"v"+data[1]);
if(mvar == null)error(`Unknown Variable: ${data[1]}`,...data.pos);
mvar.used++;
let [c,etype] = execute(data[2],mvar.type,context,local);
code+= `
;let: executing value:
${c}
;let: Store Value
STA ${dataTypes[mvar.type].length|(mvar.local?0x10:0)} ${mvar.id}
`;
ptype = dataTypes[mvar.type].ptype;
}else if(data[0]=="+"){
var etypes = [];
var etypeMax = 0;
for (var i = 1; i < data.length; i++) {
let [c,etype] = execute(data[i],"num",context,local);
code+=`
;+: next value
${c}
`;
if(i<data.length-1){
code+=`
PSH 4
`;
}
etypes.push(etype);
if(etype>etypeMax)etypeMax=etype;
}
if(etypes[0]!=etypeMax){
code+=`
;+: converting not matching types
CVA ${etypes[0]} ${etypeMax}
`;
}
for (var i = 1; i < etypes.length; i++) {
code+=`
;+: Pull/Add next
CAB
PUL 4
ADD ${etypeMax} ${etypes[i]} ${etypeMax}
`;
}
ptype = etypeMax;
}else if(data[0]=="-"){
var etypes = [];
var etypeMax = 0;
for (var i = data.length-1; i >=1 ; i--) {
let [c,etype] = execute(data[i],"num",context,local);
code+=`
;-: next value
${c}
`;
if(i>1){
code+=`
PSH 4
`;
}
etypes.push(etype);
if(etype>etypeMax)etypeMax=etype;
}
if(etypes[0]!=etypeMax){
code+=`
;-: converting not matching types
CVA ${etypes[0]} ${etypeMax}
`;
}
for (var i = 1; i < etypes.length; i++) {
code+=`
;-: Pull/Add next
CAC
PUL 4
CAB
CCA
SUB ${etypeMax} ${etypes[i]} ${etypeMax}
`;
}
ptype = etypeMax;
}else if(data[0]=="*"){
var etypes = [];
var etypeMax = 0;
for (var i = 1; i < data.length; i++) {
let [c,etype] = execute(data[i],"num",context,local);
code+=`
;*: next value
${c}
`;
if(i<data.length-1){
code+=`
PSH 4
`;
}
etypes.push(etype);
if(etype>etypeMax)etypeMax=etype;
}
if(etypes[0]!=etypeMax){
code+=`
;*: converting not matching types
CVA ${etypes[0]} ${etypeMax}
`;
}
for (var i = 1; i < etypes.length; i++) {
code+=`
;*: Pull/Add next
CAB
PUL 4
MUL ${etypeMax} ${etypes[i]} ${etypeMax}
`;
}
ptype = etypeMax;
}else if(data[0]=="/"){
var etypes = [];
var etypeMax = 0;
for (var i = data.length-1; i >=1 ; i--) {
let [c,etype] = execute(data[i],"num",context,local);
code+=`
;/: next value
${c}
`;
if(i>1){
code+=`
PSH 4
`;
}
etypes.push(etype);
if(etype>etypeMax)etypeMax=etype;
}
if(etypes[0]!=etypeMax){
code+=`
;/: converting not matching types
CVA ${etypes[0]} ${etypeMax}
`;
}
for (var i = 1; i < etypes.length; i++) {
code+=`
;/: Pull/Add next
CAC
PUL 4
CAB
CCA
DIV ${etypeMax} ${etypes[i]} ${etypeMax}
`;
}
ptype = etypeMax;
}else if(data[0]=="print"){
let [c,etype] = execute(data[1],"any",context,local);
code+=`
;print: executing value:
${c}
;print Value
OUT ${etype}
`;
ptype = etype;
}else if(data[0]=="if"){
let [c,etype] = execute(data[1],"bool",context,local);
let [c1,etype1] = execute(data[2],expect,context,local);
let c2,etype2;
if(typeof data[3]!="undefined"){
[c2,etype2] = execute(data[3],expect,context,local);
}else{
[c2,etype2] = ["LIA 0",0];
}
var id = nid++;
code+=`
;if: executing value:
${c}
;if:
LIB 1
CMP 0 0
JNE .else${id}
;then code
${c1}
JMP .afterif${id}
else${id}:
;else code
${c2}
afterif${id}:
`;
ptype = etype1;
}else if(data[0]==">"){
let [c1,etype1] = execute(data[1],"num",context,local);
let [c2,etype2] = execute(data[2],"num",context,local);
doconv = false;
var id = nid++;
code+=`
;>: execute first
${c1}
PSH 4
;>: execute secound
${c2}
CAB
PUL 4
CMP ${etype1} ${etype2}
LIA 1
JB .endcompare${id}
LIA 0
endcompare${id}:
`;
}else if(data[0]=="<"){
let [c1,etype1] = execute(data[1],"num",context,local);
let [c2,etype2] = execute(data[2],"num",context,local);
doconv = false;
var id = nid++;
code+=`
;<: execute first
${c1}
PSH 4
;<: execute secound
${c2}
CAB
PUL 4
CMP ${etype1} ${etype2}
LIA 1
JS .endcompare${id}
LIA 0
endcompare${id}:
`;
}else if(data[0]=="="){
let [c1,etype1] = execute(data[1],"num",context,local);
let [c2,etype2] = execute(data[2],"num",context,local);
doconv = false;
var id = nid++;
code+=`
;>: execute first
${c1}
PSH 4
;>: execute secound
${c2}
CAB
PUL 4
CMP ${etype1} ${etype2}
LIA 1
JE .endcompare${id}
LIA 0
endcompare${id}:
`;
2022-05-16 17:45:34 +02:00
}else if(data[0]=="loop"){
if(data[1] == "while"){
let [c,etype] = execute(data[2],"bool",context,local);
var idbefor = nid++;
var idafter = nid++;
var codeinsert = "";
for (var i = 3; i < data.length; i++) {
let [ci,ti] = execute(data[i],i==data.length-1?expect:"any",context,local);
ptype = ti;
codeinsert+=ci;
}
code+=`
beforloop${idbefor}:
${c}
LIB 1
CMP 0 0
JNE .afterloop${idafter}
;loop code
${codeinsert}
JMP .beforloop${idbefor}
afterloop${idafter}:
`;
}else if(data[1] == "for"){
error("Methode 'for' will be implemented later.",...data[1].pos);
}else{
error(`Unknown loop Methode: ${data[1]}`,...data[1].pos);
}
2022-05-15 22:32:35 +02:00
}else{
if(extrafuns[data[0]]){
var fun = extrafuns[data[0]];
for (var i = 0; i < fun.args.length; i++) {
if(typeof data[i+1] == "undefined")error(`Argument missing for function ${data[0]}`,...data.pos);
var [ecode,etype] = execute(data[i+1],fun.args[i].type,context,local);
code+=`
;${i+1} Argument
${ecode}
STA ${dataTypes[fun.args[i].type].length} ${fun.args[i].id}
`;
}
code+=`
;excute function
JSR .${data[0]}
;loading return value
LDA ${dataTypes[fun.return.type].length} ${fun.return.id}
`;
ptype = dataTypes[fun.return.type].ptype;
}else{
error(`Unknown command: ${data[0]}`,...data.pos);
}
}
}else if(type == "var"){
let mvar = find(context,"v"+d);
if(mvar == null)error(`Unknown Variable/Expression: ${d}`,...data.pos);
mvar.used++;
code += `
;var: load Variable
LDA ${dataTypes[mvar.type].length|(mvar.local?0x10:0)} ${mvar.id}
`;
ptype = dataTypes[mvar.type].ptype;
}else if(type == "num"||type=="bool"){
ptype = Number.isInteger(d)?(d>=0?0:1):2;
if(dataTypes[expect]?.ptype == ptype){
code += `
;num: Loading num
LIA ${dataTypes[expect].mask==null?d:dataTypes[expect].ptype&d}
`;
doconv = false;
}else{
code += `
;num: Loading num
LIA ${d}
`;
}
}else{
error(`Not Supported execution type: ${type} of ${d}`,...data.pos);
}
if(expect=="any")return [code,ptype];
if(expect=="num"){
if(ptype==0||ptype==1||ptype==2){
return [code,ptype];
}else{
error(`Can not convert ${dataTypesReversed[ptype]} to Number`,...data.pos);
}
}
if(ptype!=dataTypes[expect].ptype){
code+=`
CVA ${ptype} ${dataTypes[expect].ptype}
`;
}
if(doconv&&dataTypes[expect].mask != null){
code+=`
LIB ${dataTypes[expect].mask}
BWA
`;
}
return [code,dataTypes[expect].ptype];
}
var code = "";
var context = [{}];
for (var i = 0; i < data.length; i++) {
let [c,t] = execute(data[i],"any",context);
code += c;
//console.log(c);
}
var [globvars,globL] = createVars(context[0]);
var finish = `
${globvars}
SHS ${globL}
;code
${code}
HLT
;functions
${Object.entries(extrafuns).map(d=>d[0]+":\n"+d[1].code).join("\n\n")}
`;
fs.writeFileSync(pathout,finish);
console.log(`Finished compiling in ${Math.round(performance.now())/1000}sec. Assembly saved to: ${pathout}`);