package org.reasm.m68k.assembly.internal;
import java.io.IOException;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import org.reasm.AssemblyStepLocation;
import org.reasm.SymbolType;
import org.reasm.messages.DirectiveRequiresLabelErrorMessage;
import org.reasm.source.SourceLocation;
/**
* The <code>MACRO</code> directive.
*
* @author Francis Gagné
*/
@Immutable
class MacroDirective extends Mnemonic {
@Nonnull
static final MacroDirective MACRO = new MacroDirective();
private MacroDirective() {
}
@Override
void assemble(M68KAssemblyContext context) throws IOException {
context.sizeNotAllowed();
final Object block = context.getParentBlock();
if (!(block instanceof MacroBlockState)) {
throw new AssertionError();
}
if (context.numberOfLabels < 1) {
context.addMessage(new DirectiveRequiresLabelErrorMessage(Mnemonics.MACRO));
}
final MacroBlockState macroBlockState = (MacroBlockState) block;
// Get the macro's operands.
final int numberOfOperands = context.numberOfOperands;
final String[] operands = new String[numberOfOperands];
for (int i = 0; i < numberOfOperands; i++) {
operands[i] = context.getOperandText(i);
}
// Store a reference to the macro body in the macro symbol (and don't assemble it now).
// IMPORTANT: We MUST call macroBlockState.iterator.next() in all cases,
// because we don't want to assemble the macro body now!
final SourceLocation macroBody = macroBlockState.iterator.next();
// In a subsequent pass, when we meet a macro that was already defined,
// we must reuse the Macro object we created earlier
// to avoid changing the symbol's value and triggering new passes indefinitely.
final AssemblyStepLocation stepLocation = context.step.getLocation();
Macro macro = context.macrosByDefinitionLocation.get(stepLocation);
if (macro == null) {
macro = new Macro(context, operands, macroBody);
context.macrosByDefinitionLocation.put(stepLocation, macro);
}
context.defineSymbols(M68KAssemblyContext.MNEMONIC, SymbolType.VARIABLE, macro);
}
@Override
void defineLabels(M68KAssemblyContext context) {
// Don't define any labels.
}
}