Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Commit

Permalink
Added support for the JIND instruction.
Browse files Browse the repository at this point in the history
  • Loading branch information
weisJ committed Jul 13, 2019
1 parent e5b7214 commit 2cfee63
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public static Value<?> getReferenceValue(@NotNull final List<Value<?>> arguments
public static Value<?> getMemoryReference(@NotNull final List<Value<?>> arguments, final int index) {
final var argument = arguments.get(index);
if (argument == null
|| !(argument.getType() == ValueType.NUMBER
|| argument.getType() == ValueType.CONSTANT
|| argument.getType() == ValueType.MEMORY_REFERENCE)) {
|| (argument.getType() != ValueType.NUMBER
&& argument.getType() != ValueType.CONSTANT
&& argument.getType() != ValueType.MEMORY_REFERENCE)) {
fail("must pass a memory address");
}
if (!(argument.getType() == ValueType.MEMORY_REFERENCE)
Expand All @@ -80,7 +80,9 @@ public static Value<?> getMemoryReference(@NotNull final List<Value<?>> argument
*/
public static Value<?> getJumpReference(@NotNull final List<Value<?>> arguments, final int index) {
final var argument = arguments.get(index);
if (argument.getType() != ValueType.JUMP_REFERENCE) {
// jump can be referenced through number literal const reference or jump reference.
if (argument.getType() != ValueType.JUMP_REFERENCE && argument.getType() != ValueType.CONSTANT
&& argument.getType() != ValueType.NUMBER) {
throw new IllegalArgumentException("must pass jump reference");
}
return argument;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import edu.kit.mima.api.util.Tuple;
import edu.kit.mima.core.controller.DebugController;
import edu.kit.mima.core.data.MachineWord;
import edu.kit.mima.core.instruction.InstructionSet;
import edu.kit.mima.core.interpretation.environment.Environment;
import edu.kit.mima.core.interpretation.environment.GlobalEnvironment;
import edu.kit.mima.core.interpretation.stack.Continuation;
Expand Down Expand Up @@ -123,17 +124,16 @@ private void evaluate(@NotNull final Token<?> expression, @NotNull final Environ
final ProgramToken programToken = (ProgramToken) expression;
final Environment scope = environment.extend(programToken);
scope.setReservedIndex(environment.getReservedIndex());
programToken.getJumps().forEach((t, i) -> scope
.defineJump(t.getValue().toString(), i));
programToken.getJumps().forEach((t, i) -> scope.defineJump(t.getValue().toString(), i));
evaluateProgram(programToken, scope, callback);
}
case DEFINITION -> {
final var defToken = (ListToken<Token<?>>) expression.getValue();
evaluateDefinition(defToken, environment, callback);
}
case NUMBER -> callback.accept(evaluateNumber((String) expression.getValue()));
case NUMBER -> callback.accept(evaluateNumber((String) expression.getValue(), environment));
case EMPTY -> callback.accept(VOID);
case BINARY -> callback.accept(evaluateBinary((String) expression.getValue()));
case BINARY -> callback.accept(evaluateBinary((String) expression.getValue(), environment));
case IDENTIFICATION -> callback.accept(evaluateIdentification(expression, environment));
case CALL -> evaluateFunction((BinaryToken<Token<?>, ListToken<Token<?>>>) expression,
environment, callback);
Expand Down Expand Up @@ -161,11 +161,11 @@ private void evaluateProgram(@NotNull final ProgramToken programToken,
if (!isRunning()) {
return;
}
if (i < tokens.length) {
if (i < tokens.length && i >= 0) {
currentToken = tokens[i];
if (i != startIndex || !(environment instanceof GlobalEnvironment)) {
debugController.afterInstruction(currentToken);
}
currentToken = tokens[i];
environment.setExpressionIndex(i);
evaluate(currentToken, environment, v -> func.accept(v, i + 1));
} else {
Expand Down Expand Up @@ -205,21 +205,17 @@ private void evaluateReference(@NotNull final BinaryToken<Token<?>, Token<?>> de
@NotNull final Environment environment,
@NotNull final Runnable continuation) {
if (definition.getSecond().getType() == TokenType.EMPTY) {
environment.defineVariable(
definition.getFirst().getValue().toString(),
evaluateNumber(String.valueOf(environment.getReservedIndex())).getValue());
environment.defineVariable(definition.getFirst().getValue().toString(),
evaluatePrecheckedNumber(environment.getReservedIndex()).getValue());
environment.setReservedIndex(environment.getReservedIndex() - 1);
continuation.run();
} else {
evaluate(definition.getSecond(), environment, v -> {
if (v == VOID) {
fail("Not a definition body: " + definition.getSecond());
}
if (((MachineWord) v.getValue()).intValue() < 0) {
fail("Can't have negative memory references");
}
environment.defineVariable(definition.getFirst().getValue().toString(),
(MachineWord) v.getValue());
checkArgumentRange(v, environment);
environment.defineVariable(definition.getFirst().getValue().toString(), (MachineWord) v.getValue());
continuation.run();
});
}
Expand All @@ -235,6 +231,7 @@ private void evaluateConstant(@NotNull final BinaryToken<Token<?>, Token<?>> def
if (Objects.equals(v, VOID)) {
fail("Not a definition body: " + definition.getSecond());
}
checkArgumentRange(v, environment);
environment.defineConstant(definition.getFirst().getValue().toString(),
(MachineWord) v.getValue()
);
Expand All @@ -249,6 +246,7 @@ private void evaluateFunction(@NotNull final BinaryToken<Token<?>, ListToken<Tok
@NotNull final Environment environment,
final Consumer<Value<?>> callback) throws Continuation {
stackGuard.guard(() -> evaluateFunction(value, environment, callback));
System.out.println("Evaluating" + value.simpleName());
List<Token<?>> arguments = value.getSecond().getValue();
BiConsumer<List<Value<?>>, Integer> loop = LambdaUtil.createRecursive(func -> (args, i) -> {
if (i < arguments.size()) {
Expand All @@ -264,23 +262,50 @@ private void evaluateFunction(@NotNull final BinaryToken<Token<?>, ListToken<Tok
loop.accept(new ArrayList<>(), 0);
}

/*
* Evaluate a number string
*/
@NotNull
@Contract("_,_ -> new")
private Value<MachineWord> evaluateNumber(@NotNull final String value, final Environment environment) {
final var v = new Value<>(ValueType.NUMBER, new MachineWord(Integer.parseInt(value), wordLength));
checkArgumentRange(v, environment);
return v;
}

/*
* Evaluate a number string
*/
@NotNull
@Contract("_ -> new")
private Value<MachineWord> evaluateNumber(@NotNull final String value) {
return new Value<>(ValueType.NUMBER, new MachineWord(Integer.parseInt(value), wordLength));
private Value<MachineWord> evaluatePrecheckedNumber(final int value) {
return new Value<>(ValueType.NUMBER, new MachineWord(value, wordLength));
}

/*
* Evaluate a binary string
*/
@NotNull
private Value<MachineWord> evaluateBinary(@NotNull final String binary) {
private Value<MachineWord> evaluateBinary(@NotNull final String binary, final Environment environment) {
final Boolean[] bits = new StringBuilder(binary).reverse().toString()
.chars().mapToObj(i -> i == '1').toArray(Boolean[]::new);
return new Value<>(ValueType.NUMBER, new MachineWord(bits, wordLength));
final var v = new Value<>(ValueType.NUMBER, new MachineWord(bits, wordLength));
checkArgumentRange(v, environment);
return v;
}

private void checkArgumentRange(final Value<?> value, final Environment environment) {
final int index = ((MachineWord)value.getValue()).intValue();
final InstructionSet instructionSet = environment.getInstructionSet();
final int maxValue = instructionSet.getConstWordLength() == instructionSet.getWordLength()
? (2 << (instructionSet.getWordLength() - 1)) - 1
: (2 << instructionSet.getConstWordLength()) - 1;
final int minValue = instructionSet.getConstWordLength() == instructionSet.getWordLength()
? -(2 << (instructionSet.getWordLength() - 1))
: 0;
if (index < minValue || index > maxValue) {
fail("Index out of range");
}
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import edu.kit.mima.core.data.MachineWord;
import edu.kit.mima.core.instruction.Instruction;
import edu.kit.mima.core.instruction.InstructionSet;
import edu.kit.mima.core.token.ProgramToken;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
Expand All @@ -20,11 +21,13 @@
* @since 2018
*/
public class Environment {
public static final Environment EMPTY_ENV = new Environment(null, null);
public static final Environment EMPTY_ENV = new Environment(null, null, null,
0, 0);

@Nullable
private final Environment parent;
private final ProgramToken programToken;
private final InstructionSet instructionSet;
@NotNull
private final HashMap<String, MachineWord> variables;
@NotNull
Expand All @@ -33,6 +36,8 @@ public class Environment {
private final HashMap<String, Instruction> functions;
@NotNull
private final HashMap<String, Integer> jumps;
private final int instructionRangeStart;
private final int instructionRangeEnd;

/**
* Index of current expression.
Expand All @@ -49,10 +54,18 @@ public class Environment {
*
* @param parent parent Environment
* @param programToken programToken for this environment
* @param instructionSet the instruction set
* @param instructionRangeStart index of first token in environment.
* @param instructionRangeEnd index of last token in environment.
*/
public Environment(@Nullable final Environment parent, final ProgramToken programToken) {
public Environment(@Nullable final Environment parent, final ProgramToken programToken,
final InstructionSet instructionSet,
final int instructionRangeStart, final int instructionRangeEnd) {
this.parent = parent;
this.programToken = programToken;
this.instructionSet = instructionSet;
this.instructionRangeStart = instructionRangeStart;
this.instructionRangeEnd = instructionRangeEnd;
variables = new HashMap<>();
constants = new HashMap<>();
functions = new HashMap<>();
Expand All @@ -61,6 +74,33 @@ public Environment(@Nullable final Environment parent, final ProgramToken progra
reservedIndex = -1;
}

/**
* Get the current instruction set.
*
* @return the instruction set used for evaluation.
*/
public InstructionSet getInstructionSet() {
return instructionSet;
}

/**
* Index where the environment starts.
*
* @return index of first token inside environment.
*/
public int getInstructionRangeStart() {
return instructionRangeStart;
}

/**
* Index where the environment ends.
*
* @return index of last token inside environment.
*/
public int getInstructionRangeEnd() {
return instructionRangeEnd;
}

/**
* Get the variable and constants associations as follows {{variables},{constants}}.
*
Expand All @@ -79,7 +119,9 @@ public List<Map<String, MachineWord>> getDefinitions() {
*/
@NotNull
public Environment extend(final ProgramToken programToken) {
return new Environment(this, programToken);
final int startIndex = programToken.getLineIndex();
return new Environment(this, programToken,instructionSet, startIndex,
startIndex + programToken.getLength() - 1);
}

/**
Expand Down Expand Up @@ -135,6 +177,24 @@ public Environment lookupJump(final String name) {
return lookup(env -> env.jumps, name);
}

/**
* Returns the environment for which the index of the token is inside.
*
* @param index of token.
* @return Environment containing the token. Null if index is out of range.
*/
@NotNull
public Environment lookupToken(final int index) {
Environment scope = this;
while (scope != null) {
if (index >= scope.getInstructionRangeStart() && index <= scope.getInstructionRangeEnd()) {
return scope;
}
scope = scope.parent;
}
return EMPTY_ENV;
}

@NotNull
@Contract(pure = true)
private <T> Environment lookup(
Expand Down
Loading

0 comments on commit 2cfee63

Please sign in to comment.