basic generator

This commit is contained in:
User 2017-05-15 16:22:00 +02:00
parent 21dca82f4a
commit a845321785
4 changed files with 366 additions and 7 deletions

View File

@ -0,0 +1,296 @@
package pp.s1184725.boppi;
import java.util.HashMap;
import java.util.Map;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.RuleNode;
import pp.iloc.model.*;
import pp.s1184725.boppi.BasicParser.*;
public class BoppiBasicGenerator extends BasicBaseVisitor<Void> {
public Program prog;
private Annotations an;
private int regNum;
private final Reg zero = new Reg("zero");
static Map<Integer, OpCode> ops = new HashMap<Integer, OpCode>() {
private static final long serialVersionUID = 8979722313842633807L;
{
put(BasicLexer.AND, OpCode.and);
put(BasicLexer.DIVIDE, OpCode.div);
put(BasicLexer.EQ, OpCode.cmp_EQ);
put(BasicLexer.GT, OpCode.cmp_GT);
put(BasicLexer.GTE, OpCode.cmp_GE);
put(BasicLexer.LEQ, OpCode.cmp_LE);
put(BasicLexer.LT, OpCode.cmp_LT);
put(BasicLexer.MINUS, OpCode.sub);
put(BasicLexer.MULTIPLY, OpCode.mult);
put(BasicLexer.NEQ, OpCode.cmp_NE);
put(BasicLexer.PLUS, OpCode.add);
put(BasicLexer.OR, OpCode.or);
}
};
public BoppiBasicGenerator(Annotations annotations) {
an = annotations;
prog = new Program();
regNum = 0;
emit(OpCode.loadI, new Num(0), zero);
}
private Reg getReg(ParseTree parseTree) {
Reg reg = an.registers.get(parseTree);
if (reg == null) {
reg = new Reg("r_" + (regNum++));
an.registers.put(parseTree, reg);
}
return reg;
}
private Reg copyReg(ParseTree source, ParseTree destination) {
Reg reg = an.registers.get(source);
an.registers.put(destination, reg);
return reg;
}
/**
* Constructs an operation from the parameters and adds it to the program
* under construction.
*/
private Op emit(Label label, OpCode opCode, Operand... args) {
Op result = new Op(label, opCode, args);
this.prog.addInstr(result);
return result;
}
/**
* Constructs an operation from the parameters and adds it to the program
* under construction.
*/
private Op emit(OpCode opCode, Operand... args) {
return emit((Label) null, opCode, args);
}
@Override
public Void visitChildren(RuleNode tree) {
super.visitChildren(tree);
if (an.registers.get(tree) == null)
for (int i = tree.getChildCount() - 1; i >= 0; i--)
if (tree.getChild(i) instanceof RuleContext) {
copyReg(tree.getChild(i), tree);
break;
}
return null;
}
@Override
public Void visitAssign(AssignContext ctx) {
visit(ctx.singleExpr());
copyReg(ctx.singleExpr(), ctx);
switch (an.types.get(ctx)) {
case CHAR:
emit(OpCode.cstoreAI, getReg(ctx), zero, new Num(an.variables.get(ctx.variable()).getOffset()));
break;
default:
emit(OpCode.storeAI, getReg(ctx), zero, new Num(an.variables.get(ctx.variable()).getOffset()));
}
return null;
}
@Override
public Void visitBool(BoolContext ctx) {
emit(OpCode.loadI, new Num(ctx.TRUE() != null ? 1 : 0), getReg(ctx));
return null;
}
@Override
public Void visitNumber(NumberContext ctx) {
emit(OpCode.loadI, new Num(Integer.parseInt(ctx.LITERAL10().getText())), getReg(ctx));
return null;
}
@Override
public Void visitInfix1(Infix1Context ctx) {
visitChildren(ctx);
emit(ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx));
return null;
}
@Override
public Void visitInfix2(Infix2Context ctx) {
visitChildren(ctx);
emit(ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx));
return null;
}
@Override
public Void visitInfix3(Infix3Context ctx) {
visitChildren(ctx);
emit(ops.get(ctx.op.getType()), getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx));
return null;
}
@Override
public Void visitInfix4(Infix4Context ctx) {
visitChildren(ctx);
emit(OpCode.and, getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx));
return null;
}
@Override
public Void visitInfix5(Infix5Context ctx) {
visitChildren(ctx);
emit(OpCode.or, getReg(ctx.lhs), getReg(ctx.rhs), getReg(ctx));
return null;
}
@Override
public Void visitPrefix1(Prefix1Context ctx) {
visitChildren(ctx);
switch (ctx.op.getType()) {
case BasicLexer.MINUS:
emit(OpCode.rsubI, new Num(0), getReg(ctx.singleExpr()), getReg(ctx));
}
return null;
}
@Override
public Void visitVar(VarContext ctx) {
switch (an.types.get(ctx)) {
case CHAR:
emit(OpCode.cloadAI, zero, new Num(an.variables.get(ctx.variable()).getOffset()), getReg(ctx));
break;
default:
emit(OpCode.loadAI, zero, new Num(an.variables.get(ctx.variable()).getOffset()), getReg(ctx));
}
return null;
}
@Override
public Void visitChar(CharContext ctx) {
emit(OpCode.loadI, new Num(ctx.CHAR().getText().codePointAt(1)), getReg(ctx));
emit(OpCode.i2c, getReg(ctx), getReg(ctx));
return null;
}
@Override
public Void visitRead(ReadContext ctx) {
for (VariableContext expr : ctx.variable()) {
visit(expr);
switch (an.types.get(expr)) {
case BOOL:
case INT:
emit(OpCode.in, new Str(""), getReg(ctx));
emit(OpCode.storeAI, getReg(ctx), zero, new Num(an.variables.get(expr).getOffset()));
break;
case CHAR:
//Get input until at least 1 character
Label getTarget = new Label("lcin_l"+ctx.hashCode());
Label continueTarget = new Label("lcin_e"+ctx.hashCode());
Reg countReg = new Reg("tempReg");
emit(getTarget, OpCode.cin, new Str(""));
emit(OpCode.pop, countReg);
emit(OpCode.cbr, countReg, continueTarget, getTarget);
//Get character
emit(continueTarget, OpCode.cpop, getReg(ctx));
emit(OpCode.cstoreAI, getReg(ctx), zero, new Num(an.variables.get(expr).getOffset()));
//Pop all remaining characters
Label loopTarget = new Label("lcpop_l"+ctx.hashCode());
Label iterTarget = new Label("lcpop_c"+ctx.hashCode());
Label stopTarget = new Label("lcpop_e"+ctx.hashCode());
Reg tempReg2 = new Reg("tempReg2");
emit(loopTarget, OpCode.subI, countReg, new Num(1), countReg);
emit(OpCode.cbr, countReg, iterTarget, stopTarget);
emit(iterTarget, OpCode.cpop, tempReg2);
emit(OpCode.jumpI, loopTarget);
emit(stopTarget, OpCode.nop);
break;
default:
emit(OpCode.out, new Str("Unknown type: "), an.registers.get(expr));
}
}
return null;
}
@Override
public Void visitIf(IfContext ctx) {
Label toTrue = new Label("if_t"+ctx.hashCode());
Label toFalse = new Label("if_f"+ctx.hashCode());
Label toEnd = new Label("if_e"+ctx.hashCode());
visit(ctx.cond);
if (ctx.onFalse == null) {
emit(OpCode.cbr, getReg(ctx.cond), toTrue, toEnd);
emit(toTrue, OpCode.nop);
visit(ctx.onTrue);
}
else {
emit(OpCode.cbr, getReg(ctx.cond), toTrue, toFalse);
emit(toTrue, OpCode.nop);
visit(ctx.onTrue);
if (an.types.get(ctx) != SimpleType.VOID)
emit(OpCode.i2i, getReg(ctx.onTrue), getReg(ctx));
emit(OpCode.jumpI, toEnd);
emit(toFalse, OpCode.nop);
visit(ctx.onFalse);
if (an.types.get(ctx) != SimpleType.VOID)
emit(OpCode.i2i, getReg(ctx.onFalse), getReg(ctx));
}
emit(toEnd, OpCode.nop);
return null;
}
@Override
public Void visitWhile(WhileContext ctx) {
Label toLoop = new Label("while_t"+ctx.hashCode());
Label toCond = new Label("while_f"+ctx.hashCode());
Label toEnd = new Label("while_e"+ctx.hashCode());
emit(OpCode.jumpI, toCond);
emit(toLoop, OpCode.nop);
visit(ctx.onTrue);
emit(toCond, OpCode.nop);
visit(ctx.cond);
emit(OpCode.cbr, getReg(ctx.cond), toLoop, toEnd);
emit(toEnd, OpCode.nop);
return null;
}
@Override
public Void visitWrite(WriteContext ctx) {
for (ExprContext expr : ctx.expr()) {
visit(expr);
switch (an.types.get(expr)) {
case BOOL:
case INT:
emit(OpCode.out, new Str(""), getReg(expr));
break;
case CHAR:
Reg tempReg = new Reg("tempReg");
emit(OpCode.cpush, getReg(expr));
emit(OpCode.loadI, new Num(1), tempReg);
emit(OpCode.push, tempReg);
emit(OpCode.cout, new Str(""));
break;
default:
emit(OpCode.out, new Str("Unknown type: "), getReg(expr));
}
}
return null;
}
}

