mirror of
https://github.com/AppleCommander/AppleCommander.git
synced 2025-01-10 11:29:20 +00:00
Early refactoring of compiler.
This commit is contained in:
parent
370126207a
commit
79e792984e
@ -24,13 +24,16 @@ import com.webcodepro.applecommander.util.ApplesoftToken;
|
|||||||
import com.webcodepro.applecommander.util.ApplesoftTokenizer;
|
import com.webcodepro.applecommander.util.ApplesoftTokenizer;
|
||||||
import com.webcodepro.applecommander.util.ApplesoftTokens;
|
import com.webcodepro.applecommander.util.ApplesoftTokens;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile the given file as an Applesoft file.
|
* Compile the given file as an Applesoft file.
|
||||||
@ -40,13 +43,30 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class ApplesoftCompiler implements ApplesoftTokens {
|
public class ApplesoftCompiler implements ApplesoftTokens {
|
||||||
private ApplesoftTokenizer tokenizer;
|
private ApplesoftTokenizer tokenizer;
|
||||||
|
private ApplesoftToken tokenAlreadySeen;
|
||||||
|
private StringBuffer sourceAssembly = new StringBuffer();
|
||||||
|
private StringBuffer sourceLine = new StringBuffer();
|
||||||
|
|
||||||
private List stringVariables = new ArrayList();
|
/**
|
||||||
private List integerVariables = new ArrayList();
|
* Contains a list of all known Apple ROM addresses that may be used
|
||||||
private List floatVariables = new ArrayList();
|
* by the compiled program. This map is keyed by the name of the
|
||||||
private Map stringConstants = new HashMap();
|
* address and the value is the address.
|
||||||
private Map integerConstants = new HashMap();
|
*/
|
||||||
private Map floatConstants = new HashMap();
|
private Map knownAddresses = new HashMap();
|
||||||
|
/**
|
||||||
|
* Lists the names of all addresses used by the compiled program.
|
||||||
|
* To identify the value, use the knownAddresses map.
|
||||||
|
*/
|
||||||
|
private List usedAddresses = new ArrayList();
|
||||||
|
/**
|
||||||
|
* Contains a list of all variables declared or used by the
|
||||||
|
* program.
|
||||||
|
*/
|
||||||
|
private List variables = new ArrayList();
|
||||||
|
/**
|
||||||
|
* Dynamically created map of commands to Methods.
|
||||||
|
*/
|
||||||
|
private Map commandMethods = new HashMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for ApplesoftCompiler.
|
* Constructor for ApplesoftCompiler.
|
||||||
@ -54,296 +74,406 @@ public class ApplesoftCompiler implements ApplesoftTokens {
|
|||||||
public ApplesoftCompiler(FileEntry fileEntry) {
|
public ApplesoftCompiler(FileEntry fileEntry) {
|
||||||
super();
|
super();
|
||||||
tokenizer = new ApplesoftTokenizer(fileEntry);
|
tokenizer = new ApplesoftTokenizer(fileEntry);
|
||||||
|
initializeKnownAddresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load known memory addresses from AppleMemoryAddresses.properties.
|
||||||
|
*/
|
||||||
|
protected void initializeKnownAddresses() {
|
||||||
|
InputStream inputStream =
|
||||||
|
getClass().getResourceAsStream("AppleMemoryAddresses.properties");
|
||||||
|
Properties properties = new Properties();
|
||||||
|
try {
|
||||||
|
properties.load(inputStream);
|
||||||
|
Enumeration keys = properties.keys();
|
||||||
|
while (keys.hasMoreElements()) {
|
||||||
|
String key = (String) keys.nextElement();
|
||||||
|
knownAddresses.put(key, properties.getProperty(key));
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Answers true if there are more tokens to process.
|
||||||
|
*/
|
||||||
|
protected boolean hasMoreTokens() {
|
||||||
|
return peekToken() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next token.
|
||||||
|
*/
|
||||||
|
protected ApplesoftToken nextToken() {
|
||||||
|
ApplesoftToken token = tokenAlreadySeen;
|
||||||
|
if (tokenAlreadySeen != null) {
|
||||||
|
tokenAlreadySeen = null;
|
||||||
|
} else {
|
||||||
|
token = tokenizer.getNextToken();
|
||||||
|
}
|
||||||
|
if (token == null) {
|
||||||
|
// No more tokens
|
||||||
|
} else if (token.isLineNumber()) {
|
||||||
|
sourceLine.append("* ");
|
||||||
|
sourceLine.append(token.getLineNumber());
|
||||||
|
sourceLine.append(" ");
|
||||||
|
} else if (token.isToken()) {
|
||||||
|
sourceLine.append(token.getTokenString());
|
||||||
|
} else if (token.isString()) {
|
||||||
|
sourceLine.append(token.getStringValue());
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a peek at the next token.
|
||||||
|
*/
|
||||||
|
protected ApplesoftToken peekToken() {
|
||||||
|
if (tokenAlreadySeen == null) {
|
||||||
|
tokenAlreadySeen = tokenizer.getNextToken();
|
||||||
|
}
|
||||||
|
return tokenAlreadySeen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile the given FileEntry and return the assembly code.
|
* Compile the given FileEntry and return the assembly code.
|
||||||
*/
|
*/
|
||||||
public byte[] compile() {
|
public byte[] compile() throws CompileException {
|
||||||
ByteArrayOutputStream assemblyStream = new ByteArrayOutputStream();
|
StringBuffer programCode = new StringBuffer();
|
||||||
PrintWriter assemblyWriter = new PrintWriter(assemblyStream);
|
while (hasMoreTokens()) {
|
||||||
StringBuffer sourceLine = new StringBuffer();
|
|
||||||
StringBuffer sourceAssembly = new StringBuffer();
|
|
||||||
while (tokenizer.hasMoreTokens()) {
|
|
||||||
ApplesoftToken token = tokenizer.getNextToken();
|
|
||||||
if (token == null) {
|
|
||||||
break;
|
|
||||||
} else if (token.isLineNumber()) {
|
|
||||||
if (sourceLine.length() > 0) {
|
|
||||||
assemblyWriter.println(sourceLine.toString());
|
|
||||||
assemblyWriter.println(sourceAssembly.toString());
|
|
||||||
sourceLine.setLength(0);
|
|
||||||
sourceAssembly.setLength(0);
|
|
||||||
}
|
|
||||||
sourceAssembly.append("LINE");
|
|
||||||
sourceAssembly.append(token.getLineNumber());
|
|
||||||
sourceAssembly.append(":\n");
|
|
||||||
sourceLine.append("* ");
|
|
||||||
sourceLine.append(token.getLineNumber());
|
|
||||||
sourceLine.append(" ");
|
|
||||||
} else if (token.isToken()) {
|
|
||||||
sourceLine.append(token.getTokenString());
|
|
||||||
processToken(sourceAssembly, sourceLine, token, tokenizer);
|
|
||||||
} else if (token.isString()) {
|
|
||||||
sourceLine.append(token.getStringValue());
|
|
||||||
// FIXME - process string/expressions!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sourceLine.length() > 0) {
|
|
||||||
assemblyWriter.println(sourceLine.toString());
|
|
||||||
assemblyWriter.println(sourceAssembly.toString());
|
|
||||||
sourceLine.setLength(0);
|
sourceLine.setLength(0);
|
||||||
sourceAssembly.setLength(0);
|
sourceAssembly.setLength(0);
|
||||||
}
|
ApplesoftToken token = nextToken();
|
||||||
|
if (!token.isLineNumber()) {
|
||||||
if (!stringConstants.isEmpty()) {
|
throw new CompileException("Expecting a line number.");
|
||||||
assemblyWriter.println("\n* String constant values:");
|
|
||||||
Iterator iterator = stringConstants.keySet().iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
String name = (String) iterator.next();
|
|
||||||
assemblyWriter.print(name);
|
|
||||||
assemblyWriter.print(":\tASC ");
|
|
||||||
assemblyWriter.println(stringConstants.get(name));
|
|
||||||
assemblyWriter.println("\tHEX 00");
|
|
||||||
}
|
}
|
||||||
|
sourceAssembly.append("LINE");
|
||||||
|
sourceAssembly.append(token.getLineNumber());
|
||||||
|
sourceAssembly.append(":\n");
|
||||||
|
do {
|
||||||
|
evaluateCommand();
|
||||||
|
token = peekToken();
|
||||||
|
if (token != null && token.isCommandSeparator()) {
|
||||||
|
token = nextToken();
|
||||||
|
}
|
||||||
|
} while (token != null && token.isCommandSeparator());
|
||||||
|
programCode.append(sourceLine);
|
||||||
|
programCode.append("\n");
|
||||||
|
programCode.append(sourceAssembly);
|
||||||
|
programCode.append("\n");
|
||||||
}
|
}
|
||||||
if (!integerConstants.isEmpty()) {
|
programCode.insert(0, buildUsedAddresses());
|
||||||
assemblyWriter.println("\n* Integer constant values:");
|
return programCode.toString().getBytes();
|
||||||
Iterator iterator = integerConstants.keySet().iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
String name = (String) iterator.next();
|
|
||||||
assemblyWriter.print(name);
|
|
||||||
assemblyWriter.print(":\tDW ");
|
|
||||||
assemblyWriter.println(integerConstants.get(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!integerVariables.isEmpty()) {
|
|
||||||
assemblyWriter.println("\n* Integer variables:");
|
|
||||||
for (int i = 0; i<integerVariables.size(); i++) {
|
|
||||||
assemblyWriter.print(integerVariables.get(i));
|
|
||||||
assemblyWriter.println(": DW 0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!floatVariables.isEmpty()) {
|
|
||||||
assemblyWriter.println("\n* Float variables:");
|
|
||||||
for (int i = 0; i<floatVariables.size(); i++) {
|
|
||||||
assemblyWriter.print(floatVariables.get(i));
|
|
||||||
assemblyWriter.println(": DS 5");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assemblyWriter.close();
|
|
||||||
return assemblyStream.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected StringBuffer buildUsedAddresses() {
|
||||||
* Process and individual token.
|
StringBuffer buf = new StringBuffer();
|
||||||
*/
|
if (usedAddresses.size() > 0) {
|
||||||
protected void processToken(StringBuffer sourceAssembly,
|
buf.append("* Addresses:\n");
|
||||||
StringBuffer sourceLine, ApplesoftToken token, ApplesoftTokenizer tokenizer) {
|
for (int i=0; i<usedAddresses.size(); i++) {
|
||||||
String expr = null;
|
String label = (String) usedAddresses.get(i);
|
||||||
switch (token.getTokenValue()) {
|
buf.append(label);
|
||||||
case HOME: sourceAssembly.append("\tJSR $FC58\n");
|
buf.append(" = ");
|
||||||
break;
|
buf.append((String) knownAddresses.get(label));
|
||||||
case STOP:
|
buf.append("\n");
|
||||||
case RETURN:
|
}
|
||||||
case END: sourceAssembly.append("\tRTS\n");
|
buf.append("\n");
|
||||||
break;
|
|
||||||
case TEXT: sourceAssembly.append("\tJSR $FB2F\n");
|
|
||||||
break;
|
|
||||||
case HGR: sourceAssembly.append("\tJSR $F3E2\n");
|
|
||||||
break;
|
|
||||||
case HGR2: sourceAssembly.append("\tJSR $F3D8\n");
|
|
||||||
break;
|
|
||||||
case GR: sourceAssembly.append("\tJSR $FB40\n");
|
|
||||||
break;
|
|
||||||
case INVERSE:
|
|
||||||
sourceAssembly.append("\tLDA #$3F\n");
|
|
||||||
sourceAssembly.append("\tSTA $32\n");
|
|
||||||
break;
|
|
||||||
case NORMAL:
|
|
||||||
sourceAssembly.append("\tLDA #$FF\n");
|
|
||||||
sourceAssembly.append("\tSTA $32\n");
|
|
||||||
break;
|
|
||||||
case FLASH:
|
|
||||||
sourceAssembly.append("\tLDA #$7F\n");
|
|
||||||
sourceAssembly.append("\tSTA $32\n");
|
|
||||||
break;
|
|
||||||
case VTAB: expr = evaluateExpression(sourceAssembly, sourceLine);
|
|
||||||
sourceAssembly.append("\tLDA ");
|
|
||||||
sourceAssembly.append(expr);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tSTA $25\n");
|
|
||||||
sourceAssembly.append("\tJSR $FC66\n");
|
|
||||||
break;
|
|
||||||
case HTAB: expr = evaluateExpression(sourceAssembly, sourceLine);
|
|
||||||
sourceAssembly.append("\tLDA ");
|
|
||||||
sourceAssembly.append(expr);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tSTA $24\n");
|
|
||||||
break;
|
|
||||||
case HCOLOR:
|
|
||||||
expr = evaluateExpression(sourceAssembly, sourceLine);
|
|
||||||
sourceAssembly.append("\tLDX ");
|
|
||||||
sourceAssembly.append(expr);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tJSR $F6F0\n");
|
|
||||||
break;
|
|
||||||
case PRINT:
|
|
||||||
expr = evaluateExpression(sourceAssembly, sourceLine);
|
|
||||||
if (isIntegerVariable(expr)) {
|
|
||||||
throw new IllegalArgumentException("Integer not supported in print: " + expr);
|
|
||||||
} else if (isFloatVariable(expr)) {
|
|
||||||
sourceAssembly.append("\tLDY #>");
|
|
||||||
sourceAssembly.append(expr);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tLDA #<");
|
|
||||||
sourceAssembly.append(expr);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tJSR $EAF9\t; MOVFM\n");
|
|
||||||
sourceAssembly.append("\tJSR $ED2E\t; PRNTFAC\n");
|
|
||||||
} else if (isStringVariable(expr)) {
|
|
||||||
sourceAssembly.append("\tLDY #0\n");
|
|
||||||
sourceAssembly.append(":loop\tLDA ");
|
|
||||||
sourceAssembly.append(expr);
|
|
||||||
sourceAssembly.append(",Y\n");
|
|
||||||
sourceAssembly.append("\tBEQ :end\n");
|
|
||||||
sourceAssembly.append("\tJSR COUT\n");
|
|
||||||
sourceAssembly.append("\tINY\n");
|
|
||||||
sourceAssembly.append("\tBNE :loop\n");
|
|
||||||
sourceAssembly.append(":end\n");
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Invalid expr in print: " + expr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FOR:
|
|
||||||
String loopVariable = evaluateExpression(sourceAssembly, sourceLine);
|
|
||||||
if (!isFloatVariable(loopVariable)) {
|
|
||||||
throw new IllegalArgumentException("FOR loop argument must be a float");
|
|
||||||
}
|
|
||||||
token = tokenizer.getNextToken();
|
|
||||||
if (token.getTokenValue() != EQUALS) {
|
|
||||||
throw new IllegalArgumentException("FOR requires =");
|
|
||||||
}
|
|
||||||
sourceLine.append(token.getTokenString());
|
|
||||||
String startValue = evaluateExpression(sourceAssembly, sourceLine);
|
|
||||||
token = tokenizer.getNextToken();
|
|
||||||
if (token.getTokenValue() != TO) {
|
|
||||||
throw new IllegalArgumentException("FOR requires TO");
|
|
||||||
}
|
|
||||||
sourceLine.append(token.getTokenString());
|
|
||||||
String endValue = evaluateExpression(sourceAssembly, sourceLine);
|
|
||||||
if (isFloatVariable(loopVariable)) {
|
|
||||||
// FIXME: Assumes start/end are integer
|
|
||||||
sourceAssembly.append("\tLDY ");
|
|
||||||
sourceAssembly.append(startValue);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tLDA ");
|
|
||||||
sourceAssembly.append(startValue);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tJSR $E2F2 ; GIVAYF\n");
|
|
||||||
sourceAssembly.append("\tLDY #>");
|
|
||||||
sourceAssembly.append(loopVariable);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tLDX #<");
|
|
||||||
sourceAssembly.append(loopVariable);
|
|
||||||
sourceAssembly.append("\n");
|
|
||||||
sourceAssembly.append("\tJSR $EB2B ; MOVMF\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected void evaluateCommand() {
|
||||||
* Evaluate an expression and return the variable name that
|
ApplesoftToken token = nextToken();
|
||||||
* contains the value.
|
while (token != null && token.isCommandSeparator()) {
|
||||||
*/
|
token = nextToken();
|
||||||
protected String evaluateExpression(StringBuffer sourceAssembly, StringBuffer sourceLine) {
|
}
|
||||||
// FIXME: no type checking available
|
if (token == null || !token.isToken()) {
|
||||||
ApplesoftToken token = tokenizer.getNextToken();
|
return; // end of line (no command on line...)
|
||||||
if (token.isString()) {
|
}
|
||||||
String value = token.getStringValue();
|
Method method = getMethod(token);
|
||||||
sourceLine.append(value);
|
if (method != null) {
|
||||||
if (isIntegerNumber(value)) {
|
try {
|
||||||
return addIntegerConstant(value);
|
method.invoke(this, new Object[0]);
|
||||||
} else if (value.startsWith("\"")) {
|
} catch (IllegalArgumentException e) {
|
||||||
return addStringConstant(value);
|
e.printStackTrace();
|
||||||
} else { // assume variable name
|
} catch (IllegalAccessException e) {
|
||||||
return addVariable(value);
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Oops!");
|
// FIXME: Just during development - this should throw an exception!
|
||||||
}
|
while (peekToken() != null && !peekToken().isCommandSeparator() && !peekToken().isLineNumber()) {
|
||||||
}
|
nextToken();
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if this string is a number.
|
|
||||||
*/
|
|
||||||
protected boolean isIntegerNumber(String value) {
|
|
||||||
for (int i=0; i<value.length(); i++) {
|
|
||||||
if (!Character.isDigit(value.charAt(i))) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String addIntegerConstant(String value) {
|
protected Method getMethod(ApplesoftToken token) {
|
||||||
String name = "INT" + value;
|
String tokenName = "evaluate" + token.getTokenString().trim();
|
||||||
if (!integerConstants.containsKey(name)) {
|
Method method = (Method) commandMethods.get(tokenName);
|
||||||
integerConstants.put(name, value);
|
if (method == null) {
|
||||||
|
try {
|
||||||
|
method = getClass().getMethod(tokenName, new Class[0]);
|
||||||
|
commandMethods.put(tokenName, method);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// This is actually valid (during development anyway)
|
||||||
|
//e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return name;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String addStringConstant(String value) {
|
protected void addAssembly(String label, String mnemonic, String parameter) {
|
||||||
String name = "STR" + stringConstants.size();
|
if (label != null) {
|
||||||
if (stringConstants.containsValue(value)) {
|
sourceAssembly.append(label);
|
||||||
Iterator iterator = stringConstants.keySet().iterator();
|
sourceAssembly.append(":\n");
|
||||||
while (iterator.hasNext()) {
|
}
|
||||||
String key = (String) iterator.next();
|
if (mnemonic != null) {
|
||||||
String keyValue = (String) stringConstants.get(key);
|
sourceAssembly.append(" ");
|
||||||
if (value.equals(keyValue)) {
|
sourceAssembly.append(mnemonic);
|
||||||
name = key;
|
if (parameter != null) {
|
||||||
break;
|
sourceAssembly.append(" ");
|
||||||
|
sourceAssembly.append(parameter);
|
||||||
|
if (!usedAddresses.contains(parameter)) {
|
||||||
|
usedAddresses.add(parameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
sourceAssembly.append("\n");
|
||||||
stringConstants.put(name, value);
|
|
||||||
}
|
}
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String addVariable(String variableName) {
|
public void evaluateHOME() {
|
||||||
if (variableName.endsWith("$")) {
|
addAssembly(null, "JSR", "HOME");
|
||||||
variableName = "STR" + variableName;
|
|
||||||
if (!stringVariables.contains(variableName)) {
|
|
||||||
stringVariables.add(variableName);
|
|
||||||
}
|
|
||||||
} else if (variableName.endsWith("%")) {
|
|
||||||
variableName = "INT" + variableName;
|
|
||||||
if (!integerVariables.contains(variableName)) {
|
|
||||||
integerVariables.add(variableName);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
variableName = "FP" + variableName;
|
|
||||||
if (!floatVariables.contains(variableName)) {
|
|
||||||
floatVariables.add(variableName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return variableName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isIntegerVariable(String name) {
|
public void evaluateTEXT() {
|
||||||
return integerVariables.contains(name) || integerConstants.containsKey(name);
|
addAssembly(null, "JSR", "TEXT");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isFloatVariable(String name) {
|
public void evaluateRETURN() {
|
||||||
return floatVariables.contains(name) || floatConstants.containsKey(name);
|
addAssembly(null, "RTS", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isStringVariable(String name) {
|
public void evaluateEND() {
|
||||||
return stringVariables.contains(name) || stringConstants.containsKey(name);
|
evaluateRETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void evaluateHGR() {
|
||||||
|
addAssembly(null, "JSR", "HGR");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evaluateHGR2() {
|
||||||
|
addAssembly(null, "JSR", "HGR2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evaluateGR() {
|
||||||
|
addAssembly(null, "JSR", "GR");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evaluateINVERSE() {
|
||||||
|
addAssembly(null, "LDA", "#$3F");
|
||||||
|
addAssembly(null, "STA", "$32");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evaluateNORMAL() {
|
||||||
|
addAssembly(null, "LDA", "#$FF");
|
||||||
|
addAssembly(null, "STA", "$32");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evaluateFLASH() {
|
||||||
|
addAssembly(null, "LDA", "#$7F");
|
||||||
|
addAssembly(null, "STA", "$32");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Process and individual token.
|
||||||
|
// */
|
||||||
|
// protected void processToken(StringBuffer sourceAssembly,
|
||||||
|
// StringBuffer sourceLine, ApplesoftToken token, ApplesoftTokenizer tokenizer) {
|
||||||
|
// String expr = null;
|
||||||
|
// switch (token.getTokenValue()) {
|
||||||
|
// case VTAB: expr = evaluateExpression(sourceAssembly, sourceLine);
|
||||||
|
// sourceAssembly.append("\tLDA ");
|
||||||
|
// sourceAssembly.append(expr);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tSTA $25\n");
|
||||||
|
// sourceAssembly.append("\tJSR $FC66\n");
|
||||||
|
// break;
|
||||||
|
// case HTAB: expr = evaluateExpression(sourceAssembly, sourceLine);
|
||||||
|
// sourceAssembly.append("\tLDA ");
|
||||||
|
// sourceAssembly.append(expr);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tSTA $24\n");
|
||||||
|
// break;
|
||||||
|
// case HCOLOR:
|
||||||
|
// expr = evaluateExpression(sourceAssembly, sourceLine);
|
||||||
|
// sourceAssembly.append("\tLDX ");
|
||||||
|
// sourceAssembly.append(expr);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tJSR $F6F0\n");
|
||||||
|
// break;
|
||||||
|
// case PRINT:
|
||||||
|
// expr = evaluateExpression(sourceAssembly, sourceLine);
|
||||||
|
// if (isIntegerVariable(expr)) {
|
||||||
|
// throw new IllegalArgumentException("Integer not supported in print: " + expr);
|
||||||
|
// } else if (isFloatVariable(expr)) {
|
||||||
|
// sourceAssembly.append("\tLDY #>");
|
||||||
|
// sourceAssembly.append(expr);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tLDA #<");
|
||||||
|
// sourceAssembly.append(expr);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tJSR $EAF9\t; MOVFM\n");
|
||||||
|
// sourceAssembly.append("\tJSR $ED2E\t; PRNTFAC\n");
|
||||||
|
// } else if (isStringVariable(expr)) {
|
||||||
|
// sourceAssembly.append("\tLDY #0\n");
|
||||||
|
// sourceAssembly.append(":loop\tLDA ");
|
||||||
|
// sourceAssembly.append(expr);
|
||||||
|
// sourceAssembly.append(",Y\n");
|
||||||
|
// sourceAssembly.append("\tBEQ :end\n");
|
||||||
|
// sourceAssembly.append("\tJSR COUT\n");
|
||||||
|
// sourceAssembly.append("\tINY\n");
|
||||||
|
// sourceAssembly.append("\tBNE :loop\n");
|
||||||
|
// sourceAssembly.append(":end\n");
|
||||||
|
// } else {
|
||||||
|
// throw new IllegalArgumentException("Invalid expr in print: " + expr);
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case FOR:
|
||||||
|
// String loopVariable = evaluateExpression(sourceAssembly, sourceLine);
|
||||||
|
// if (!isFloatVariable(loopVariable)) {
|
||||||
|
// throw new IllegalArgumentException("FOR loop argument must be a float");
|
||||||
|
// }
|
||||||
|
// token = tokenizer.getNextToken();
|
||||||
|
// if (token.getTokenValue() != EQUALS) {
|
||||||
|
// throw new IllegalArgumentException("FOR requires =");
|
||||||
|
// }
|
||||||
|
// sourceLine.append(token.getTokenString());
|
||||||
|
// String startValue = evaluateExpression(sourceAssembly, sourceLine);
|
||||||
|
// token = tokenizer.getNextToken();
|
||||||
|
// if (token.getTokenValue() != TO) {
|
||||||
|
// throw new IllegalArgumentException("FOR requires TO");
|
||||||
|
// }
|
||||||
|
// sourceLine.append(token.getTokenString());
|
||||||
|
// String endValue = evaluateExpression(sourceAssembly, sourceLine);
|
||||||
|
// if (isFloatVariable(loopVariable)) {
|
||||||
|
// // FIXME: Assumes start/end are integer
|
||||||
|
// sourceAssembly.append("\tLDY ");
|
||||||
|
// sourceAssembly.append(startValue);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tLDA ");
|
||||||
|
// sourceAssembly.append(startValue);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tJSR $E2F2 ; GIVAYF\n");
|
||||||
|
// sourceAssembly.append("\tLDY #>");
|
||||||
|
// sourceAssembly.append(loopVariable);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tLDX #<");
|
||||||
|
// sourceAssembly.append(loopVariable);
|
||||||
|
// sourceAssembly.append("\n");
|
||||||
|
// sourceAssembly.append("\tJSR $EB2B ; MOVMF\n");
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Evaluate an expression and return the variable name that
|
||||||
|
// * contains the value.
|
||||||
|
// */
|
||||||
|
// protected String evaluateExpression(StringBuffer sourceAssembly, StringBuffer sourceLine) {
|
||||||
|
// // FIXME: no type checking available
|
||||||
|
// ApplesoftToken token = tokenizer.getNextToken();
|
||||||
|
// if (token.isString()) {
|
||||||
|
// String value = token.getStringValue();
|
||||||
|
// sourceLine.append(value);
|
||||||
|
// if (isIntegerNumber(value)) {
|
||||||
|
// return addIntegerConstant(value);
|
||||||
|
// } else if (value.startsWith("\"")) {
|
||||||
|
// return addStringConstant(value);
|
||||||
|
// } else { // assume variable name
|
||||||
|
// return addVariable(value);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// throw new IllegalArgumentException("Oops!");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * Indicates if this string is a number.
|
||||||
|
// */
|
||||||
|
// protected boolean isIntegerNumber(String value) {
|
||||||
|
// for (int i=0; i<value.length(); i++) {
|
||||||
|
// if (!Character.isDigit(value.charAt(i))) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected String addIntegerConstant(String value) {
|
||||||
|
// String name = "INT" + value;
|
||||||
|
// if (!integerConstants.containsKey(name)) {
|
||||||
|
// integerConstants.put(name, value);
|
||||||
|
// }
|
||||||
|
// return name;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected String addStringConstant(String value) {
|
||||||
|
// String name = "STR" + stringConstants.size();
|
||||||
|
// if (stringConstants.containsValue(value)) {
|
||||||
|
// Iterator iterator = stringConstants.keySet().iterator();
|
||||||
|
// while (iterator.hasNext()) {
|
||||||
|
// String key = (String) iterator.next();
|
||||||
|
// String keyValue = (String) stringConstants.get(key);
|
||||||
|
// if (value.equals(keyValue)) {
|
||||||
|
// name = key;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// stringConstants.put(name, value);
|
||||||
|
// }
|
||||||
|
// return name;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected String addVariable(String variableName) {
|
||||||
|
// if (variableName.endsWith("$")) {
|
||||||
|
// variableName = "STR" + variableName;
|
||||||
|
// if (!stringVariables.contains(variableName)) {
|
||||||
|
// stringVariables.add(variableName);
|
||||||
|
// }
|
||||||
|
// } else if (variableName.endsWith("%")) {
|
||||||
|
// variableName = "INT" + variableName;
|
||||||
|
// if (!integerVariables.contains(variableName)) {
|
||||||
|
// integerVariables.add(variableName);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// variableName = "FP" + variableName;
|
||||||
|
// if (!floatVariables.contains(variableName)) {
|
||||||
|
// floatVariables.add(variableName);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return variableName;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected boolean isIntegerVariable(String name) {
|
||||||
|
// return integerVariables.contains(name) || integerConstants.containsKey(name);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected boolean isFloatVariable(String name) {
|
||||||
|
// return floatVariables.contains(name) || floatConstants.containsKey(name);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// protected boolean isStringVariable(String name) {
|
||||||
|
// return stringVariables.contains(name) || stringConstants.containsKey(name);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user