diff --git a/build/pom.xml b/build/pom.xml
index fae8aefd..a2e1a2a7 100644
--- a/build/pom.xml
+++ b/build/pom.xml
@@ -2,7 +2,7 @@
4.0.0
com.maccasoft
spin-tools-runtime
- 0.32.1
+ 0.33.0
pom
diff --git a/modules/spin-tools/pom.xml b/modules/spin-tools/pom.xml
index c77b87b9..3f91c4fa 100644
--- a/modules/spin-tools/pom.xml
+++ b/modules/spin-tools/pom.xml
@@ -2,7 +2,7 @@
4.0.0
com.maccasoft
spin-tools
- 0.32.1
+ 0.33.0
jar
UTF-8
diff --git a/modules/spin-tools/src-tests/com/maccasoft/propeller/spin2/Spin2ObjectCompilerTest.java b/modules/spin-tools/src-tests/com/maccasoft/propeller/spin2/Spin2ObjectCompilerTest.java
index be14a5ed..a9c6a104 100644
--- a/modules/spin-tools/src-tests/com/maccasoft/propeller/spin2/Spin2ObjectCompilerTest.java
+++ b/modules/spin-tools/src-tests/com/maccasoft/propeller/spin2/Spin2ObjectCompilerTest.java
@@ -5123,49 +5123,80 @@ void testBytesWordsLongs() throws Exception {
+ " b := words(\"1234\", byte 13, 10)\n"
+ " c := longs(\"1234\", word 13, 10)\n"
+ "\n"
+ + " test(bytes(\"1234\", 13, 10))\n"
+ + " test(words(\"1234\", 13, 10))\n"
+ + " test(longs(\"1234\", 13, 10))\n"
+ + "\n"
+ + "PUB test(p)\n"
+ + "\n"
+ "";
Assertions.assertEquals(""
+ "' Object header (var size 4)\n"
- + "00000 00000 08 00 00 80 Method main @ $00008 (0 parameters, 0 returns)\n"
- + "00004 00004 70 00 00 00 End\n"
+ + "00000 00000 0C 00 00 80 Method main @ $0000C (0 parameters, 0 returns)\n"
+ + "00004 00004 AD 00 00 81 Method test @ $000AD (1 parameters, 0 returns)\n"
+ + "00008 00008 AF 00 00 00 End\n"
+ "' PUB main() | a, b, c\n"
- + "00008 00008 03 (stack size)\n"
+ + "0000C 0000C 03 (stack size)\n"
+ "' a := bytes(\"1234\", 13, 10)\n"
- + "00009 00009 9E 06 31 32 33 BYTES\n"
- + "0000E 0000E 34 0D 0A\n"
- + "00011 00011 F0 VAR_WRITE LONG DBASE+$00000 (short)\n"
+ + "0000D 0000D 9E 06 31 32 33 BYTES\n"
+ + "00012 00012 34 0D 0A\n"
+ + "00015 00015 F0 VAR_WRITE LONG DBASE+$00000 (short)\n"
+ "' b := words(\"1234\", 13, 10)\n"
- + "00012 00012 9E 0C 31 00 32 WORDS\n"
- + "00017 00017 00 33 00 34 00\n"
- + "0001C 0001C 0D 00 0A 00\n"
- + "00020 00020 F1 VAR_WRITE LONG DBASE+$00001 (short)\n"
+ + "00016 00016 9E 0C 31 00 32 WORDS\n"
+ + "0001B 0001B 00 33 00 34 00\n"
+ + "00020 00020 0D 00 0A 00\n"
+ + "00024 00024 F1 VAR_WRITE LONG DBASE+$00001 (short)\n"
+ "' c := longs(\"1234\", 13, 10)\n"
- + "00021 00021 9E 18 31 00 00 LONGS\n"
- + "00026 00026 00 32 00 00 00\n"
- + "0002B 0002B 33 00 00 00 34\n"
- + "00030 00030 00 00 00 0D 00\n"
- + "00035 00035 00 00 0A 00 00\n"
- + "0003A 0003A 00\n"
- + "0003B 0003B F2 VAR_WRITE LONG DBASE+$00002 (short)\n"
+ + "00025 00025 9E 18 31 00 00 LONGS\n"
+ + "0002A 0002A 00 32 00 00 00\n"
+ + "0002F 0002F 33 00 00 00 34\n"
+ + "00034 00034 00 00 00 0D 00\n"
+ + "00039 00039 00 00 0A 00 00\n"
+ + "0003E 0003E 00\n"
+ + "0003F 0003F F2 VAR_WRITE LONG DBASE+$00002 (short)\n"
+ "' a := bytes(\"1234\", long 13, 10)\n"
- + "0003C 0003C 9E 09 31 32 33 BYTES\n"
- + "00041 00041 34 0D 00 00 00\n"
- + "00046 00046 0A\n"
- + "00047 00047 F0 VAR_WRITE LONG DBASE+$00000 (short)\n"
+ + "00040 00040 9E 09 31 32 33 BYTES\n"
+ + "00045 00045 34 0D 00 00 00\n"
+ + "0004A 0004A 0A\n"
+ + "0004B 0004B F0 VAR_WRITE LONG DBASE+$00000 (short)\n"
+ "' b := words(\"1234\", byte 13, 10)\n"
- + "00048 00048 9E 0B 31 00 32 WORDS\n"
- + "0004D 0004D 00 33 00 34 00\n"
- + "00052 00052 0D 0A 00\n"
- + "00055 00055 F1 VAR_WRITE LONG DBASE+$00001 (short)\n"
+ + "0004C 0004C 9E 0B 31 00 32 WORDS\n"
+ + "00051 00051 00 33 00 34 00\n"
+ + "00056 00056 0D 0A 00\n"
+ + "00059 00059 F1 VAR_WRITE LONG DBASE+$00001 (short)\n"
+ "' c := longs(\"1234\", word 13, 10)\n"
- + "00056 00056 9E 16 31 00 00 LONGS\n"
- + "0005B 0005B 00 32 00 00 00\n"
- + "00060 00060 33 00 00 00 34\n"
- + "00065 00065 00 00 00 0D 00\n"
- + "0006A 0006A 0A 00 00 00\n"
- + "0006E 0006E F2 VAR_WRITE LONG DBASE+$00002 (short)\n"
- + "0006F 0006F 04 RETURN\n"
+ + "0005A 0005A 9E 16 31 00 00 LONGS\n"
+ + "0005F 0005F 00 32 00 00 00\n"
+ + "00064 00064 33 00 00 00 34\n"
+ + "00069 00069 00 00 00 0D 00\n"
+ + "0006E 0006E 0A 00 00 00\n"
+ + "00072 00072 F2 VAR_WRITE LONG DBASE+$00002 (short)\n"
+ + "' test(bytes(\"1234\", 13, 10))\n"
+ + "00073 00073 00 ANCHOR\n"
+ + "00074 00074 9E 06 31 32 33 BYTES\n"
+ + "00079 00079 34 0D 0A\n"
+ + "0007C 0007C 0A 01 CALL_SUB (1)\n"
+ + "' test(words(\"1234\", 13, 10))\n"
+ + "0007E 0007E 00 ANCHOR\n"
+ + "0007F 0007F 9E 0C 31 00 32 WORDS\n"
+ + "00084 00084 00 33 00 34 00\n"
+ + "00089 00089 0D 00 0A 00\n"
+ + "0008D 0008D 0A 01 CALL_SUB (1)\n"
+ + "' test(longs(\"1234\", 13, 10))\n"
+ + "0008F 0008F 00 ANCHOR\n"
+ + "00090 00090 9E 18 31 00 00 LONGS\n"
+ + "00095 00095 00 32 00 00 00\n"
+ + "0009A 0009A 33 00 00 00 34\n"
+ + "0009F 0009F 00 00 00 0D 00\n"
+ + "000A4 000A4 00 00 0A 00 00\n"
+ + "000A9 000A9 00\n"
+ + "000AA 000AA 0A 01 CALL_SUB (1)\n"
+ + "000AC 000AC 04 RETURN\n"
+ + "' PUB test(p)\n"
+ + "000AD 000AD 00 (stack size)\n"
+ + "000AE 000AE 04 RETURN\n"
+ + "000AF 000AF 00 Padding\n"
+ "", compile(text));
}
@@ -6195,6 +6226,101 @@ void testChainedAssignments() throws Exception {
+ "", compile(text));
}
+ @Test
+ void testMethodKeywordsOverride() throws Exception {
+ String text = ""
+ + "PUB start()\n"
+ + "\n"
+ + " bytes(1, 2)\n"
+ + "\n"
+ + "PUB bytes(a, b)\n"
+ + "\n"
+ + "";
+
+ Assertions.assertEquals(""
+ + "' Object header (var size 4)\n"
+ + "00000 00000 0C 00 00 80 Method start @ $0000C (0 parameters, 0 returns)\n"
+ + "00004 00004 13 00 00 82 Method bytes @ $00013 (2 parameters, 0 returns)\n"
+ + "00008 00008 15 00 00 00 End\n"
+ + "' PUB start()\n"
+ + "0000C 0000C 00 (stack size)\n"
+ + "' bytes(1, 2)\n"
+ + "0000D 0000D 00 ANCHOR\n"
+ + "0000E 0000E A2 CONSTANT (1)\n"
+ + "0000F 0000F A3 CONSTANT (2)\n"
+ + "00010 00010 0A 01 CALL_SUB (1)\n"
+ + "00012 00012 04 RETURN\n"
+ + "' PUB bytes(a, b)\n"
+ + "00013 00013 00 (stack size)\n"
+ + "00014 00014 04 RETURN\n"
+ + "00015 00015 00 00 00 Padding\n"
+ + "", compile(text));
+ }
+
+ @Test
+ void testLocalVariableKeywordsOverride() throws Exception {
+ String text = ""
+ + "PUB start()\n"
+ + "\n"
+ + " test(bytes(1, 2))\n"
+ + "\n"
+ + "PUB test(bytes) | a, i\n"
+ + "\n"
+ + " a := byte[bytes][i]\n"
+ + "\n"
+ + "";
+
+ Assertions.assertEquals(""
+ + "' Object header (var size 4)\n"
+ + "00000 00000 0C 00 00 80 Method start @ $0000C (0 parameters, 0 returns)\n"
+ + "00004 00004 15 00 00 81 Method test @ $00015 (1 parameters, 0 returns)\n"
+ + "00008 00008 1C 00 00 00 End\n"
+ + "' PUB start()\n"
+ + "0000C 0000C 00 (stack size)\n"
+ + "' test(bytes(1, 2))\n"
+ + "0000D 0000D 00 ANCHOR\n"
+ + "0000E 0000E 9E 02 01 02 BYTES\n"
+ + "00012 00012 0A 01 CALL_SUB (1)\n"
+ + "00014 00014 04 RETURN\n"
+ + "' PUB test(bytes) | a, i\n"
+ + "00015 00015 02 (stack size)\n"
+ + "' a := byte[bytes][i]\n"
+ + "00016 00016 E0 VAR_READ LONG DBASE+$00000 (short)\n"
+ + "00017 00017 E2 VAR_READ LONG DBASE+$00002 (short)\n"
+ + "00018 00018 63 80 MEM_READ BYTE INDEXED\n"
+ + "0001A 0001A F1 VAR_WRITE LONG DBASE+$00001 (short)\n"
+ + "0001B 0001B 04 RETURN\n"
+ + "", compile(text));
+ }
+
+ @Test
+ void testGlobalVariableKeywordsOverride() throws Exception {
+ String text = ""
+ + "VAR\n"
+ + "\n"
+ + " long words[2]\n"
+ + "\n"
+ + "PUB start()\n"
+ + "\n"
+ + " words := longs(1, 2)\n"
+ + "\n"
+ + "";
+
+ Assertions.assertEquals(""
+ + "' Object header (var size 12)\n"
+ + "00000 00000 08 00 00 80 Method start @ $00008 (0 parameters, 0 returns)\n"
+ + "00004 00004 16 00 00 00 End\n"
+ + "' PUB start()\n"
+ + "00008 00008 00 (stack size)\n"
+ + "' words := longs(1, 2)\n"
+ + "00009 00009 9E 08 01 00 00 LONGS\n"
+ + "0000E 0000E 00 02 00 00 00\n"
+ + "00013 00013 C1 81 VAR_WRITE LONG VBASE+$00001 (short)\n"
+ + "00015 00015 04 RETURN\n"
+ + "00016 00016 00 00 Padding\n"
+ + "", compile(text));
+ }
+
String compile(String text) throws Exception {
return compile(text, false);
}
diff --git a/modules/spin-tools/src/com/maccasoft/propeller/SourceEditor.java b/modules/spin-tools/src/com/maccasoft/propeller/SourceEditor.java
index 1b736a65..e907433e 100644
--- a/modules/spin-tools/src/com/maccasoft/propeller/SourceEditor.java
+++ b/modules/spin-tools/src/com/maccasoft/propeller/SourceEditor.java
@@ -653,45 +653,45 @@ public void mouseHover(MouseEvent e) {
}
if (token != null && helpProvider != null) {
- String text = helpProvider.getString(context != null ? context.getClass().getSimpleName() : null, token.getText().toLowerCase());
- if (text == null) {
- text = tokenMarker.getMethod(token.getText());
- if (text == null && token.getText().startsWith("@")) {
- text = tokenMarker.getMethod(token.getText().substring(1));
- }
- if (text == null && token.getText().startsWith(".")) {
- int line = styledText.getLineAtOffset(offset);
- int lineOffset = styledText.getOffsetAtLine(line);
- String lineText = styledText.getLine(line);
- int endIndex = token.start - lineOffset - 1;
- if (lineText.charAt(endIndex) == ']') {
- int depth = -1;
- while (endIndex >= 0) {
- if (lineText.charAt(endIndex) == ']') {
- depth++;
- }
- else if (lineText.charAt(endIndex) == '[') {
- if (depth == 0) {
- break;
- }
- depth--;
+ String text = tokenMarker.getMethod(token.getText());
+ if (text == null && token.getText().startsWith("@")) {
+ text = tokenMarker.getMethod(token.getText().substring(1));
+ }
+ if (text == null && token.getText().startsWith(".")) {
+ int line = styledText.getLineAtOffset(offset);
+ int lineOffset = styledText.getOffsetAtLine(line);
+ String lineText = styledText.getLine(line);
+ int endIndex = token.start - lineOffset - 1;
+ if (lineText.charAt(endIndex) == ']') {
+ int depth = -1;
+ while (endIndex >= 0) {
+ if (lineText.charAt(endIndex) == ']') {
+ depth++;
+ }
+ else if (lineText.charAt(endIndex) == '[') {
+ if (depth == 0) {
+ break;
}
- endIndex--;
+ depth--;
}
endIndex--;
}
- if (endIndex >= 0) {
- Token objectToken = tokenMarker.getTokenAt(endIndex + lineOffset);
- if (objectToken != null) {
- String qualifiedName = objectToken.getText() + token.getText();
- text = tokenMarker.getMethod(qualifiedName);
- if (text == null && qualifiedName.startsWith("@")) {
- text = tokenMarker.getMethod(qualifiedName.substring(1));
- }
+ endIndex--;
+ }
+ if (endIndex >= 0) {
+ Token objectToken = tokenMarker.getTokenAt(endIndex + lineOffset);
+ if (objectToken != null) {
+ String qualifiedName = objectToken.getText() + token.getText();
+ text = tokenMarker.getMethod(qualifiedName);
+ if (text == null && qualifiedName.startsWith("@")) {
+ text = tokenMarker.getMethod(qualifiedName.substring(1));
}
}
}
}
+ if (text == null) {
+ text = helpProvider.getString(context != null ? context.getClass().getSimpleName() : null, token.getText().toLowerCase());
+ }
if (text != null && !"".equals(text)) {
popupWindow = new Shell(styledText.getShell(), SWT.RESIZE | SWT.ON_TOP);
FillLayout layout = new FillLayout();
diff --git a/modules/spin-tools/src/com/maccasoft/propeller/SpinTools.java b/modules/spin-tools/src/com/maccasoft/propeller/SpinTools.java
index 74b5e8f0..8aa05010 100644
--- a/modules/spin-tools/src/com/maccasoft/propeller/SpinTools.java
+++ b/modules/spin-tools/src/com/maccasoft/propeller/SpinTools.java
@@ -110,7 +110,7 @@
public class SpinTools {
public static final String APP_TITLE = "Spin Tools IDE";
- public static final String APP_VERSION = "0.32.1";
+ public static final String APP_VERSION = "0.33.0";
static final File defaultSpin1Examples = new File(System.getProperty("APP_DIR"), "examples/P1").getAbsoluteFile();
static final File defaultSpin2Examples = new File(System.getProperty("APP_DIR"), "examples/P2").getAbsoluteFile();
diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2Bytecode.java b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2Bytecode.java
index 0af34f22..aebf9b01 100644
--- a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2Bytecode.java
+++ b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2Bytecode.java
@@ -52,7 +52,7 @@ public int getReturns() {
static {
descriptors.put("HUBSET", new Descriptor(0x19, 0x54, 1, 0));
descriptors.put("CLKSET", new Descriptor(0x19, 0x56, 2, 0));
- descriptors.put("CLKFREQ", new Descriptor(0x19, 0x58, 0, 1));
+ //descriptors.put("CLKFREQ", new Descriptor(0x19, 0x58, 0, 1));
//descriptors.put("COGSPIN", new Descriptor(0x19, 0x5A, 3));
descriptors.put("COGCHK", new Descriptor(0x19, 0x5C, 1, 1));
descriptors.put("REGEXEC", new Descriptor(0x19, 0x60, 1, 0));
diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2BytecodeCompiler.java b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2BytecodeCompiler.java
index 6949510f..eb41d729 100644
--- a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2BytecodeCompiler.java
+++ b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2BytecodeCompiler.java
@@ -107,280 +107,12 @@ public List compileBytecodeExpression(Context context, Spin2Metho
List source = new ArrayList();
try {
- Descriptor desc = Spin2Bytecode.getDescriptor(node.getText());
- if (desc != null) {
- int actual = getArgumentsCount(context, node);
- if (actual != desc.getParameters()) {
- throw new RuntimeException("expected " + desc.getParameters() + " argument(s), found " + actual);
- }
- for (int i = 0; i < node.getChildCount(); i++) {
- source.addAll(compileConstantExpression(context, method, node.getChild(i)));
- }
- source.add(new Bytecode(context, desc.code, node.getText().toUpperCase()));
- }
- else if ("ABORT".equalsIgnoreCase(node.getText())) {
- int actual = getArgumentsCount(context, node);
- if (actual == 0) {
- source.add(new Bytecode(context, 0x06, node.getText().toUpperCase()));
- }
- else if (actual == 1) {
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
- source.add(new Bytecode(context, 0x07, node.getText().toUpperCase()));
- }
- else {
- throw new RuntimeException("expected 0 or 1 argument(s), found " + actual);
- }
- }
- else if ("CLKMODE".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() != 0) {
- throw new CompilerException("syntax error", node);
- }
- source.add(new Constant(context, new NumberLiteral(0x40, 16)));
- source.add(new MemoryOp(context, MemoryOp.Size.Long, MemoryOp.Base.Pop, MemoryOp.Op.Read, null));
- }
- else if ("COGINIT".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() != 3) {
- throw new RuntimeException("expected " + 3 + " argument(s), found " + node.getChildCount());
- }
- for (int i = 0; i < node.getChildCount(); i++) {
- source.addAll(compileBytecodeExpression(context, method, node.getChild(i), true));
- }
- source.add(new Bytecode(context, push ? 0x26 : 0x25, node.getText().toUpperCase()));
- }
- else if ("COGNEW".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() != 2) {
- throw new RuntimeException("expected " + 2 + " argument(s), found " + node.getChildCount());
- }
- source.add(new Constant(context, new NumberLiteral(16)));
- for (int i = 0; i < node.getChildCount(); i++) {
- source.addAll(compileBytecodeExpression(context, method, node.getChild(i), true));
- }
- source.add(new Bytecode(context, push ? 0x26 : 0x25, node.getText().toUpperCase()));
- }
- else if ("COGSPIN".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() != 3) {
- throw new RuntimeException("expected " + 3 + " argument(s), found " + node.getChildCount());
- }
-
- source.addAll(compileConstantExpression(context, method, node.getChild(0)));
-
- Spin2StatementNode methodNode = node.getChild(1);
- Expression expression = context.getLocalSymbol(methodNode.getText());
- if (!(expression instanceof Method)) {
- throw new CompilerException("invalid method " + methodNode.getText(), methodNode.getToken());
- }
- int actual = getArgumentsCount(context, methodNode);
- if (actual != ((Method) expression).getArgumentsCount()) {
- throw new CompilerException("expected " + ((Method) expression).getArgumentsCount() + " argument(s), found " + actual, methodNode.getToken());
- }
- for (int i = 0; i < methodNode.getChildCount(); i++) {
- source.addAll(compileConstantExpression(context, method, methodNode.getChild(i)));
- }
- source.add(new SubAddress(context, (Method) expression, false));
- Spin2Method calledMethod = (Spin2Method) expression.getData(Spin2Method.class.getName());
- calledMethod.setCalledBy(method);
-
- source.addAll(compileConstantExpression(context, method, node.getChild(2)));
-
- source.add(new Bytecode(context, new byte[] {
- 0x19, 0x5A
- }, node.getText().toUpperCase()));
-
- source.add(new Bytecode(context, new byte[] {
- (byte) methodNode.getChildCount(), (byte) (push ? 0x26 : 0x25)
- }, "POP_RETURN (???)"));
- }
- else if ("RECV".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() != 0) {
- throw new RuntimeException("expected " + 0 + " argument(s), found " + node.getChildCount());
- }
- source.add(new Bytecode(context, 0x0C, node.getText().toUpperCase()));
- }
- else if ("SEND".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() == 0) {
- throw new RuntimeException("syntax error");
- }
- boolean bytes = true;
- for (Spin2StatementNode child : node.getChilds()) {
- if (child.getType() != Token.NUMBER) {
- bytes = false;
- break;
- }
- }
- if (bytes) {
- byte[] code = new byte[node.getChildCount() + 2];
- code[0] = 0x0E;
- code[1] = (byte) node.getChildCount();
- for (int i = 0; i < node.getChildCount(); i++) {
- code[i + 2] = (byte) new NumberLiteral(node.getChild(i).getText()).getNumber().intValue();
- }
- source.add(new Bytecode(context, code, node.getText().toUpperCase()));
- }
- else {
- for (Spin2StatementNode child : node.getChilds()) {
- source.addAll(compileBytecodeExpression(context, method, child, true));
- source.add(new Bytecode(context, 0x0D, node.getText().toUpperCase()));
- }
- }
- }
- else if ("DEBUG".equalsIgnoreCase(node.getText())) {
- int stack = 0;
- for (Spin2StatementNode child : node.getChilds()) {
- for (Spin2StatementNode param : child.getChilds()) {
- source.addAll(compileBytecodeExpression(context, method, param, true));
- stack += 4;
- }
- }
- node.setData("context", context);
- method.debugNodes.add(node);
- compiler.debugStatements.add(node);
-
- int pop = stack;
- source.add(new Bytecode(context, 0x43, "") {
-
- int index;
-
- @Override
- public int resolve(int address) {
- index = compiler.debugStatements.indexOf(node) + 1;
- if (index >= 255) {
- throw new CompilerException("too much debug statements", node);
- }
- return super.resolve(address);
- }
-
- @Override
- public int getSize() {
- return index == -1 ? 0 : 3;
- }
-
- @Override
- public byte[] getBytes() {
- if (index == -1) {
- return new byte[0];
- }
- return new byte[] {
- 0x43, (byte) pop, (byte) index
- };
- }
-
- @Override
- public String toString() {
- if (index == -1) {
- return "";
- }
- return node.getText().toUpperCase() + " #" + index;
- }
-
- });
- }
- else if ("END".equalsIgnoreCase(node.getText())) {
- // Ignored
- }
- else if ("LOOKDOWN".equalsIgnoreCase(node.getText()) || "LOOKDOWNZ".equalsIgnoreCase(node.getText()) || "LOOKUP".equalsIgnoreCase(node.getText())
- || "LOOKUPZ".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() == 0) {
- throw new RuntimeException("expected argument(s), found none");
- }
- Spin2StatementNode argsNode = node.getChild(0);
- if (!":".equalsIgnoreCase(argsNode.getText()) || argsNode.getChildCount() < 2) {
- throw new RuntimeException("invalid argument(s)");
- }
-
- int code = 0x1F;
- int code_range = 0x21;
- if ("LOOKDOWN".equalsIgnoreCase(node.getText()) || "LOOKDOWNZ".equalsIgnoreCase(node.getText())) {
- code = 0x20;
- code_range = 0x22;
- }
-
- Spin2Bytecode end = new Spin2Bytecode(context);
- source.add(new Address(context, new ContextLiteral(end.getContext())));
-
- source.addAll(compileBytecodeExpression(context, method, argsNode.getChild(0), true));
-
- source.add(new Constant(context, new NumberLiteral(node.getText().toUpperCase().endsWith("Z") ? 0 : 1)));
-
- for (int i = 1; i < argsNode.getChildCount(); i++) {
- Spin2StatementNode arg = argsNode.getChild(i);
- if ("..".equals(arg.getText())) {
- source.addAll(compileBytecodeExpression(context, method, arg.getChild(0), true));
- source.addAll(compileBytecodeExpression(context, method, arg.getChild(1), true));
- source.add(new Bytecode(context, code_range, node.getText().toUpperCase()));
- }
- else if (arg.getType() == Token.STRING) {
- String s = arg.getText().substring(1, arg.getText().length() - 1);
- for (int x = 0; x < s.length(); x++) {
- source.add(new Constant(context, new CharacterLiteral(s.substring(x, x + 1))));
- source.add(new Bytecode(context, code, node.getText().toUpperCase()));
- }
- }
- else {
- source.addAll(compileBytecodeExpression(context, method, arg, true));
- source.add(new Bytecode(context, code, node.getText().toUpperCase()));
- }
- }
-
- source.add(new Bytecode(context, 0x23, "LOOKDONE"));
- source.add(end);
- }
- else if ("STRING".equalsIgnoreCase(node.getText()) || "LSTRING".equalsIgnoreCase(node.getText())) {
- ByteArrayOutputStream sb = new ByteArrayOutputStream();
- for (Spin2StatementNode child : node.getChilds()) {
- if (child.getType() == Token.STRING) {
- String s = child.getText().substring(1);
- sb.write(s.substring(0, s.length() - 1).getBytes());
- }
- else if (child.getType() == Token.NUMBER) {
- NumberLiteral expression = new NumberLiteral(child.getText());
- sb.write((byte) expression.getNumber().intValue());
- }
- else {
- try {
- Expression expression = buildConstantExpression(context, child);
- if (!expression.isConstant()) {
- throw new CompilerException("expression is not constant", child.getToken());
- }
- sb.write((byte) expression.getNumber().intValue());
- } catch (Exception e) {
- throw new CompilerException("expression is not constant", child.getToken());
- }
- }
- }
- if (sb.size() > 254) {
- logMessage(new CompilerException(CompilerException.ERROR, "string data cannot exceed 254 bytes", node.getTokens()));
- }
- if ("STRING".equalsIgnoreCase(node.getText())) {
- sb.write(0x00);
- }
- byte[] code = sb.toByteArray();
-
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- os.write(0x9E);
- if ("LSTRING".equalsIgnoreCase(node.getText())) {
- os.write(code.length + 1);
- }
- os.write(code.length);
- os.writeBytes(code);
- source.add(new Bytecode(context, os.toByteArray(), node.getText().toUpperCase()));
- }
- else if (("BYTES".equalsIgnoreCase(node.getText()) || "WORDS".equalsIgnoreCase(node.getText()) || "LONGS".equalsIgnoreCase(node.getText())) && node.getChildCount() != 0) {
- byte[] code = compileTypes(context, node, node.getText().substring(0, node.getText().length() - 1));
- if (code.length > 255) {
- logMessage(new CompilerException(CompilerException.ERROR, "data cannot exceed 255 bytes", node.getTokens()));
- }
-
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- os.write(0x9E);
- os.write(code.length);
- os.writeBytes(code);
- source.add(new Bytecode(context, os.toByteArray(), node.getText().toUpperCase()));
- }
- else if (node.getType() == Token.NUMBER) {
+ if (node.getType() == Token.NUMBER) {
Expression expression = new NumberLiteral(node.getText());
source.add(new Constant(context, expression));
+ return source;
}
- else if (node.getType() == Token.STRING) {
+ if (node.getType() == Token.STRING) {
String s = node.getText();
if (s.startsWith("@")) {
StringBuilder sb = new StringBuilder(s.substring(2, s.length() - 1));
@@ -411,176 +143,96 @@ else if (node.getType() == Token.STRING) {
source.add(new Bytecode(context, os.toByteArray(), "STRING"));
}
}
+ return source;
}
- else if ("-".equalsIgnoreCase(node.getText()) && node.getChildCount() == 1) {
- try {
- Expression expression = buildConstantExpression(context, node);
- source.add(new Constant(context, expression));
- } catch (Exception e) {
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
- source.add(new Bytecode(context, 0x79, "NEGATE"));
- }
- }
- else if ("-.".equalsIgnoreCase(node.getText()) && node.getChildCount() == 1) {
- try {
- Expression expression = buildConstantExpression(context, node);
- source.add(new Constant(context, expression));
- } catch (Exception e) {
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
- source.add(new Bytecode(context, new byte[] {
- 0x19, (byte) 0x94
- }, "FLOAT_NEGATE"));
- }
- }
- else if (("+".equalsIgnoreCase(node.getText()) || "+.".equalsIgnoreCase(node.getText())) && node.getChildCount() == 1) {
- try {
- Expression expression = buildConstantExpression(context, node);
- source.add(new Constant(context, expression));
- } catch (Exception e) {
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
- }
- }
- else if ("-=".equalsIgnoreCase(node.getText()) && node.getChildCount() == 1) {
- source.addAll(leftAssign(context, method, node.getChild(0), true, false));
- if (push) {
- source.add(new Bytecode(context, 0xB9, "NEGATE_ASSIGN (push)"));
- }
- else {
- source.add(new Bytecode(context, 0x92, "NEGATE_ASSIGN"));
- }
- }
- else if (":=".equals(node.getText())) {
- if (node.getChildCount() != 2) {
- throw new RuntimeException("expression syntax error");
- }
- source.addAll(compileConstantExpression(context, method, node.getChild(1)));
- source.addAll(leftAssign(context, method, node.getChild(0), push, push));
- }
- else if (MathOp.isAssignMathOp(node.getText()) && node.getChildCount() == 1) {
- source.addAll(leftAssign(context, method, node.getChild(0), true, false));
- source.add(new MathOp(context, node.getText(), push));
- }
- else if (MathOp.isAssignMathOp(node.getText())) {
- source.addAll(compileConstantExpression(context, method, node.getChild(1)));
- source.addAll(leftAssign(context, method, node.getChild(0), true, false));
- source.add(new MathOp(context, node.getText(), push));
- }
- else if (MathOp.isUnaryMathOp(node.getText())) {
- if (node.getChildCount() != 1) {
- throw new RuntimeException("expression syntax error");
- }
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
- source.add(new MathOp(context, node.getText(), push));
- }
- else if (MathOp.isMathOp(node.getText())) {
- if (node.getChildCount() != 2) {
- throw new RuntimeException("expression syntax error");
- }
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
- source.addAll(compileBytecodeExpression(context, method, node.getChild(1), true));
- source.add(new MathOp(context, node.getText(), false));
- }
- else if ("?".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() != 2) {
- throw new RuntimeException("expression syntax error");
- }
- if (!":".equals(node.getChild(1).getText())) {
- throw new RuntimeException("expression syntax error");
- }
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
- source.addAll(compileBytecodeExpression(context, method, node.getChild(1).getChild(0), true));
- source.addAll(compileBytecodeExpression(context, method, node.getChild(1).getChild(1), true));
- source.add(new Bytecode(context, 0x6B, "TERNARY_IF_ELSE"));
- }
- else if ("_".equalsIgnoreCase(node.getText())) {
- source.add(new Bytecode(context, 0x17, "POP"));
- }
- else if ("(".equalsIgnoreCase(node.getText())) {
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), push));
- }
- else if (",".equalsIgnoreCase(node.getText())) {
- for (Spin2StatementNode child : node.getChilds()) {
- source.addAll(compileBytecodeExpression(context, method, child, push));
- }
- }
- else if ("\\".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() == 2) {
- source.addAll(compileConstantExpression(context, method, node.getChild(1)));
- source.addAll(leftAssign(context, method, node.getChild(0), push, false));
- source.add(new Bytecode(context, 0x8D, "SWAP"));
- }
- else {
- if (node.getChildCount() != 1) {
- throw new RuntimeException("expression syntax error");
- }
- Expression expression = context.getLocalSymbol(node.getChild(0).getText());
- if (expression instanceof Method) {
- source.addAll(compileMethodCall(context, method, expression, node.getChild(0), push, true));
+ if (node.isMethod()) {
+ if ("RECV".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() != 0) {
+ throw new RuntimeException("expected " + 0 + " argument(s), found " + node.getChildCount());
}
- else if (expression instanceof Variable) {
- source.addAll(compileMethodCall(context, method, expression, node.getChild(0), push, true));
+ source.add(new Bytecode(context, 0x0C, node.getText().toUpperCase()));
+ return source;
+ }
+
+ if ("SEND".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() == 0) {
+ throw new RuntimeException("syntax error");
}
- else if (expression instanceof DataVariable) {
- source.addAll(compileMethodCall(context, method, expression, node.getChild(0), push, true));
+ boolean bytes = true;
+ for (Spin2StatementNode child : node.getChilds()) {
+ if (child.getType() != Token.NUMBER) {
+ bytes = false;
+ break;
+ }
}
- else if ("BYTE".equalsIgnoreCase(node.getChild(0).getText()) || "WORD".equalsIgnoreCase(node.getChild(0).getText()) || "LONG".equalsIgnoreCase(node.getChild(0).getText())) {
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), push));
+ if (bytes) {
+ byte[] code = new byte[node.getChildCount() + 2];
+ code[0] = 0x0E;
+ code[1] = (byte) node.getChildCount();
+ for (int i = 0; i < node.getChildCount(); i++) {
+ code[i + 2] = (byte) new NumberLiteral(node.getChild(i).getText()).getNumber().intValue();
+ }
+ source.add(new Bytecode(context, code, node.getText().toUpperCase()));
}
else {
- throw new CompilerException("symbol " + node.getChild(0).getText() + " is not a method", node.getChild(0).getToken());
+ for (Spin2StatementNode child : node.getChilds()) {
+ source.addAll(compileBytecodeExpression(context, method, child, true));
+ source.add(new Bytecode(context, 0x0D, node.getText().toUpperCase()));
+ }
}
+ return source;
}
}
- else if ("++".equalsIgnoreCase(node.getText()) || "--".equalsIgnoreCase(node.getText()) || "??".equalsIgnoreCase(node.getText())) {
- if (node.getChildCount() != 1) {
- throw new RuntimeException("expression syntax error " + node.getText());
- }
-
- Spin2StatementNode childNode = node.getChild(0);
-
- String[] s = childNode.getText().split("[\\.]");
- if (s.length == 2 && ("BYTE".equalsIgnoreCase(s[1]) || "WORD".equalsIgnoreCase(s[1]) || "LONG".equalsIgnoreCase(s[1]))) {
- Spin2StatementNode indexNode = null;
- Spin2StatementNode bitfieldNode = null;
- Expression expression = context.getLocalSymbol(s[0]);
- if (expression == null) {
- throw new CompilerException("undefined symbol " + node.getText(), node.getToken());
- }
+ String[] ar = node.getText().split("[\\.]");
+ if (ar.length == 2 && ("BYTE".equalsIgnoreCase(ar[1]) || "WORD".equalsIgnoreCase(ar[1]) || "LONG".equalsIgnoreCase(ar[1]))) {
+ int index = 0;
+ boolean popIndex = false;
+ Spin2StatementNode indexNode = null;
+ Spin2StatementNode bitfieldNode = null;
+ Spin2StatementNode postEffectNode = null;
+ Expression expression = context.getLocalSymbol(ar[0]);
+ if (expression == null && isAbsoluteAddress(ar[0])) {
+ expression = context.getLocalSymbol(ar[0].substring(2));
+ }
+ if (expression == null && isAddress(ar[0])) {
+ expression = context.getLocalSymbol(ar[0].substring(1));
+ }
+ if (expression instanceof ObjectContextLiteral) {
+ expression = context.getLocalSymbol(ar[0].substring(1));
+ }
+ if (expression != null) {
int n = 0;
- if (n < childNode.getChildCount() && (childNode.getChild(n) instanceof Spin2StatementNode.Index)) {
- indexNode = childNode.getChild(n++);
+ if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ indexNode = node.getChild(n++);
}
- if (n < childNode.getChildCount() && ".".equals(childNode.getChild(n).getText())) {
+ if (n < node.getChildCount() && ".".equals(node.getChild(n).getText())) {
+ if (node.getText().startsWith("@")) {
+ throw new CompilerException("bitfield expression not allowed", node.getChild(n).getToken());
+ }
n++;
- if (n >= childNode.getChildCount()) {
- throw new CompilerException("expected bitfield expression", childNode.getToken());
+ if (n >= node.getChildCount()) {
+ throw new RuntimeException("expected bitfield expression");
}
- if (!(childNode.getChild(n) instanceof Spin2StatementNode.Index)) {
+ if (!(node.getChild(n) instanceof Spin2StatementNode.Index)) {
throw new RuntimeException("syntax error");
}
- bitfieldNode = childNode.getChild(n++);
- }
- if (n < childNode.getChildCount()) {
- throw new RuntimeException("syntax error");
+ bitfieldNode = node.getChild(n++);
}
-
- if (indexNode != null) {
- source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ if (n < node.getChildCount() && isPostEffect(node.getChild(n))) {
+ postEffectNode = node.getChild(n++);
}
-
- int bitfield = -1;
- if (bitfieldNode != null) {
- bitfield = compileBitfield(context, method, bitfieldNode, source);
+ if (n < node.getChildCount()) {
+ throw new CompilerException("syntax error", node.getChild(n).getToken());
}
MemoryOp.Size ss = MemoryOp.Size.Long;
- if ("BYTE".equalsIgnoreCase(s[1])) {
+ if ("BYTE".equalsIgnoreCase(ar[1])) {
ss = MemoryOp.Size.Byte;
}
- else if ("WORD".equalsIgnoreCase(s[1])) {
+ else if ("WORD".equalsIgnoreCase(ar[1])) {
ss = MemoryOp.Size.Word;
}
MemoryOp.Base bb = MemoryOp.Base.PBase;
@@ -588,328 +240,729 @@ else if ("WORD".equalsIgnoreCase(s[1])) {
bb = expression instanceof LocalVariable ? MemoryOp.Base.DBase : MemoryOp.Base.VBase;
((Variable) expression).setCalledBy(method);
}
- source.add(new MemoryOp(context, ss, bb, MemoryOp.Op.Setup, indexNode != null, expression, 0));
+ int bitfield = -1;
if (bitfieldNode != null) {
- source.add(new BitField(context, BitField.Op.Setup, bitfield));
+ bitfield = compileBitfield(context, method, bitfieldNode, source);
}
- }
- else if ("BYTE".equalsIgnoreCase(childNode.getText()) || "WORD".equalsIgnoreCase(childNode.getText()) || "LONG".equalsIgnoreCase(childNode.getText())) {
- Spin2StatementNode indexNode = null;
- Spin2StatementNode bitfieldNode = null;
- int n = 1;
- if (n < childNode.getChildCount() && (childNode.getChild(n) instanceof Spin2StatementNode.Index)) {
- indexNode = childNode.getChild(n++);
- }
- if (n < childNode.getChildCount() && ".".equals(childNode.getChild(n).getText())) {
- n++;
- if (n >= childNode.getChildCount()) {
- throw new CompilerException("expected bitfield expression", childNode.getToken());
+ if (indexNode != null) {
+ popIndex = true;
+ try {
+ Expression exp = buildConstantExpression(context, indexNode);
+ if (exp.isConstant()) {
+ index = exp.getNumber().intValue();
+ popIndex = false;
+ }
+ } catch (Exception e) {
+ // Do nothing
}
- if (!(childNode.getChild(n) instanceof Spin2StatementNode.Index)) {
- throw new RuntimeException("syntax error");
+ if (popIndex) {
+ source.addAll(compileBytecodeExpression(context, method, indexNode, true));
}
- bitfieldNode = childNode.getChild(n++);
}
- if (n < childNode.getChildCount()) {
- throw new RuntimeException("syntax error");
- }
-
- source.addAll(compileBytecodeExpression(context, method, childNode.getChild(0), true));
- if (indexNode != null) {
- source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ if (ar[0].startsWith("@")) {
+ source.add(new MemoryOp(context, ss, bb, MemoryOp.Op.Address, popIndex, expression, index));
+ }
+ else {
+ MemoryOp.Op op = bitfieldNode == null && postEffectNode == null ? (push ? MemoryOp.Op.Read : MemoryOp.Op.Write) : MemoryOp.Op.Setup;
+ source.add(new MemoryOp(context, ss, bb, op, popIndex, expression, index));
}
- int bitfield = -1;
if (bitfieldNode != null) {
- bitfield = compileBitfield(context, method, bitfieldNode, source);
+ source.add(new BitField(context, postEffectNode == null ? BitField.Op.Read : BitField.Op.Setup, bitfield));
}
- MemoryOp.Size ss = MemoryOp.Size.Long;
- if ("BYTE".equalsIgnoreCase(childNode.getText())) {
- ss = MemoryOp.Size.Byte;
- }
- else if ("WORD".equalsIgnoreCase(childNode.getText())) {
- ss = MemoryOp.Size.Word;
+ if (postEffectNode != null) {
+ if ("++".equalsIgnoreCase(postEffectNode.getText())) {
+ source.add(new Bytecode(context, push ? 0x87 : 0x83, "POST_INC" + (push ? " (push)" : "")));
+ }
+ else if ("--".equalsIgnoreCase(postEffectNode.getText())) {
+ source.add(new Bytecode(context, push ? 0x88 : 0x84, "POST_DEC" + (push ? " (push)" : "")));
+ }
+ else if ("!!".equalsIgnoreCase(postEffectNode.getText())) {
+ source.add(new Bytecode(context, push ? 0x8A : 0x89, "POST_LOGICAL_NOT" + (push ? " (push)" : "")));
+ }
+ else if ("!".equalsIgnoreCase(postEffectNode.getText())) {
+ source.add(new Bytecode(context, push ? 0x8C : 0x8B, "POST_NOT" + (push ? " (push)" : "")));
+ }
+ else {
+ throw new CompilerException("unhandled post effect " + postEffectNode.getText(), postEffectNode.getToken());
+ }
}
- source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, MemoryOp.Op.Setup, indexNode != null));
- if (bitfieldNode != null) {
- source.add(new BitField(context, BitField.Op.Setup, bitfield));
- }
+ return source;
}
- else {
- Expression expression = context.getLocalSymbol(childNode.getText());
- if (expression == null) {
- throw new CompilerException("unsupported operation on " + childNode.getText(), childNode.getToken());
- }
- source.addAll(compileVariableSetup(context, method, expression, childNode));
+ }
+ else {
+ Expression expression = context.getLocalSymbol(node.getText());
+ if (expression == null && isAbsoluteAddress(node.getText())) {
+ expression = context.getLocalSymbol(node.getText().substring(2));
}
- if ("++".equalsIgnoreCase(node.getText())) {
- source.add(new Bytecode(context, push ? 0x85 : 0x83, "PRE_INC" + (push ? " (push)" : "")));
+ if (expression == null && isAddress(node.getText())) {
+ expression = context.getLocalSymbol(node.getText().substring(1));
}
- else if ("--".equalsIgnoreCase(node.getText())) {
- source.add(new Bytecode(context, push ? 0x86 : 0x84, "PRE_DEC" + (push ? " (push)" : "")));
+ if (expression == null && node.getText().startsWith("^@")) {
+ expression = context.getLocalSymbol(node.getText().substring(2));
}
- else if ("??".equalsIgnoreCase(node.getText())) {
- source.add(new Bytecode(context, push ? 0x8F : 0x8E, "PRE_RND" + (push ? " (push)" : "")));
+ if (expression instanceof ObjectContextLiteral) {
+ expression = context.getLocalSymbol(node.getText().substring(1));
}
- }
- else if ("BYTE".equalsIgnoreCase(node.getText()) || "WORD".equalsIgnoreCase(node.getText()) || "LONG".equalsIgnoreCase(node.getText())
- || "@BYTE".equalsIgnoreCase(node.getText()) || "@WORD".equalsIgnoreCase(node.getText()) || "@LONG".equalsIgnoreCase(node.getText())
- || "@@BYTE".equalsIgnoreCase(node.getText()) || "@@WORD".equalsIgnoreCase(node.getText()) || "@@LONG".equalsIgnoreCase(node.getText())) {
- Spin2StatementNode indexNode = null;
- Spin2StatementNode bitfieldNode = null;
- Spin2StatementNode postEffectNode = null;
+ if (expression != null) {
+ if (expression instanceof SpinObject) {
+ Spin2StatementNode indexNode = null;
+ Spin2StatementNode methodNode = null;
- int n = 1;
- if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
- indexNode = node.getChild(n++);
- }
- if (n < node.getChildCount() && ".".equals(node.getChild(n).getText())) {
- if (node.getText().startsWith("@")) {
- throw new CompilerException("bitfield expression not allowed", node.getChild(n).getToken());
- }
- n++;
- if (n >= node.getChildCount()) {
- throw new RuntimeException("expected bitfield expression");
- }
- if (!(node.getChild(n) instanceof Spin2StatementNode.Index)) {
- throw new RuntimeException("syntax error");
- }
- bitfieldNode = node.getChild(n++);
- }
+ int n = 0;
+ if (n < node.getChildCount()) {
+ if (node.getChild(n) instanceof Spin2StatementNode.Index) {
+ indexNode = node.getChild(n++);
+ }
+ }
+ if (n < node.getChildCount()) {
+ methodNode = node.getChild(n++);
+ }
+ if (n < node.getChildCount() || methodNode == null) {
+ throw new CompilerException("syntax error", node.getTokens());
+ }
- if (node instanceof Spin2StatementNode.Method) {
- if (node.getParent() != null && node.getParent().getText().startsWith("\\")) {
- source.add(new Bytecode(context, push ? 0x03 : 0x02, "ANCHOR_TRAP"));
- }
- else {
- source.add(new Bytecode(context, push ? 0x01 : 0x00, "ANCHOR"));
- }
+ String qualifiedName = node.getText() + methodNode.getText();
- while (n < node.getChildCount()) {
- if (!(node.getChild(n) instanceof Spin2StatementNode.Argument)) {
- throw new CompilerException("syntax error", node.getChild(n));
+ expression = context.getLocalSymbol(qualifiedName);
+ if (expression == null && isAddress(qualifiedName)) {
+ expression = context.getLocalSymbol(qualifiedName.substring(1));
}
- source.addAll(compileConstantExpression(context, method, node.getChild(n++)));
- }
- }
- else if (node.getText().startsWith("@")) {
- if (n < node.getChildCount()) {
- throw new CompilerException("syntax error", node.getChild(n).getToken());
- }
- }
+ if (expression == null) {
+ throw new CompilerException("undefined symbol " + methodNode.getText(), methodNode.getToken());
+ }
+ if (!(expression instanceof Method)) {
+ throw new CompilerException(methodNode.getText() + " is not a method", methodNode.getToken());
+ }
+ Method methodExpression = (Method) expression;
+ Spin2Method calledMethod = (Spin2Method) methodExpression.getData(Spin2Method.class.getName());
+ if (isAddress(node.getText())) {
+ if (indexNode != null) {
+ source.addAll(compileConstantExpression(context, method, indexNode));
+ }
+ source.add(new SubAddress(context, methodExpression, indexNode != null));
+ calledMethod.setCalledBy(method);
+ }
+ else {
+ source.add(new Bytecode(context, push ? 0x01 : 0x00, "ANCHOR"));
- if (n < node.getChildCount() && isPostEffect(node.getChild(n))) {
- postEffectNode = node.getChild(n++);
- }
- if (n < node.getChildCount()) {
- throw new RuntimeException("syntax error");
- }
+ source.addAll(compileMethodArguments(context, method, calledMethod, methodNode));
+ if (indexNode != null) {
+ source.addAll(compileConstantExpression(context, method, indexNode));
+ }
+ source.add(new CallSub(context, methodExpression, indexNode != null));
+ calledMethod.setCalledBy(method);
- int bitfield = -1;
- if (bitfieldNode != null) {
- bitfield = compileBitfield(context, method, bitfieldNode, source);
- }
+ if (push && methodExpression.getReturnsCount() == 0) {
+ throw new RuntimeException("method doesn't return any value");
+ }
+ }
+ return source;
+ }
+ else if (expression instanceof Method) {
+ if (isAddress(node.getText())) {
+ Method methodExpression = (Method) expression;
+ source.add(new SubAddress(context, methodExpression));
+ Spin2Method calledMethod = (Spin2Method) methodExpression.getData(Spin2Method.class.getName());
+ calledMethod.setCalledBy(method);
+ }
+ else {
+ source.addAll(compileMethodCall(context, method, expression, node, push, false));
+ }
+ }
+ else if (expression instanceof Variable) {
+ if (isAddress(node.getText())) {
+ int index = 0;
+ boolean popIndex = false;
+ boolean hasIndex = false;
+ Spin2StatementNode indexNode = null;
- source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
+ int n = 0;
+ if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ indexNode = node.getChild(n++);
+ }
+ if (n < node.getChildCount()) {
+ throw new CompilerException("unexpected " + node.getChild(n).getText(), node.getChild(n));
+ }
- if (indexNode != null) {
- source.addAll(compileBytecodeExpression(context, method, indexNode, true));
- }
+ if (indexNode != null) {
+ popIndex = true;
+ try {
+ Expression exp = buildConstantExpression(context, indexNode);
+ if (exp.isConstant()) {
+ index = exp.getNumber().intValue();
+ hasIndex = true;
+ popIndex = false;
+ }
+ } catch (Exception e) {
+ // Do nothing
+ }
+ if (popIndex) {
+ source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ }
+ }
- MemoryOp.Size ss = MemoryOp.Size.Long;
- if ("BYTE".equalsIgnoreCase(node.getText()) || "@BYTE".equalsIgnoreCase(node.getText()) || "@@BYTE".equalsIgnoreCase(node.getText())) {
- ss = MemoryOp.Size.Byte;
- }
- else if ("WORD".equalsIgnoreCase(node.getText()) || "@WORD".equalsIgnoreCase(node.getText()) || "@@WORD".equalsIgnoreCase(node.getText())) {
- ss = MemoryOp.Size.Word;
- }
+ VariableOp.Op op = VariableOp.Op.Address;
+ if (node.getText().startsWith("@@")) {
+ op = VariableOp.Op.PBaseAddress;
+ }
- if (node instanceof Spin2StatementNode.Method) {
- if (ss != MemoryOp.Size.Long) {
- throw new RuntimeException("method pointers must be long");
- }
- source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, MemoryOp.Op.Read, indexNode != null));
- source.add(new Bytecode(context, new byte[] {
- (byte) 0x0B,
- }, "CALL_PTR"));
- }
- else if (node.getText().startsWith("@@")) {
- source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, MemoryOp.Op.Read, indexNode != null));
- source.add(new Bytecode(context, 0x24, "ADD_PBASE"));
- }
- else if (node.getText().startsWith("@")) {
- source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, MemoryOp.Op.Address, indexNode != null));
- }
- else {
- MemoryOp.Op op = bitfieldNode == null && postEffectNode == null ? (push ? MemoryOp.Op.Read : MemoryOp.Op.Write) : MemoryOp.Op.Setup;
- source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, op, indexNode != null));
- }
+ source.add(new VariableOp(context, op, popIndex, (Variable) expression, hasIndex, index));
+ }
+ else {
+ if (node.isMethod()) {
+ source.addAll(compileMethodCall(context, method, expression, node, push, false));
+ }
+ else {
+ source.addAll(compileVariableRead(context, method, expression, node, push));
+ }
+ }
+ ((Variable) expression).setCalledBy(method);
+ }
+ else {
+ if (isAddress(node.getText())) {
+ int index = 0;
+ boolean popIndex = false;
+ Spin2StatementNode indexNode = null;
- if (bitfieldNode != null) {
- source.add(new BitField(context, postEffectNode == null ? BitField.Op.Read : BitField.Op.Setup, bitfield));
- }
+ int n = 0;
+ if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ indexNode = node.getChild(n++);
+ }
+ if (n < node.getChildCount()) {
+ throw new CompilerException("unexpected " + node.getChild(n).getText(), node.getChild(n));
+ }
- if (postEffectNode != null) {
- compilePostEffect(context, postEffectNode, source, push);
+ if (indexNode != null) {
+ popIndex = true;
+ try {
+ Expression exp = buildConstantExpression(context, indexNode);
+ if (exp.isConstant()) {
+ index = exp.getNumber().intValue();
+ popIndex = false;
+ }
+ } catch (Exception e) {
+ // Do nothing
+ }
+ if (popIndex) {
+ source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ }
+ }
+
+ MemoryOp.Size ss = MemoryOp.Size.Long;
+ MemoryOp.Base bb = MemoryOp.Base.PBase;
+
+ if ((expression instanceof MemoryContextLiteral) && node.getText().startsWith("@@")) {
+ expression = context.getLocalSymbol(node.getText().substring(1));
+ }
+ if (expression instanceof DataVariable) {
+ switch (((DataVariable) expression).getType()) {
+ case "BYTE":
+ ss = MemoryOp.Size.Byte;
+ break;
+ case "WORD":
+ ss = MemoryOp.Size.Word;
+ break;
+ }
+ }
+ else if (expression instanceof ObjectContextLiteral) {
+ switch (((ObjectContextLiteral) expression).getType()) {
+ case "BYTE":
+ ss = MemoryOp.Size.Byte;
+ break;
+ case "WORD":
+ ss = MemoryOp.Size.Word;
+ break;
+ }
+ }
+ if (isAbsoluteAddress(node.getText())) {
+ source.add(new MemoryOp(context, ss, bb, MemoryOp.Op.Read, popIndex, expression, index));
+ source.add(new Bytecode(context, 0x24, "ADD_PBASE"));
+ }
+ else {
+ source.add(new MemoryOp(context, ss, bb, MemoryOp.Op.Address, popIndex, expression, index));
+ }
+ }
+ else if (expression.isConstant()) {
+ if (node.getChildCount() != 0) {
+ throw new RuntimeException("syntax error");
+ }
+ source.add(new Constant(context, expression));
+ }
+ else if (expression instanceof Register) {
+ source.addAll(compileVariableRead(context, method, expression, node, push));
+ }
+ else if (expression instanceof DataVariable) {
+ if (node.isMethod()) {
+ source.addAll(compileMethodCall(context, method, expression, node, push, false));
+ }
+ else {
+ source.addAll(compileVariableRead(context, method, expression, node, push));
+ }
+ }
+ else if (expression instanceof ContextLiteral) {
+ source.addAll(compileVariableRead(context, method, expression, node, push));
+ }
+ else {
+ if (node.getChildCount() != 0) {
+ throw new RuntimeException("syntax error");
+ }
+ source.add(new MemoryOp(context, MemoryOp.Size.Long, MemoryOp.Base.PBase, MemoryOp.Op.Read, expression));
+ }
+ }
+
+ return source;
}
}
- else if ("REG".equalsIgnoreCase(node.getText())) {
- Spin2StatementNode indexNode = null;
- Spin2StatementNode bitfieldNode = null;
- Spin2StatementNode postEffectNode = null;
- int n = 1;
- if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
- indexNode = node.getChild(n++);
- }
- if (n < node.getChildCount() && ".".equals(node.getChild(n).getText())) {
- n++;
- if (n >= node.getChildCount()) {
- throw new RuntimeException("expected bitfield expression");
+ if (node.isMethod()) {
+ Descriptor desc = Spin2Bytecode.getDescriptor(node.getText());
+ if (desc != null) {
+ int actual = getArgumentsCount(context, node);
+ if (actual != desc.getParameters()) {
+ throw new RuntimeException("expected " + desc.getParameters() + " argument(s), found " + actual);
}
- if (!(node.getChild(n) instanceof Spin2StatementNode.Index)) {
- throw new RuntimeException("syntax error");
+ for (int i = 0; i < node.getChildCount(); i++) {
+ source.addAll(compileConstantExpression(context, method, node.getChild(i)));
}
- bitfieldNode = node.getChild(n++);
+ source.add(new Bytecode(context, desc.code, node.getText().toUpperCase()));
+ return source;
}
-
- if (n < node.getChildCount() && isPostEffect(node.getChild(n))) {
- postEffectNode = node.getChild(n++);
+ if ("ABORT".equalsIgnoreCase(node.getText())) {
+ int actual = getArgumentsCount(context, node);
+ if (actual == 0) {
+ source.add(new Bytecode(context, 0x06, node.getText().toUpperCase()));
+ return source;
+ }
+ if (actual == 1) {
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
+ source.add(new Bytecode(context, 0x07, node.getText().toUpperCase()));
+ return source;
+ }
+ throw new RuntimeException("expected 0 or 1 argument(s), found " + actual);
}
- if (n < node.getChildCount()) {
- throw new RuntimeException("syntax error");
+ if ("COGINIT".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() != 3) {
+ throw new RuntimeException("expected " + 3 + " argument(s), found " + node.getChildCount());
+ }
+ for (int i = 0; i < node.getChildCount(); i++) {
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(i), true));
+ }
+ source.add(new Bytecode(context, push ? 0x26 : 0x25, node.getText().toUpperCase()));
+ return source;
}
-
- int bitfield = -1;
- if (bitfieldNode != null) {
- bitfield = compileBitfield(context, method, bitfieldNode, source);
+ if ("COGNEW".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() != 2) {
+ throw new RuntimeException("expected " + 2 + " argument(s), found " + node.getChildCount());
+ }
+ source.add(new Constant(context, new NumberLiteral(16)));
+ for (int i = 0; i < node.getChildCount(); i++) {
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(i), true));
+ }
+ source.add(new Bytecode(context, push ? 0x26 : 0x25, node.getText().toUpperCase()));
+ return source;
}
+ if ("COGSPIN".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() != 3) {
+ throw new RuntimeException("expected " + 3 + " argument(s), found " + node.getChildCount());
+ }
- Expression expression = null;
- try {
- expression = buildConstantExpression(context, node.getChild(0), true);
- } catch (Exception e) {
- // Do nothing
- }
- if (expression == null) {
- throw new CompilerException("expected constant expression", node.getChild(0).getToken());
- }
+ source.addAll(compileConstantExpression(context, method, node.getChild(0)));
- int index = 0;
- boolean popIndex = indexNode != null;
- if (indexNode != null) {
- try {
- Expression exp = buildConstantExpression(context, indexNode);
- if (exp.isConstant()) {
- index = exp.getNumber().intValue();
- popIndex = false;
- }
- } catch (Exception e) {
- // Do nothing
+ Spin2StatementNode methodNode = node.getChild(1);
+ Expression expression = context.getLocalSymbol(methodNode.getText());
+ if (!(expression instanceof Method)) {
+ throw new CompilerException("invalid method " + methodNode.getText(), methodNode.getToken());
}
- if (popIndex) {
- source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ int actual = getArgumentsCount(context, methodNode);
+ if (actual != ((Method) expression).getArgumentsCount()) {
+ throw new CompilerException("expected " + ((Method) expression).getArgumentsCount() + " argument(s), found " + actual, methodNode.getToken());
}
- }
+ for (int i = 0; i < methodNode.getChildCount(); i++) {
+ source.addAll(compileConstantExpression(context, method, methodNode.getChild(i)));
+ }
+ source.add(new SubAddress(context, (Method) expression, false));
+ Spin2Method calledMethod = (Spin2Method) expression.getData(Spin2Method.class.getName());
+ calledMethod.setCalledBy(method);
- RegisterOp.Op op = bitfieldNode == null && postEffectNode == null ? (push ? RegisterOp.Op.Read : RegisterOp.Op.Write) : RegisterOp.Op.Setup;
- source.add(new RegisterOp(context, op, popIndex, expression, index));
+ source.addAll(compileConstantExpression(context, method, node.getChild(2)));
- if (bitfieldNode != null) {
- source.add(new BitField(context, postEffectNode == null ? BitField.Op.Read : BitField.Op.Setup, bitfield));
- }
+ source.add(new Bytecode(context, new byte[] {
+ 0x19, 0x5A
+ }, node.getText().toUpperCase()));
- if (postEffectNode != null) {
- compilePostEffect(context, postEffectNode, source, push);
- }
- }
- else if ("FIELD".equalsIgnoreCase(node.getText()) && node.getChildCount() != 0) {
- Spin2StatementNode indexNode = null;
- Spin2StatementNode postEffectNode = null;
+ source.add(new Bytecode(context, new byte[] {
+ (byte) methodNode.getChildCount(), (byte) (push ? 0x26 : 0x25)
+ }, "POP_RETURN (???)"));
- int n = 1;
- if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
- indexNode = node.getChild(n++);
- }
- if (n < node.getChildCount() && isPostEffect(node.getChild(n))) {
- postEffectNode = node.getChild(n++);
- }
- if (n < node.getChildCount()) {
- throw new RuntimeException("syntax error");
+ return source;
}
+ if ("LOOKDOWN".equalsIgnoreCase(node.getText()) || "LOOKDOWNZ".equalsIgnoreCase(node.getText()) || "LOOKUP".equalsIgnoreCase(node.getText())
+ || "LOOKUPZ".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() == 0) {
+ throw new RuntimeException("expected argument(s), found none");
+ }
+ Spin2StatementNode argsNode = node.getChild(0);
+ if (!":".equalsIgnoreCase(argsNode.getText()) || argsNode.getChildCount() < 2) {
+ throw new RuntimeException("invalid argument(s)");
+ }
- source.addAll(compileConstantExpression(context, method, node.getChild(0)));
+ int code = 0x1F;
+ int code_range = 0x21;
+ if ("LOOKDOWN".equalsIgnoreCase(node.getText()) || "LOOKDOWNZ".equalsIgnoreCase(node.getText())) {
+ code = 0x20;
+ code_range = 0x22;
+ }
- if (indexNode != null) {
- source.addAll(compileConstantExpression(context, method, indexNode));
- }
+ Spin2Bytecode end = new Spin2Bytecode(context);
+ source.add(new Address(context, new ContextLiteral(end.getContext())));
- if (postEffectNode == null) {
- source.add(new Bytecode(context, new byte[] {
- (byte) (indexNode == null ? 0x4D : 0x4E),
- (byte) (push ? 0x80 : 0x81)
- }, "FIELD_" + (push ? "READ" : "WRITE")));
- }
- else {
- source.add(new Bytecode(context, new byte[] {
- (byte) (indexNode == null ? 0x4D : 0x4E)
- }, "FIELD_SETUP"));
- }
+ source.addAll(compileBytecodeExpression(context, method, argsNode.getChild(0), true));
- if (postEffectNode != null) {
- compilePostEffect(context, postEffectNode, source, push);
- }
- }
- else {
- String[] s = node.getText().split("[\\.]");
- if (s.length == 2 && ("BYTE".equalsIgnoreCase(s[1]) || "WORD".equalsIgnoreCase(s[1]) || "LONG".equalsIgnoreCase(s[1]))) {
- int index = 0;
- boolean popIndex = false;
- Spin2StatementNode indexNode = null;
- Spin2StatementNode bitfieldNode = null;
- Spin2StatementNode postEffectNode = null;
+ source.add(new Constant(context, new NumberLiteral(node.getText().toUpperCase().endsWith("Z") ? 0 : 1)));
- Expression expression = context.getLocalSymbol(s[0]);
- if (expression == null && isAbsoluteAddress(s[0])) {
- expression = context.getLocalSymbol(s[0].substring(2));
+ for (int i = 1; i < argsNode.getChildCount(); i++) {
+ Spin2StatementNode arg = argsNode.getChild(i);
+ if ("..".equals(arg.getText())) {
+ source.addAll(compileBytecodeExpression(context, method, arg.getChild(0), true));
+ source.addAll(compileBytecodeExpression(context, method, arg.getChild(1), true));
+ source.add(new Bytecode(context, code_range, node.getText().toUpperCase()));
+ }
+ else if (arg.getType() == Token.STRING) {
+ String s = arg.getText().substring(1, arg.getText().length() - 1);
+ for (int x = 0; x < s.length(); x++) {
+ source.add(new Constant(context, new CharacterLiteral(s.substring(x, x + 1))));
+ source.add(new Bytecode(context, code, node.getText().toUpperCase()));
+ }
+ }
+ else {
+ source.addAll(compileBytecodeExpression(context, method, arg, true));
+ source.add(new Bytecode(context, code, node.getText().toUpperCase()));
+ }
}
- if (expression == null && isAddress(s[0])) {
- expression = context.getLocalSymbol(s[0].substring(1));
+
+ source.add(new Bytecode(context, 0x23, "LOOKDONE"));
+ source.add(end);
+
+ return source;
+ }
+ if ("STRING".equalsIgnoreCase(node.getText()) || "LSTRING".equalsIgnoreCase(node.getText())) {
+ ByteArrayOutputStream sb = new ByteArrayOutputStream();
+ for (Spin2StatementNode child : node.getChilds()) {
+ if (child.getType() == Token.STRING) {
+ String s = child.getText().substring(1);
+ sb.write(s.substring(0, s.length() - 1).getBytes());
+ }
+ else {
+ Expression expression;
+ if (child.getType() == Token.NUMBER) {
+ expression = new NumberLiteral(child.getText());
+ }
+ else {
+ try {
+ expression = buildConstantExpression(context, child);
+ if (!expression.isConstant()) {
+ throw new CompilerException("expression is not constant", child.getTokens());
+ }
+ } catch (CompilerException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CompilerException("expression is not constant", child.getTokens());
+ }
+ }
+ if (expression.getNumber().intValue() < -0x80 || expression.getNumber().intValue() > 0xFF) {
+ logMessage(new CompilerException(CompilerException.WARNING, "byte value range from -$80 to $FF", child.getTokens()));
+ }
+ sb.write(expression.getByte());
+ }
}
- if (expression instanceof ObjectContextLiteral) {
- expression = context.getLocalSymbol(s[0].substring(1));
+ if (sb.size() > 254) {
+ logMessage(new CompilerException(CompilerException.ERROR, "string data cannot exceed 254 bytes", node.getTokens()));
}
- if (expression == null) {
- throw new CompilerException("undefined symbol " + node.getText(), node.getToken());
+ if ("STRING".equalsIgnoreCase(node.getText())) {
+ sb.write(0x00);
}
+ byte[] code = sb.toByteArray();
- int n = 0;
- if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
- indexNode = node.getChild(n++);
- }
- if (n < node.getChildCount() && ".".equals(node.getChild(n).getText())) {
- if (node.getText().startsWith("@")) {
- throw new CompilerException("bitfield expression not allowed", node.getChild(n).getToken());
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ os.write(0x9E);
+ if ("LSTRING".equalsIgnoreCase(node.getText())) {
+ os.write(code.length + 1);
+ }
+ os.write(code.length);
+ os.writeBytes(code);
+ source.add(new Bytecode(context, os.toByteArray(), node.getText().toUpperCase()));
+
+ return source;
+ }
+ if (("BYTES".equalsIgnoreCase(node.getText()) || "WORDS".equalsIgnoreCase(node.getText()) || "LONGS".equalsIgnoreCase(node.getText()))) {
+ byte[] code = compileTypes(context, node, node.getText().substring(0, node.getText().length() - 1));
+ if (code.length > 255) {
+ logMessage(new CompilerException(CompilerException.ERROR, "data cannot exceed 255 bytes", node.getTokens()));
+ }
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ os.write(0x9E);
+ os.write(code.length);
+ os.writeBytes(code);
+ source.add(new Bytecode(context, os.toByteArray(), node.getText().toUpperCase()));
+
+ return source;
+ }
+ if ("DEBUG".equalsIgnoreCase(node.getText())) {
+ int stack = 0;
+ for (Spin2StatementNode child : node.getChilds()) {
+ for (Spin2StatementNode param : child.getChilds()) {
+ source.addAll(compileBytecodeExpression(context, method, param, true));
+ stack += 4;
+ }
+ }
+ node.setData("context", context);
+ method.debugNodes.add(node);
+ compiler.debugStatements.add(node);
+
+ int pop = stack;
+ source.add(new Bytecode(context, 0x43, "") {
+
+ int index;
+
+ @Override
+ public int resolve(int address) {
+ index = compiler.debugStatements.indexOf(node) + 1;
+ if (index >= 255) {
+ throw new CompilerException("too much debug statements", node);
+ }
+ return super.resolve(address);
+ }
+
+ @Override
+ public int getSize() {
+ return index == -1 ? 0 : 3;
+ }
+
+ @Override
+ public byte[] getBytes() {
+ if (index == -1) {
+ return new byte[0];
+ }
+ return new byte[] {
+ 0x43, (byte) pop, (byte) index
+ };
+ }
+
+ @Override
+ public String toString() {
+ if (index == -1) {
+ return "";
+ }
+ return node.getText().toUpperCase() + " #" + index;
}
+
+ });
+ return source;
+ }
+ }
+
+ if ("CLKMODE".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() != 0) {
+ throw new CompilerException("syntax error", node);
+ }
+ source.add(new Constant(context, new NumberLiteral(0x40, 16)));
+ source.add(new MemoryOp(context, MemoryOp.Size.Long, MemoryOp.Base.Pop, MemoryOp.Op.Read, null));
+ return source;
+ }
+ if ("CLKFREQ".equalsIgnoreCase(node.getText())) {
+ source.add(new Bytecode(context, new byte[] {
+ 0x19, 0x58
+ }, node.getText().toUpperCase()));
+ return source;
+ }
+ if ("END".equalsIgnoreCase(node.getText())) {
+ // Ignored
+ return source;
+ }
+
+ if ("-".equalsIgnoreCase(node.getText()) && node.getChildCount() == 1) {
+ try {
+ Expression expression = buildConstantExpression(context, node);
+ source.add(new Constant(context, expression));
+ } catch (Exception e) {
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
+ source.add(new Bytecode(context, 0x79, "NEGATE"));
+ }
+ return source;
+ }
+ if ("-.".equalsIgnoreCase(node.getText()) && node.getChildCount() == 1) {
+ try {
+ Expression expression = buildConstantExpression(context, node);
+ source.add(new Constant(context, expression));
+ } catch (Exception e) {
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
+ source.add(new Bytecode(context, new byte[] {
+ 0x19, (byte) 0x94
+ }, "FLOAT_NEGATE"));
+ }
+ return source;
+ }
+ if (("+".equalsIgnoreCase(node.getText()) || "+.".equalsIgnoreCase(node.getText())) && node.getChildCount() == 1) {
+ try {
+ Expression expression = buildConstantExpression(context, node);
+ source.add(new Constant(context, expression));
+ } catch (Exception e) {
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
+ }
+ return source;
+ }
+ if ("-=".equalsIgnoreCase(node.getText()) && node.getChildCount() == 1) {
+ source.addAll(leftAssign(context, method, node.getChild(0), true, false));
+ if (push) {
+ source.add(new Bytecode(context, 0xB9, "NEGATE_ASSIGN (push)"));
+ }
+ else {
+ source.add(new Bytecode(context, 0x92, "NEGATE_ASSIGN"));
+ }
+ return source;
+ }
+ if (":=".equals(node.getText())) {
+ if (node.getChildCount() != 2) {
+ throw new RuntimeException("expression syntax error");
+ }
+ source.addAll(compileConstantExpression(context, method, node.getChild(1)));
+ source.addAll(leftAssign(context, method, node.getChild(0), push, push));
+ return source;
+ }
+ if (MathOp.isAssignMathOp(node.getText()) && node.getChildCount() == 1) {
+ source.addAll(leftAssign(context, method, node.getChild(0), true, false));
+ source.add(new MathOp(context, node.getText(), push));
+ return source;
+ }
+ if (MathOp.isAssignMathOp(node.getText())) {
+ source.addAll(compileConstantExpression(context, method, node.getChild(1)));
+ source.addAll(leftAssign(context, method, node.getChild(0), true, false));
+ source.add(new MathOp(context, node.getText(), push));
+ return source;
+ }
+ if (MathOp.isUnaryMathOp(node.getText())) {
+ if (node.getChildCount() != 1) {
+ throw new RuntimeException("expression syntax error");
+ }
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
+ source.add(new MathOp(context, node.getText(), push));
+ return source;
+ }
+ if (MathOp.isMathOp(node.getText())) {
+ if (node.getChildCount() != 2) {
+ throw new RuntimeException("expression syntax error");
+ }
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(1), true));
+ source.add(new MathOp(context, node.getText(), false));
+ return source;
+ }
+ if ("?".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() != 2) {
+ throw new RuntimeException("expression syntax error");
+ }
+ if (!":".equals(node.getChild(1).getText())) {
+ throw new RuntimeException("expression syntax error");
+ }
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(1).getChild(0), true));
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(1).getChild(1), true));
+ source.add(new Bytecode(context, 0x6B, "TERNARY_IF_ELSE"));
+ return source;
+ }
+ if ("_".equalsIgnoreCase(node.getText())) {
+ source.add(new Bytecode(context, 0x17, "POP"));
+ return source;
+ }
+ if ("(".equalsIgnoreCase(node.getText())) {
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), push));
+ return source;
+ }
+ if (",".equalsIgnoreCase(node.getText())) {
+ for (Spin2StatementNode child : node.getChilds()) {
+ source.addAll(compileBytecodeExpression(context, method, child, push));
+ }
+ return source;
+ }
+ if ("\\".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() == 2) {
+ source.addAll(compileConstantExpression(context, method, node.getChild(1)));
+ source.addAll(leftAssign(context, method, node.getChild(0), push, false));
+ source.add(new Bytecode(context, 0x8D, "SWAP"));
+ }
+ else {
+ if (node.getChildCount() != 1) {
+ throw new RuntimeException("expression syntax error");
+ }
+ Expression expression = context.getLocalSymbol(node.getChild(0).getText());
+
+ if (expression instanceof Method) {
+ source.addAll(compileMethodCall(context, method, expression, node.getChild(0), push, true));
+ }
+ else if (expression instanceof Variable) {
+ source.addAll(compileMethodCall(context, method, expression, node.getChild(0), push, true));
+ }
+ else if (expression instanceof DataVariable) {
+ source.addAll(compileMethodCall(context, method, expression, node.getChild(0), push, true));
+ }
+ else if ("BYTE".equalsIgnoreCase(node.getChild(0).getText()) || "WORD".equalsIgnoreCase(node.getChild(0).getText()) || "LONG".equalsIgnoreCase(node.getChild(0).getText())) {
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), push));
+ }
+ else {
+ throw new CompilerException("symbol " + node.getChild(0).getText() + " is not a method", node.getChild(0).getToken());
+ }
+ }
+ return source;
+ }
+ if ("++".equalsIgnoreCase(node.getText()) || "--".equalsIgnoreCase(node.getText()) || "??".equalsIgnoreCase(node.getText())) {
+ if (node.getChildCount() != 1) {
+ throw new RuntimeException("expression syntax error " + node.getText());
+ }
+
+ Spin2StatementNode childNode = node.getChild(0);
+
+ String[] s = childNode.getText().split("[\\.]");
+ if (s.length == 2 && ("BYTE".equalsIgnoreCase(s[1]) || "WORD".equalsIgnoreCase(s[1]) || "LONG".equalsIgnoreCase(s[1]))) {
+ Spin2StatementNode indexNode = null;
+ Spin2StatementNode bitfieldNode = null;
+
+ Expression expression = context.getLocalSymbol(s[0]);
+ if (expression == null) {
+ throw new CompilerException("undefined symbol " + node.getText(), node.getToken());
+ }
+
+ int n = 0;
+ if (n < childNode.getChildCount() && (childNode.getChild(n) instanceof Spin2StatementNode.Index)) {
+ indexNode = childNode.getChild(n++);
+ }
+ if (n < childNode.getChildCount() && ".".equals(childNode.getChild(n).getText())) {
n++;
- if (n >= node.getChildCount()) {
- throw new RuntimeException("expected bitfield expression");
+ if (n >= childNode.getChildCount()) {
+ throw new CompilerException("expected bitfield expression", childNode.getToken());
}
- if (!(node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ if (!(childNode.getChild(n) instanceof Spin2StatementNode.Index)) {
throw new RuntimeException("syntax error");
}
- bitfieldNode = node.getChild(n++);
+ bitfieldNode = childNode.getChild(n++);
}
- if (n < node.getChildCount() && isPostEffect(node.getChild(n))) {
- postEffectNode = node.getChild(n++);
+ if (n < childNode.getChildCount()) {
+ throw new RuntimeException("syntax error");
}
- if (n < node.getChildCount()) {
- throw new CompilerException("syntax error", node.getChild(n).getToken());
+
+ if (indexNode != null) {
+ source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ }
+
+ int bitfield = -1;
+ if (bitfieldNode != null) {
+ bitfield = compileBitfield(context, method, bitfieldNode, source);
}
MemoryOp.Size ss = MemoryOp.Size.Long;
@@ -924,282 +977,289 @@ else if ("WORD".equalsIgnoreCase(s[1])) {
bb = expression instanceof LocalVariable ? MemoryOp.Base.DBase : MemoryOp.Base.VBase;
((Variable) expression).setCalledBy(method);
}
+ source.add(new MemoryOp(context, ss, bb, MemoryOp.Op.Setup, indexNode != null, expression, 0));
- int bitfield = -1;
if (bitfieldNode != null) {
- bitfield = compileBitfield(context, method, bitfieldNode, source);
+ source.add(new BitField(context, BitField.Op.Setup, bitfield));
}
+ }
+ else if ("BYTE".equalsIgnoreCase(childNode.getText()) || "WORD".equalsIgnoreCase(childNode.getText()) || "LONG".equalsIgnoreCase(childNode.getText())) {
+ Spin2StatementNode indexNode = null;
+ Spin2StatementNode bitfieldNode = null;
- if (indexNode != null) {
- popIndex = true;
- try {
- Expression exp = buildConstantExpression(context, indexNode);
- if (exp.isConstant()) {
- index = exp.getNumber().intValue();
- popIndex = false;
- }
- } catch (Exception e) {
- // Do nothing
+ int n = 1;
+ if (n < childNode.getChildCount() && (childNode.getChild(n) instanceof Spin2StatementNode.Index)) {
+ indexNode = childNode.getChild(n++);
+ }
+ if (n < childNode.getChildCount() && ".".equals(childNode.getChild(n).getText())) {
+ n++;
+ if (n >= childNode.getChildCount()) {
+ throw new CompilerException("expected bitfield expression", childNode.getToken());
}
- if (popIndex) {
- source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ if (!(childNode.getChild(n) instanceof Spin2StatementNode.Index)) {
+ throw new RuntimeException("syntax error");
}
+ bitfieldNode = childNode.getChild(n++);
}
-
- if (s[0].startsWith("@")) {
- source.add(new MemoryOp(context, ss, bb, MemoryOp.Op.Address, popIndex, expression, index));
+ if (n < childNode.getChildCount()) {
+ throw new RuntimeException("syntax error");
}
- else {
- MemoryOp.Op op = bitfieldNode == null && postEffectNode == null ? (push ? MemoryOp.Op.Read : MemoryOp.Op.Write) : MemoryOp.Op.Setup;
- source.add(new MemoryOp(context, ss, bb, op, popIndex, expression, index));
+
+ source.addAll(compileBytecodeExpression(context, method, childNode.getChild(0), true));
+
+ if (indexNode != null) {
+ source.addAll(compileBytecodeExpression(context, method, indexNode, true));
}
+ int bitfield = -1;
if (bitfieldNode != null) {
- source.add(new BitField(context, postEffectNode == null ? BitField.Op.Read : BitField.Op.Setup, bitfield));
+ bitfield = compileBitfield(context, method, bitfieldNode, source);
}
- if (postEffectNode != null) {
- if ("++".equalsIgnoreCase(postEffectNode.getText())) {
- source.add(new Bytecode(context, push ? 0x87 : 0x83, "POST_INC" + (push ? " (push)" : "")));
- }
- else if ("--".equalsIgnoreCase(postEffectNode.getText())) {
- source.add(new Bytecode(context, push ? 0x88 : 0x84, "POST_DEC" + (push ? " (push)" : "")));
- }
- else if ("!!".equalsIgnoreCase(postEffectNode.getText())) {
- source.add(new Bytecode(context, push ? 0x8A : 0x89, "POST_LOGICAL_NOT" + (push ? " (push)" : "")));
- }
- else if ("!".equalsIgnoreCase(postEffectNode.getText())) {
- source.add(new Bytecode(context, push ? 0x8C : 0x8B, "POST_NOT" + (push ? " (push)" : "")));
- }
- else {
- throw new CompilerException("unhandled post effect " + postEffectNode.getText(), postEffectNode.getToken());
- }
+ MemoryOp.Size ss = MemoryOp.Size.Long;
+ if ("BYTE".equalsIgnoreCase(childNode.getText())) {
+ ss = MemoryOp.Size.Byte;
+ }
+ else if ("WORD".equalsIgnoreCase(childNode.getText())) {
+ ss = MemoryOp.Size.Word;
+ }
+ source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, MemoryOp.Op.Setup, indexNode != null));
+
+ if (bitfieldNode != null) {
+ source.add(new BitField(context, BitField.Op.Setup, bitfield));
}
}
else {
- Expression expression = context.getLocalSymbol(node.getText());
- if (expression == null && isAbsoluteAddress(node.getText())) {
- expression = context.getLocalSymbol(node.getText().substring(2));
+ Expression expression = context.getLocalSymbol(childNode.getText());
+ if (expression == null) {
+ throw new CompilerException("unsupported operation on " + childNode.getText(), childNode.getToken());
}
- if (expression == null && isAddress(node.getText())) {
- expression = context.getLocalSymbol(node.getText().substring(1));
+ source.addAll(compileVariableSetup(context, method, expression, childNode));
+ }
+ if ("++".equalsIgnoreCase(node.getText())) {
+ source.add(new Bytecode(context, push ? 0x85 : 0x83, "PRE_INC" + (push ? " (push)" : "")));
+ }
+ else if ("--".equalsIgnoreCase(node.getText())) {
+ source.add(new Bytecode(context, push ? 0x86 : 0x84, "PRE_DEC" + (push ? " (push)" : "")));
+ }
+ else if ("??".equalsIgnoreCase(node.getText())) {
+ source.add(new Bytecode(context, push ? 0x8F : 0x8E, "PRE_RND" + (push ? " (push)" : "")));
+ }
+ return source;
+ }
+ if ("BYTE".equalsIgnoreCase(node.getText()) || "WORD".equalsIgnoreCase(node.getText()) || "LONG".equalsIgnoreCase(node.getText())
+ || "@BYTE".equalsIgnoreCase(node.getText()) || "@WORD".equalsIgnoreCase(node.getText()) || "@LONG".equalsIgnoreCase(node.getText())
+ || "@@BYTE".equalsIgnoreCase(node.getText()) || "@@WORD".equalsIgnoreCase(node.getText()) || "@@LONG".equalsIgnoreCase(node.getText())) {
+ Spin2StatementNode indexNode = null;
+ Spin2StatementNode bitfieldNode = null;
+ Spin2StatementNode postEffectNode = null;
+
+ int n = 1;
+ if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ indexNode = node.getChild(n++);
+ }
+ if (n < node.getChildCount() && ".".equals(node.getChild(n).getText())) {
+ if (node.getText().startsWith("@")) {
+ throw new CompilerException("bitfield expression not allowed", node.getChild(n).getToken());
}
- if (expression == null && node.getText().startsWith("^@")) {
- expression = context.getLocalSymbol(node.getText().substring(2));
+ n++;
+ if (n >= node.getChildCount()) {
+ throw new RuntimeException("expected bitfield expression");
}
- if (expression instanceof ObjectContextLiteral) {
- expression = context.getLocalSymbol(node.getText().substring(1));
+ if (!(node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ throw new RuntimeException("syntax error");
}
- if (expression == null) {
- throw new CompilerException("undefined symbol " + node.getText(), node.getToken());
+ bitfieldNode = node.getChild(n++);
+ }
+
+ if (node.isMethod()) {
+ if (node.getParent() != null && node.getParent().getText().startsWith("\\")) {
+ source.add(new Bytecode(context, push ? 0x03 : 0x02, "ANCHOR_TRAP"));
+ }
+ else {
+ source.add(new Bytecode(context, push ? 0x01 : 0x00, "ANCHOR"));
}
- if (expression instanceof SpinObject) {
- Spin2StatementNode indexNode = null;
- Spin2StatementNode methodNode = null;
- int n = 0;
- if (n < node.getChildCount()) {
- if (node.getChild(n) instanceof Spin2StatementNode.Index) {
- indexNode = node.getChild(n++);
- }
- }
- if (n < node.getChildCount()) {
- methodNode = node.getChild(n++);
- }
- if (n < node.getChildCount() || methodNode == null) {
- throw new CompilerException("syntax error", node.getTokens());
+ while (n < node.getChildCount()) {
+ if (!(node.getChild(n) instanceof Spin2StatementNode.Argument)) {
+ throw new CompilerException("syntax error", node.getChild(n));
}
+ source.addAll(compileConstantExpression(context, method, node.getChild(n++)));
+ }
+ }
+ else if (node.getText().startsWith("@")) {
+ if (n < node.getChildCount()) {
+ throw new CompilerException("syntax error", node.getChild(n).getToken());
+ }
+ }
- String qualifiedName = node.getText() + methodNode.getText();
+ if (n < node.getChildCount() && isPostEffect(node.getChild(n))) {
+ postEffectNode = node.getChild(n++);
+ }
+ if (n < node.getChildCount()) {
+ throw new RuntimeException("syntax error");
+ }
- expression = context.getLocalSymbol(qualifiedName);
- if (expression == null && isAddress(qualifiedName)) {
- expression = context.getLocalSymbol(qualifiedName.substring(1));
- }
- if (expression == null) {
- throw new CompilerException("undefined symbol " + methodNode.getText(), methodNode.getToken());
- }
- if (!(expression instanceof Method)) {
- throw new CompilerException(methodNode.getText() + " is not a method", methodNode.getToken());
- }
- Method methodExpression = (Method) expression;
- Spin2Method calledMethod = (Spin2Method) methodExpression.getData(Spin2Method.class.getName());
- if (isAddress(node.getText())) {
- if (indexNode != null) {
- source.addAll(compileConstantExpression(context, method, indexNode));
- }
- source.add(new SubAddress(context, methodExpression, indexNode != null));
- calledMethod.setCalledBy(method);
- }
- else {
- source.add(new Bytecode(context, push ? 0x01 : 0x00, "ANCHOR"));
+ int bitfield = -1;
+ if (bitfieldNode != null) {
+ bitfield = compileBitfield(context, method, bitfieldNode, source);
+ }
- source.addAll(compileMethodArguments(context, method, calledMethod, methodNode));
- if (indexNode != null) {
- source.addAll(compileConstantExpression(context, method, indexNode));
- }
- source.add(new CallSub(context, methodExpression, indexNode != null));
- calledMethod.setCalledBy(method);
+ source.addAll(compileBytecodeExpression(context, method, node.getChild(0), true));
- if (push && methodExpression.getReturnsCount() == 0) {
- throw new RuntimeException("method doesn't return any value");
- }
- }
- return source;
+ if (indexNode != null) {
+ source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ }
+
+ MemoryOp.Size ss = MemoryOp.Size.Long;
+ if ("BYTE".equalsIgnoreCase(node.getText()) || "@BYTE".equalsIgnoreCase(node.getText()) || "@@BYTE".equalsIgnoreCase(node.getText())) {
+ ss = MemoryOp.Size.Byte;
+ }
+ else if ("WORD".equalsIgnoreCase(node.getText()) || "@WORD".equalsIgnoreCase(node.getText()) || "@@WORD".equalsIgnoreCase(node.getText())) {
+ ss = MemoryOp.Size.Word;
+ }
+
+ if (node.isMethod()) {
+ if (ss != MemoryOp.Size.Long) {
+ throw new RuntimeException("method pointers must be long");
}
- else if (expression instanceof Method) {
- if (isAddress(node.getText())) {
- Method methodExpression = (Method) expression;
- source.add(new SubAddress(context, methodExpression));
- Spin2Method calledMethod = (Spin2Method) methodExpression.getData(Spin2Method.class.getName());
- calledMethod.setCalledBy(method);
- }
- else {
- source.addAll(compileMethodCall(context, method, expression, node, push, false));
- }
+ source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, MemoryOp.Op.Read, indexNode != null));
+ source.add(new Bytecode(context, new byte[] {
+ (byte) 0x0B,
+ }, "CALL_PTR"));
+ }
+ else if (node.getText().startsWith("@@")) {
+ source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, MemoryOp.Op.Read, indexNode != null));
+ source.add(new Bytecode(context, 0x24, "ADD_PBASE"));
+ }
+ else if (node.getText().startsWith("@")) {
+ source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, MemoryOp.Op.Address, indexNode != null));
+ }
+ else {
+ MemoryOp.Op op = bitfieldNode == null && postEffectNode == null ? (push ? MemoryOp.Op.Read : MemoryOp.Op.Write) : MemoryOp.Op.Setup;
+ source.add(new MemoryOp(context, ss, MemoryOp.Base.Pop, op, indexNode != null));
+ }
+
+ if (bitfieldNode != null) {
+ source.add(new BitField(context, postEffectNode == null ? BitField.Op.Read : BitField.Op.Setup, bitfield));
+ }
+
+ if (postEffectNode != null) {
+ compilePostEffect(context, postEffectNode, source, push);
+ }
+ return source;
+ }
+ if ("REG".equalsIgnoreCase(node.getText())) {
+ Spin2StatementNode indexNode = null;
+ Spin2StatementNode bitfieldNode = null;
+ Spin2StatementNode postEffectNode = null;
+
+ int n = 1;
+ if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ indexNode = node.getChild(n++);
+ }
+ if (n < node.getChildCount() && ".".equals(node.getChild(n).getText())) {
+ n++;
+ if (n >= node.getChildCount()) {
+ throw new RuntimeException("expected bitfield expression");
}
- else if (expression instanceof Variable) {
- if (isAddress(node.getText())) {
- int index = 0;
- boolean popIndex = false;
- boolean hasIndex = false;
- Spin2StatementNode indexNode = null;
+ if (!(node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ throw new RuntimeException("syntax error");
+ }
+ bitfieldNode = node.getChild(n++);
+ }
- int n = 0;
- if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
- indexNode = node.getChild(n++);
- }
- if (n < node.getChildCount()) {
- throw new CompilerException("unexpected " + node.getChild(n).getText(), node.getChild(n));
- }
+ if (n < node.getChildCount() && isPostEffect(node.getChild(n))) {
+ postEffectNode = node.getChild(n++);
+ }
+ if (n < node.getChildCount()) {
+ throw new RuntimeException("syntax error");
+ }
- if (indexNode != null) {
- popIndex = true;
- try {
- Expression exp = buildConstantExpression(context, indexNode);
- if (exp.isConstant()) {
- index = exp.getNumber().intValue();
- hasIndex = true;
- popIndex = false;
- }
- } catch (Exception e) {
- // Do nothing
- }
- if (popIndex) {
- source.addAll(compileBytecodeExpression(context, method, indexNode, true));
- }
- }
+ int bitfield = -1;
+ if (bitfieldNode != null) {
+ bitfield = compileBitfield(context, method, bitfieldNode, source);
+ }
- VariableOp.Op op = VariableOp.Op.Address;
- if (node.getText().startsWith("@@")) {
- op = VariableOp.Op.PBaseAddress;
- }
+ Expression expression = null;
+ try {
+ expression = buildConstantExpression(context, node.getChild(0), true);
+ } catch (Exception e) {
+ // Do nothing
+ }
+ if (expression == null) {
+ throw new CompilerException("expected constant expression", node.getChild(0).getToken());
+ }
- source.add(new VariableOp(context, op, popIndex, (Variable) expression, hasIndex, index));
- }
- else {
- if (node instanceof Spin2StatementNode.Method) {
- source.addAll(compileMethodCall(context, method, expression, node, push, false));
- }
- else {
- source.addAll(compileVariableRead(context, method, expression, node, push));
- }
+ int index = 0;
+ boolean popIndex = indexNode != null;
+ if (indexNode != null) {
+ try {
+ Expression exp = buildConstantExpression(context, indexNode);
+ if (exp.isConstant()) {
+ index = exp.getNumber().intValue();
+ popIndex = false;
}
- ((Variable) expression).setCalledBy(method);
+ } catch (Exception e) {
+ // Do nothing
}
- else {
- if (isAddress(node.getText())) {
- int index = 0;
- boolean popIndex = false;
- Spin2StatementNode indexNode = null;
+ if (popIndex) {
+ source.addAll(compileBytecodeExpression(context, method, indexNode, true));
+ }
+ }
- int n = 0;
- if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
- indexNode = node.getChild(n++);
- }
- if (n < node.getChildCount()) {
- throw new CompilerException("unexpected " + node.getChild(n).getText(), node.getChild(n));
- }
+ RegisterOp.Op op = bitfieldNode == null && postEffectNode == null ? (push ? RegisterOp.Op.Read : RegisterOp.Op.Write) : RegisterOp.Op.Setup;
+ source.add(new RegisterOp(context, op, popIndex, expression, index));
- if (indexNode != null) {
- popIndex = true;
- try {
- Expression exp = buildConstantExpression(context, indexNode);
- if (exp.isConstant()) {
- index = exp.getNumber().intValue();
- popIndex = false;
- }
- } catch (Exception e) {
- // Do nothing
- }
- if (popIndex) {
- source.addAll(compileBytecodeExpression(context, method, indexNode, true));
- }
- }
+ if (bitfieldNode != null) {
+ source.add(new BitField(context, postEffectNode == null ? BitField.Op.Read : BitField.Op.Setup, bitfield));
+ }
- MemoryOp.Size ss = MemoryOp.Size.Long;
- MemoryOp.Base bb = MemoryOp.Base.PBase;
+ if (postEffectNode != null) {
+ compilePostEffect(context, postEffectNode, source, push);
+ }
+ return source;
+ }
+ if ("FIELD".equalsIgnoreCase(node.getText())) {
+ Spin2StatementNode indexNode = null;
+ Spin2StatementNode postEffectNode = null;
- if ((expression instanceof MemoryContextLiteral) && node.getText().startsWith("@@")) {
- expression = context.getLocalSymbol(node.getText().substring(1));
- }
- if (expression instanceof DataVariable) {
- switch (((DataVariable) expression).getType()) {
- case "BYTE":
- ss = MemoryOp.Size.Byte;
- break;
- case "WORD":
- ss = MemoryOp.Size.Word;
- break;
- }
- }
- else if (expression instanceof ObjectContextLiteral) {
- switch (((ObjectContextLiteral) expression).getType()) {
- case "BYTE":
- ss = MemoryOp.Size.Byte;
- break;
- case "WORD":
- ss = MemoryOp.Size.Word;
- break;
- }
- }
- if (isAbsoluteAddress(node.getText())) {
- source.add(new MemoryOp(context, ss, bb, MemoryOp.Op.Read, popIndex, expression, index));
- source.add(new Bytecode(context, 0x24, "ADD_PBASE"));
- }
- else {
- source.add(new MemoryOp(context, ss, bb, MemoryOp.Op.Address, popIndex, expression, index));
- }
- }
- else if (expression.isConstant()) {
- if (node.getChildCount() != 0) {
- throw new RuntimeException("syntax error");
- }
- source.add(new Constant(context, expression));
- }
- else if (expression instanceof Register) {
- source.addAll(compileVariableRead(context, method, expression, node, push));
- }
- else if (expression instanceof DataVariable) {
- if (node instanceof Spin2StatementNode.Method) {
- source.addAll(compileMethodCall(context, method, expression, node, push, false));
- }
- else {
- source.addAll(compileVariableRead(context, method, expression, node, push));
- }
- }
- else if (expression instanceof ContextLiteral) {
- source.addAll(compileVariableRead(context, method, expression, node, push));
- }
- else {
- if (node.getChildCount() != 0) {
- throw new RuntimeException("syntax error");
- }
- source.add(new MemoryOp(context, MemoryOp.Size.Long, MemoryOp.Base.PBase, MemoryOp.Op.Read, expression));
- }
- }
+ int n = 1;
+ if (n < node.getChildCount() && (node.getChild(n) instanceof Spin2StatementNode.Index)) {
+ indexNode = node.getChild(n++);
+ }
+ if (n < node.getChildCount() && isPostEffect(node.getChild(n))) {
+ postEffectNode = node.getChild(n++);
}
+ if (n < node.getChildCount()) {
+ throw new RuntimeException("syntax error");
+ }
+
+ source.addAll(compileConstantExpression(context, method, node.getChild(0)));
+
+ if (indexNode != null) {
+ source.addAll(compileConstantExpression(context, method, indexNode));
+ }
+
+ if (postEffectNode == null) {
+ source.add(new Bytecode(context, new byte[] {
+ (byte) (indexNode == null ? 0x4D : 0x4E),
+ (byte) (push ? 0x80 : 0x81)
+ }, "FIELD_" + (push ? "READ" : "WRITE")));
+ }
+ else {
+ source.add(new Bytecode(context, new byte[] {
+ (byte) (indexNode == null ? 0x4D : 0x4E)
+ }, "FIELD_SETUP"));
+ }
+
+ if (postEffectNode != null) {
+ compilePostEffect(context, postEffectNode, source, push);
+ }
+
+ return source;
}
+ throw new CompilerException("undefined symbol " + node.getText(), node.getToken());
} catch (CompilerException e) {
logMessage(e);
} catch (Exception e) {
diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2StatementNode.java b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2StatementNode.java
index dc92eb78..9a436bf4 100644
--- a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2StatementNode.java
+++ b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2StatementNode.java
@@ -24,6 +24,8 @@ public class Spin2StatementNode {
Token firstToken;
Token lastToken;
+ boolean method;
+
protected Map properties = new HashMap();
protected List childs = new ArrayList();
@@ -43,22 +45,7 @@ public Index(Spin2StatementNode node, Token firstToken, Token lastToken) {
this.childs.addAll(node.childs);
this.data = node.data;
this.keyedData = node.keyedData;
- }
- }
-
- public static class Method extends Spin2StatementNode {
-
- public Method(Token token) {
- super(token);
- }
-
- public Method(Spin2StatementNode node) {
- super(node.token);
- this.token.type = Token.FUNCTION;
- this.properties.putAll(node.properties);
- this.childs.addAll(node.childs);
- this.data = node.data;
- this.keyedData = node.keyedData;
+ this.method = node.method;
}
}
@@ -70,6 +57,7 @@ public Argument(Spin2StatementNode node) {
this.childs.addAll(node.childs);
this.data = node.data;
this.keyedData = node.keyedData;
+ this.method = node.method;
}
public Argument(Token token) {
@@ -81,6 +69,11 @@ public Spin2StatementNode(Token token) {
this.token = token;
}
+ public Spin2StatementNode(Token token, boolean method) {
+ this.token = token;
+ this.method = method;
+ }
+
public int getType() {
return token.type;
}
@@ -189,6 +182,14 @@ public void setData(String key, Object data) {
this.keyedData.put(key, data);
}
+ public boolean isMethod() {
+ return method;
+ }
+
+ public void setMethod(boolean method) {
+ this.method = method;
+ }
+
@Override
public String toString() {
int[] result = new int[] {
diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2TreeBuilder.java b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2TreeBuilder.java
index 60144e7a..85055366 100644
--- a/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2TreeBuilder.java
+++ b/modules/spin-tools/src/com/maccasoft/propeller/spin2/Spin2TreeBuilder.java
@@ -409,7 +409,7 @@ else if ("byte".equalsIgnoreCase(node.getText()) || "word".equalsIgnoreCase(node
}
else if ("(".equals(peek().getText())) {
next();
- node = new Spin2StatementNode.Method(node);
+ node.method = true;
if (peek() != null && ")".equals(peek().getText())) {
token = next();
if (peek() != null && peek().column == token.column + 1) {
diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spinc/Spin2CBytecodeCompiler.java b/modules/spin-tools/src/com/maccasoft/propeller/spinc/Spin2CBytecodeCompiler.java
index 9dcacf55..de4d4151 100644
--- a/modules/spin-tools/src/com/maccasoft/propeller/spinc/Spin2CBytecodeCompiler.java
+++ b/modules/spin-tools/src/com/maccasoft/propeller/spinc/Spin2CBytecodeCompiler.java
@@ -416,7 +416,7 @@ public List compileBytecodeExpression(Context context, Spin2Metho
List source = new ArrayList();
try {
- if (node instanceof Spin2StatementNode.Method) {
+ if (node.isMethod()) {
FunctionDescriptor desc = descriptors.get(node.getText());
if (desc != null) {
int actual = getArgumentsCount(context, node);
@@ -426,7 +426,7 @@ public List compileBytecodeExpression(Context context, Spin2Metho
for (int i = 0; i < node.getChildCount(); i++) {
if (isFloat(context, node.getChild(i))) {
logMessage(new CompilerException(CompilerException.WARNING, "float to integer conversion", node.getChild(i).getTokens()));
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "round"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "round"), true);
exp.getChilds().add(node.getChild(i));
source.addAll(compileConstantExpression(context, method, exp));
}
@@ -472,7 +472,7 @@ else if ("nan".equals(node.getText())) {
throw new RuntimeException("expected " + 1 + " argument(s), found " + actual);
}
if (!isFloat(context, node.getChild(0))) {
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "float"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "float"), true);
exp.getChilds().add(node.getChild(0));
source.addAll(compileConstantExpression(context, method, exp));
}
@@ -872,13 +872,13 @@ else if ("=".equals(node.getText())) {
boolean rightIsFloat = isFloat(context, node.getChild(1));
if (leftIsFloat && !rightIsFloat) {
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "float"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "float"), true);
exp.getChilds().add(node.getChild(1));
source.addAll(compileConstantExpression(context, method, exp));
}
else if (!leftIsFloat && rightIsFloat) {
logMessage(new CompilerException(CompilerException.WARNING, "float to integer conversion", node.getChild(0).getToken()));
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "round"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "round"), true);
exp.getChilds().add(node.getChild(1));
source.addAll(compileConstantExpression(context, method, exp));
}
@@ -897,13 +897,13 @@ else if (assignOperators.containsKey(node.getText())) {
Descriptor desc = assignOperators.get(node.getText());
if (leftIsFloat && !rightIsFloat) {
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "float"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "float"), true);
exp.getChilds().add(node.getChild(1));
source.addAll(compileConstantExpression(context, method, exp));
}
else if (!leftIsFloat && rightIsFloat) {
logMessage(new CompilerException(CompilerException.WARNING, "float to integer conversion", node.getChild(0).getToken()));
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "round"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "round"), true);
exp.getChilds().add(node.getChild(1));
source.addAll(compileConstantExpression(context, method, exp));
}
@@ -933,7 +933,7 @@ else if (operators.containsKey(node.getText())) {
}
if (!leftIsFloat && rightIsFloat) {
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "float"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "float"), true);
exp.getChilds().add(node.getChild(0));
source.addAll(compileBytecodeExpression(context, method, exp, true));
}
@@ -942,7 +942,7 @@ else if (operators.containsKey(node.getText())) {
}
if (leftIsFloat && !rightIsFloat) {
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "float"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "float"), true);
exp.getChilds().add(node.getChild(1));
source.addAll(compileConstantExpression(context, method, exp));
}
@@ -1087,7 +1087,7 @@ else if ("BYTE".equals(node.getText()) || "WORD".equals(node.getText()) || "LONG
bitfieldNode = node.getChild(n++);
}
- if (node instanceof Spin2StatementNode.Method) {
+ if (node.isMethod()) {
if (node.getParent() != null && node.getParent().getText().startsWith("\\")) {
source.add(new Bytecode(context, push ? 0x03 : 0x02, "ANCHOR_TRAP"));
}
@@ -1134,7 +1134,7 @@ else if ("WORD".equalsIgnoreCase(node.getText()) || "@WORD".equalsIgnoreCase(nod
ss = MemoryOp.Size.Word;
}
- if (node instanceof Spin2StatementNode.Method) {
+ if (node.isMethod()) {
if (ss != MemoryOp.Size.Long) {
throw new RuntimeException("method pointers must be long");
}
@@ -1554,7 +1554,7 @@ else if ("WORD".equalsIgnoreCase(variable.getType())) {
}
}
else {
- if (node instanceof Spin2StatementNode.Method) {
+ if (node.isMethod()) {
source.addAll(compileMethodCall(context, method, expression, node, push, false));
}
else {
@@ -1631,7 +1631,7 @@ else if (expression instanceof Register) {
source.addAll(compileVariableRead(context, method, expression, node, push));
}
else if (expression instanceof DataVariable) {
- if (node instanceof Spin2StatementNode.Method) {
+ if (node.isMethod()) {
source.addAll(compileMethodCall(context, method, expression, node, push, false));
}
else {
@@ -2390,13 +2390,13 @@ List compileMethodCall(Context context, Spin2Method method, Expre
boolean rightIsFloat = isFloat(context, node.getChild(i));
if (leftIsFloat && !rightIsFloat) {
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "float"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "float"), true);
exp.getChilds().add(node.getChild(i));
source.addAll(compileConstantExpression(context, method, exp));
}
else if (!leftIsFloat && rightIsFloat) {
logMessage(new CompilerException(CompilerException.WARNING, "float to integer conversion", node.getChild(i).getTokens()));
- Spin2StatementNode exp = new Spin2StatementNode.Method(new Token(Token.FUNCTION, "round"));
+ Spin2StatementNode exp = new Spin2StatementNode(new Token(Token.FUNCTION, "round"), true);
exp.getChilds().add(node.getChild(i));
source.addAll(compileConstantExpression(context, method, exp));
}
diff --git a/modules/spin-tools/src/com/maccasoft/propeller/spinc/Spin2CTreeBuilder.java b/modules/spin-tools/src/com/maccasoft/propeller/spinc/Spin2CTreeBuilder.java
index 2057cdf6..4f9b977f 100644
--- a/modules/spin-tools/src/com/maccasoft/propeller/spinc/Spin2CTreeBuilder.java
+++ b/modules/spin-tools/src/com/maccasoft/propeller/spinc/Spin2CTreeBuilder.java
@@ -298,7 +298,7 @@ Spin2StatementNode parseAtom() {
}
if ("sizeof".equals(token.getText())) {
- Spin2StatementNode node = new Spin2StatementNode.Method(next());
+ Spin2StatementNode node = new Spin2StatementNode(next(), true);
token = peek();
if (token != null && "(".equals(token.getText())) {
next();
@@ -406,7 +406,7 @@ else if (peek().getText().startsWith(".")) {
}
else if ("(".equals(peek().getText())) {
next();
- node = new Spin2StatementNode.Method(node);
+ node.setMethod(true);
if (peek() != null && ")".equals(peek().getText())) {
token = next();
if (peek() != null && peek().column == token.column + 1) {
diff --git a/pom.xml b/pom.xml
index 47cf3474..914b5098 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
com.maccasoft
spin-tools-ide
- 0.32.1
+ 0.33.0
pom
Integrated Development Environment for Parallax Propeller microcontrollers.
@@ -20,7 +20,7 @@
com.maccasoft
spin-tools
- 0.32.1
+ 0.33.0
runtime