package org.reasm.m68k.assembly.internal; import java.io.IOException; import javax.annotation.Nonnull; import org.reasm.FunctionValue; import org.reasm.SymbolContext; import org.reasm.SymbolType; import org.reasm.Value; import org.reasm.expressions.Expression; import org.reasm.m68k.expressions.internal.TokenType; import org.reasm.m68k.messages.FunctionParameterIsNotSimpleIdentifierErrorMessage; import org.reasm.messages.DirectiveRequiresLabelErrorMessage; /** * The <code>FUNCTION</code> directive. * * @author Francis Gagné */ class FunctionDirective extends Mnemonic { @Nonnull static final FunctionDirective FUNCTION = new FunctionDirective(); private FunctionDirective() { } @Override void assemble(M68KAssemblyContext context) throws IOException { context.sizeNotAllowed(); final int numberOfOperands = context.numberOfOperands; if (context.numberOfLabels == 0) { context.addMessage(new DirectiveRequiresLabelErrorMessage("FUNCTION")); } else if (numberOfOperands == 0) { context.addWrongNumberOfOperandsErrorMessage(); } else { // All operands except the last one must be simple identifiers. final String[] parameterNames = new String[numberOfOperands - 1]; boolean argumentsAreValid = true; for (int i = 0; i < numberOfOperands - 1; i++) { final String operandText = context.getOperandText(i); context.tokenizer.setCharSequence(operandText); boolean isValid = context.tokenizer.getTokenType() == TokenType.IDENTIFIER; if (isValid) { parameterNames[i] = context.tokenizer.getTokenText().toString(); context.tokenizer.advance(); isValid = context.tokenizer.getTokenType() == TokenType.END; } if (!isValid) { context.addMessage(new FunctionParameterIsNotSimpleIdentifierErrorMessage(operandText)); argumentsAreValid = false; } } // The last operand must be a valid expression. final Expression functionExpression = parseExpressionOperand(context, numberOfOperands - 1); final Value functionValue; if (functionExpression != null && argumentsAreValid) { functionValue = new FunctionValue(new UserFunction(context, functionExpression, parameterNames)); } else { functionValue = null; } context.defineSymbols(SymbolContext.VALUE, SymbolType.CONSTANT, functionValue); } } @Override void defineLabels(M68KAssemblyContext context) { // Don't define any labels. } }