-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[#201] First draft on SSEM ANTLR4 parser
- Loading branch information
Showing
11 changed files
with
386 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
src/main/java/net/emustudio/plugins/compiler/ssem/LexerImpl.java | ||
*.tokens |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
lexer grammar SSEMLexer; | ||
|
||
tokens { | ||
COMMENT, | ||
EOL, | ||
JMP, JRP, JPR, JMR, LDN, STO, SUB, CMP, SKN, STP, HLT, | ||
START, NUM, BNUM, | ||
NUMBER, HEXNUMBER | ||
} | ||
|
||
WS : (' ' | '\t') -> skip; | ||
COMMENT: ('//' | '--' | ';' | '#' ) ~[\r\n]*; | ||
EOL: '\r'? '\n'; | ||
|
||
fragment J: [jJ]; | ||
fragment M: [mM]; | ||
fragment P: [pP]; | ||
fragment R: [rR]; | ||
fragment L: [lL]; | ||
fragment D: [dD]; | ||
fragment N: [nN]; | ||
fragment S: [sS]; | ||
fragment T: [tT]; | ||
fragment O: [oO]; | ||
fragment U: [uU]; | ||
fragment B: [bB]; | ||
fragment C: [cC]; | ||
fragment K: [kK]; | ||
fragment H: [hH]; | ||
fragment A: [aA]; | ||
fragment I: [iI]; | ||
|
||
// reserved | ||
JMP: J M P; | ||
JRP: J R P; | ||
JPR: J P R; | ||
JMR: J M R; | ||
LDN: L D N; | ||
STO: S T O; | ||
SUB: S U B; | ||
CMP: C M P; | ||
SKN: S K N; | ||
STP: S T P; | ||
HLT: H L T; | ||
|
||
// preprocessor | ||
START: S T A R T; | ||
NUM: N U M; | ||
BNUM: ((B N U M) | (B I N S)) -> pushMode(BIN); | ||
|
||
// literals | ||
NUMBER: [\-]? [0-9]+; | ||
HEXNUMBER: [\-]? ('0x'|'0X') [0-9a-fA-F]+; | ||
|
||
mode BIN; | ||
BWS : (' ' | '\t') -> skip; | ||
BinaryNumber: [01]+ -> popMode; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
parser grammar SSEMParser; | ||
|
||
options { | ||
tokenVocab = SSEMLexer; | ||
} | ||
|
||
start: | ||
(line EOL line)* EOF | ||
| line EOF | ||
; | ||
|
||
line: | ||
linenumber=(NUMBER|HEXNUMBER) command=statement? comment | ||
| comment | ||
; | ||
|
||
comment: COMMENT? ; | ||
|
||
statement: | ||
instr=START | ||
| instr=JPR operand=(NUMBER|HEXNUMBER) | ||
| instr=LDN operand=(NUMBER|HEXNUMBER) | ||
| instr=STO operand=(NUMBER|HEXNUMBER) | ||
| instr=SUB operand=(NUMBER|HEXNUMBER) | ||
| instr=CMP | ||
| instr=STP | ||
| instr=NUM operand=(NUMBER|HEXNUMBER) | ||
| instr=BNUM operand=BinaryNumber | ||
; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
...compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/CodeGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package net.emustudio.plugins.compiler.ssem.ast; | ||
|
||
import net.emustudio.emulib.runtime.helpers.NumberUtils; | ||
import net.emustudio.plugins.compiler.ssem.CompileException; | ||
import net.emustudio.plugins.compiler.ssem.SSEMParser; | ||
|
||
import java.nio.ByteBuffer; | ||
|
||
public class CodeGenerator { | ||
private final ByteBuffer code = ByteBuffer.allocate(33 * 4); // one is for start line | ||
|
||
public ByteBuffer generateCode(Program program) { | ||
code.position(0); | ||
code.putInt(program.getStartLine()); | ||
|
||
program.forEach((line, instruction) -> { | ||
code.position(4 * line); | ||
if (instruction.tokenType == SSEMParser.BNUM || instruction.tokenType == SSEMParser.NUM) { | ||
code.putInt(instruction.operand); | ||
} else { | ||
writeInstruction(instruction.getOpcode(), instruction.operand); | ||
} | ||
}); | ||
return code.clear(); | ||
} | ||
|
||
private void writeInstruction(int opcode, int operand) { | ||
if (operand < 0 || operand > 31) { | ||
throw new CompileException("Operand must be between <0, 31>; it was " + operand); | ||
} | ||
|
||
byte address = (byte)(NumberUtils.reverseBits((byte)(operand & 0xFF), 8) & 0xF8); | ||
// 5 bits address + 3 empty bits | ||
code.put(address); | ||
// next: 5 empty bits + 3 bit instruction | ||
code.put((byte)(opcode & 0xFF)); | ||
// 16 empty bits | ||
code.put((byte)0); | ||
code.put((byte)0); | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
...s/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Instruction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package net.emustudio.plugins.compiler.ssem.ast; | ||
|
||
import net.emustudio.plugins.compiler.ssem.CompileException; | ||
import net.emustudio.plugins.compiler.ssem.SSEMParser; | ||
import net.jcip.annotations.Immutable; | ||
|
||
import java.util.Map; | ||
|
||
@Immutable | ||
public class Instruction { | ||
private final static Map<Integer, Byte> OPCODES = Map.of( | ||
SSEMParser.JMP, (byte)0, // 000 | ||
SSEMParser.SUB, (byte)1, // 001 | ||
SSEMParser.LDN, (byte)2, // 010 | ||
SSEMParser.CMP, (byte)3, // 011 | ||
SSEMParser.JRP, (byte)4, // 100 | ||
SSEMParser.STO, (byte)6, // 110 | ||
SSEMParser.STP, (byte)7, // 111, | ||
SSEMParser.BNUM, (byte)0, | ||
SSEMParser.NUM, (byte)0 | ||
); | ||
|
||
public final int tokenType; | ||
public final int operand; | ||
|
||
public Instruction(int tokenType) { | ||
if (!OPCODES.containsKey(tokenType)) { | ||
throw new CompileException("Unknown instruction"); | ||
} | ||
this.tokenType = tokenType; | ||
this.operand = 0; | ||
} | ||
|
||
public Instruction(int tokenType, int operand) { | ||
if (!OPCODES.containsKey(tokenType)) { | ||
throw new CompileException("Unknown instruction"); | ||
} | ||
this.tokenType = tokenType; | ||
this.operand = operand; | ||
} | ||
|
||
public int getOpcode() { | ||
return OPCODES.get(tokenType); | ||
} | ||
|
||
public String toString() { | ||
return String.format("%02d %02d", getOpcode(), operand); | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
plugins/compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/Program.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package net.emustudio.plugins.compiler.ssem.ast; | ||
|
||
import net.emustudio.plugins.compiler.ssem.CompileException; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.function.BiConsumer; | ||
|
||
public class Program { | ||
private int startLine; | ||
private boolean startLineDefined; | ||
|
||
private final Map<Integer, Instruction> instructions = new HashMap<>(); | ||
|
||
public void setStartLine(int startLine) { | ||
if (startLineDefined) { | ||
throw new CompileException("Start line is already defined!"); | ||
} | ||
this.startLine = startLine; | ||
startLineDefined = true; | ||
} | ||
|
||
public int getStartLine() { | ||
return startLine; | ||
} | ||
|
||
public void add(int line, Instruction instruction) { | ||
if (instructions.containsKey(line)) { | ||
throw new CompileException("Duplicate line definition: " + line); | ||
} | ||
if (line > 31) { | ||
throw new CompileException("Line number is out of bounds <0;31>: " + line); | ||
} | ||
instructions.put(line, instruction); | ||
} | ||
|
||
public void forEach(BiConsumer<Integer, Instruction> processor) { | ||
instructions.forEach(processor); | ||
} | ||
|
||
public String toString() { | ||
StringBuffer buffer = new StringBuffer(); | ||
buffer.append(startLine).append(" start\n"); | ||
forEach((line, instr) -> { | ||
buffer.append(String.format("%02d %s\n", line, instr)); | ||
}); | ||
return buffer.toString(); | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
...compiler/as-ssem/src/main/java/net/emustudio/plugins/compiler/ssem/ast/ProgramParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package net.emustudio.plugins.compiler.ssem.ast; | ||
|
||
import net.emustudio.plugins.compiler.ssem.SSEMParser; | ||
import net.emustudio.plugins.compiler.ssem.SSEMParserBaseVisitor; | ||
import org.antlr.v4.runtime.Token; | ||
|
||
public class ProgramParser extends SSEMParserBaseVisitor<Program> { | ||
private final Program program = new Program(); | ||
|
||
@Override | ||
public Program visitLine(SSEMParser.LineContext ctx) { | ||
if (ctx.linenumber != null) { | ||
int line = parseNumber(ctx.linenumber); | ||
|
||
if (ctx.command != null) { | ||
int operand = 0; | ||
if (ctx.command.operand != null) { | ||
if (ctx.command.instr.getType() == SSEMParser.BNUM) { | ||
operand = Integer.parseInt(ctx.command.operand.getText(), 2); | ||
} else { | ||
operand = parseNumber(ctx.command.operand); | ||
} | ||
} | ||
|
||
int instrType = ctx.command.instr.getType(); | ||
if (instrType == SSEMParser.START) { | ||
program.setStartLine(line); | ||
} else { | ||
program.add(line, new Instruction(instrType, operand)); | ||
} | ||
} | ||
} | ||
return program; | ||
} | ||
|
||
private int parseNumber(Token token) { | ||
if (token.getType() == SSEMParser.HEXNUMBER) { | ||
return Integer.decode(token.getText()); | ||
} else { | ||
// Do not use decode because we don't support octal numbers | ||
return Integer.parseUnsignedInt(token.getText()); | ||
} | ||
} | ||
|
||
public Program getProgram() { | ||
return program; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.