Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Parser seems to be working now.

Do not get confused that it doesn't get the same results as described in
the demo files, they are outdated. 
Example: IFN was 0x0d in the past, but with spec 1.7 it is now 0x13. And
so on.
  • Loading branch information...
commit 1fa42b2687c6f90527518b4eb6a3b972bf15fee3 1 parent 9e730d4
@NetzwergX authored
View
60 DCPU-16 Toolkit/src/net/teumert/dcpu16/toolkit/assembler/Parameter.java
@@ -31,7 +31,7 @@
REGISTER_NEXT_WORD_REFERENCE(5, true),
PUSH(1, false), POP(1, false),
PEEK(1, false),
- PICK(2, false),
+ PICK(2, true), // parameter b will be NUM_16, and therefore extending the instruction count. => WRONG
SP(1, false),
PC(1, false),
EX(1, false),
@@ -40,7 +40,7 @@
LITERAL_VALUE(1, false);
private int tokenNo;
- /** true, if this paramater extends the word count of the instruction by 1 */
+ /** true, if this parameter extends the word count of the instruction by 1 */
private boolean extendsInstructionLength;
private Type(int tokenNo, boolean extendsIL) {
@@ -75,4 +75,60 @@ public Parameter(Type type, Token... tokens) {
public Type getType() {
return type;
}
+
+ private enum REGISTER {
+ A, B, C, X, Y, Z, I , J;
+ }
+
+ public int assemble() {
+ // a parameter can always assemble himself.
+ // if a label was used in a parameter,
+ // it extends its instruction count and
+ // the label is inserted as new word.
+ switch(type) {
+ case REGISTER:
+ return REGISTER.valueOf(getTokens()[0].getRepresentation()).ordinal();
+ case REGISTER_REFERENCE:
+ return REGISTER.valueOf(getTokens()[1].getRepresentation()).ordinal() + 0x08;
+ case REGISTER_NEXT_WORD_REFERENCE:
+ if(tokens[3].type == TokenType.REGISTER) // workaround for unusual [A+0xYYYY] syntax
+ return REGISTER.valueOf(getTokens()[3].getRepresentation()).ordinal() + 0x10;
+ return REGISTER.valueOf(getTokens()[1].getRepresentation()).ordinal() + 0x10;
+ case PUSH:
+ return 0x18;
+ case PEEK:
+ return 0x19;
+ case PICK:
+ return 0x1a;
+ case PC:
+ return 0x1c;
+ case EX:
+ return 0x1d;
+ case NEXT_WORD_REFERENCE:
+ return 0x1e;
+ case NEXT_WORD_LITERAL:
+ return 0x1f;
+ case LITERAL_VALUE:
+ return (Integer.decode(tokens[0].getRepresentation()) + 0x20) /*& 0b0000000000011111*/;
+ }
+
+ return 0;
+ }
+
+ public String getExtendedInstructionWordRepresentation() {
+ switch(type) {
+ case REGISTER_NEXT_WORD_REFERENCE:
+ if(tokens[3].type == TokenType.REGISTER) // workaround for unusual [A+0xYYYY] syntax
+ return tokens[1].getRepresentation();
+ return tokens[3].getRepresentation();
+ case PICK:
+ return tokens[1].getRepresentation(); // 0 = PICK, 1 = n
+ case NEXT_WORD_REFERENCE:
+ return tokens[1].getRepresentation();
+ case NEXT_WORD_LITERAL:
+ return tokens[0].getRepresentation();
+ }
+
+ return "0";
+ }
}
View
215 DCPU-16 Toolkit/src/net/teumert/dcpu16/toolkit/assembler/Parser.java
@@ -29,24 +29,29 @@
import java.util.List;
import java.util.Map;
+import net.teumert.dcpu16.toolkit.assembler.Parameter.Type;
import net.teumert.javax.mutable.MutableInteger;
public class Parser {
private Token[][] tokens;
+ private List<Statement> statementList;
+
/**
* Table for symbols.
* Currently only used for labels.
*/
- private Map<String, MutableInteger> symbolTable = new HashMap<>();
+ private Map<String, Integer> symbolTable = new HashMap<>();
public Parser(Token[][] tokens) {
this.tokens = tokens;
}
- public Statement[] parse() {
- List<Statement> statementList = new ArrayList<>(tokens.length);
+
+
+ public int[] parse() {
+ statementList = new ArrayList<>(tokens.length);
/*
* Line desc:
@@ -65,25 +70,27 @@ public Parser(Token[][] tokens) {
// parameters might expand word count of an instruction
int wordCount = 0;
- for(int i = 0; i < tokens.length; i++) {
+ for(int i = 0; i < tokens.length; i++) {
+ //System.out.println("pass 1 line #" + (i+1));
List<Token> tokenList = Arrays.asList(tokens[i]);
Iterator<Token> lineIterator = tokenList.iterator();
Token token = lineIterator.next();
- if(token.type == TokenType.WHITESPACE)
+ if(token.type == TokenType.WHITESPACE) {
+ if(!lineIterator.hasNext())
+ continue;
token = lineIterator.next();
+ }
if(token.type == TokenType.COMMENT)
continue; // ignore full comment lines
else if(token.type == TokenType.LABEL) {
// store label
- symbolTable.put(token.getRepresentation(), new MutableInteger(wordCount));
- lineIterator.remove();
+ symbolTable.put(token.getRepresentation(), wordCount);
+ //lineIterator.remove();
+
+ token = nextNotWhitespace(lineIterator);
}
- token = lineIterator.next();
- if(token.type == TokenType.WHITESPACE)
- token = lineIterator.next();
-
// labels are handled by now
// so now has to come an OP
if(!(token.type == TokenType.OPERATOR))
@@ -101,15 +108,21 @@ else if(token.type == TokenType.LABEL) {
Parameter a, b;
a = b = null;
+ // parse p
+
if(type.isNBI()) {
- // only one param (b)
-
- // TODO parse parameter
+ // only one param
+ b = parseParameter(lineIterator);
+ // a is null
}
else {
- // two params
+ // two params
+ // parse a and b
- // TODO parse paremeter
+ a = parseParameter(lineIterator);
+ if(!lineIterator.next().getRepresentation().equals(","))
+ throw new Error("Syntax error in line #" +i + " at position " + token.getOffset() + "',' expected, " + token.getRepresentation() + " given.");
+ b = parseParameter(lineIterator);
if(a.getType().extendsInstructionLength())
wordCount++;
@@ -122,19 +135,171 @@ else if(token.type == TokenType.LABEL) {
statementList.add(new Statement(i, op, a, b));
}
- /*
- * Second pass:
- * We now have statements.
- * Retrieve final label addresses.
- */
+ //System.out.println("Symbols: " + symbolTable);
- /*
- * Third pass:
- * Parse statements, replace labels with addresses.
+ /**
+ * Second pass.
+ * Assemble. Replace labels with stored addresses.
*/
- return null;
+
+ int[] words = new int[wordCount];
+ int pc = 0;
+
+ for(Statement statement : statementList) {
+ Token op = statement.getOperator();
+ Parameter a = statement.getA(), b = statement.getB();
+ OperandType opType = OperandType.valueOf(op.getRepresentation());
+ int opMask = 0;
+ int aMask = 0;
+ int bMask = 0;
+
+ if(opType.isNBI()) {
+ bMask = opType.getBitmask() << 5;
+
+ } else {
+ opMask = opType.getBitmask();
+ aMask = a.assemble() << 4;
+ }
+ bMask = b.assemble() << 10;
+
+ /*System.out.println("###################################");
+ System.out.println(opType.name() + " " + (a != null ? a.getType().name() : "") + ", " + b.getType().name());
+ System.out.println(opType.name() + " " + Integer.toHexString(opType.getBitmask()) + " " + Integer.toBinaryString(opType.getBitmask()));
+ if (a != null) System.out.println(a.getType().name() + " " + Integer.toHexString(a.assemble()) + " " + Integer.toBinaryString(a.assemble()));
+ System.out.println(b.getType().name() + " " + Integer.toHexString(b.assemble()) + " " + Integer.toBinaryString(b.assemble()));*/
+
+ int instruction = opMask | aMask | bMask;
+ /*System.out.println(Integer.toHexString(instruction));
+ if(a != null && a.getType().extendsInstructionLength()) System.out.println(a.getExtendedInstructionWordRepresentation());
+ if(b.getType().extendsInstructionLength()) System.out.println(b.getExtendedInstructionWordRepresentation());*/
+
+ // insert extended word if necessary.
+ words[pc++] = instruction;
+ if(a != null && a.getType().extendsInstructionLength()){
+ String s = a.getExtendedInstructionWordRepresentation();
+ if(symbolTable.containsKey(s))
+ words[pc++] = symbolTable.get(s);
+ else {
+ words[pc++] = Integer.decode(s);
+ }
+
+ }
+ if(b.getType().extendsInstructionLength()) {
+ String s = b.getExtendedInstructionWordRepresentation();
+ if(symbolTable.containsKey(s))
+ words[pc++] = symbolTable.get(s);
+ else {
+ words[pc++] = Integer.decode(s);
+ }
+ }
+ }
+
+ return words;
+ }
+
+ private Parameter parseParameter(Iterator<Token> tokens) {
+ Token token = nextNotWhitespace(tokens);
+ List<Token> tl = null;
+
+ switch(token.type) {
+ case REGISTER:
+ // workaround for SP PC and EX being recognized as REGISTER
+ if(token.getRepresentation().equalsIgnoreCase("SP"))
+ return new Parameter(Type.SP, token);
+ else if(token.getRepresentation().equalsIgnoreCase("PC"))
+ return new Parameter(Type.PC, token);
+ else if(token.getRepresentation().equalsIgnoreCase("EX"))
+ return new Parameter(Type.EX, token);
+ return new Parameter(Type.REGISTER, token);
+
+ case NUM_INT_HEX_5: case NUM_INT_DEC_5: case NUM_INT_OCTAL_5:
+ return new Parameter(Type.LITERAL_VALUE, token);
+
+ case NUM_INT_HEX_16: case NUM_INT_DEC_16: case NUM_INT_OCTAL_16:
+ return new Parameter(Type.NEXT_WORD_LITERAL, token);
+
+ case LABEL:
+ // workaround for PUSH, POP, PEEK and PICK being recognized as LABEL
+ if(token.getRepresentation().equalsIgnoreCase("PUSH"))
+ return new Parameter(Type.PUSH, token);
+ else if (token.getRepresentation().equalsIgnoreCase("POP"))
+ return new Parameter(Type.POP, token);
+ else if(token.getRepresentation().equalsIgnoreCase("PICK")) // FIXME Syntax is 'PICK n', not 'PICK, b'
+ return new Parameter(Type.PICK, token);
+ else if(token.getRepresentation().equalsIgnoreCase("PEEK"))
+ return new Parameter(Type.PEEK, token);
+ // when 'PICK' is recognized, the next parameter MUST be NUM_16
+ // => validate that in second pass!
+ return new Parameter(Type.NEXT_WORD_REFERENCE, new Token[]{new Token("[", TokenType.LEFT_BRACKET, -1, -1), token, new Token("]", TokenType.RIGHT_BRACKET, -1, -1)});
+
+ // these are all simple cases
+ // now the multiple token cases are starting
+ case LEFT_BRACKET:
+ tl = new ArrayList<>(5);
+ tl.add(token);
+ token = nextNotWhitespace(tokens);
+ if(token.type == TokenType.REGISTER) {
+ tl.add(token);
+ if(((token = nextNotWhitespace(tokens)).type == TokenType.SIGN_PLUS)) {
+ tl.add(token);
+ token = tokens.next();
+ if(token.type == TokenType.NUM_INT_HEX_16
+ || token.type == TokenType.NUM_INT_DEC_16
+ || token.type == TokenType.NUM_INT_OCTAL_16
+ || token.type == TokenType.NUM_INT_HEX_5
+ || token.type == TokenType.NUM_INT_DEC_5
+ || token.type == TokenType.NUM_INT_OCTAL_5) {
+ tl.add(token);
+ if(((token = nextNotWhitespace(tokens)).type == TokenType.RIGHT_BRACKET)) {
+ tl.add(token);
+ return new Parameter(Type.REGISTER_NEXT_WORD_REFERENCE, tl.toArray(new Token[]{}));
+ }
+ }
+ } else if(((token /*= nextNotWhitespace(tokens)*/).type == TokenType.RIGHT_BRACKET)) {
+ tl.add(token);
+ return new Parameter(Type.REGISTER_REFERENCE, tl.toArray(new Token[]{}));
+ }
+ } else if(token.type == TokenType.NUM_INT_HEX_16
+ || token.type == TokenType.NUM_INT_DEC_16
+ || token.type == TokenType.NUM_INT_OCTAL_16
+ || token.type == TokenType.NUM_INT_HEX_5
+ || token.type == TokenType.NUM_INT_DEC_5
+ || token.type == TokenType.NUM_INT_OCTAL_5) {
+ tl.add(token);
+ token = nextNotWhitespace(tokens);
+ if(((token).type == TokenType.RIGHT_BRACKET)) {
+ tl.add(token);
+ return new Parameter(Type.NEXT_WORD_REFERENCE, tl.toArray(new Token[]{}));
+ } else if(token.type == TokenType.SIGN_PLUS) {
+ tl.add(token);
+ if(((token = nextNotWhitespace(tokens)).type == TokenType.REGISTER)) {
+ tl.add(token);
+ if(((token = nextNotWhitespace(tokens)).type == TokenType.RIGHT_BRACKET)) {
+ tl.add(token);
+ return new Parameter(Type.REGISTER_NEXT_WORD_REFERENCE, tl.toArray(new Token[]{}));
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ // just break and go to error
+ break;
+ }
+ throw new Error("Syntax error near " + (tl == null ? token: tl));
}
+ public List<Statement> getStatementList() {
+ return statementList;
+ }
+ public Token nextNotWhitespace(Iterator<Token> iterator) {
+ Token t;
+ do {
+ t = iterator.next();
+ } while(t.type == TokenType.WHITESPACE);
+ return t;
+ }
}
View
7 DCPU-16 Toolkit/src/net/teumert/dcpu16/toolkit/assembler/TestAssembler.java
@@ -26,6 +26,13 @@ public static void main(String[] args) {
for(Token[] t : new Tokenizer(sb.toString()).tokenize()) {
System.out.println(Arrays.asList(t));
}
+
+ int[] words = new Parser(new Tokenizer(sb.toString()).tokenize()).parse();
+ for (int i = 0; i < words.length; i++) {
+ int j = words[i];
+ System.out.println(Integer.toHexString(j));
+
+ }
}
}
View
2  DCPU-16 Toolkit/src/net/teumert/dcpu16/toolkit/assembler/Tokenizer.java
@@ -242,7 +242,7 @@ else if(no <= 0xffff)
}
} // label
- else if(cur.matches("[a-zA-Z0-9_]+")) {
+ else if(cur.matches("[a-zA-Z0-9_]+")) {
type = TokenType.LABEL;
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.