Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Foerster-H
committed
Jul 3, 2017
1 parent
9a1e5e5
commit d2e4600
Showing
10 changed files
with
1,235 additions
and
579 deletions.
There are no files selected for viewing
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
351 changes: 223 additions & 128 deletions
351
src/main/java/com/sixtyfour/cbmnative/NativeCompiler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,128 +1,223 @@ | ||
package com.sixtyfour.cbmnative; | ||
|
||
import java.util.ArrayList; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
|
||
import com.sixtyfour.parser.Term; | ||
import com.sixtyfour.system.Machine; | ||
|
||
|
||
/** | ||
* @author Foerster-H | ||
* | ||
*/ | ||
public class NativeCompiler | ||
{ | ||
|
||
public List<String> compileToPseudoCode(Machine machine, Term term) | ||
{ | ||
List<String> code = new ArrayList<String>(); | ||
List<String> expr = term.evalToExpression(machine); | ||
LinkedList<String> stack = new LinkedList<String>(); | ||
String left = null; | ||
String right = null; | ||
int stacked = 0; | ||
int peekPos = 0; | ||
|
||
for (String exp : expr) | ||
{ | ||
boolean isOp = exp.startsWith(":"); | ||
boolean isBreak = exp.equals("_"); | ||
|
||
if (!isBreak) | ||
{ | ||
if (!isOp) | ||
{ | ||
if (right == null) | ||
{ | ||
code.add("MOV Y," + exp); | ||
right = exp; | ||
} | ||
else if (left == null) | ||
{ | ||
code.add("MOV X," + exp); | ||
left = exp; | ||
} | ||
} | ||
} | ||
if (isOp && right != null && left == null) | ||
{ | ||
code.add("PUSH Y"); | ||
stacked++; | ||
right = null; | ||
} | ||
|
||
if (isBreak) | ||
{ | ||
if (right == null) | ||
{ | ||
code.add("POP X"); | ||
left = ""; | ||
stacked--; | ||
} | ||
if (left == null) | ||
{ | ||
code.add("POP Y"); | ||
right = ""; | ||
stacked--; | ||
} | ||
|
||
String ex = stack.pop(); | ||
String op = ex.replace(":", ""); | ||
switch (op) | ||
{ | ||
case "+": | ||
code.add("ADD X,Y"); | ||
break; | ||
case "-": | ||
code.add("SUB X,Y"); | ||
break; | ||
case "*": | ||
code.add("MUL X,Y"); | ||
break; | ||
case "/": | ||
code.add("DIV X,Y"); | ||
break; | ||
case "^": | ||
code.add("POW X,Y"); | ||
break; | ||
case "|": | ||
code.add("OR X,Y"); | ||
break; | ||
case "&": | ||
code.add("AND X,Y"); | ||
break; | ||
case "!": | ||
code.add("NOT Y"); | ||
break; | ||
default: | ||
throw new RuntimeException("Unknown operator: " + op); | ||
} | ||
|
||
stacked++; | ||
code.add("PUSH Y"); | ||
|
||
if (stack.isEmpty() || stacked == 1) | ||
{ | ||
left = null; | ||
right = null; | ||
} | ||
} | ||
|
||
if (isOp) | ||
{ | ||
stack.push(exp); | ||
} | ||
peekPos++; | ||
} | ||
System.out.println("Elements remaining: " + stack.size() + "/" + stacked); | ||
|
||
if (!stack.isEmpty()) | ||
{ | ||
// throw new RuntimeException("Operator stack not empty, "+stack.size()+" elements remaining!"); | ||
} | ||
return code; | ||
} | ||
|
||
} | ||
package com.sixtyfour.cbmnative; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Deque; | ||
import java.util.HashSet; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
import java.util.Locale; | ||
import java.util.Set; | ||
|
||
import com.sixtyfour.parser.Term; | ||
import com.sixtyfour.system.Machine; | ||
|
||
/** | ||
* @author Foerster-H | ||
* | ||
*/ | ||
public class NativeCompiler { | ||
|
||
private Set<String> SINGLES = new HashSet<String>() { | ||
private static final long serialVersionUID = 1L; | ||
|
||
{ | ||
this.add("!"); | ||
this.add("SIN"); | ||
this.add("COS"); | ||
this.add("TAN"); | ||
this.add("LOG"); | ||
this.add("INT"); | ||
this.add("ABS"); | ||
this.add("SGN"); | ||
this.add("SQR"); | ||
this.add("RND"); | ||
} | ||
}; | ||
|
||
public List<String> compileToPseudoCode(Machine machine, Term term) { | ||
List<String> code = new ArrayList<String>(); | ||
List<String> expr = term.evalToExpression(machine); | ||
|
||
Deque<String> stack = new LinkedList<String>(); | ||
Deque<String> yStack = new LinkedList<String>(); | ||
boolean left = false; | ||
boolean right = false; | ||
Set<Integer> fromAbove = new HashSet<Integer>(); | ||
|
||
for (String exp : expr) { | ||
boolean isOp = exp.startsWith(":"); | ||
boolean isBreak = exp.equals("_"); | ||
|
||
if (!isBreak) { | ||
if (!isOp) { | ||
if (!right) { | ||
code.add("MOV Y," + exp); | ||
right = true; | ||
} else if (!left) { | ||
code.add("MOV X," + exp); | ||
left = true; | ||
} | ||
} | ||
} | ||
|
||
if (isOp && right && !left) { | ||
String lc = getLastEntry(code); | ||
if (lc.startsWith("MOV Y")) { | ||
yStack.push(lc); | ||
code.remove(code.size() - 1); | ||
} else { | ||
code.add("PUSH Y"); | ||
yStack.push(null); | ||
} | ||
right = false; | ||
} | ||
|
||
if (isBreak) { | ||
String ex = stack.pop(); | ||
String op = ex.replace(":", ""); | ||
boolean isSingle = isSingle(op); | ||
|
||
if (!left && !isSingle) { | ||
if (code.size() >= 1 && getLastEntry(code).equals("PUSH X")) { | ||
code.remove(code.size() - 1); | ||
yStack.pop(); | ||
} else { | ||
if (code.size() >= 2 && code.get(code.size() - 2).equals("PUSH X") && getLastEntry(code).startsWith("MOV Y")) { | ||
code.remove(code.size() - 2); | ||
yStack.pop(); | ||
} else { | ||
code.add("POP X"); | ||
yStack.pop(); | ||
} | ||
} | ||
left = true; | ||
} | ||
if (!right) { | ||
if (yStack.isEmpty()) { | ||
popy(code); | ||
} else { | ||
String v = yStack.pop(); | ||
if (v == null) { | ||
popy(code); | ||
} else { | ||
code.add(v); | ||
fromAbove.add(code.size() - 1); | ||
} | ||
} | ||
right = true; | ||
} | ||
|
||
if (!code.isEmpty() && getLastEntry(code).startsWith("MOV Y") && !getLastEntry(code).equals("MOV Y,X") && !fromAbove.contains(code.size() - 1)) { | ||
// code.add("SWAP X,Y"); | ||
// Swap register usage is needed | ||
code.add(code.size() - 1, "MOV Y,X"); | ||
code.set(code.size() - 1, getLastEntry(code).replace("MOV Y,", "MOV X,")); | ||
} else { | ||
// Fix wrong register order for single operand function calls | ||
if (isSingle && !code.isEmpty() && getLastEntry(code).startsWith("MOV X")) { | ||
code.add(code.size() - 1, "PUSH Y"); | ||
code.set(code.size() - 1, getLastEntry(code).replace("MOV X,", "MOV Y,")); | ||
yStack.push(null); | ||
} | ||
} | ||
|
||
switch (op) { | ||
case "+": | ||
code.add("ADD X,Y"); | ||
break; | ||
case "-": | ||
code.add("SUB X,Y"); | ||
break; | ||
case "*": | ||
code.add("MUL X,Y"); | ||
break; | ||
case "/": | ||
code.add("DIV X,Y"); | ||
break; | ||
case "^": | ||
code.add("POW X,Y"); | ||
break; | ||
case "|": | ||
code.add("OR X,Y"); | ||
break; | ||
case "&": | ||
code.add("AND X,Y"); | ||
break; | ||
case "!": | ||
code.add("NOT X,Y"); | ||
break; | ||
case "SIN": | ||
code.add("SIN X,Y"); | ||
break; | ||
case "COS": | ||
code.add("COS X,Y"); | ||
break; | ||
case "LOG": | ||
code.add("LOG X,Y"); | ||
break; | ||
case "SQR": | ||
code.add("SQR X,Y"); | ||
break; | ||
case "INT": | ||
code.add("INT X,Y"); | ||
break; | ||
case "ABS": | ||
code.add("ABS X,Y"); | ||
break; | ||
case "SGN": | ||
code.add("SGN X,Y"); | ||
break; | ||
case "TAN": | ||
code.add("TAN X,Y"); | ||
break; | ||
case "RND": | ||
code.add("RND X,Y"); | ||
break; | ||
default: | ||
throw new RuntimeException("Unknown operator: " + op); | ||
} | ||
code.add("PUSH X"); | ||
yStack.push(null); | ||
left = false; | ||
right = false; | ||
} | ||
|
||
if (isOp) { | ||
stack.push(exp); | ||
} | ||
} | ||
|
||
if (!stack.isEmpty()) { | ||
throw new RuntimeException("Operator stack not empty, " + stack.size() + " elements remaining!"); | ||
} | ||
|
||
// End simple expressions properly | ||
if (!code.isEmpty() && !getLastEntry(code).equals("PUSH X")) { | ||
String cl = getLastEntry(code); | ||
if (cl.startsWith("MOV Y")) { | ||
code.add("PUSH Y"); | ||
} else { | ||
code.add("PUSH X"); | ||
} | ||
} | ||
|
||
return code; | ||
} | ||
|
||
private String getLastEntry(List<String> code) { | ||
return code.get(code.size() - 1); | ||
} | ||
|
||
private void popy(List<String> code) { | ||
if (getLastEntry(code).equals("PUSH X")) { | ||
code.set(code.size() - 1, "MOV Y,X"); | ||
} else { | ||
code.add("POP Y"); | ||
} | ||
} | ||
|
||
private boolean isSingle(String op) { | ||
return SINGLES.contains(op.toUpperCase(Locale.ENGLISH)); | ||
} | ||
|
||
} |
Oops, something went wrong.