Allowing tree rewrite to remove REM statements and renumber application.

Closes #1.
This commit is contained in:
Rob Greene 2018-05-14 22:17:21 -05:00
parent bbc6b29bda
commit 047591ec58
2 changed files with 88 additions and 3 deletions

View File

@ -3,11 +3,14 @@ package com.webcodepro.applecommander.util.applesoft;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Stack;
import java.util.function.Function;
import com.webcodepro.applecommander.util.applesoft.Token.Type;
/**
* This class presents all of the common Visitor implementations via builder patterns.
* The number is currently small enough that all the builders and visitors are defined
@ -49,6 +52,11 @@ public class Visitors {
public static ByteVisitor byteVisitor(int address) {
return new ByteVisitor(address);
}
/** Rewrite the Program tree with the line number reassignments given. */
public static ReassignmentVisitor reassignVisitor(Map<Integer,Integer> reassignments) {
return new ReassignmentVisitor(reassignments);
}
private static class PrettyPrintVisitor implements Visitor {
private PrintStream printStream;
@ -268,4 +276,64 @@ public class Visitors {
}
}
}
/** This is a mildly rewritable Visitor. */
private static class ReassignmentVisitor implements Visitor {
private Map<Integer,Integer> reassignments;
private ReassignmentVisitor(Map<Integer,Integer> reassignments) {
this.reassignments = reassignments;
}
@Override
public Program visit(Program program) {
Program newProgram = new Program();
program.lines.forEach(l -> {
Line line = l.accept(this);
newProgram.lines.add(line);
});
return newProgram;
}
@Override
public Line visit(Line line) {
Line newLine = new Line(line.lineNumber);
line.statements.forEach(s -> {
Statement statement = s.accept(this);
newLine.statements.add(statement);
});
return newLine;
}
/**
* We saw a trigger, reassign any numbers that follow.
*
* Trigger cases:
* - GOSUB n
* - GOTO n
* - IF ... THEN n
* - LIST n [ ,m ]
* - ON x GOTO n, m, ...
* - ON x GOSUB n, m, ...
* - ONERR GOTO n
* - RUN n
*/
@Override
public Statement visit(Statement statement) {
boolean next = false;
Statement newStatement = new Statement();
for (Token t : statement.tokens) {
Token newToken = t;
if (next) {
if (t.type == Type.NUMBER && reassignments.containsKey(t.number.intValue())) {
newToken = Token.number(t.line, reassignments.get(t.number.intValue()).doubleValue());
}
} else {
next = t.keyword == ApplesoftKeyword.GOSUB || t.keyword == ApplesoftKeyword.GOTO
|| t.keyword == ApplesoftKeyword.THEN || t.keyword == ApplesoftKeyword.RUN
|| t.keyword == ApplesoftKeyword.LIST;
}
newStatement.tokens.add(newToken);
}
return newStatement;
}
}
}

View File

@ -1,11 +1,15 @@
package io.github.applecommander.bastokenizer;
import java.util.HashMap;
import java.util.Map;
import com.webcodepro.applecommander.util.applesoft.Line;
import com.webcodepro.applecommander.util.applesoft.Program;
import com.webcodepro.applecommander.util.applesoft.Statement;
import com.webcodepro.applecommander.util.applesoft.Token;
import com.webcodepro.applecommander.util.applesoft.Token.Type;
import com.webcodepro.applecommander.util.applesoft.Visitor;
import com.webcodepro.applecommander.util.applesoft.Visitors;
import picocli.CommandLine.ITypeConverter;
@ -51,12 +55,25 @@ public enum Optimization {
private static class BaseVisitor implements Visitor {
@Override
public Program visit(Program program) {
Program newProgram = new Program();
final Program newProgram = new Program();
Map<Integer,Integer> reassignments = new HashMap<>();
program.lines.forEach(l -> {
Line line = l.accept(this);
if (line != null && !line.statements.isEmpty()) newProgram.lines.add(line);
boolean lineKept = line != null && !line.statements.isEmpty();
if (lineKept) {
newProgram.lines.add(line);
reassignments.replaceAll((k,v) -> v == null ? l.lineNumber : v);
} else {
// Make a place-holder for the reassignment; we'll patch it in once we find a line that sticks around.
reassignments.put(l.lineNumber, null);
}
});
return newProgram;
if (!reassignments.isEmpty()) {
// Now, renumber based on our findings!
return newProgram.accept(Visitors.reassignVisitor(reassignments));
} else {
return newProgram;
}
}
@Override
public Line visit(Line line) {