diff --git a/src/dk/camelot64/kickc/asm/AsmFragment.java b/src/dk/camelot64/kickc/asm/AsmFragment.java index 88e359eb4..40d57a792 100644 --- a/src/dk/camelot64/kickc/asm/AsmFragment.java +++ b/src/dk/camelot64/kickc/asm/AsmFragment.java @@ -187,7 +187,7 @@ public class AsmFragment { } } else if (value instanceof ConstantInteger) { ConstantInteger intValue = (ConstantInteger) value; - if (intValue.getType().equals(SymbolType.BYTE)) { + if (intValue.getType().equals(SymbolTypeBasic.BYTE)) { String name = "coby" + nextConstByteIdx++; bindings.put(name, value); return name; @@ -223,7 +223,7 @@ public class AsmFragment { } } else if (boundValue instanceof ConstantInteger) { ConstantInteger boundInt = (ConstantInteger) boundValue; - if (boundInt.getType().equals(SymbolType.BYTE)) { + if (boundInt.getType().equals(SymbolTypeBasic.BYTE)) { bound = Integer.toString(boundInt.getNumber()); } else { throw new RuntimeException("Bound Value Type not implemented " + boundValue); diff --git a/src/dk/camelot64/kickc/icl/Label.java b/src/dk/camelot64/kickc/icl/Label.java index dbe1eb5d3..0e3668674 100644 --- a/src/dk/camelot64/kickc/icl/Label.java +++ b/src/dk/camelot64/kickc/icl/Label.java @@ -22,7 +22,7 @@ public class Label implements Symbol { } public SymbolType getType() { - return SymbolType.LABEL; + return SymbolTypeBasic.LABEL; } @Override diff --git a/src/dk/camelot64/kickc/icl/ParseTreeConstantEvaluator.java b/src/dk/camelot64/kickc/icl/ParseTreeConstantEvaluator.java new file mode 100644 index 000000000..c28e1d366 --- /dev/null +++ b/src/dk/camelot64/kickc/icl/ParseTreeConstantEvaluator.java @@ -0,0 +1,91 @@ +package dk.camelot64.kickc.icl; + +import dk.camelot64.kickc.parser.KickCBaseVisitor; +import dk.camelot64.kickc.parser.KickCParser; +import org.antlr.v4.runtime.tree.TerminalNode; + +/** Capable of evaluating constants directly on the parse tree. */ +public class ParseTreeConstantEvaluator extends KickCBaseVisitor { + + /** + * Attempt to evaluate a constant expression. + * + * @param expr The expression to evaluate + * @return The constant value of the expression. null if the expression is not constant. + */ + public static Constant evaluate(KickCParser.ExprContext expr) { + return (new ParseTreeConstantEvaluator()).visit(expr); + } + + @Override + public Constant 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 Constant visitExprString(KickCParser.ExprStringContext ctx) { + return new ConstantString(ctx.getText()); + } + + @Override + public Constant visitExprBool(KickCParser.ExprBoolContext ctx) { + return new ConstantBool(Boolean.getBoolean(ctx.getText())); + } + + @Override + public Constant visitExprPar(KickCParser.ExprParContext ctx) { + return visit(ctx.expr()); + } + + @Override + public Constant visitExprCast(KickCParser.ExprCastContext ctx) { + return visit(ctx.expr()); + } + + @Override + public Constant visitExprCall(KickCParser.ExprCallContext ctx) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Constant visitExprArray(KickCParser.ExprArrayContext ctx) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Constant visitExprId(KickCParser.ExprIdContext ctx) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Constant visitInitExpr(KickCParser.InitExprContext ctx) { + return visit(ctx.expr()); + } + + @Override + public Constant visitInitList(KickCParser.InitListContext ctx) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Constant visitExprUnary(KickCParser.ExprUnaryContext ctx) { + Constant sub = visit(ctx.expr()); + String op = ((TerminalNode)ctx.getChild(0)).getSymbol().getText(); + Operator operator = new Operator(op); + return Pass2ConstantPropagation.calculateUnary(operator, sub); + } + + @Override + public Constant visitExprBinary(KickCParser.ExprBinaryContext ctx) { + Constant left = this.visit(ctx.expr(0)); + Constant right = this.visit(ctx.expr(1)); + String op = ((TerminalNode)ctx.getChild(1)).getSymbol().getText(); + Operator operator = new Operator(op); + return Pass2ConstantPropagation.calculateBinary(operator, left, right); + } +} diff --git a/src/dk/camelot64/kickc/icl/Pass1GenerateStatementSequence.java b/src/dk/camelot64/kickc/icl/Pass1GenerateStatementSequence.java index a07f7c5b9..7e46a3d7d 100644 --- a/src/dk/camelot64/kickc/icl/Pass1GenerateStatementSequence.java +++ b/src/dk/camelot64/kickc/icl/Pass1GenerateStatementSequence.java @@ -174,7 +174,7 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor { @Override public SymbolType visitTypeSimple(KickCParser.TypeSimpleContext ctx) { - return SymbolType.get(ctx.getText()); + return SymbolTypeBasic.get(ctx.getText()); } @Override @@ -184,7 +184,13 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor { @Override public SymbolType visitTypeArray(KickCParser.TypeArrayContext ctx) { - throw new RuntimeException("Not implemented"); + SymbolType elementType = (SymbolType) visit(ctx.typeDecl()); + Constant size = ParseTreeConstantEvaluator.evaluate(ctx.expr()); + if(size instanceof ConstantInteger) { + return new SymbolTypeArray(elementType, ((ConstantInteger) size).getNumber()); + } else { + throw new RuntimeException("Array size not a constant integer "+ctx.getText()); + } } @Override diff --git a/src/dk/camelot64/kickc/icl/Pass2ConstantPropagation.java b/src/dk/camelot64/kickc/icl/Pass2ConstantPropagation.java index 0df412f9d..521cf94aa 100644 --- a/src/dk/camelot64/kickc/icl/Pass2ConstantPropagation.java +++ b/src/dk/camelot64/kickc/icl/Pass2ConstantPropagation.java @@ -95,6 +95,13 @@ public class Pass2ConstantPropagation extends Pass2Optimization { return new ConstantDouble(getDouble(c1) + getDouble(c2)); } } + case "*": { + if (c1 instanceof ConstantInteger && c2 instanceof ConstantInteger) { + return new ConstantInteger(getInteger(c1) * getInteger(c2)); + } else { + return new ConstantDouble(getDouble(c1) * getDouble(c2)); + } + } default: throw new RuntimeException("Unhandled Binary Operator " + operator.getOperator()); } diff --git a/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java b/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java index b1e301087..37bfc9315 100644 --- a/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java +++ b/src/dk/camelot64/kickc/icl/Pass3RegisterAllocation.java @@ -16,9 +16,9 @@ public class Pass3RegisterAllocation { int currentZp = 2; for (Variable var : symbols.getAllVariables()) { if(var instanceof VariableIntermediate || var instanceof VariableVersion) - if(var.getType().equals(SymbolType.BYTE)) { + if(var.getType().equals(SymbolTypeBasic.BYTE)) { allocation.allocate(var, new RegisterAllocation.RegisterZpByte(currentZp++)); - } else if(var.getType().equals(SymbolType.BOOLEAN)) { + } else if(var.getType().equals(SymbolTypeBasic.BOOLEAN)) { allocation.allocate(var, new RegisterAllocation.RegisterZpBool(currentZp++)); } } diff --git a/src/dk/camelot64/kickc/icl/PassTypeInference.java b/src/dk/camelot64/kickc/icl/PassTypeInference.java index 54a48b3f1..05bf4e871 100644 --- a/src/dk/camelot64/kickc/icl/PassTypeInference.java +++ b/src/dk/camelot64/kickc/icl/PassTypeInference.java @@ -10,7 +10,7 @@ public class PassTypeInference { if (statement instanceof StatementAssignment) { StatementAssignment assignment = (StatementAssignment) statement; Variable symbol = (Variable) assignment.getLValue(); - if (SymbolType.VAR.equals(symbol.getType())) { + if (SymbolTypeBasic.VAR.equals(symbol.getType())) { // Unresolved symbol - perform inference Operator operator = assignment.getOperator(); if (operator == null || assignment.getRValue1() == null) { @@ -46,37 +46,40 @@ public class PassTypeInference { case "||": case "and": case "or": - return SymbolType.BOOLEAN; + return SymbolTypeBasic.BOOLEAN; case "+": case "-": case "*": case "/": - if (type1.equals(SymbolType.WORD) || type2.equals(SymbolType.WORD)) { - return SymbolType.WORD; + if (type1.equals(SymbolTypeBasic.WORD) || type2.equals(SymbolTypeBasic.WORD)) { + return SymbolTypeBasic.WORD; } else { - return SymbolType.BYTE; + return SymbolTypeBasic.BYTE; } default: - return SymbolType.VAR; + throw new RuntimeException("Type inference case not handled "+type1+" "+operator+" "+type2); } } public static SymbolType inferType(RValue rValue) { - SymbolType type = SymbolType.VAR; + SymbolType type = null; if (rValue instanceof Symbol) { Symbol rSymbol = (Symbol) rValue; type = rSymbol.getType(); } else if (rValue instanceof ConstantInteger) { ConstantInteger rInt = (ConstantInteger) rValue; if (rInt.getNumber() < 256) { - type = SymbolType.BYTE; + type = SymbolTypeBasic.BYTE; } else { - type = SymbolType.WORD; + type = SymbolTypeBasic.WORD; } } else if (rValue instanceof ConstantString) { - type = SymbolType.STRING; + type = SymbolTypeBasic.STRING; } else if (rValue instanceof ConstantBool) { - type = SymbolType.BOOLEAN; + type = SymbolTypeBasic.BOOLEAN; + } + if(type==null) { + throw new RuntimeException("Cannot infer type for "+rValue); } return type; } diff --git a/src/dk/camelot64/kickc/icl/SymbolTable.java b/src/dk/camelot64/kickc/icl/SymbolTable.java index 46ae85ea1..6eec7ecee 100644 --- a/src/dk/camelot64/kickc/icl/SymbolTable.java +++ b/src/dk/camelot64/kickc/icl/SymbolTable.java @@ -43,7 +43,7 @@ public class SymbolTable { } public VariableUnversioned newVariableDeclaration(String name, String type) { - SymbolType symbolType = SymbolType.get(type); + SymbolType symbolType = SymbolTypeBasic.get(type); VariableUnversioned symbol = new VariableUnversioned(name, symbolType); addSymbol(symbol); return symbol; @@ -55,7 +55,7 @@ public class SymbolTable { public VariableIntermediate newIntermediateAssignment() { String name = "$"+intermediateVarCount++; - VariableIntermediate symbol = new VariableIntermediate(name, SymbolType.VAR); + VariableIntermediate symbol = new VariableIntermediate(name, SymbolTypeBasic.VAR); addSymbol(symbol); return symbol; } diff --git a/src/dk/camelot64/kickc/icl/SymbolType.java b/src/dk/camelot64/kickc/icl/SymbolType.java index d66bf44f8..7c6ca2c35 100644 --- a/src/dk/camelot64/kickc/icl/SymbolType.java +++ b/src/dk/camelot64/kickc/icl/SymbolType.java @@ -1,33 +1,8 @@ package dk.camelot64.kickc.icl; /** Symbol Types */ -public enum SymbolType { - BYTE("byte"), - WORD("word"), - STRING("string"), - BOOLEAN("boolean"), - LABEL("label"), - VAR("var"); - - private String typeName; - - SymbolType(String typeName) { - this.typeName = typeName; - } - - public String getTypeName() { - return typeName; - } - - public static SymbolType get(String name) { - switch (name) { - case "byte": return BYTE; - case "word": return WORD; - case "string": return STRING; - case "boolean": return BOOLEAN; - } - return null; - } +public interface SymbolType { + public String getTypeName(); } diff --git a/src/dk/camelot64/kickc/icl/SymbolTypeArray.java b/src/dk/camelot64/kickc/icl/SymbolTypeArray.java new file mode 100644 index 000000000..af8baedec --- /dev/null +++ b/src/dk/camelot64/kickc/icl/SymbolTypeArray.java @@ -0,0 +1,26 @@ +package dk.camelot64.kickc.icl; + +/** A fixed size array of another type */ +public class SymbolTypeArray implements SymbolType { + + private SymbolType elementType; + private int size; + + public SymbolTypeArray(SymbolType elementType, int size) { + this.elementType = elementType; + this.size = size; + } + + public SymbolType getElementType() { + return elementType; + } + + public int getSize() { + return size; + } + + @Override + public String getTypeName() { + return elementType.getTypeName()+"["+size+"]"; + } +} diff --git a/src/dk/camelot64/kickc/icl/SymbolTypeBasic.java b/src/dk/camelot64/kickc/icl/SymbolTypeBasic.java new file mode 100644 index 000000000..57b62199d --- /dev/null +++ b/src/dk/camelot64/kickc/icl/SymbolTypeBasic.java @@ -0,0 +1,33 @@ +package dk.camelot64.kickc.icl; + +/** Basic Symbol Types */ +public enum SymbolTypeBasic implements SymbolType { + BYTE("byte"), + WORD("word"), + STRING("string"), + BOOLEAN("boolean"), + LABEL("label"), + VAR("var"); + + private String typeName; + + SymbolTypeBasic(String typeName) { + this.typeName = typeName; + } + + public String getTypeName() { + return typeName; + } + + public static SymbolTypeBasic get(String name) { + switch (name) { + case "byte": return BYTE; + case "word": return WORD; + case "string": return STRING; + case "boolean": return BOOLEAN; + } + return null; + } + + +} diff --git a/src/dk/camelot64/kickc/test/Main.java b/src/dk/camelot64/kickc/test/Main.java index 01181287e..f7e7f3f1e 100644 --- a/src/dk/camelot64/kickc/test/Main.java +++ b/src/dk/camelot64/kickc/test/Main.java @@ -13,7 +13,7 @@ import java.util.List; /** Test my KickC Grammar */ public class Main { public static void main(String[] args) throws IOException { - final String fileName = "src/dk/camelot64/kickc/test/fib.kc"; + final String fileName = "src/dk/camelot64/kickc/test/mem.kc"; final CharStream input = CharStreams.fromFileName(fileName); System.out.println(input.toString()); KickCLexer lexer = new KickCLexer(input); diff --git a/src/dk/camelot64/kickc/test/mem.kc b/src/dk/camelot64/kickc/test/mem.kc index 40b5ecc38..4e589016e 100644 --- a/src/dk/camelot64/kickc/test/mem.kc +++ b/src/dk/camelot64/kickc/test/mem.kc @@ -1,12 +1,10 @@ // Array declaration & allocation (allocated in same memory space as the program) -byte[64] idtab; +byte[8*8] idtab; // Array assignment idtab[0] = 12; // Using array indexing -byte id6 = idtab[1]; - - +//byte id6 = idtab[1];