View File

@ -2,8 +2,6 @@ package pp.s1184725.boppi;
import java.util.*;
import pp.iloc.eval.Machine;
public class CachingSymbolTable<T> {
protected Stack<Map<String,Variable<T>>> symbolMapStack;
protected Stack<Integer> offsets;
@ -56,7 +54,8 @@ public class CachingSymbolTable<T> {
throw new Exception(String.format("Identifier '%s' already declared in this scope.", id));
Variable<T> var = new Variable<>(type, offset);
offset += Machine.INT_SIZE;
// TODO refactor to get type size
offset += ((SimpleType)type).getSize();
symbolMapStack.peek().put(id, var);
symbolCache.put(id, var);
return var;

View File

@ -1,17 +1,30 @@
package pp.s1184725.boppi;
import static pp.s1184725.boppi.BasicLexer.*;
import pp.iloc.eval.Machine;
public enum SimpleType {
INT, CHAR, BOOL, VOID;
INT(Machine.INT_SIZE), CHAR(Machine.DEFAULT_CHAR_SIZE), BOOL(Machine.INT_SIZE), VOID(0);
private final int size;
public int getSize() {
return size;
}
private SimpleType(int typeSize) {
size = typeSize;
}
public static SimpleType fromToken(int token) {
switch (token) {
case BasicLexer.INTTYPE:
case INTTYPE:
return SimpleType.INT;
case BasicLexer.CHARTYPE:
case CHARTYPE:
return SimpleType.CHAR;
case BasicLexer.BOOLTYPE:
case BOOLTYPE:
return SimpleType.BOOL;
default:

View File

@ -0,0 +1,51 @@
package pp.s1184725.boppi.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.antlr.v4.runtime.ParserRuleContext;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.Test;
import pp.iloc.Simulator;
import pp.s1184725.boppi.Annotations;
import pp.s1184725.boppi.BasicParser;
import pp.s1184725.boppi.BasicParserHelper;
import pp.s1184725.boppi.BoppiBasicChecker;
import pp.s1184725.boppi.BoppiBasicGenerator;
public class GeneratorTest {
static private List<LogRecord> generateAndGetLog(String code) {
Logger logger = Logger.getAnonymousLogger();
Pair<BasicParser, List<LogRecord>> pair = BasicParserHelper.getParserWithLog(code, logger);
Annotations annotater = new Annotations();
ParserRuleContext tree = pair.getLeft().program();
new BoppiBasicChecker(logger, annotater).visit(tree);
BoppiBasicGenerator generator = new BoppiBasicGenerator(annotater);
generator.visit(tree);
// System.out.println(generator.prog.prettyPrint());
// System.out.println(BasicParserHelper.getAnnotatedDOT(tree, annotater));
Simulator s = new Simulator(generator.prog);
InputStream in = new ByteArrayInputStream("1\nq\n".getBytes(StandardCharsets.UTF_8));
ByteArrayOutputStream out = new ByteArrayOutputStream();
s.setIn(in);
s.setOut(out);
s.run();
System.out.println(out.toString());
return pair.getRight();
}
@Test
public void basicTest() {
// generateAndGetLog("print(5*3)");
// generateAndGetLog("var int x; var int y; x := 3*(y := 4); print(x,y)");
// generateAndGetLog("print('T', 'e', 's', 't', '!')");
// generateAndGetLog("var int i; if read(i) == 1 then var char c; read(c); print(c,c); else print(i) fi");
generateAndGetLog("var int i; i := 10; while i > 0 do print('A', i); i := i-1 od");
}
}