749 lines
29 KiB
Java
749 lines
29 KiB
Java
package pins25.phase;
|
|
|
|
import java.util.*;
|
|
|
|
import pins25.common.*;
|
|
|
|
/**
|
|
* Generiranje kode.
|
|
*/
|
|
public class CodeGen {
|
|
|
|
@SuppressWarnings({"doclint:missing"})
|
|
public CodeGen() {
|
|
throw new Report.InternalError();
|
|
}
|
|
|
|
/**
|
|
* Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
|
|
* predstavitve.
|
|
* <p>
|
|
* Atributi:
|
|
* <ol>
|
|
* <li>({@link Abstr}) lokacija kode, ki pripada posameznemu vozliscu;</li>
|
|
* <li>({@link SemAn}) definicija uporabljenega imena;</li>
|
|
* <li>({@link SemAn}) ali je dani izraz levi izraz;</li>
|
|
* <li>({@link Memory}) klicni zapis funkcije;</li>
|
|
* <li>({@link Memory}) dostop do parametra;</li>
|
|
* <li>({@link Memory}) dostop do spremenljivke;</li>
|
|
* <li>({@link CodeGen}) seznam ukazov, ki predstavljajo kodo programa;</li>
|
|
* <li>({@link CodeGen}) seznam ukazov, ki predstavljajo podatke programa.</li>
|
|
* </ol>
|
|
*/
|
|
public static class AttrAST extends Memory.AttrAST {
|
|
|
|
/**
|
|
* Atribut: seznam ukazov, ki predstavljajo kodo programa.
|
|
*/
|
|
public final Map<AST.Node, List<PDM.CodeInstr>> attrCode;
|
|
|
|
/**
|
|
* Atribut: seznam ukazov, ki predstavljajo podatke programa.
|
|
*/
|
|
public final Map<AST.Node, List<PDM.DataInstr>> attrData;
|
|
|
|
/**
|
|
* Ustvari novo abstraktno sintaksno drevo z dodanimi atributi generiranja kode.
|
|
*
|
|
* @param attrAST Abstraktno sintaksno drevo z dodanimi atributi pomnilniske
|
|
* predstavitve.
|
|
* @param attrCode Attribut: seznam ukazov, ki predstavljajo kodo programa.
|
|
* @param attrData Attribut: seznam ukazov, ki predstavljajo podatke programa.
|
|
*/
|
|
public AttrAST(final Memory.AttrAST attrAST, final Map<AST.Node, List<PDM.CodeInstr>> attrCode, final Map<AST.Node, List<PDM.DataInstr>> attrData) {
|
|
super(attrAST);
|
|
this.attrCode = attrCode;
|
|
this.attrData = attrData;
|
|
}
|
|
|
|
/**
|
|
* Ustvari novo abstraktno sintaksno drevo z dodanimi atributi generiranja kode.
|
|
*
|
|
* @param attrAST Abstraktno sintaksno drevo z dodanimi atributi generiranja
|
|
* kode.
|
|
*/
|
|
public AttrAST(final AttrAST attrAST) {
|
|
super(attrAST);
|
|
this.attrCode = attrAST.attrCode;
|
|
this.attrData = attrAST.attrData;
|
|
}
|
|
|
|
@Override
|
|
public String head(final AST.Node node, final boolean highlighted) {
|
|
final StringBuffer head = new StringBuffer();
|
|
head.append(super.head(node, false));
|
|
return head.toString();
|
|
}
|
|
|
|
@Override
|
|
public void desc(final int indent, final AST.Node node, final boolean highlighted) {
|
|
super.desc(indent, node, false);
|
|
System.out.print(highlighted ? "\033[31m" : "");
|
|
if (attrCode.get(node) != null) {
|
|
List<PDM.CodeInstr> instrs = attrCode.get(node);
|
|
if (instrs != null) {
|
|
if (indent > 0) System.out.printf("%" + indent + "c", ' ');
|
|
System.out.printf("--- Code: ---\n");
|
|
for (final PDM.CodeInstr instr : instrs) {
|
|
if (indent > 0) System.out.printf("%" + indent + "c", ' ');
|
|
System.out.println((instr instanceof PDM.LABEL ? "" : " ") + instr.toString());
|
|
}
|
|
}
|
|
}
|
|
if (attrData.get(node) != null) {
|
|
List<PDM.DataInstr> instrs = attrData.get(node);
|
|
if (instrs != null) {
|
|
if (indent > 0) System.out.printf("%" + indent + "c", ' ');
|
|
System.out.printf("--- Data: ---\n");
|
|
for (final PDM.DataInstr instr : instrs) {
|
|
if (indent > 0) System.out.printf("%" + indent + "c", ' ');
|
|
System.out.println((instr instanceof PDM.LABEL ? "" : " ") + instr.toString());
|
|
}
|
|
}
|
|
}
|
|
System.out.print(highlighted ? "\033[30m" : "");
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Izracuna kodo programa
|
|
*
|
|
* @param memoryAttrAST Abstraktno sintaksno drevo z dodanimi atributi izracuna
|
|
* pomnilniske predstavitve.
|
|
* @return Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
|
|
* predstavitve.
|
|
*/
|
|
public static AttrAST generate(final Memory.AttrAST memoryAttrAST) {
|
|
AttrAST attrAST = new AttrAST(memoryAttrAST, new HashMap<AST.Node, List<PDM.CodeInstr>>(), new HashMap<AST.Node, List<PDM.DataInstr>>());
|
|
(new CodeGenerator(attrAST)).generate();
|
|
return attrAST;
|
|
}
|
|
|
|
/**
|
|
* Generiranje kode v abstraktnem sintaksnem drevesu.
|
|
*/
|
|
private static class CodeGenerator {
|
|
|
|
/**
|
|
* Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
|
|
* predstavitve.
|
|
*/
|
|
private final AttrAST attrAST;
|
|
|
|
/**
|
|
* Stevec anonimnih label.
|
|
*/
|
|
private int labelCounter = 0;
|
|
|
|
/**
|
|
* Ustvari nov generator kode v abstraktnem sintaksnem drevesu.
|
|
*
|
|
* @param attrAST Abstraktno sintaksno drevo z dodanimi atributi izracuna
|
|
* pomnilniske predstavitve.
|
|
*/
|
|
public CodeGenerator(final AttrAST attrAST) {
|
|
this.attrAST = attrAST;
|
|
}
|
|
|
|
/**
|
|
* Sprozi generiranje kode v abstraktnem sintaksnem drevesu.
|
|
*
|
|
* @return Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
|
|
* predstavitve.
|
|
*/
|
|
public AttrAST generate() {
|
|
attrAST.ast.accept(new Generator(), null);
|
|
return new AttrAST(attrAST, Collections.unmodifiableMap(attrAST.attrCode), Collections.unmodifiableMap(attrAST.attrData));
|
|
}
|
|
|
|
/**
|
|
* Obiskovalec, ki generira kodo v abstraktnem sintaksnem drevesu.
|
|
*/
|
|
private class Generator implements AST.FullVisitor<List<PDM.CodeInstr>, Mem.Frame> {
|
|
|
|
@SuppressWarnings({"doclint:missing"})
|
|
public Generator() {
|
|
}
|
|
|
|
private String funLabel(AST.FunDef funDef) {
|
|
if (funDef.name.equals("main") || funDef.stmts.size() == 0) {
|
|
return funDef.name;
|
|
}
|
|
Report.Location loc = attrAST.attrLoc.get(funDef).location();
|
|
return "$fun:" + funDef.name + "@" + loc.begLine() + ":" + loc.begColumn();
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.FunDef funDef, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(funDef);
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
|
|
frame = attrAST.attrFrame.get(funDef);
|
|
|
|
code.add(new PDM.LABEL(funLabel(funDef), loc));
|
|
|
|
code.addAll(funDef.stmts.accept(this, frame));
|
|
|
|
code.add(new PDM.PUSH(attrAST.attrFrame.get(funDef).parsSize, loc));
|
|
code.add(new PDM.RETN(attrAST.attrFrame.get(funDef), loc));
|
|
|
|
attrAST.attrCode.put(funDef, code);
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.ParDef parDef, Mem.Frame frame) {
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.AtomExpr atomExpr, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(atomExpr);
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
switch (atomExpr.type) {
|
|
case INTCONST:
|
|
code.add(new PDM.PUSH(Memory.decodeIntConst(atomExpr, loc), loc));
|
|
break;
|
|
case CHRCONST:
|
|
code.add(new PDM.PUSH(Memory.decodeChrConst(atomExpr, loc), loc));
|
|
break;
|
|
case STRCONST:
|
|
List<PDM.DataInstr> data = new ArrayList<>();
|
|
String label = "$str@" + loc.location().begLine() + ":" + loc.location().begColumn();
|
|
data.add(new PDM.LABEL(label, loc));
|
|
for (Integer value : Memory.decodeStrConst(atomExpr, loc)) {
|
|
data.add(new PDM.DATA(value, loc));
|
|
}
|
|
attrAST.attrData.put(atomExpr, data);
|
|
code.add(new PDM.NAME(label, loc));
|
|
break;
|
|
}
|
|
|
|
attrAST.attrCode.put(atomExpr, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.BinExpr binExpr, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(binExpr);
|
|
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
|
|
code.addAll(binExpr.fstExpr.accept(this, frame));
|
|
code.addAll(binExpr.sndExpr.accept(this, frame));
|
|
|
|
PDM.OPER.Oper oper = switch (binExpr.oper) {
|
|
case OR -> PDM.OPER.Oper.OR;
|
|
case AND -> PDM.OPER.Oper.AND;
|
|
case EQU -> PDM.OPER.Oper.EQU;
|
|
case NEQ -> PDM.OPER.Oper.NEQ;
|
|
case GTH -> PDM.OPER.Oper.GTH;
|
|
case LTH -> PDM.OPER.Oper.LTH;
|
|
case GEQ -> PDM.OPER.Oper.GEQ;
|
|
case LEQ -> PDM.OPER.Oper.LEQ;
|
|
case ADD -> PDM.OPER.Oper.ADD;
|
|
case SUB -> PDM.OPER.Oper.SUB;
|
|
case MUL -> PDM.OPER.Oper.MUL;
|
|
case DIV -> PDM.OPER.Oper.DIV;
|
|
case MOD -> PDM.OPER.Oper.MOD;
|
|
};
|
|
|
|
code.add(new PDM.OPER(oper, loc));
|
|
|
|
attrAST.attrCode.put(binExpr, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.Nodes<? extends AST.Node> nodes, Mem.Frame frame) {
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
for (AST.Node node : nodes) {
|
|
code.addAll(node.accept(this, frame));
|
|
}
|
|
attrAST.attrCode.put(nodes, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.ExprStmt exprStmt, Mem.Frame frame) {
|
|
return exprStmt.expr.accept(this, frame);
|
|
}
|
|
|
|
private List<PDM.CodeInstr> resolveAddr(AST.Expr expr, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(expr);
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
|
|
switch (expr) {
|
|
case AST.UnExpr unExpr:
|
|
if (unExpr.oper != AST.UnExpr.Oper.VALUEAT) {
|
|
return code;
|
|
}
|
|
|
|
code.addAll(unExpr.expr.accept(this, frame));
|
|
break;
|
|
|
|
case AST.VarExpr varExpr:
|
|
AST.Def def = attrAST.attrDef.get(varExpr);
|
|
|
|
Mem.Access access = switch (def) {
|
|
case AST.VarDef varDef -> attrAST.attrVarAccess.get(varDef);
|
|
case AST.ParDef parDef -> attrAST.attrParAccess.get(parDef);
|
|
default -> null;
|
|
};
|
|
if (access == null) {
|
|
return code;
|
|
}
|
|
|
|
switch (access) {
|
|
case Mem.AbsAccess absAccess:
|
|
code.add(new PDM.NAME("$var:" + absAccess.name, loc));
|
|
break;
|
|
case Mem.RelAccess relAccess:
|
|
code.add(new PDM.REGN(PDM.REGN.Reg.FP, loc));
|
|
for (int i = 0; i < frame.depth - relAccess.depth; i++) {
|
|
code.add(new PDM.LOAD(loc));
|
|
}
|
|
code.add(new PDM.PUSH(relAccess.offset, loc));
|
|
code.add(new PDM.OPER(PDM.OPER.Oper.ADD, loc));
|
|
break;
|
|
default:
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.VarExpr varExpr, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(varExpr);
|
|
|
|
List<PDM.CodeInstr> code = resolveAddr(varExpr, frame);
|
|
code.add(new PDM.LOAD(loc));
|
|
|
|
attrAST.attrCode.put(varExpr, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.UnExpr unExpr, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(unExpr);
|
|
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
|
|
if (unExpr.oper != AST.UnExpr.Oper.MEMADDR) {
|
|
code.addAll(unExpr.expr.accept(this, frame));
|
|
}
|
|
|
|
switch (unExpr.oper) {
|
|
case NOT -> code.add(new PDM.OPER(PDM.OPER.Oper.NOT, loc));
|
|
case SUB -> code.add(new PDM.OPER(PDM.OPER.Oper.NEG, loc));
|
|
case VALUEAT -> code.add(new PDM.LOAD(loc));
|
|
case MEMADDR -> {
|
|
if (unExpr.expr instanceof AST.VarExpr varExpr) {
|
|
code.addAll(resolveAddr(varExpr, frame));
|
|
} else {
|
|
throw new Report.Error(loc, "Expression not a variable");
|
|
}
|
|
}
|
|
case ADD -> {
|
|
}
|
|
}
|
|
|
|
attrAST.attrCode.put(unExpr, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.CallExpr callExpr, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(callExpr);
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
|
|
AST.FunDef funDef = (AST.FunDef) attrAST.attrDef.get(callExpr);
|
|
|
|
for (int i = callExpr.args.size() - 1; i >= 0; i--) {
|
|
AST.Expr expr = (AST.Expr) callExpr.args.get(i);
|
|
code.addAll(expr.accept(this, frame));
|
|
}
|
|
|
|
// SL
|
|
code.add(new PDM.REGN(PDM.REGN.Reg.FP, loc));
|
|
if (attrAST.attrFrame.get(funDef).depth.equals(frame.depth)) {
|
|
code.add(new PDM.LOAD(loc));
|
|
}
|
|
|
|
code.add(new PDM.NAME(funLabel(funDef), loc));
|
|
code.add(new PDM.CALL(frame, loc));
|
|
|
|
attrAST.attrCode.put(callExpr, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.VarDef varDef, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(varDef);
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
List<PDM.DataInstr> data = new ArrayList<>();
|
|
|
|
Mem.Access access = attrAST.attrVarAccess.get(varDef);
|
|
|
|
switch (access) {
|
|
case Mem.AbsAccess absAccess -> {
|
|
String varLabel = "$var:" + absAccess.name;
|
|
data.add(new PDM.LABEL(varLabel, loc));
|
|
for (int i = 0; i < absAccess.size / 4; i++) {
|
|
data.add(new PDM.DATA(0, loc));
|
|
}
|
|
|
|
String initLabel = "$init:" + absAccess.name;
|
|
data.add(new PDM.LABEL(initLabel, loc));
|
|
for (Integer init : absAccess.inits) {
|
|
data.add(new PDM.DATA(init, loc));
|
|
}
|
|
|
|
code.add(new PDM.NAME(varLabel, loc));
|
|
code.add(new PDM.NAME(initLabel, loc));
|
|
code.add(new PDM.INIT(loc));
|
|
}
|
|
|
|
case Mem.RelAccess relAccess -> {
|
|
String initLabel = "$init:" + varDef.name + "@" + loc.location().begLine() + ":" + loc.location().begColumn();
|
|
data.add(new PDM.LABEL(initLabel, loc));
|
|
for (Integer init : relAccess.inits) {
|
|
data.add(new PDM.DATA(init, loc));
|
|
}
|
|
|
|
code.add(new PDM.PUSH(-relAccess.size, loc));
|
|
code.add(new PDM.POPN(loc));
|
|
|
|
code.add(new PDM.REGN(PDM.REGN.Reg.SP, loc));
|
|
code.add(new PDM.NAME(initLabel, loc));
|
|
code.add(new PDM.INIT(loc));
|
|
}
|
|
|
|
default -> {
|
|
}
|
|
}
|
|
|
|
attrAST.attrCode.put(varDef, code);
|
|
attrAST.attrData.put(varDef, data);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.Init init, Mem.Frame frame) {
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.AssignStmt assignStmt, Mem.Frame frame) {
|
|
Report.Locatable loc = attrAST.attrLoc.get(assignStmt);
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
|
|
code.addAll(assignStmt.srcExpr.accept(this, frame));
|
|
code.addAll(resolveAddr(assignStmt.dstExpr, frame));
|
|
code.add(new PDM.SAVE(loc));
|
|
|
|
attrAST.attrCode.put(assignStmt, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.LetStmt letStmt, Mem.Frame frame) {
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
|
|
for (AST.MainDef def : letStmt.defs) {
|
|
code.addAll(def.accept(this, frame));
|
|
}
|
|
|
|
for (AST.Stmt stmt : letStmt.stmts) {
|
|
code.addAll(stmt.accept(this, frame));
|
|
}
|
|
|
|
attrAST.attrCode.put(letStmt, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.IfStmt ifStmt, Mem.Frame frame) {
|
|
Report.Location loc = attrAST.attrLoc.get(ifStmt).location();
|
|
|
|
String locStr = loc.begLine() + ":" + loc.begColumn();
|
|
String thenLabel = "$if:then@" + locStr;
|
|
String elseLabel = "$if:else@" + locStr;
|
|
String endLabel = "$if:end@" + locStr;
|
|
|
|
List<PDM.CodeInstr> code = ifStmt.cond.accept(this, frame);
|
|
code.add(new PDM.NAME(thenLabel, loc));
|
|
code.add(new PDM.NAME(elseLabel, loc));
|
|
code.add(new PDM.CJMP(loc));
|
|
|
|
code.add(new PDM.LABEL(thenLabel, loc));
|
|
code.addAll(ifStmt.thenStmts.accept(this, frame));
|
|
code.add(new PDM.NAME(endLabel, loc));
|
|
code.add(new PDM.UJMP(loc));
|
|
|
|
code.add(new PDM.LABEL(elseLabel, loc));
|
|
code.addAll(ifStmt.elseStmts.accept(this, frame));
|
|
|
|
code.add(new PDM.LABEL(endLabel, loc));
|
|
|
|
attrAST.attrCode.put(ifStmt, code);
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public List<PDM.CodeInstr> visit(AST.WhileStmt whileStmt, Mem.Frame frame) {
|
|
Report.Location loc = attrAST.attrLoc.get(whileStmt).location();
|
|
List<PDM.CodeInstr> code = new ArrayList<>();
|
|
|
|
String locStr = loc.begLine() + ":" + loc.begColumn();
|
|
String condLabel = "$while:cond@" + locStr;
|
|
String begLabel = "$while:beg@" + locStr;
|
|
String endLabel = "$while:end@" + locStr;
|
|
|
|
code.add(new PDM.LABEL(condLabel, loc));
|
|
code.addAll(whileStmt.cond.accept(this, frame));
|
|
code.add(new PDM.NAME(begLabel, loc));
|
|
code.add(new PDM.NAME(endLabel, loc));
|
|
code.add(new PDM.CJMP(loc));
|
|
|
|
code.add(new PDM.LABEL(begLabel, loc));
|
|
code.addAll(whileStmt.stmts.accept(this, frame));
|
|
|
|
code.add(new PDM.NAME(condLabel, loc));
|
|
code.add(new PDM.UJMP(loc));
|
|
|
|
code.add(new PDM.LABEL(endLabel, loc));
|
|
|
|
attrAST.attrCode.put(whileStmt, code);
|
|
return code;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generator seznama ukazov, ki predstavljajo kodo programa.
|
|
*/
|
|
public static class CodeSegmentGenerator {
|
|
|
|
/**
|
|
* Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
|
|
* predstavitve.
|
|
*/
|
|
private final AttrAST attrAST;
|
|
|
|
/**
|
|
* Seznam ukazov za inicializacijo staticnih spremenljivk.
|
|
*/
|
|
private final Vector<PDM.CodeInstr> codeInitSegment = new Vector<PDM.CodeInstr>();
|
|
|
|
/**
|
|
* Seznam ukazov funkcij.
|
|
*/
|
|
private final Vector<PDM.CodeInstr> codeFunsSegment = new Vector<PDM.CodeInstr>();
|
|
|
|
/**
|
|
* Klicni zapis funkcije {@code main}.
|
|
*/
|
|
private Mem.Frame main = null;
|
|
|
|
/**
|
|
* Ustvari nov generator seznama ukazov, ki predstavljajo kodo programa.
|
|
*
|
|
* @param attrAST Abstraktno sintaksno drevo z dodanimi atributi izracuna
|
|
* pomnilniske predstavitve.
|
|
*/
|
|
public CodeSegmentGenerator(final AttrAST attrAST) {
|
|
this.attrAST = attrAST;
|
|
}
|
|
|
|
/**
|
|
* Izracuna seznam ukazov, ki predstavljajo kodo programa.
|
|
*
|
|
* @return Seznam ukazov, ki predstavljajo kodo programa.
|
|
*/
|
|
public List<PDM.CodeInstr> codeSegment() {
|
|
attrAST.ast.accept(new Generator(), null);
|
|
codeInitSegment.addLast(new PDM.PUSH(0, null));
|
|
codeInitSegment.addLast(new PDM.NAME("main", null));
|
|
codeInitSegment.addLast(new PDM.CALL(main, null));
|
|
codeInitSegment.addLast(new PDM.PUSH(0, null));
|
|
codeInitSegment.addLast(new PDM.NAME("exit", null));
|
|
codeInitSegment.addLast(new PDM.CALL(null, null));
|
|
final Vector<PDM.CodeInstr> codeSegment = new Vector<PDM.CodeInstr>();
|
|
codeSegment.addAll(codeInitSegment);
|
|
codeSegment.addAll(codeFunsSegment);
|
|
return Collections.unmodifiableList(codeSegment);
|
|
}
|
|
|
|
/**
|
|
* Obiskovalec, ki izracuna seznam ukazov, ki predstavljajo kodo programa.
|
|
*/
|
|
private class Generator implements AST.FullVisitor<Object, Object> {
|
|
|
|
@SuppressWarnings({"doclint:missing"})
|
|
public Generator() {
|
|
}
|
|
|
|
@Override
|
|
public Object visit(final AST.FunDef funDef, final Object arg) {
|
|
if (funDef.stmts.size() == 0) return null;
|
|
List<PDM.CodeInstr> code = attrAST.attrCode.get(funDef);
|
|
codeFunsSegment.addAll(code);
|
|
funDef.pars.accept(this, arg);
|
|
funDef.stmts.accept(this, arg);
|
|
switch (funDef.name) {
|
|
case "main" -> main = attrAST.attrFrame.get(funDef);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public Object visit(final AST.VarDef varDef, final Object arg) {
|
|
switch (attrAST.attrVarAccess.get(varDef)) {
|
|
case Mem.AbsAccess __: {
|
|
List<PDM.CodeInstr> code = attrAST.attrCode.get(varDef);
|
|
codeInitSegment.addAll(code);
|
|
break;
|
|
}
|
|
case Mem.RelAccess __: {
|
|
break;
|
|
}
|
|
default:
|
|
throw new Report.InternalError();
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generator seznama ukazov, ki predstavljajo podatke programa.
|
|
*/
|
|
public static class DataSegmentGenerator {
|
|
|
|
/**
|
|
* Abstraktno sintaksno drevo z dodanimi atributi izracuna pomnilniske
|
|
* predstavitve.
|
|
*/
|
|
private final AttrAST attrAST;
|
|
|
|
/**
|
|
* Seznam ukazov, ki predstavljajo podatke programa.
|
|
*/
|
|
private final Vector<PDM.DataInstr> dataSegment = new Vector<PDM.DataInstr>();
|
|
|
|
/**
|
|
* Ustvari nov generator seznama ukazov, ki predstavljajo podatke programa.
|
|
*
|
|
* @param attrAST Abstraktno sintaksno drevo z dodanimi atributi izracuna
|
|
* pomnilniske predstavitve.
|
|
*/
|
|
public DataSegmentGenerator(final AttrAST attrAST) {
|
|
this.attrAST = attrAST;
|
|
}
|
|
|
|
/**
|
|
* Izracuna seznam ukazov, ki predstavljajo podatke programa.
|
|
*
|
|
* @return Seznam ukazov, ki predstavljajo podatke programa.
|
|
*/
|
|
public List<PDM.DataInstr> dataSegment() {
|
|
attrAST.ast.accept(new Generator(), null);
|
|
return Collections.unmodifiableList(dataSegment);
|
|
}
|
|
|
|
/**
|
|
* Obiskovalec, ki izracuna seznam ukazov, ki predstavljajo podatke programa.
|
|
*/
|
|
private class Generator implements AST.FullVisitor<Object, Object> {
|
|
|
|
@SuppressWarnings({"doclint:missing"})
|
|
public Generator() {
|
|
}
|
|
|
|
@Override
|
|
public Object visit(final AST.VarDef varDef, final Object arg) {
|
|
List<PDM.DataInstr> data = attrAST.attrData.get(varDef);
|
|
if (data != null) dataSegment.addAll(data);
|
|
varDef.inits.accept(this, arg);
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public Object visit(final AST.AtomExpr atomExpr, final Object arg) {
|
|
List<PDM.DataInstr> data = attrAST.attrData.get(atomExpr);
|
|
if (data != null) dataSegment.addAll(data);
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// --- ZAGON ---
|
|
|
|
/**
|
|
* Zagon izracuna pomnilniske predstavitve kot samostojnega programa.
|
|
*
|
|
* @param cmdLineArgs Argumenti v ukazni vrstici.
|
|
*/
|
|
public static void main(final String[] cmdLineArgs) {
|
|
System.out.println("This is PINS'25 compiler (code generation):");
|
|
|
|
try {
|
|
if (cmdLineArgs.length == 0) throw new Report.Error("No source file specified in the command line.");
|
|
if (cmdLineArgs.length > 1) Report.warning("Unused arguments in the command line.");
|
|
|
|
try (SynAn synAn = new SynAn(cmdLineArgs[0])) {
|
|
// abstraktna sintaksa:
|
|
final Abstr.AttrAST abstrAttrAST = Abstr.constructAST(synAn);
|
|
// semanticna analiza:
|
|
final SemAn.AttrAST semanAttrAST = SemAn.analyze(abstrAttrAST);
|
|
// pomnilniska predstavitev:
|
|
final Memory.AttrAST memoryAttrAST = Memory.organize(semanAttrAST);
|
|
// generiranje kode:
|
|
final AttrAST codegenAttrAST = CodeGen.generate(memoryAttrAST);
|
|
|
|
(new AST.Logger(codegenAttrAST)).log();
|
|
{
|
|
int addr = 0;
|
|
final List<PDM.CodeInstr> codeSegment = (new CodeSegmentGenerator(codegenAttrAST)).codeSegment();
|
|
{
|
|
System.out.println("\n\033[1mCODE SEGMENT:\033[0m");
|
|
for (final PDM.CodeInstr instr : codeSegment) {
|
|
System.out.printf("%8d [%s] %s\n", addr, instr.size(), (instr instanceof PDM.LABEL ? "" : " ") + instr.toString());
|
|
addr += instr.size();
|
|
}
|
|
}
|
|
final List<PDM.DataInstr> dataSegment = (new DataSegmentGenerator(codegenAttrAST)).dataSegment();
|
|
{
|
|
System.out.println("\n\033[1mDATA SEGMENT:\033[0m");
|
|
for (final PDM.DataInstr instr : dataSegment) {
|
|
System.out.printf("%8d [%s] %s\n", addr, (instr instanceof PDM.SIZE) ? " " : instr.size(), (instr instanceof PDM.LABEL ? "" : " ") + instr.toString());
|
|
addr += instr.size();
|
|
}
|
|
}
|
|
System.out.println();
|
|
}
|
|
}
|
|
|
|
// Upajmo, da kdaj pridemo to te tocke.
|
|
// A zavedajmo se sledecega:
|
|
// 1. Prevod je zaradi napak v programu lahko napacen :-o
|
|
// 2. Izvorni program se zdalec ni tisto, kar je programer hotel, da bi bil ;-)
|
|
Report.info("Done.");
|
|
} catch (Report.Error error) {
|
|
// Izpis opisa napake.
|
|
System.err.println(error.getMessage());
|
|
System.exit(1);
|
|
}
|
|
}
|
|
|
|
} |