Assembler { @Nonnull public static List<Instruction> parseAssembly(@Nonnull String input) { String[] lines = input.split("\\R"); List<Instruction> instructions = new ArrayList<>(); long currentLine = 0; for (String line : lines) { currentLine++; Matcher instructionMatcher = instructionPattern.matcher(line); Matcher directiveMatcher = directivePattern.matcher(line); if (instructionMatcher.matches()) { String opcode = instructionMatcher.group("opcode"); if (opcode != null && !opcodes.containsKey(opcode)) { throw new IllegalArgumentException("Opcode '" + opcode + "' is not recognised."); } Long operandInteger = null; if (instructionMatcher.group("constantoperand") != null) { operandInteger = tryParse(instructionMatcher.group("constantoperand")); } instructions.add(new Instruction(InstructionType.INSTRUCTION, instructionMatcher.group("label"), opcodes.get(opcode), operandInteger, instructionMatcher.group("labeloperand"), instructionMatcher.group("comment"), null, currentLine)); } else if (directiveMatcher.matches()) { instructions.add(new Instruction(InstructionType.DIRECTIVE, directiveMatcher.group("label"), null, null, null, directiveMatcher.group("comment"), directiveMatcher.group("directive"), currentLine)); } else { throw new IllegalArgumentException("Line '" + line + "' does not match the expected format."); } } return instructions; } private  Assembler(); @Nullable static AssemblerConfig loadConfig(@Nullable Reader configReader); static List<String> assemble(@Nonnull String input, @Nullable AssemblerConfig config, @Nonnull PrintStream logger, boolean insertIOConfiguration); @Nonnull static List<Instruction> parseAssembly(@Nonnull String input); static List<Instruction> insertIOConfiguration(List<Instruction> instructions, AssemblerConfig config); static List<Instruction> processDollarLabelOperands(List<Instruction> instructions); static List<Instruction> processChanDirectives(List<Instruction> instructions, AssemblerConfig config); static List<Instruction> processDataDirectives(List<Instruction> instructions); static Assembly makeLabelMap(List<Instruction> instructions); static Map<String, Long> getConfigLabels(@Nonnull AssemblerConfig config); static Assembly patchLabels(Assembly assembly); static List<Byte> processIndirectInstruction(Instruction instruction); static List<Byte> processDirectInstructionWithLabelOperand(Instruction instruction, Map<String, Long> labelMap); static byte processDirectInstructionWithConstantOperand(Instruction instruction); static List<Instruction> prefix(Instruction instruction); static ParseTree parseExpression(String expression, Function<AssemblerExpressionParser, ParseTree> startRule); final static long maxInt; final static long minInt; final static Pattern inputComment; final static Pattern instructionPattern; final static Pattern directivePattern; final static Pattern dollarPattern; static Map<String, Opcode> opcodes; }
@Test public void testParseAssembly() { String assembly = "GlobalVariable_global1:\n" + "#data 4\n" + "init: \n" + "ajw -11\n" + "ldc init~IL_35\n" + "ldc L0-L_StartP_7\n" + "ldc L0-$\n" + "ldlp $\n" + "startp \n" + "END: -- exit program"; List<Instruction> instructions = Assembler.parseAssembly(assembly); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, "GlobalVariable_global1", null, null, null, null, null, 1), instructions.get(0)); checkInstructionEquality( new Instruction(InstructionType.DIRECTIVE, null, null, null, null, null, "#data 4", 2), instructions.get(1)); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, "init", null, null, null, null, null, 3), instructions.get(2)); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, null, Assembler.opcodes.get("ajw"), -11L, null, null, null, 4), instructions.get(3)); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, null, Assembler.opcodes.get("ldc"), null, "init~IL_35", null, null, 5), instructions.get(4)); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, null, Assembler.opcodes.get("ldc"), null, "L0-L_StartP_7", null, null, 6), instructions.get(5)); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, null, Assembler.opcodes.get("ldc"), null, "L0-$", null, null, 7), instructions.get(6)); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, null, Assembler.opcodes.get("ldlp"), null, "$", null, null, 8), instructions.get(7)); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, null, Assembler.opcodes.get("startp"), null, null, null, null, 9), instructions.get(8)); checkInstructionEquality( new Instruction(InstructionType.INSTRUCTION, "END", null, null, null, "exit program", null, 10), instructions.get(9)); }