mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-31 22:31:14 +00:00
Constructing Control Flow Graph.
This commit is contained in:
parent
a06fe6e989
commit
4eb905b15c
7
src/dk/camelot64/kickc/icl/Constant.java
Normal file
7
src/dk/camelot64/kickc/icl/Constant.java
Normal file
@ -0,0 +1,7 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** SSA form constant value */
|
||||
public interface Constant extends RValue {
|
||||
|
||||
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* SSA form constant integer value
|
||||
*/
|
||||
public class SSAConstantBool implements SSAConstant {
|
||||
public class ConstantBool implements Constant {
|
||||
|
||||
private Boolean value;
|
||||
|
||||
public SSAConstantBool(Boolean value) {
|
||||
public ConstantBool(Boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* SSA form constant integer value
|
||||
*/
|
||||
public class SSAConstantDouble implements SSAConstant {
|
||||
public class ConstantDouble implements Constant {
|
||||
|
||||
private Double number;
|
||||
|
||||
public SSAConstantDouble(Double number) {
|
||||
public ConstantDouble(Double number) {
|
||||
this.number= number;
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* SSA form constant integer value
|
||||
*/
|
||||
public class SSAConstantInteger implements SSAConstant {
|
||||
public class ConstantInteger implements Constant {
|
||||
|
||||
private Integer number;
|
||||
|
||||
public SSAConstantInteger(Integer number) {
|
||||
public ConstantInteger(Integer number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* SSA form constant integer value
|
||||
*/
|
||||
public class SSAConstantString implements SSAConstant {
|
||||
public class ConstantString implements Constant {
|
||||
|
||||
private String value;
|
||||
|
||||
public SSAConstantString(String value) {
|
||||
public ConstantString(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
101
src/dk/camelot64/kickc/icl/ControlFlowBlock.java
Normal file
101
src/dk/camelot64/kickc/icl/ControlFlowBlock.java
Normal file
@ -0,0 +1,101 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** A named/labelled sequence of SSA statements connected to other basic blocks.
|
||||
* The connections defines the control flow of the program. */
|
||||
public class ControlFlowBlock {
|
||||
|
||||
private Symbol label;
|
||||
|
||||
private List<ControlFlowBlock> predecessors;
|
||||
|
||||
private List<Statement> statements;
|
||||
|
||||
private ControlFlowBlock defaultSuccessor;
|
||||
|
||||
private ControlFlowBlock conditionalSuccessor;
|
||||
|
||||
public ControlFlowBlock(Symbol label) {
|
||||
this.label = label;
|
||||
this.statements = new ArrayList<>();
|
||||
this.predecessors = new ArrayList<>();
|
||||
this.defaultSuccessor = null;
|
||||
this.conditionalSuccessor = null;
|
||||
}
|
||||
|
||||
public Symbol getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void addStatement(Statement statement) {
|
||||
this.statements.add(statement);
|
||||
}
|
||||
|
||||
public void addPredecessor(ControlFlowBlock block) {
|
||||
this.predecessors.add(block);
|
||||
}
|
||||
|
||||
public void setDefaultSuccessor(ControlFlowBlock defaultSuccessor) {
|
||||
this.defaultSuccessor = defaultSuccessor;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getDefaultSuccessor() {
|
||||
return defaultSuccessor;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getConditionalSuccessor() {
|
||||
return conditionalSuccessor;
|
||||
}
|
||||
|
||||
public List<ControlFlowBlock> getPredecessors() {
|
||||
return predecessors;
|
||||
}
|
||||
|
||||
public void setConditionalSuccessor(ControlFlowBlock conditionalSuccessor) {
|
||||
this.conditionalSuccessor = conditionalSuccessor;
|
||||
}
|
||||
|
||||
public void removePredecessor(ControlFlowBlock block) {
|
||||
predecessors.remove(block);
|
||||
}
|
||||
|
||||
public List<Statement> getStatements() {
|
||||
return statements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer();
|
||||
out.append(label.getName() + ":" + "\n");
|
||||
out.append(" from:");
|
||||
for (ControlFlowBlock predecessor : predecessors) {
|
||||
out.append(predecessor.getLabel().getName()+" ");
|
||||
}
|
||||
out.append("\n");
|
||||
for (Statement statement : statements) {
|
||||
out.append(" "+statement+"\n");
|
||||
}
|
||||
out.append(" to:");
|
||||
if(defaultSuccessor!=null) {
|
||||
out.append(defaultSuccessor.getLabel().getName());
|
||||
}
|
||||
out.append("\n");
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ControlFlowBlock that = (ControlFlowBlock) o;
|
||||
return label.equals(that.label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return label.hashCode();
|
||||
}
|
||||
|
||||
}
|
34
src/dk/camelot64/kickc/icl/ControlFlowGraph.java
Normal file
34
src/dk/camelot64/kickc/icl/ControlFlowGraph.java
Normal file
@ -0,0 +1,34 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/** The control flow graph of the program.
|
||||
* The control flow graph is a set of connected basic blocks. */
|
||||
public class ControlFlowGraph {
|
||||
|
||||
private Map<Symbol, ControlFlowBlock> blocks;
|
||||
|
||||
private ControlFlowBlock firstBlock;
|
||||
|
||||
public ControlFlowGraph(Map<Symbol, ControlFlowBlock> blocks, ControlFlowBlock firstBlock) {
|
||||
this.blocks = blocks;
|
||||
this.firstBlock = firstBlock;
|
||||
}
|
||||
|
||||
public ControlFlowBlock getBlock(Symbol symbol) {
|
||||
return blocks.get(symbol);
|
||||
}
|
||||
|
||||
public ControlFlowBlock getFirstBlock() {
|
||||
return firstBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (ControlFlowBlock block : blocks.values()) {
|
||||
out.append(block);
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
5
src/dk/camelot64/kickc/icl/LValue.java
Normal file
5
src/dk/camelot64/kickc/icl/LValue.java
Normal file
@ -0,0 +1,5 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** Assignable value (capable of being on the left part of an assignment)*/
|
||||
public interface LValue {
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** Parser for converting literal numbers to the corresponding Java Integer/Double */
|
||||
public class KickCNumberParser {
|
||||
public class NumberParser {
|
||||
|
||||
public static Number parseLiteral(String literal) {
|
||||
boolean isInt = !literal.contains(".");
|
@ -1,11 +1,11 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** SSA Form Operator. The operation performed on the rvalues in an SSA Statement. */
|
||||
public class SSAOperator {
|
||||
/** An Operator. The operation performed on the rvalues in a Statement. */
|
||||
public class Operator {
|
||||
|
||||
private String operator;
|
||||
|
||||
public SSAOperator(String operator) {
|
||||
public Operator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
91
src/dk/camelot64/kickc/icl/PassGenerateControlFlowGraph.java
Normal file
91
src/dk/camelot64/kickc/icl/PassGenerateControlFlowGraph.java
Normal file
@ -0,0 +1,91 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Pass that generates a control flow graph for the program */
|
||||
public class PassGenerateControlFlowGraph {
|
||||
|
||||
public static final String FIRST_BLOCK_NAME = "@0";
|
||||
private SymbolManager symbolManager;
|
||||
private Map<Symbol, ControlFlowBlock> blocks;
|
||||
private ControlFlowBlock firstBlock;
|
||||
|
||||
public PassGenerateControlFlowGraph(SymbolManager symbolManager) {
|
||||
this.symbolManager = symbolManager;
|
||||
this.blocks = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public ControlFlowGraph generate(StatementSequence sequence) {
|
||||
this.firstBlock = getOrCreateBlock(symbolManager.newNamedJumpLabel(FIRST_BLOCK_NAME));
|
||||
ControlFlowBlock currentBlock = this.firstBlock;
|
||||
for (Statement statement : sequence.getStatements()) {
|
||||
if(statement instanceof StatementJumpTarget) {
|
||||
StatementJumpTarget statementJumpTarget = (StatementJumpTarget) statement;
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(statementJumpTarget.getLabel());
|
||||
currentBlock.setDefaultSuccessor(nextBlock);
|
||||
nextBlock.addPredecessor(currentBlock);
|
||||
currentBlock = nextBlock;
|
||||
} else if(statement instanceof StatementJump) {
|
||||
StatementJump statementJump = (StatementJump) statement;
|
||||
ControlFlowBlock jmpBlock = getOrCreateBlock(statementJump.getDestination());
|
||||
currentBlock.setDefaultSuccessor(jmpBlock);
|
||||
jmpBlock.addPredecessor(currentBlock);
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(symbolManager.newIntermediateJumpLabel());
|
||||
currentBlock = nextBlock;
|
||||
} else if(statement instanceof StatementConditionalJump) {
|
||||
currentBlock.addStatement(statement);
|
||||
StatementConditionalJump statementConditionalJump = (StatementConditionalJump) statement;
|
||||
ControlFlowBlock jmpBlock = getOrCreateBlock(statementConditionalJump.getDestination());
|
||||
ControlFlowBlock nextBlock = getOrCreateBlock(symbolManager.newIntermediateJumpLabel());
|
||||
currentBlock.setDefaultSuccessor(nextBlock);
|
||||
currentBlock.setConditionalSuccessor(jmpBlock);
|
||||
nextBlock.addPredecessor(currentBlock);
|
||||
jmpBlock.addPredecessor(currentBlock);
|
||||
currentBlock = nextBlock;
|
||||
} else {
|
||||
currentBlock.addStatement(statement);
|
||||
}
|
||||
}
|
||||
cullEmptyBlocks();
|
||||
return new ControlFlowGraph(blocks, firstBlock);
|
||||
}
|
||||
|
||||
private void cullEmptyBlocks() {
|
||||
List<ControlFlowBlock> remove = new ArrayList<>();
|
||||
for (ControlFlowBlock block : blocks.values()) {
|
||||
if(block.getStatements().isEmpty()) {
|
||||
ControlFlowBlock successor = block.getDefaultSuccessor();
|
||||
for (ControlFlowBlock predecessor : block.getPredecessors()) {
|
||||
if(predecessor.getDefaultSuccessor().equals(block)) {
|
||||
predecessor.setDefaultSuccessor(successor);
|
||||
successor.addPredecessor(predecessor);
|
||||
}
|
||||
if(predecessor.getConditionalSuccessor().equals(block)) {
|
||||
predecessor.setConditionalSuccessor(successor);
|
||||
successor.addPredecessor(predecessor);
|
||||
}
|
||||
}
|
||||
successor.removePredecessor(block);
|
||||
remove.add(block);
|
||||
}
|
||||
}
|
||||
for (ControlFlowBlock block : remove) {
|
||||
blocks.remove(block.getLabel());
|
||||
symbolManager.remove(block.getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
private ControlFlowBlock getOrCreateBlock(Symbol label) {
|
||||
ControlFlowBlock block = blocks.get(label);
|
||||
if(block==null) {
|
||||
block = new ControlFlowBlock(label);
|
||||
blocks.put(block.getLabel(), block);
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
}
|
172
src/dk/camelot64/kickc/icl/PassGenerateStatementSequence.java
Normal file
172
src/dk/camelot64/kickc/icl/PassGenerateStatementSequence.java
Normal file
@ -0,0 +1,172 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import dk.camelot64.kickc.parser.KickCBaseVisitor;
|
||||
import dk.camelot64.kickc.parser.KickCParser;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
/** Generates program SSA form by visiting the ANTLR4 parse tree*/
|
||||
public class PassGenerateStatementSequence extends KickCBaseVisitor<RValue> {
|
||||
|
||||
private SymbolManager symbolManager;
|
||||
private StatementSequence sequence;
|
||||
|
||||
public PassGenerateStatementSequence() {
|
||||
this.symbolManager = new SymbolManager();
|
||||
this.sequence = new StatementSequence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitFile(KickCParser.FileContext ctx) {
|
||||
this.visit(ctx.stmtSeq());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RValue visitStmtSeq(KickCParser.StmtSeqContext ctx) {
|
||||
for(int i=0; i<ctx.getChildCount(); i++) {
|
||||
this.visit(ctx.stmt(i));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitStmtBlock(KickCParser.StmtBlockContext ctx) {
|
||||
this.visit(ctx.stmtSeq());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitStmtExpr(KickCParser.StmtExprContext ctx) {
|
||||
this.visit(ctx.expr());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitStmtIfElse(KickCParser.StmtIfElseContext ctx) {
|
||||
RValue rValue = this.visit(ctx.expr());
|
||||
Symbol ifJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
Symbol elseJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
Statement ifJmpStmt = new StatementConditionalJump(rValue, ifJumpLabel);
|
||||
sequence.addStatement(ifJmpStmt);
|
||||
Statement elseJmpStmt = new StatementJump(elseJumpLabel);
|
||||
sequence.addStatement(elseJmpStmt);
|
||||
StatementJumpTarget ifJumpTarget = new StatementJumpTarget(ifJumpLabel);
|
||||
sequence.addStatement(ifJumpTarget);
|
||||
this.visit(ctx.stmt(0));
|
||||
KickCParser.StmtContext elseStmt = ctx.stmt(1);
|
||||
if(elseStmt!=null) {
|
||||
Symbol endJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
Statement endJmpStmt = new StatementJump(endJumpLabel);
|
||||
sequence.addStatement(endJmpStmt);
|
||||
StatementJumpTarget elseJumpTarget = new StatementJumpTarget(elseJumpLabel);
|
||||
sequence.addStatement(elseJumpTarget);
|
||||
this.visit(elseStmt);
|
||||
StatementJumpTarget endJumpTarget = new StatementJumpTarget(endJumpLabel);
|
||||
sequence.addStatement(endJumpTarget);
|
||||
} else {
|
||||
StatementJumpTarget elseJumpTarget = new StatementJumpTarget(elseJumpLabel);
|
||||
sequence.addStatement(elseJumpTarget);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitStmtWhile(KickCParser.StmtWhileContext ctx) {
|
||||
Symbol beginJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
Symbol doJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
Symbol endJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
StatementJumpTarget beginJumpTarget = new StatementJumpTarget(beginJumpLabel);
|
||||
sequence.addStatement(beginJumpTarget);
|
||||
RValue rValue = this.visit(ctx.expr());
|
||||
Statement doJmpStmt = new StatementConditionalJump(rValue, doJumpLabel);
|
||||
sequence.addStatement(doJmpStmt);
|
||||
Statement endJmpStmt = new StatementJump(endJumpLabel);
|
||||
sequence.addStatement(endJmpStmt);
|
||||
StatementJumpTarget doJumpTarget = new StatementJumpTarget(doJumpLabel);
|
||||
sequence.addStatement(doJumpTarget);
|
||||
this.visit(ctx.stmt());
|
||||
Statement beginJmpStmt = new StatementJump(beginJumpLabel);
|
||||
sequence.addStatement(beginJmpStmt);
|
||||
StatementJumpTarget endJumpTarget = new StatementJumpTarget(endJumpLabel);
|
||||
sequence.addStatement(endJumpTarget);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitStmtAssignment(KickCParser.StmtAssignmentContext ctx) {
|
||||
if(ctx.TYPE()!=null) {
|
||||
symbolManager.newVariableDeclaration(ctx.NAME().getText(), ctx.TYPE().getText());
|
||||
}
|
||||
if(ctx.expr()!=null) {
|
||||
RValue rValue = this.visit(ctx.expr());
|
||||
Symbol variable = symbolManager.newVariableAssignment(ctx.NAME().getText());
|
||||
Statement stmt = new StatementAssignment(variable, rValue);
|
||||
sequence.addStatement(stmt);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitExprNumber(KickCParser.ExprNumberContext ctx) {
|
||||
Number number = NumberParser.parseLiteral(ctx.getText());
|
||||
if(number instanceof Integer) {
|
||||
return new ConstantInteger((Integer) number);
|
||||
} else {
|
||||
return new ConstantDouble((Double) number);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitExprString(KickCParser.ExprStringContext ctx) {
|
||||
return new ConstantString(ctx.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitExprBool(KickCParser.ExprBoolContext ctx) {
|
||||
String bool = ctx.getText();
|
||||
return new ConstantBool(Boolean.valueOf(bool));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RValue visitExprBinary(KickCParser.ExprBinaryContext ctx) {
|
||||
RValue left = this.visit(ctx.expr(0));
|
||||
RValue right = this.visit(ctx.expr(1));
|
||||
String op = ((TerminalNode)ctx.getChild(1)).getSymbol().getText();
|
||||
Operator operator = new Operator(op);
|
||||
Symbol tmpVar = symbolManager.newIntermediateAssignment();
|
||||
Statement stmt = new StatementAssignment(tmpVar, left, operator, right);
|
||||
sequence.addStatement(stmt);
|
||||
return tmpVar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitExprUnary(KickCParser.ExprUnaryContext ctx) {
|
||||
RValue child = this.visit(ctx.expr());
|
||||
String op = ((TerminalNode)ctx.getChild(0)).getSymbol().getText();
|
||||
Operator operator = new Operator(op);
|
||||
Symbol tmpVar = symbolManager.newIntermediateAssignment();
|
||||
Statement stmt = new StatementAssignment(tmpVar, operator, child);
|
||||
sequence.addStatement(stmt);
|
||||
return tmpVar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitExprPar(KickCParser.ExprParContext ctx) {
|
||||
return this.visit(ctx.expr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue visitExprId(KickCParser.ExprIdContext ctx) {
|
||||
return symbolManager.newVariableUsage(ctx.NAME().getText());
|
||||
}
|
||||
|
||||
public StatementSequence getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public SymbolManager getSymbols() {
|
||||
return this.symbolManager;
|
||||
}
|
||||
}
|
@ -1,21 +1,21 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* Pass through the SSA statements inferring types of unresolved variables.
|
||||
*/
|
||||
public class PassTypeInference {
|
||||
|
||||
public void inferTypes(SSASequence sequence, SymbolManager symbols) {
|
||||
for (SSAStatement statement : sequence.getStatements()) {
|
||||
if (statement instanceof SSAStatementAssignment) {
|
||||
SSAStatementAssignment assignment = (SSAStatementAssignment) statement;
|
||||
public void inferTypes(StatementSequence sequence, SymbolManager symbols) {
|
||||
for (Statement statement : sequence.getStatements()) {
|
||||
if (statement instanceof StatementAssignment) {
|
||||
StatementAssignment assignment = (StatementAssignment) statement;
|
||||
Symbol symbol = (Symbol) assignment.getlValue();
|
||||
if (SymbolType.VAR.equals(symbol.getType())) {
|
||||
// Unresolved symbol - perform inference
|
||||
SSAOperator operator = assignment.getOperator();
|
||||
Operator operator = assignment.getOperator();
|
||||
if (operator == null || assignment.getRValue1() == null) {
|
||||
// Copy operation or Unary operation
|
||||
SSARValue rValue = assignment.getRValue2();
|
||||
RValue rValue = assignment.getRValue2();
|
||||
SymbolType type = inferType(rValue);
|
||||
symbol.setInferredType(type);
|
||||
} else {
|
||||
@ -30,7 +30,7 @@ public class PassTypeInference {
|
||||
}
|
||||
}
|
||||
|
||||
private SymbolType inferType(SymbolType type1, SSAOperator operator, SymbolType type2) {
|
||||
private SymbolType inferType(SymbolType type1, Operator operator, SymbolType type2) {
|
||||
String op = operator.getOperator();
|
||||
switch (op) {
|
||||
case "==":
|
||||
@ -61,21 +61,21 @@ public class PassTypeInference {
|
||||
}
|
||||
}
|
||||
|
||||
private SymbolType inferType(SSARValue rValue) {
|
||||
private SymbolType inferType(RValue rValue) {
|
||||
SymbolType type = SymbolType.VAR;
|
||||
if (rValue instanceof Symbol) {
|
||||
Symbol rSymbol = (Symbol) rValue;
|
||||
type = rSymbol.getType();
|
||||
} else if (rValue instanceof SSAConstantInteger) {
|
||||
SSAConstantInteger rInt = (SSAConstantInteger) rValue;
|
||||
} else if (rValue instanceof ConstantInteger) {
|
||||
ConstantInteger rInt = (ConstantInteger) rValue;
|
||||
if (rInt.getNumber() < 256) {
|
||||
type = SymbolType.BYTE;
|
||||
} else {
|
||||
type = SymbolType.WORD;
|
||||
}
|
||||
} else if (rValue instanceof SSAConstantString) {
|
||||
} else if (rValue instanceof ConstantString) {
|
||||
type = SymbolType.STRING;
|
||||
} else if (rValue instanceof SSAConstantBool) {
|
||||
} else if (rValue instanceof ConstantBool) {
|
||||
type = SymbolType.BOOLEAN;
|
||||
}
|
||||
return type;
|
5
src/dk/camelot64/kickc/icl/RValue.java
Normal file
5
src/dk/camelot64/kickc/icl/RValue.java
Normal file
@ -0,0 +1,5 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** A value usable as part of a calculation (ib the right side of an assignment)*/
|
||||
public interface RValue {
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* Single Static Assignment Form Statement.
|
||||
* Intermediate form used for compiler optimization.
|
||||
*/
|
||||
public interface SSAStatement extends SSAFragment {
|
||||
public interface Statement {
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* Single Static Assignment Form Statement.
|
||||
@ -8,56 +8,56 @@ package dk.camelot64.kickc.ssa;
|
||||
* <br>
|
||||
* <i> lValue := rValue1 <operator> rValue2 </i>
|
||||
*/
|
||||
public class SSAStatementAssignment implements SSAStatement {
|
||||
public class StatementAssignment implements Statement {
|
||||
|
||||
/** The variable being assigned a value by the statement. */
|
||||
private SSALValue lValue;
|
||||
private LValue lValue;
|
||||
|
||||
private SSARValue rValue1;
|
||||
private SSAOperator operator;
|
||||
private SSARValue rValue2;
|
||||
private RValue rValue1;
|
||||
private Operator operator;
|
||||
private RValue rValue2;
|
||||
|
||||
public SSAStatementAssignment(SSALValue lValue, SSARValue rValue2) {
|
||||
public StatementAssignment(LValue lValue, RValue rValue2) {
|
||||
this.lValue = lValue;
|
||||
this.rValue1 = null;
|
||||
this.operator = null;
|
||||
this.rValue2 = rValue2;
|
||||
}
|
||||
|
||||
public SSAStatementAssignment(SSALValue lValue, SSARValue rValue1, SSAOperator operator, SSARValue rValue2) {
|
||||
public StatementAssignment(LValue lValue, RValue rValue1, Operator operator, RValue rValue2) {
|
||||
this.lValue = lValue;
|
||||
this.rValue1 = rValue1;
|
||||
this.operator = operator;
|
||||
this.rValue2 = rValue2;
|
||||
}
|
||||
|
||||
public SSAStatementAssignment(SSALValue lValue, SSAOperator operator, SSARValue rValue2) {
|
||||
public StatementAssignment(LValue lValue, Operator operator, RValue rValue2) {
|
||||
this.lValue = lValue;
|
||||
this.rValue1 = null;
|
||||
this.operator = operator;
|
||||
this.rValue2 = rValue2;
|
||||
}
|
||||
|
||||
public SSALValue getlValue() {
|
||||
public LValue getlValue() {
|
||||
return lValue;
|
||||
}
|
||||
|
||||
public SSARValue getRValue1() {
|
||||
public RValue getRValue1() {
|
||||
return rValue1;
|
||||
}
|
||||
|
||||
public SSAOperator getOperator() {
|
||||
public Operator getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public SSARValue getRValue2() {
|
||||
public RValue getRValue2() {
|
||||
return rValue2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return
|
||||
" "+
|
||||
|
||||
lValue + " ← " +
|
||||
(rValue1==null?"":rValue1+" ") +
|
||||
(operator==null?"":operator+" ") +
|
31
src/dk/camelot64/kickc/icl/StatementConditionalJump.java
Normal file
31
src/dk/camelot64/kickc/icl/StatementConditionalJump.java
Normal file
@ -0,0 +1,31 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* Intermediate Compiler Form Statement with a conditional jump.
|
||||
* Intermediate form used for compiler optimization.
|
||||
* <br>
|
||||
* <i> if ( Y<sub>j</sub> ) goto XX </i>
|
||||
*/
|
||||
public class StatementConditionalJump implements Statement {
|
||||
|
||||
private RValue condition;
|
||||
private Symbol destination;
|
||||
|
||||
public StatementConditionalJump(RValue condition, Symbol destination) {
|
||||
this.condition = condition;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public RValue getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public Symbol getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if("+condition+") goto "+destination.getName();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* Single Static Assignment Form Statement unconditional jump.
|
||||
@ -6,20 +6,20 @@ package dk.camelot64.kickc.ssa;
|
||||
* <br>
|
||||
* <i> goto XX </i>
|
||||
*/
|
||||
public class SSAStatementJump implements SSAStatement {
|
||||
public class StatementJump implements Statement {
|
||||
|
||||
private SSAJumpLabel destination;
|
||||
private Symbol destination;
|
||||
|
||||
public SSAStatementJump(SSAJumpLabel destination) {
|
||||
public StatementJump(Symbol destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public SSAJumpLabel getDestination() {
|
||||
public Symbol getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return " "+"goto "+destination;
|
||||
return "goto "+destination.getName();
|
||||
}
|
||||
}
|
24
src/dk/camelot64/kickc/icl/StatementJumpTarget.java
Normal file
24
src/dk/camelot64/kickc/icl/StatementJumpTarget.java
Normal file
@ -0,0 +1,24 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/**
|
||||
* Single Static Assignment Form Statement Jump target.
|
||||
*/
|
||||
public class StatementJumpTarget implements Statement {
|
||||
|
||||
private Symbol label;
|
||||
|
||||
public StatementJumpTarget(Symbol label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public Symbol getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return label+":";
|
||||
}
|
||||
|
||||
|
||||
}
|
34
src/dk/camelot64/kickc/icl/StatementSequence.java
Normal file
34
src/dk/camelot64/kickc/icl/StatementSequence.java
Normal file
@ -0,0 +1,34 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** A sequence of Statements */
|
||||
public class StatementSequence {
|
||||
|
||||
private List<Statement> statements;
|
||||
|
||||
public StatementSequence() {
|
||||
this.statements = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addStatement(Statement statement) {
|
||||
this.statements.add(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (Statement statement : statements) {
|
||||
if(!(statement instanceof StatementJumpTarget)) {
|
||||
out.append(" ");
|
||||
}
|
||||
out.append(statement.toString()+"\n");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public List<Statement> getStatements() {
|
||||
return statements;
|
||||
}
|
||||
}
|
62
src/dk/camelot64/kickc/icl/Symbol.java
Normal file
62
src/dk/camelot64/kickc/icl/Symbol.java
Normal file
@ -0,0 +1,62 @@
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** A Symbol (variable, jump label, etc.) */
|
||||
public class Symbol implements RValue, LValue {
|
||||
|
||||
private String name;
|
||||
|
||||
private SymbolType type;
|
||||
|
||||
private boolean intermediate;
|
||||
|
||||
private boolean inferredType;
|
||||
|
||||
public Symbol(String name, SymbolType type, boolean intermediate) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.intermediate = intermediate;
|
||||
this.inferredType = false;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public SymbolType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setInferredType(SymbolType type) {
|
||||
this.type = type;
|
||||
this.inferredType = true;
|
||||
}
|
||||
|
||||
public boolean isIntermediate() {
|
||||
return intermediate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "("+name + ": " + type.getTypeName() + (inferredType ?"*":"") + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Symbol symbol = (Symbol) o;
|
||||
if (intermediate != symbol.intermediate) return false;
|
||||
if (inferredType != symbol.inferredType) return false;
|
||||
if (!name.equals(symbol.name)) return false;
|
||||
return type == symbol.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + (type != null ? type.hashCode() : 0);
|
||||
result = 31 * result + (intermediate ? 1 : 0);
|
||||
result = 31 * result + (inferredType ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
@ -11,7 +11,7 @@ public class SymbolManager {
|
||||
private Map<String, Symbol> symbols;
|
||||
|
||||
private int intermediateVarCount = 0;
|
||||
private int intermediateLabelCount = 0;
|
||||
private int intermediateLabelCount = 1;
|
||||
|
||||
public SymbolManager() {
|
||||
this.symbols = new LinkedHashMap<>();
|
||||
@ -45,15 +45,15 @@ public class SymbolManager {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public SSAJumpLabel newNamedJumpLabel(String name) {
|
||||
public Symbol newNamedJumpLabel(String name) {
|
||||
Symbol symbol = addSymbol(name, SymbolType.LABEL, false);
|
||||
return new SSAJumpLabel(name);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public SSAJumpLabel newIntermediateJumpLabel() {
|
||||
public Symbol newIntermediateJumpLabel() {
|
||||
String name = "@"+ intermediateLabelCount++;
|
||||
addSymbol(name, SymbolType.LABEL, true);
|
||||
return new SSAJumpLabel(name);
|
||||
Symbol symbol = addSymbol(name, SymbolType.LABEL, true);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,4 +65,8 @@ public class SymbolManager {
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public void remove(Symbol symbol) {
|
||||
symbols.remove(symbol.getName());
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
package dk.camelot64.kickc.icl;
|
||||
|
||||
/** Symbol Types */
|
||||
public enum SymbolType {
|
@ -1,172 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
import dk.camelot64.kickc.parser.KickCBaseVisitor;
|
||||
import dk.camelot64.kickc.parser.KickCParser;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
/** Generates program SSA form by visiting the ANTLR4 parse tree*/
|
||||
public class GenerateSSA extends KickCBaseVisitor<SSARValue> {
|
||||
|
||||
private SymbolManager symbolManager;
|
||||
private SSASequence sequence;
|
||||
|
||||
public GenerateSSA() {
|
||||
this.symbolManager = new SymbolManager();
|
||||
this.sequence = new SSASequence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitFile(KickCParser.FileContext ctx) {
|
||||
this.visit(ctx.stmtSeq());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SSARValue visitStmtSeq(KickCParser.StmtSeqContext ctx) {
|
||||
for(int i=0; i<ctx.getChildCount(); i++) {
|
||||
this.visit(ctx.stmt(i));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitStmtBlock(KickCParser.StmtBlockContext ctx) {
|
||||
this.visit(ctx.stmtSeq());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitStmtExpr(KickCParser.StmtExprContext ctx) {
|
||||
this.visit(ctx.expr());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitStmtIfElse(KickCParser.StmtIfElseContext ctx) {
|
||||
SSARValue rValue = this.visit(ctx.expr());
|
||||
SSAJumpLabel ifJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
SSAJumpLabel elseJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
SSAStatement ifJmpStmt = new SSAStatementConditionalJump(rValue, ifJumpLabel);
|
||||
sequence.addStatement(ifJmpStmt);
|
||||
SSAStatement elseJmpStmt = new SSAStatementJump(elseJumpLabel);
|
||||
sequence.addStatement(elseJmpStmt);
|
||||
SSAStatementJumpTarget ifJumpTarget = new SSAStatementJumpTarget(ifJumpLabel);
|
||||
sequence.addStatement(ifJumpTarget);
|
||||
this.visit(ctx.stmt(0));
|
||||
KickCParser.StmtContext elseStmt = ctx.stmt(1);
|
||||
if(elseStmt!=null) {
|
||||
SSAJumpLabel endJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
SSAStatement endJmpStmt = new SSAStatementJump(endJumpLabel);
|
||||
sequence.addStatement(endJmpStmt);
|
||||
SSAStatementJumpTarget elseJumpTarget = new SSAStatementJumpTarget(elseJumpLabel);
|
||||
sequence.addStatement(elseJumpTarget);
|
||||
this.visit(elseStmt);
|
||||
SSAStatementJumpTarget endJumpTarget = new SSAStatementJumpTarget(endJumpLabel);
|
||||
sequence.addStatement(endJumpTarget);
|
||||
} else {
|
||||
SSAStatementJumpTarget elseJumpTarget = new SSAStatementJumpTarget(elseJumpLabel);
|
||||
sequence.addStatement(elseJumpTarget);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitStmtWhile(KickCParser.StmtWhileContext ctx) {
|
||||
SSAJumpLabel beginJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
SSAJumpLabel doJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
SSAJumpLabel endJumpLabel = symbolManager.newIntermediateJumpLabel();
|
||||
SSAStatementJumpTarget beginJumpTarget = new SSAStatementJumpTarget(beginJumpLabel);
|
||||
sequence.addStatement(beginJumpTarget);
|
||||
SSARValue rValue = this.visit(ctx.expr());
|
||||
SSAStatement doJmpStmt = new SSAStatementConditionalJump(rValue, doJumpLabel);
|
||||
sequence.addStatement(doJmpStmt);
|
||||
SSAStatement endJmpStmt = new SSAStatementJump(endJumpLabel);
|
||||
sequence.addStatement(endJmpStmt);
|
||||
SSAStatementJumpTarget doJumpTarget = new SSAStatementJumpTarget(doJumpLabel);
|
||||
sequence.addStatement(doJumpTarget);
|
||||
this.visit(ctx.stmt());
|
||||
SSAStatement beginJmpStmt = new SSAStatementJump(beginJumpLabel);
|
||||
sequence.addStatement(beginJmpStmt);
|
||||
SSAStatementJumpTarget endJumpTarget = new SSAStatementJumpTarget(endJumpLabel);
|
||||
sequence.addStatement(endJumpTarget);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitStmtAssignment(KickCParser.StmtAssignmentContext ctx) {
|
||||
if(ctx.TYPE()!=null) {
|
||||
symbolManager.newVariableDeclaration(ctx.NAME().getText(), ctx.TYPE().getText());
|
||||
}
|
||||
if(ctx.expr()!=null) {
|
||||
SSARValue rValue = this.visit(ctx.expr());
|
||||
Symbol variable = symbolManager.newVariableAssignment(ctx.NAME().getText());
|
||||
SSAStatement stmt = new SSAStatementAssignment(variable, rValue);
|
||||
sequence.addStatement(stmt);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitExprNumber(KickCParser.ExprNumberContext ctx) {
|
||||
Number number = KickCNumberParser.parseLiteral(ctx.getText());
|
||||
if(number instanceof Integer) {
|
||||
return new SSAConstantInteger((Integer) number);
|
||||
} else {
|
||||
return new SSAConstantDouble((Double) number);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitExprString(KickCParser.ExprStringContext ctx) {
|
||||
return new SSAConstantString(ctx.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitExprBool(KickCParser.ExprBoolContext ctx) {
|
||||
String bool = ctx.getText();
|
||||
return new SSAConstantBool(Boolean.valueOf(bool));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SSARValue visitExprBinary(KickCParser.ExprBinaryContext ctx) {
|
||||
SSARValue left = this.visit(ctx.expr(0));
|
||||
SSARValue right = this.visit(ctx.expr(1));
|
||||
String op = ((TerminalNode)ctx.getChild(1)).getSymbol().getText();
|
||||
SSAOperator operator = new SSAOperator(op);
|
||||
Symbol tmpVar = symbolManager.newIntermediateAssignment();
|
||||
SSAStatement stmt = new SSAStatementAssignment(tmpVar, left, operator, right);
|
||||
sequence.addStatement(stmt);
|
||||
return tmpVar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitExprUnary(KickCParser.ExprUnaryContext ctx) {
|
||||
SSARValue child = this.visit(ctx.expr());
|
||||
String op = ((TerminalNode)ctx.getChild(0)).getSymbol().getText();
|
||||
SSAOperator operator = new SSAOperator(op);
|
||||
Symbol tmpVar = symbolManager.newIntermediateAssignment();
|
||||
SSAStatement stmt = new SSAStatementAssignment(tmpVar, operator, child);
|
||||
sequence.addStatement(stmt);
|
||||
return tmpVar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitExprPar(KickCParser.ExprParContext ctx) {
|
||||
return this.visit(ctx.expr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSARValue visitExprId(KickCParser.ExprIdContext ctx) {
|
||||
return symbolManager.newVariableUsage(ctx.NAME().getText());
|
||||
}
|
||||
|
||||
public SSASequence getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public SymbolManager getSymbols() {
|
||||
return this.symbolManager;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** A sequence of SSA statements */
|
||||
public class SSABasicBlock {
|
||||
|
||||
List<SSAStatement> statements;
|
||||
|
||||
public SSABasicBlock() {
|
||||
this.statements = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addStatement(SSAStatement statement) {
|
||||
this.statements.add(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SSABasicBlock{" +
|
||||
"statements=" + statements +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/** SSA form constant value */
|
||||
public interface SSAConstant extends SSARValue, SSAFragment {
|
||||
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/**
|
||||
* Any SSA Form fragment resulting from translating a part of the parse tree
|
||||
*/
|
||||
public interface SSAFragment {
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/** A label representing a target of a jump in SSA code */
|
||||
public class SSAJumpLabel {
|
||||
|
||||
private String name;
|
||||
|
||||
public SSAJumpLabel(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/** Left value in SSA Form */
|
||||
public interface SSALValue {
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/** Right value in SSA FORM */
|
||||
public interface SSARValue {
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A sequence of SSA Statements
|
||||
*/
|
||||
public class SSASequence {
|
||||
|
||||
List<SSAStatement> statements;
|
||||
|
||||
public SSASequence() {
|
||||
this.statements = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addStatement(SSAStatement statement) {
|
||||
this.statements.add(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer();
|
||||
for (SSAStatement statement : statements) {
|
||||
out.append(statement.toString()+"\n");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public List<SSAStatement> getStatements() {
|
||||
return statements;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/**
|
||||
* Single Static Assignment Form Statement with a conditional jump.
|
||||
* Intermediate form used for compiler optimization.
|
||||
* <br>
|
||||
* <i> if ( Y<sub>j</sub> ) goto XX </i>
|
||||
*/
|
||||
public class SSAStatementConditionalJump implements SSAStatement {
|
||||
|
||||
private SSARValue condition;
|
||||
private SSAJumpLabel destination;
|
||||
|
||||
public SSAStatementConditionalJump(SSARValue condition, SSAJumpLabel destination) {
|
||||
this.condition = condition;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public SSARValue getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public SSAJumpLabel getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return " "+"if("+condition+") goto "+destination;
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/**
|
||||
* Single Static Assignment Form Statement Jump target.
|
||||
*/
|
||||
public class SSAStatementJumpTarget implements SSAStatement {
|
||||
|
||||
private SSAJumpLabel label;
|
||||
|
||||
public SSAStatementJumpTarget(SSAJumpLabel label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public SSAJumpLabel getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return label+":";
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/** An SSA form Variable. SSA form variables come in different flavors:
|
||||
* <ul>
|
||||
* <li>Each potential modification of a language variable becomes a separate versioned SSA variable.</li>
|
||||
* <li>Expressions are broken into separate SSA statements, each defining a new temporary/intermediate variable.</li>
|
||||
* </ul>
|
||||
*
|
||||
* Named variables are initially created without serials. These are first added after the basic control blocks have been defined.
|
||||
*
|
||||
* */
|
||||
public class SSAVariable implements SSARValue, SSALValue, SSAFragment {
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer serial;
|
||||
|
||||
public SSAVariable(String name) {
|
||||
this.name = name;
|
||||
this.serial = null;
|
||||
}
|
||||
|
||||
public SSAVariable(String name, int serial) {
|
||||
this.name = name;
|
||||
this.serial = serial;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getSerial() {
|
||||
return serial;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + (serial==null?"":"_"+serial);
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package dk.camelot64.kickc.ssa;
|
||||
|
||||
/** A Symbol (variable, jump label, etc.) */
|
||||
public class Symbol implements SSARValue, SSALValue, SSAFragment {
|
||||
|
||||
private String name;
|
||||
|
||||
private SymbolType type;
|
||||
|
||||
private boolean intermediate;
|
||||
|
||||
private boolean inferredType;
|
||||
|
||||
public Symbol(String name, SymbolType type, boolean intermediate) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.intermediate = intermediate;
|
||||
this.inferredType = false;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public SymbolType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setInferredType(SymbolType type) {
|
||||
this.type = type;
|
||||
this.inferredType = true;
|
||||
}
|
||||
|
||||
public boolean isIntermediate() {
|
||||
return intermediate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "("+name + (intermediate?"*":"") + ": " + type.getTypeName() + (inferredType ?"*":"") + ")";
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package dk.camelot64.kickc.test;
|
||||
|
||||
import dk.camelot64.kickc.icl.ControlFlowGraph;
|
||||
import dk.camelot64.kickc.icl.PassGenerateControlFlowGraph;
|
||||
import dk.camelot64.kickc.parser.KickCLexer;
|
||||
import dk.camelot64.kickc.parser.KickCParser;
|
||||
import dk.camelot64.kickc.ssa.GenerateSSA;
|
||||
import dk.camelot64.kickc.ssa.PassTypeInference;
|
||||
import dk.camelot64.kickc.ssa.SSASequence;
|
||||
import dk.camelot64.kickc.icl.PassGenerateStatementSequence;
|
||||
import dk.camelot64.kickc.icl.PassTypeInference;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
@ -20,16 +21,18 @@ public class main {
|
||||
KickCParser parser = new KickCParser(new CommonTokenStream(lexer));
|
||||
parser.setBuildParseTree(true);
|
||||
KickCParser.FileContext file = parser.file();
|
||||
GenerateSSA ev = new GenerateSSA();
|
||||
ev.visit(file);
|
||||
|
||||
PassTypeInference passTypeInference = new PassTypeInference();
|
||||
passTypeInference.inferTypes(ev.getSequence(), ev.getSymbols());
|
||||
|
||||
System.out.println("PROGRAM");
|
||||
System.out.println(ev.getSequence().toString());
|
||||
PassGenerateStatementSequence passGenerateStatementSequence = new PassGenerateStatementSequence();
|
||||
passGenerateStatementSequence.visit(file);
|
||||
new PassTypeInference().inferTypes(passGenerateStatementSequence.getSequence(), passGenerateStatementSequence.getSymbols());
|
||||
PassGenerateControlFlowGraph passGenerateControlFlowGraph = new PassGenerateControlFlowGraph(passGenerateStatementSequence.getSymbols());
|
||||
ControlFlowGraph controlFlowGraph = passGenerateControlFlowGraph.generate(passGenerateStatementSequence.getSequence());
|
||||
System.out.println("SYMBOLS");
|
||||
System.out.println(ev.getSymbols().toString());
|
||||
System.out.println(passGenerateStatementSequence.getSymbols().toString());
|
||||
System.out.println("PROGRAM");
|
||||
System.out.println(passGenerateStatementSequence.getSequence().toString());
|
||||
System.out.println("CONTROL FLOW GRAPH");
|
||||
System.out.println(controlFlowGraph.toString());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user