Refactor textual IR parser

This commit is contained in:
Alexey Andreev 2016-12-04 17:00:24 +03:00
parent 6084491119
commit fb53667e77

View File

@ -27,6 +27,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming; import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Phi; import org.teavm.model.Phi;
import org.teavm.model.Program; import org.teavm.model.Program;
@ -78,9 +79,10 @@ public class ListingParser {
private ListingLexer lexer; private ListingLexer lexer;
private Map<String, Variable> variableMap; private Map<String, Variable> variableMap;
private Map<String, BasicBlock> blockMap; private Map<String, BasicBlock> blockMap;
private Map<String, Integer> blockFirstOccurence; private Map<String, Integer> blockFirstOccurrence;
private Set<String> declaredBlocks = new HashSet<>(); private Set<String> declaredBlocks = new HashSet<>();
private TextLocation currentLocation; private TextLocation currentLocation;
private BasicBlock currentBlock;
public Program parse(Reader reader) throws IOException, ListingParseException { public Program parse(Reader reader) throws IOException, ListingParseException {
try { try {
@ -88,7 +90,7 @@ public class ListingParser {
lexer = new ListingLexer(reader); lexer = new ListingLexer(reader);
variableMap = new HashMap<>(); variableMap = new HashMap<>();
blockMap = new HashMap<>(); blockMap = new HashMap<>();
blockFirstOccurence = new LinkedHashMap<>(); blockFirstOccurrence = new LinkedHashMap<>();
lexer.nextToken(); lexer.nextToken();
parsePrologue(); parsePrologue();
@ -97,9 +99,9 @@ public class ListingParser {
parseBasicBlock(); parseBasicBlock();
} while (lexer.getToken() != ListingToken.EOF); } while (lexer.getToken() != ListingToken.EOF);
if (!blockFirstOccurence.isEmpty()) { if (!blockFirstOccurrence.isEmpty()) {
String blockName = blockFirstOccurence.keySet().iterator().next(); String blockName = blockFirstOccurrence.keySet().iterator().next();
int blockIndex = blockFirstOccurence.get(blockName); int blockIndex = blockFirstOccurrence.get(blockName);
throw new ListingParseException("Block not defined: " + blockName, blockIndex); throw new ListingParseException("Block not defined: " + blockName, blockIndex);
} }
@ -109,7 +111,7 @@ public class ListingParser {
lexer = null; lexer = null;
variableMap = null; variableMap = null;
blockMap = null; blockMap = null;
blockFirstOccurence = null; blockFirstOccurrence = null;
} }
} }
@ -153,7 +155,7 @@ public class ListingParser {
if (!declaredBlocks.add(label)) { if (!declaredBlocks.add(label)) {
throw new ListingParseException("Block with label " + label + " already exists", lexer.getTokenStart()); throw new ListingParseException("Block with label " + label + " already exists", lexer.getTokenStart());
} }
blockFirstOccurence.remove(label); blockFirstOccurrence.remove(label);
lexer.nextToken(); lexer.nextToken();
expect(ListingToken.EOL); expect(ListingToken.EOL);
@ -161,7 +163,7 @@ public class ListingParser {
lexer.nextToken(); lexer.nextToken();
} }
BasicBlock block = blockMap.computeIfAbsent(label, k -> { currentBlock = blockMap.computeIfAbsent(label, k -> {
BasicBlock b = program.createBasicBlock(); BasicBlock b = program.createBasicBlock();
b.setLabel(k); b.setLabel(k);
return b; return b;
@ -169,7 +171,7 @@ public class ListingParser {
currentLocation = null; currentLocation = null;
do { do {
parseInstruction(block); parseInstruction();
} while (lexer.getToken() != ListingToken.LABEL && lexer.getToken() != ListingToken.EOF); } while (lexer.getToken() != ListingToken.LABEL && lexer.getToken() != ListingToken.EOF);
while (lexer.getToken() == ListingToken.EOL) { while (lexer.getToken() == ListingToken.EOL) {
@ -177,7 +179,7 @@ public class ListingParser {
} }
} }
private void parseInstruction(BasicBlock block) throws IOException, ListingParseException { private void parseInstruction() throws IOException, ListingParseException {
switch (lexer.getToken()) { switch (lexer.getToken()) {
case IDENTIFIER: { case IDENTIFIER: {
String id = (String) lexer.getTokenValue(); String id = (String) lexer.getTokenValue();
@ -189,8 +191,7 @@ public class ListingParser {
} }
case "nop": { case "nop": {
EmptyInstruction insn = new EmptyInstruction(); EmptyInstruction insn = new EmptyInstruction();
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
lexer.nextToken(); lexer.nextToken();
break; break;
} }
@ -198,38 +199,35 @@ public class ListingParser {
lexer.nextToken(); lexer.nextToken();
BasicBlock target = expectBlock(); BasicBlock target = expectBlock();
JumpInstruction insn = new JumpInstruction(); JumpInstruction insn = new JumpInstruction();
insn.setLocation(currentLocation);
insn.setTarget(target); insn.setTarget(target);
block.getInstructions().add(insn); addInstruction(insn);
break; break;
} }
case "return": { case "return": {
lexer.nextToken(); lexer.nextToken();
ExitInstruction insn = new ExitInstruction(); ExitInstruction insn = new ExitInstruction();
insn.setLocation(currentLocation);
if (lexer.getToken() == ListingToken.VARIABLE) { if (lexer.getToken() == ListingToken.VARIABLE) {
insn.setValueToReturn(expectVariable()); insn.setValueToReturn(expectVariable());
} }
block.getInstructions().add(insn); addInstruction(insn);
break; break;
} }
case "throw": { case "throw": {
lexer.nextToken(); lexer.nextToken();
RaiseInstruction insn = new RaiseInstruction(); RaiseInstruction insn = new RaiseInstruction();
insn.setLocation(currentLocation);
insn.setException(expectVariable()); insn.setException(expectVariable());
block.getInstructions().add(insn); addInstruction(insn);
break; break;
} }
case "if": { case "if": {
lexer.nextToken(); lexer.nextToken();
parseIf(block); parseIf();
break; break;
} }
case "invoke": case "invoke":
case "invokeStatic": case "invokeStatic":
case "invokeVirtual": { case "invokeVirtual": {
parseInvoke(block, null); parseInvoke(null);
break; break;
} }
case "initClass": { case "initClass": {
@ -238,24 +236,21 @@ public class ListingParser {
expect(ListingToken.IDENTIFIER); expect(ListingToken.IDENTIFIER);
insn.setClassName((String) lexer.getTokenValue()); insn.setClassName((String) lexer.getTokenValue());
lexer.nextToken(); lexer.nextToken();
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
break; break;
} }
case "monitorEnter": { case "monitorEnter": {
lexer.nextToken(); lexer.nextToken();
MonitorEnterInstruction insn = new MonitorEnterInstruction(); MonitorEnterInstruction insn = new MonitorEnterInstruction();
insn.setObjectRef(expectVariable()); insn.setObjectRef(expectVariable());
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
break; break;
} }
case "monitorExit": { case "monitorExit": {
lexer.nextToken(); lexer.nextToken();
MonitorExitInstruction insn = new MonitorExitInstruction(); MonitorExitInstruction insn = new MonitorExitInstruction();
insn.setObjectRef(expectVariable()); insn.setObjectRef(expectVariable());
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
break; break;
} }
default: default:
@ -272,11 +267,11 @@ public class ListingParser {
switch (lexer.getToken()) { switch (lexer.getToken()) {
case ASSIGN: case ASSIGN:
lexer.nextToken(); lexer.nextToken();
parseAssignment(block, receiver); parseAssignment(receiver);
break; break;
case LEFT_SQUARE_BRACKET: case LEFT_SQUARE_BRACKET:
lexer.nextToken(); lexer.nextToken();
parseArrayAssignment(block, receiver); parseArrayAssignment(receiver);
break; break;
default: default:
unexpected(); unexpected();
@ -319,12 +314,12 @@ public class ListingParser {
+ "Expected 'unknown location' or '<string> : <number>'", lexer.getTokenStart()); + "Expected 'unknown location' or '<string> : <number>'", lexer.getTokenStart());
} }
private void parseAssignment(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseAssignment(Variable receiver) throws IOException, ListingParseException {
switch (lexer.getToken()) { switch (lexer.getToken()) {
case VARIABLE: { case VARIABLE: {
Variable variable = getVariable((String) lexer.getTokenValue()); Variable variable = getVariable((String) lexer.getTokenValue());
lexer.nextToken(); lexer.nextToken();
parseAssignmentVariable(block, receiver, variable); parseAssignmentVariable(receiver, variable);
break; break;
} }
case IDENTIFIER: { case IDENTIFIER: {
@ -332,33 +327,32 @@ public class ListingParser {
switch (keyword) { switch (keyword) {
case "phi": case "phi":
lexer.nextToken(); lexer.nextToken();
parsePhi(block, receiver); parsePhi(receiver);
break; break;
case "classOf": case "classOf":
lexer.nextToken(); lexer.nextToken();
parseClassLiteral(block, receiver); parseClassLiteral(receiver);
break; break;
case "invoke": case "invoke":
case "invokeVirtual": case "invokeVirtual":
case "invokeStatic": case "invokeStatic":
parseInvoke(block, receiver); parseInvoke(receiver);
break; break;
case "cast": case "cast":
parseCast(block, receiver); parseCast(receiver);
break; break;
case "new": case "new":
parseNew(block, receiver); parseNew(receiver);
break; break;
case "newArray": case "newArray":
parseNewArray(block, receiver); parseNewArray(receiver);
break; break;
case "nullCheck": { case "nullCheck": {
lexer.nextToken(); lexer.nextToken();
NullCheckInstruction insn = new NullCheckInstruction(); NullCheckInstruction insn = new NullCheckInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setValue(expectVariable()); insn.setValue(expectVariable());
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
break; break;
} }
case "data": { case "data": {
@ -369,8 +363,7 @@ public class ListingParser {
UnwrapArrayInstruction insn = new UnwrapArrayInstruction(type); UnwrapArrayInstruction insn = new UnwrapArrayInstruction(type);
insn.setArray(value); insn.setArray(value);
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
break; break;
} }
case "lengthOf": { case "lengthOf": {
@ -378,8 +371,7 @@ public class ListingParser {
ArrayLengthInstruction insn = new ArrayLengthInstruction(); ArrayLengthInstruction insn = new ArrayLengthInstruction();
insn.setArray(expectVariable()); insn.setArray(expectVariable());
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
break; break;
} }
case "clone": { case "clone": {
@ -387,8 +379,7 @@ public class ListingParser {
CloneArrayInstruction insn = new CloneArrayInstruction(); CloneArrayInstruction insn = new CloneArrayInstruction();
insn.setArray(expectVariable()); insn.setArray(expectVariable());
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
break; break;
} }
default: default:
@ -398,27 +389,27 @@ public class ListingParser {
break; break;
} }
case INTEGER: { case INTEGER: {
parseIntConstant(block, receiver); parseIntConstant(receiver);
break; break;
} }
case LONG: { case LONG: {
parseLongConstant(block, receiver); parseLongConstant(receiver);
break; break;
} }
case FLOAT: { case FLOAT: {
parseFloatConstant(block, receiver); parseFloatConstant(receiver);
break; break;
} }
case DOUBLE: { case DOUBLE: {
parseDoubleConstant(block, receiver); parseDoubleConstant(receiver);
break; break;
} }
case STRING: { case STRING: {
parseStringConstant(block, receiver); parseStringConstant(receiver);
break; break;
} }
case SUBTRACT: { case SUBTRACT: {
parseNegate(block, receiver); parseNegate(receiver);
break; break;
} }
default: default:
@ -426,55 +417,54 @@ public class ListingParser {
} }
} }
private void parseAssignmentVariable(BasicBlock block, Variable receiver, Variable variable) private void parseAssignmentVariable(Variable receiver, Variable variable)
throws IOException, ListingParseException { throws IOException, ListingParseException {
switch (lexer.getToken()) { switch (lexer.getToken()) {
case EOL: case EOL:
case EOF: { case EOF: {
AssignInstruction insn = new AssignInstruction(); AssignInstruction insn = new AssignInstruction();
insn.setLocation(currentLocation);
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setAssignee(variable); insn.setAssignee(variable);
block.getInstructions().add(insn); addInstruction(insn);
break; break;
} }
case ADD: case ADD:
parseBinary(block, receiver, variable, BinaryOperation.ADD); parseBinary(receiver, variable, BinaryOperation.ADD);
break; break;
case SUBTRACT: case SUBTRACT:
parseBinary(block, receiver, variable, BinaryOperation.SUBTRACT); parseBinary(receiver, variable, BinaryOperation.SUBTRACT);
break; break;
case MULTIPLY: case MULTIPLY:
parseBinary(block, receiver, variable, BinaryOperation.MULTIPLY); parseBinary(receiver, variable, BinaryOperation.MULTIPLY);
break; break;
case DIVIDE: case DIVIDE:
parseBinary(block, receiver, variable, BinaryOperation.DIVIDE); parseBinary(receiver, variable, BinaryOperation.DIVIDE);
break; break;
case REMAINDER: case REMAINDER:
parseBinary(block, receiver, variable, BinaryOperation.MODULO); parseBinary(receiver, variable, BinaryOperation.MODULO);
break; break;
case AND: case AND:
parseBinary(block, receiver, variable, BinaryOperation.AND); parseBinary(receiver, variable, BinaryOperation.AND);
break; break;
case OR: case OR:
parseBinary(block, receiver, variable, BinaryOperation.OR); parseBinary(receiver, variable, BinaryOperation.OR);
break; break;
case XOR: case XOR:
parseBinary(block, receiver, variable, BinaryOperation.XOR); parseBinary(receiver, variable, BinaryOperation.XOR);
break; break;
case SHIFT_LEFT: case SHIFT_LEFT:
parseBinary(block, receiver, variable, BinaryOperation.SHIFT_LEFT); parseBinary(receiver, variable, BinaryOperation.SHIFT_LEFT);
break; break;
case SHIFT_RIGHT: case SHIFT_RIGHT:
parseBinary(block, receiver, variable, BinaryOperation.SHIFT_RIGHT); parseBinary(receiver, variable, BinaryOperation.SHIFT_RIGHT);
break; break;
case SHIFT_RIGHT_UNSIGNED: case SHIFT_RIGHT_UNSIGNED:
parseBinary(block, receiver, variable, BinaryOperation.SHIFT_RIGHT_UNSIGNED); parseBinary(receiver, variable, BinaryOperation.SHIFT_RIGHT_UNSIGNED);
break; break;
case IDENTIFIER: case IDENTIFIER:
switch ((String) lexer.getTokenValue()) { switch ((String) lexer.getTokenValue()) {
case "compareTo": case "compareTo":
parseBinary(block, receiver, variable, BinaryOperation.COMPARE); parseBinary(receiver, variable, BinaryOperation.COMPARE);
break; break;
case "instanceOf": { case "instanceOf": {
lexer.nextToken(); lexer.nextToken();
@ -483,8 +473,7 @@ public class ListingParser {
insn.setValue(variable); insn.setValue(variable);
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setType(type); insn.setType(type);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
break; break;
} }
default: default:
@ -497,23 +486,22 @@ public class ListingParser {
} }
} }
private void parseBinary(BasicBlock block, Variable receiver, Variable first, BinaryOperation operation) private void parseBinary(Variable receiver, Variable first, BinaryOperation operation)
throws IOException, ListingParseException { throws IOException, ListingParseException {
lexer.nextToken(); lexer.nextToken();
Variable second = expectVariable(); Variable second = expectVariable();
expectKeyword("as"); expectKeyword("as");
NumericOperandType type = expectNumericType(); NumericOperandType type = expectNumericType();
BinaryInstruction instruction = new BinaryInstruction(operation, type); BinaryInstruction insn = new BinaryInstruction(operation, type);
instruction.setFirstOperand(first); insn.setFirstOperand(first);
instruction.setSecondOperand(second); insn.setSecondOperand(second);
instruction.setReceiver(receiver); insn.setReceiver(receiver);
instruction.setLocation(currentLocation);
block.getInstructions().add(instruction); addInstruction(insn);
} }
private void parseArrayAssignment(BasicBlock block, Variable array) throws IOException, ListingParseException { private void parseArrayAssignment(Variable array) throws IOException, ListingParseException {
Variable index = expectVariable(); Variable index = expectVariable();
expect(ListingToken.RIGHT_SQUARE_BRACKET); expect(ListingToken.RIGHT_SQUARE_BRACKET);
lexer.nextToken(); lexer.nextToken();
@ -524,14 +512,13 @@ public class ListingParser {
ArrayElementType type = expectArrayType(); ArrayElementType type = expectArrayType();
PutElementInstruction insn = new PutElementInstruction(type); PutElementInstruction insn = new PutElementInstruction(type);
insn.setLocation(currentLocation);
insn.setArray(array); insn.setArray(array);
insn.setIndex(index); insn.setIndex(index);
insn.setValue(value); insn.setValue(value);
block.getInstructions().add(insn); addInstruction(insn);
} }
private void parsePhi(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parsePhi(Variable receiver) throws IOException, ListingParseException {
int phiStart = lexer.getIndex(); int phiStart = lexer.getIndex();
Phi phi = new Phi(); Phi phi = new Phi();
@ -549,69 +536,62 @@ public class ListingParser {
lexer.nextToken(); lexer.nextToken();
} }
if (!block.getInstructions().isEmpty() || block.getExceptionVariable() != null) { if (!currentBlock.getInstructions().isEmpty() || currentBlock.getExceptionVariable() != null) {
throw new ListingParseException("Phi must be first instruction in block", phiStart); throw new ListingParseException("Phi must be first instruction in block", phiStart);
} }
block.getPhis().add(phi); currentBlock.getPhis().add(phi);
} }
private void parseClassLiteral(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseClassLiteral(Variable receiver) throws IOException, ListingParseException {
ValueType type = expectValueType(); ValueType type = expectValueType();
ClassConstantInstruction insn = new ClassConstantInstruction(); ClassConstantInstruction insn = new ClassConstantInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setConstant(type); insn.setConstant(type);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} }
private void parseIntConstant(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseIntConstant(Variable receiver) throws IOException, ListingParseException {
IntegerConstantInstruction insn = new IntegerConstantInstruction(); IntegerConstantInstruction insn = new IntegerConstantInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setConstant((Integer) lexer.getTokenValue()); insn.setConstant((Integer) lexer.getTokenValue());
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
lexer.nextToken(); lexer.nextToken();
addInstruction(insn);
} }
private void parseLongConstant(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseLongConstant(Variable receiver) throws IOException, ListingParseException {
LongConstantInstruction insn = new LongConstantInstruction(); LongConstantInstruction insn = new LongConstantInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setConstant((Long) lexer.getTokenValue()); insn.setConstant((Long) lexer.getTokenValue());
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
lexer.nextToken(); lexer.nextToken();
addInstruction(insn);
} }
private void parseFloatConstant(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseFloatConstant(Variable receiver) throws IOException, ListingParseException {
FloatConstantInstruction insn = new FloatConstantInstruction(); FloatConstantInstruction insn = new FloatConstantInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setConstant((Float) lexer.getTokenValue()); insn.setConstant((Float) lexer.getTokenValue());
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
lexer.nextToken(); lexer.nextToken();
addInstruction(insn);
} }
private void parseDoubleConstant(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseDoubleConstant(Variable receiver) throws IOException, ListingParseException {
DoubleConstantInstruction insn = new DoubleConstantInstruction(); DoubleConstantInstruction insn = new DoubleConstantInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setConstant((Double) lexer.getTokenValue()); insn.setConstant((Double) lexer.getTokenValue());
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
lexer.nextToken(); lexer.nextToken();
addInstruction(insn);
} }
private void parseStringConstant(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseStringConstant(Variable receiver) throws IOException, ListingParseException {
StringConstantInstruction insn = new StringConstantInstruction(); StringConstantInstruction insn = new StringConstantInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setConstant((String) lexer.getTokenValue()); insn.setConstant((String) lexer.getTokenValue());
insn.setLocation(currentLocation);
block.getInstructions().add(insn);
lexer.nextToken(); lexer.nextToken();
addInstruction(insn);
} }
private void parseNegate(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseNegate(Variable receiver) throws IOException, ListingParseException {
lexer.nextToken(); lexer.nextToken();
Variable value = expectVariable(); Variable value = expectVariable();
expectKeyword("as"); expectKeyword("as");
@ -619,11 +599,10 @@ public class ListingParser {
NegateInstruction insn = new NegateInstruction(type); NegateInstruction insn = new NegateInstruction(type);
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setOperand(value); insn.setOperand(value);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} }
private void parseInvoke(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseInvoke(Variable receiver) throws IOException, ListingParseException {
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
@ -642,7 +621,6 @@ public class ListingParser {
} }
lexer.nextToken(); lexer.nextToken();
expect(ListingToken.IDENTIFIER); expect(ListingToken.IDENTIFIER);
MethodReference method = MethodReference.parseIfPossible((String) lexer.getTokenValue()); MethodReference method = MethodReference.parseIfPossible((String) lexer.getTokenValue());
if (method == null) { if (method == null) {
@ -671,41 +649,37 @@ public class ListingParser {
insn.getArguments().addAll(arguments); insn.getArguments().addAll(arguments);
} }
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} }
private void parseCast(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseCast(Variable receiver) throws IOException, ListingParseException {
lexer.nextToken(); lexer.nextToken();
Variable value = expectVariable(); Variable value = expectVariable();
expect(ListingToken.IDENTIFIER); expect(ListingToken.IDENTIFIER);
switch ((String) lexer.getTokenValue()) { switch ((String) lexer.getTokenValue()) {
case "from": case "from":
parseNumericCast(block, receiver, value); parseNumericCast(receiver, value);
break; break;
case "to": case "to":
parseObjectCast(block, receiver, value); parseObjectCast(receiver, value);
break; break;
default: default:
unexpected(); unexpected();
} }
} }
private void parseNumericCast(BasicBlock block, Variable receiver, Variable value) private void parseNumericCast(Variable receiver, Variable value) throws IOException, ListingParseException {
throws IOException, ListingParseException {
lexer.nextToken(); lexer.nextToken();
NumericTypeOrIntegerSubtype source = expectTypeOrIntegerSubtype(); NumericTypeOrIntegerSubtype source = expectTypeOrIntegerSubtype();
if (source.subtype != null) { if (source.subtype != null) {
CastIntegerInstruction insn = new CastIntegerInstruction(source.subtype, CastIntegerInstruction insn = new CastIntegerInstruction(source.subtype, CastIntegerDirection.TO_INTEGER);
CastIntegerDirection.TO_INTEGER);
expectKeyword("to"); expectKeyword("to");
expectKeyword("int"); expectKeyword("int");
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setValue(value); insn.setValue(value);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} else { } else {
expectKeyword("to"); expectKeyword("to");
expect(ListingToken.IDENTIFIER); expect(ListingToken.IDENTIFIER);
@ -719,14 +693,12 @@ public class ListingParser {
CastIntegerDirection.FROM_INTEGER); CastIntegerDirection.FROM_INTEGER);
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setValue(value); insn.setValue(value);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} else { } else {
CastNumberInstruction insn = new CastNumberInstruction(source.type, target.type); CastNumberInstruction insn = new CastNumberInstruction(source.type, target.type);
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setValue(value); insn.setValue(value);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} }
} }
} }
@ -769,14 +741,13 @@ public class ListingParser {
NumericOperandType type; NumericOperandType type;
IntegerSubtype subtype; IntegerSubtype subtype;
public NumericTypeOrIntegerSubtype(NumericOperandType type, IntegerSubtype subtype) { NumericTypeOrIntegerSubtype(NumericOperandType type, IntegerSubtype subtype) {
this.type = type; this.type = type;
this.subtype = subtype; this.subtype = subtype;
} }
} }
private void parseObjectCast(BasicBlock block, Variable receiver, Variable value) private void parseObjectCast(Variable receiver, Variable value) throws IOException, ListingParseException {
throws IOException, ListingParseException {
lexer.nextToken(); lexer.nextToken();
ValueType type = expectValueType(); ValueType type = expectValueType();
@ -784,11 +755,10 @@ public class ListingParser {
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setValue(value); insn.setValue(value);
insn.setTargetType(type); insn.setTargetType(type);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} }
private void parseNew(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseNew(Variable receiver) throws IOException, ListingParseException {
lexer.nextToken(); lexer.nextToken();
expect(ListingToken.IDENTIFIER); expect(ListingToken.IDENTIFIER);
String type = (String) lexer.getTokenValue(); String type = (String) lexer.getTokenValue();
@ -797,11 +767,10 @@ public class ListingParser {
ConstructInstruction insn = new ConstructInstruction(); ConstructInstruction insn = new ConstructInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setType(type); insn.setType(type);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} }
private void parseNewArray(BasicBlock block, Variable receiver) throws IOException, ListingParseException { private void parseNewArray(Variable receiver) throws IOException, ListingParseException {
lexer.nextToken(); lexer.nextToken();
ValueType type = expectValueType(); ValueType type = expectValueType();
List<Variable> dimensions = new ArrayList<>(); List<Variable> dimensions = new ArrayList<>();
@ -818,19 +787,17 @@ public class ListingParser {
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setItemType(type); insn.setItemType(type);
insn.setSize(dimensions.get(0)); insn.setSize(dimensions.get(0));
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} else { } else {
ConstructMultiArrayInstruction insn = new ConstructMultiArrayInstruction(); ConstructMultiArrayInstruction insn = new ConstructMultiArrayInstruction();
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setItemType(type); insn.setItemType(type);
insn.getDimensions().addAll(dimensions); insn.getDimensions().addAll(dimensions);
insn.setLocation(currentLocation); addInstruction(insn);
block.getInstructions().add(insn);
} }
} }
private void parseIf(BasicBlock block) throws IOException, ListingParseException { private void parseIf() throws IOException, ListingParseException {
Variable first = expectVariable(); Variable first = expectVariable();
BinaryBranchingCondition binaryCondition = null; BinaryBranchingCondition binaryCondition = null;
@ -900,19 +867,17 @@ public class ListingParser {
throw new ListingParseException("Unsupported binary operation: " + operationToken, operationIndex); throw new ListingParseException("Unsupported binary operation: " + operationToken, operationIndex);
} }
BinaryBranchingInstruction insn = new BinaryBranchingInstruction(binaryCondition); BinaryBranchingInstruction insn = new BinaryBranchingInstruction(binaryCondition);
insn.setLocation(currentLocation);
insn.setFirstOperand(first); insn.setFirstOperand(first);
insn.setSecondOperand(second); insn.setSecondOperand(second);
insn.setConsequent(consequent); insn.setConsequent(consequent);
insn.setAlternative(alternative); insn.setAlternative(alternative);
block.getInstructions().add(insn); addInstruction(insn);
} else { } else {
BranchingInstruction insn = new BranchingInstruction(condition); BranchingInstruction insn = new BranchingInstruction(condition);
insn.setLocation(currentLocation);
insn.setOperand(first); insn.setOperand(first);
insn.setConsequent(consequent); insn.setConsequent(consequent);
insn.setAlternative(alternative); insn.setAlternative(alternative);
block.getInstructions().add(insn); addInstruction(insn);
} }
} }
@ -1013,7 +978,7 @@ public class ListingParser {
return blockMap.computeIfAbsent(name, k -> { return blockMap.computeIfAbsent(name, k -> {
BasicBlock block = program.createBasicBlock(); BasicBlock block = program.createBasicBlock();
block.setLabel(k); block.setLabel(k);
blockFirstOccurence.put(k, lexer.getTokenStart()); blockFirstOccurrence.put(k, lexer.getTokenStart());
return block; return block;
}); });
} }
@ -1048,4 +1013,9 @@ public class ListingParser {
private void unexpected() throws IOException, ListingParseException { private void unexpected() throws IOException, ListingParseException {
throw new ListingParseException("Unexpected token " + lexer.getToken(), lexer.getTokenStart()); throw new ListingParseException("Unexpected token " + lexer.getToken(), lexer.getTokenStart());
} }
private void addInstruction(Instruction instruction) {
instruction.setLocation(currentLocation);
currentBlock.getInstructions().add(instruction);
}
} }