package org.reasm.m68k.assembly.internal; import java.io.IOException; import java.util.Iterator; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import org.reasm.AssemblyBuilder; import org.reasm.AssemblyStepLocation; import org.reasm.BlockEvents; import org.reasm.Symbol; import org.reasm.commons.source.SourceLocationUtils; import org.reasm.messages.UnknownMnemonicErrorMessage; import org.reasm.source.SourceLocation; import org.reasm.source.SourceNode; /** * Provides the implementation for assembling the various {@link SourceNode} subclasses defined in the * <code>org.reasm.m68k.source</code> package. * * @author Francis Gagné */ public final class SourceNodesImpl { /** * Assembles a directive that delimits a block. * * @param builder * an assembly builder * @throws IOException * an I/O exception occurred while assembling the directive */ public static void assembleBlockDirectiveLine(@Nonnull AssemblyBuilder builder) throws IOException { // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); context.setMnemonic(); String mnemonicName = context.mnemonic; if (mnemonicName.startsWith("!")) { mnemonicName = mnemonicName.substring(1); } assembleMnemonic(context, Mnemonics.MAP.get(mnemonicName), true); } /** * Assembles a <code>DO</code> block. * * @param builder * an assembly builder */ public static void assembleDoBlock(@Nonnull AssemblyBuilder builder) { final AssemblyStepLocation stepLocation = builder.getStep().getLocation(); // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); final DoBlockState doBlockState = new DoBlockState(); final Iterable<SourceLocation> sourceLocations = new Iterable<SourceLocation>() { @Override public Iterator<SourceLocation> iterator() { final DynamicSourceLocationIterator iterator = new DynamicSourceLocationIterator(stepLocation.getSourceLocation() .getChildSourceLocations().iterator()); context.blockStateMap.put(stepLocation, doBlockState); return iterator; } }; builder.enterBlock(sourceLocations, doBlockState, false, null); } /** * Assembles a <code>FOR</code> block. * * @param builder * an assembly builder */ public static void assembleForBlock(@Nonnull AssemblyBuilder builder) { final AssemblyStepLocation stepLocation = builder.getStep().getLocation(); // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); final ForBlockState forBlockState = new ForBlockState(); final Iterable<SourceLocation> sourceLocations = new Iterable<SourceLocation>() { @Override public Iterator<SourceLocation> iterator() { final DynamicSourceLocationIterator iterator = new DynamicSourceLocationIterator(stepLocation.getSourceLocation() .getChildSourceLocations().iterator()); forBlockState.iterator = iterator; context.blockStateMap.put(stepLocation, forBlockState); return iterator; } }; builder.enterBlock(sourceLocations, forBlockState, false, null); } /** * Assembles an <code>IF</code> block. * * @param builder * an assembly builder */ public static void assembleIfBlock(@Nonnull AssemblyBuilder builder) { final AssemblyStepLocation stepLocation = builder.getStep().getLocation(); // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); final Iterable<SourceLocation> sourceLocations = new Iterable<SourceLocation>() { @Override public Iterator<SourceLocation> iterator() { final DynamicSourceLocationIterator iterator = new DynamicSourceLocationIterator(stepLocation.getSourceLocation() .getChildSourceLocations().iterator()); context.blockStateMap.put(stepLocation, new IfBlockState(iterator)); return iterator; } }; builder.enterBlock(sourceLocations, null, false, null); } /** * Assembles a logical line. * * @param builder * an assembly builder * @throws IOException * an I/O exception occurred while assembling the logical line */ public static void assembleLogicalLine(@Nonnull AssemblyBuilder builder) throws IOException { // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); if (SourceLocationUtils.hasMnemonic(builder.getStep().getLocation().getSourceLocation())) { context.setMnemonic(); final Symbol mnemonicSymbol; final boolean builtInMnemonic; // If the mnemonic starts with !, ignore macros and search only the built-in mnemonics. if (context.mnemonic.startsWith("!")) { mnemonicSymbol = Mnemonics.MAP.get(context.mnemonic.substring(1)); builtInMnemonic = true; } else { mnemonicSymbol = context.getMnemonicSymbolByName(context.mnemonic); builtInMnemonic = false; } assembleMnemonic(context, mnemonicSymbol, builtInMnemonic); } else { context.defineLabels(); } } /** * Assembles a <code>MACRO</code> block. * * @param builder * an assembly builder */ public static void assembleMacroBlock(@Nonnull AssemblyBuilder builder) { final AssemblyStepLocation stepLocation = builder.getStep().getLocation(); // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); final Iterable<SourceLocation> sourceLocations = new Iterable<SourceLocation>() { @Override public Iterator<SourceLocation> iterator() { final DynamicSourceLocationIterator iterator = new DynamicSourceLocationIterator(stepLocation.getSourceLocation() .getChildSourceLocations().iterator()); context.blockStateMap.put(stepLocation, new MacroBlockState(iterator)); return iterator; } }; builder.enterBlock(sourceLocations, null, true, null); } /** * Assembles a <code>NAMESPACE</code> block. * * @param builder * an assembly builder */ public static void assembleNamespaceBlock(@Nonnull final AssemblyBuilder builder) { builder.enterComposite(true, new ScopedEffectBlockEvents() { @Override void cancelEffect() { builder.exitNamespace(); } }); } /** * Assembles an <code>OBJ</code> or <code>PHASE</code> block. * * @param builder * an assembly builder */ public static void assembleObjBlock(@Nonnull AssemblyBuilder builder) { final AssemblyStepLocation stepLocation = builder.getStep().getLocation(); // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); final ObjBlockState objBlockState = new ObjBlockState(); context.blockStateMap.put(stepLocation, objBlockState); builder.enterBlock(stepLocation.getSourceLocation().getChildSourceLocations(), null, true, new BlockEvents() { @Override public void exitBlock() { if (objBlockState.programCounterOffset != 0) { context.builder.setProgramCounter(context.builder.getAssembly().getProgramCounter() + objBlockState.programCounterOffset); } } }); } /** * Assembles a <code>REPT</code> block. * * @param builder * an assembly builder */ public static void assembleReptBlock(@Nonnull AssemblyBuilder builder) { final AssemblyStepLocation stepLocation = builder.getStep().getLocation(); // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); context.blockStateMap.put(stepLocation, new ReptBlockState()); builder.enterBlock(stepLocation.getSourceLocation().getChildSourceLocations(), null, true, null); } /** * Assembles a <code>REPT</code> block body. * * @param builder * an assembly builder */ public static void assembleReptBody(@Nonnull AssemblyBuilder builder) { // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); final Object blockState = context.getParentBlock(); if (!(blockState instanceof ReptBlockState)) { throw new AssertionError(); } builder.enterBlock(builder.getStep().getLocation().getSourceLocation().getChildSourceLocations(), (ReptBlockState) blockState, false, null); } /** * Assembles a <code>TRANSFORM</code> block. * * @param builder * an assembly builder */ public static void assembleTransformBlock(@Nonnull final AssemblyBuilder builder) { builder.enterComposite(true, new ScopedEffectBlockEvents() { @Override void cancelEffect() throws IOException { builder.exitTransformationBlock(); } }); } /** * Assembles a <code>WHILE</code> block. * * @param builder * an assembly builder */ public static void assembleWhileBlock(@Nonnull AssemblyBuilder builder) { final AssemblyStepLocation stepLocation = builder.getStep().getLocation(); // Get our assembly context for this assembly. final M68KAssemblyContext context = M68KAssemblyContext.getAssemblyContext(builder); final WhileBlockState whileBlockState = new WhileBlockState(); final Iterable<SourceLocation> sourceLocations = new Iterable<SourceLocation>() { @Override public Iterator<SourceLocation> iterator() { final DynamicSourceLocationIterator iterator = new DynamicSourceLocationIterator(stepLocation.getSourceLocation() .getChildSourceLocations().iterator()); whileBlockState.iterator = iterator; context.blockStateMap.put(stepLocation, whileBlockState); return iterator; } }; builder.enterBlock(sourceLocations, whileBlockState, false, null); } private static void assembleMnemonic(@Nonnull M68KAssemblyContext context, @CheckForNull Symbol mnemonicSymbol, boolean builtInMnemonic) throws IOException { final Mnemonic mnemonic; if (mnemonicSymbol != null && mnemonicSymbol.getValue() != null) { mnemonic = (Mnemonic) mnemonicSymbol.getValue(); } else { mnemonic = null; } if (mnemonic != null) { mnemonic.defineLabels(context); mnemonic.checkInstructionSet(context); mnemonic.assemble(context); } else { if (builtInMnemonic) { context.addMessage(new UnknownMnemonicErrorMessage()); } context.defineLabels(); } } // This class is not meant to be instantiated. private SourceNodesImpl() { } }