Assembler { public static List<Byte> processDirectInstructionWithLabelOperand(Instruction instruction, Map<String, Long> labelMap) { if (instruction.labelOperand == null) { throw new IllegalArgumentException("Label operand cannot be null"); } Long labelOp = null; if (labelMap.containsKey(instruction.labelOperand)) { labelOp = labelMap.get(instruction.labelOperand); } else { ExpressionEvaluator evaluator = new ExpressionEvaluator(labelMap); ParseTree expressionTree = parseExpression(instruction.labelOperand, AssemblerExpressionParser::expression); if (expressionTree != null) { labelOp = evaluator.visit(expressionTree); } else { throw new IllegalArgumentException("Invalid label operand '" + instruction.labelOperand + "'"); } } if (labelOp < minInt || labelOp > maxInt) { throw new IllegalArgumentException("Label '" + instruction.labelOperand + "' (" + labelOp + ") is out of range"); } List<Instruction> prefix = new ArrayList<>(prefix(new Instruction(instruction.type, instruction.label, instruction.opcode, labelOp, null, instruction.comment, instruction.directive, instruction.originalLine))); while (prefix.size() < 8) { prefix.add(0, new Instruction(InstructionType.INSTRUCTION, null, opcodes.get("pfix"), 0L, null, null, null, instruction.originalLine)); } return prefix .stream() .map(Assembler::processDirectInstructionWithConstantOperand) .collect(Collectors.toList()); } 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 testProcessDirectInstructionWithLabelOperand() { Map<String, Long> labelMap = new HashMap<>(); labelMap.put("somelabel", 20L); List<Byte> result = Assembler.processDirectInstructionWithLabelOperand(new Instruction(InstructionType.INSTRUCTION, "alabel", Assembler.opcodes.get("cj"), null, "somelabel", "a comment", null, 1), labelMap); assertEquals(new Byte((byte) 0x20), result.get(0)); assertEquals(new Byte((byte) 0x20), result.get(1)); assertEquals(new Byte((byte) 0x20), result.get(2)); assertEquals(new Byte((byte) 0x20), result.get(3)); assertEquals(new Byte((byte) 0x20), result.get(4)); assertEquals(new Byte((byte) 0x20), result.get(5)); assertEquals(new Byte((byte) 0x21), result.get(6)); assertEquals(new Byte((byte) 0xA4), result.get(7)); assertEquals(8, result.size()); }