From a2d856b65d293abe4211281ae7851b05b8adbefe Mon Sep 17 00:00:00 2001 From: Marco Maccaferri Date: Wed, 15 Nov 2023 07:51:18 +0100 Subject: [PATCH] Bytecode compiler refactoring to allow keywords override --- build/pom.xml | 2 +- modules/spin-tools/pom.xml | 2 +- .../spin2/Spin2ObjectCompilerTest.java | 190 +- .../com/maccasoft/propeller/SourceEditor.java | 62 +- .../com/maccasoft/propeller/SpinTools.java | 2 +- .../propeller/spin2/Spin2Bytecode.java | 2 +- .../spin2/Spin2BytecodeCompiler.java | 1872 +++++++++-------- .../propeller/spin2/Spin2StatementNode.java | 33 +- .../propeller/spin2/Spin2TreeBuilder.java | 2 +- .../spinc/Spin2CBytecodeCompiler.java | 30 +- .../propeller/spinc/Spin2CTreeBuilder.java | 4 +- pom.xml | 4 +- 12 files changed, 1196 insertions(+), 1009 deletions(-) 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