RosettaCodeData/Task/Compiler-code-generator/Zkl/compiler-code-generator-1.zkl

114 lines
3.9 KiB
Plaintext

// This is a little endian machine
const WORD_SIZE=4;
const{ var _n=-1; var[proxy]N=fcn{ _n+=1 }; } // enumerator
const FETCH=N, STORE=N, PUSH=N, ADD=N, SUB=N, MUL=N, DIV=N, MOD=N,
LT=N, GT=N, LE=N, GE=N, EQ=N, NE=N,
AND=N, OR=N, NEG=N, NOT=N,
JMP=N, JZ=N, PRTC=N, PRTS=N, PRTI=N, HALT=N;
const nd_String=N, nd_Sequence=N, nd_If=N, nd_While=N;
var all_syms=Dictionary(
"Identifier" ,FETCH, "String" ,nd_String,
"Integer" ,PUSH, "Sequence" ,nd_Sequence,
"If" ,nd_If, "Prtc" ,PRTC,
"Prts" ,PRTS, "Prti" ,PRTI,
"While" ,nd_While, "Assign" ,STORE,
"Negate" ,NEG, "Not" ,NOT,
"Multiply" ,MUL, "Divide" ,DIV,
"Mod" ,MOD, "Add" ,ADD,
"Subtract" ,SUB, "Less" ,LT,
"LessEqual" ,LE, "Greater" ,GT,
"GreaterEqual",GE, "Equal" ,EQ,
"NotEqual" ,NE, "And" ,AND,
"Or" ,OR, "halt" ,HALT);
var binOps=T(LT,GT,LE,GE,EQ,NE, AND,OR, SUB,ADD,DIV,MUL,MOD),
unaryOps=T(NEG,NOT);
class Node{
fcn init(_node_type, _value, _left=Void, _right=Void){
var type=_node_type, left=_left, right=_right, value=_value;
}
}
var vars=Dictionary(), strings=Dictionary(); // ( value:offset, ...)
fcn doVar(value){
var offset=-1; // fcn local static var
offset=_doValue(value,vars,offset)
}
fcn doString(str){ str=str[1,-1]; // str is \"text\"
var offset=-1; // fcn local static var
str=str.replace("\\n","\n");
offset=_doValue(str,strings,offset)
}
fcn _doValue(value,vars,offset){ //--> offset of value in vars
if(Void!=(n:=vars.find(value))) return(n); // fetch existing value
vars[value]=offset+=1; // store new value
}
fcn asm(node,code){
if(Void==node) return(code);
emitB:='wrap(n){ code.append(n) };
emitW:='wrap(n){ code.append(n.toLittleEndian(WORD_SIZE)) }; // signed
switch(node.type){
case(FETCH) { emitB(FETCH); emitW(doVar(node.value)); }
case(PUSH) { emitB(PUSH); emitW(node.value); }
case(nd_String){ emitB(PUSH); emitW(doString(node.value)); }
case(STORE){
asm(node.right,code);
emitB(STORE); emitW(doVar(node.left.value));
}
case(nd_If){
asm(node.left,code); # expr
emitB(JZ); # if false, jump
p1,p2 := code.len(),0;
emitW(0); # place holder for jump dest
asm(node.right.left,code); # if true statements
if (node.right.right!=Void){
emitB(JMP); # jump over else statements
p2=code.len();
emitW(0);
}
code[p1,WORD_SIZE]=(code.len() - p1).toLittleEndian(WORD_SIZE);
if(node.right.right!=Void){
asm(node.right.right,code); # else statements
code[p2,WORD_SIZE]=(code.len() - p2).toLittleEndian(WORD_SIZE)
}
}
case(nd_While){
p1:=code.len();
asm(node.left,code);
emitB(JZ);
p2:=code.len();
emitW(0); # place holder
asm(node.right,code);
emitB(JMP); # jump back to the top
emitW(p1 - code.len());
code[p2,WORD_SIZE]=(code.len() - p2).toLittleEndian(WORD_SIZE);
}
case(nd_Sequence){ asm(node.left,code); asm(node.right,code); }
case(PRTC,PRTI,PRTS){ asm(node.left,code); emitB(node.type); }
else{
if(binOps.holds(node.type)){
asm(node.left,code); asm(node.right,code);
emitB(node.type);
}
else if(unaryOps.holds(node.type))
{ asm(node.left,code); emitB(node.type); }
else throw(Exception.AssertionError(
"error in code generator - found %d, expecting operator"
.fmt(node.type)))
}
}
code
}
fcn code_finish(code){
code.append(HALT);
// prepend the strings to the code,
// using my magic [66,1 byte len,text], no trailing '\0' needed
idxs:=strings.pump(Dictionary(),"reverse");
idxs.keys.sort().reverse().pump(Void,'wrap(n){
text:=idxs[n];
code.insert(0,66,text.len(),text);
})
}