mirror of
https://github.com/AppleCommander/bastools.git
synced 2025-01-15 04:29:56 +00:00
Adding merge-lines. Still need to work out max line length. #2.
This commit is contained in:
parent
e208fa453c
commit
e5193a024f
@ -5,9 +5,11 @@ import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.Stack;
|
||||
import java.util.TreeSet;
|
||||
@ -62,6 +64,11 @@ public class Visitors {
|
||||
return new ReassignmentVisitor(reassignments);
|
||||
}
|
||||
|
||||
/** Collect all line numbers that are a target of GOTO, GOSUB, etc. */
|
||||
public static LineNumberTargetCollector lineNumberTargetCollector() {
|
||||
return new LineNumberTargetCollector();
|
||||
}
|
||||
|
||||
public static Visitor variableReportVisitor() {
|
||||
return new VariableReportVisitor();
|
||||
}
|
||||
@ -345,6 +352,44 @@ public class Visitors {
|
||||
}
|
||||
}
|
||||
|
||||
public static class LineNumberTargetCollector implements Visitor {
|
||||
private Set<Integer> targets = new HashSet<>();
|
||||
|
||||
public Set<Integer> getTargets() {
|
||||
return targets;
|
||||
}
|
||||
|
||||
/**
|
||||
* We saw a trigger, collect 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;
|
||||
for (Token t : statement.tokens) {
|
||||
if (next) {
|
||||
if (t.type == Type.NUMBER) {
|
||||
targets.add(t.number.intValue());
|
||||
}
|
||||
} else {
|
||||
next = t.keyword == ApplesoftKeyword.GOSUB || t.keyword == ApplesoftKeyword.GOTO
|
||||
|| t.keyword == ApplesoftKeyword.THEN || t.keyword == ApplesoftKeyword.RUN
|
||||
|| t.keyword == ApplesoftKeyword.LIST;
|
||||
}
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
}
|
||||
|
||||
private static class VariableReportVisitor implements Visitor {
|
||||
private Map<String,SortedSet<Integer>> refs = new HashMap<>();
|
||||
private int currentLineNumber = -1;
|
||||
|
@ -62,11 +62,12 @@ public class Main implements Callable<Void> {
|
||||
"Enable specific optimizations.",
|
||||
"* @|green remove-empty-statements|@ - Strip out all '::'-like statements.",
|
||||
"* @|green remove-rem-statements|@ - Remove all REM statements.",
|
||||
"* @|green merge-lines|@ - Merge lines.",
|
||||
"* @|green renumber|@ - Renumber program."
|
||||
})
|
||||
private List<Optimization> optimizations = new ArrayList<>();
|
||||
|
||||
@Option(names = "-O", description = "Apply all optimizations.")
|
||||
@Option(names = { "-O", "--optimize" }, description = "Apply all optimizations.")
|
||||
private boolean allOptimizations;
|
||||
|
||||
@Parameters(index = "0", description = "AppleSoft BASIC program to process.")
|
||||
|
@ -2,7 +2,9 @@ package io.github.applecommander.bastokenizer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.webcodepro.applecommander.util.applesoft.ApplesoftKeyword;
|
||||
import com.webcodepro.applecommander.util.applesoft.Line;
|
||||
import com.webcodepro.applecommander.util.applesoft.Program;
|
||||
import com.webcodepro.applecommander.util.applesoft.Statement;
|
||||
@ -10,6 +12,7 @@ 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 com.webcodepro.applecommander.util.applesoft.Visitors.LineNumberTargetCollector;
|
||||
|
||||
import picocli.CommandLine.ITypeConverter;
|
||||
|
||||
@ -26,6 +29,47 @@ public enum Optimization {
|
||||
return statement.tokens.get(0).type == Type.COMMENT ? null : statement;
|
||||
}
|
||||
}),
|
||||
MERGE_LINES(new BaseVisitor() {
|
||||
private Set<Integer> targets;
|
||||
private Line mergeLine;
|
||||
@Override
|
||||
public Program visit(Program program) {
|
||||
LineNumberTargetCollector c = Visitors.lineNumberTargetCollector();
|
||||
program.accept(c);
|
||||
targets = c.getTargets();
|
||||
return super.visit(program);
|
||||
}
|
||||
@Override
|
||||
public Line visit(Line line) {
|
||||
if (mergeLine == null || targets.contains(line.lineNumber)) {
|
||||
// merge may null out mergeLine if the this line has a "terminal".
|
||||
// Preserve it with newLine so it get added to the program.
|
||||
Line newLine = new Line(line.lineNumber);
|
||||
mergeLine = newLine;
|
||||
merge(line);
|
||||
return newLine;
|
||||
}
|
||||
merge(line);
|
||||
// Do not preserve old line!
|
||||
return null;
|
||||
}
|
||||
private void merge(Line line) {
|
||||
mergeLine.statements.addAll(line.statements);
|
||||
// Terminals are: IF, REM, GOTO, END, ON .. GOTO (GOTO is trigger), RESUME, RETURN, STOP
|
||||
boolean terminal = false;
|
||||
for (Statement s : line.statements) {
|
||||
for (Token t : s.tokens) {
|
||||
terminal |= t.keyword == ApplesoftKeyword.IF || t.type == Type.COMMENT /* REM */
|
||||
|| t.keyword == ApplesoftKeyword.GOTO || t.keyword == ApplesoftKeyword.END
|
||||
|| t.keyword == ApplesoftKeyword.RESUME || t.keyword == ApplesoftKeyword.RETURN
|
||||
|| t.keyword == ApplesoftKeyword.STOP;
|
||||
}
|
||||
}
|
||||
if (terminal) {
|
||||
mergeLine = null;
|
||||
}
|
||||
}
|
||||
}),
|
||||
RENUMBER(new BaseVisitor() {
|
||||
protected int lineNumber = 0;
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user