diff --git a/README.md b/README.md index 759476a..0771c70 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Operates with a instruction parse then execute pattern. * repeat >>> or <<< are replaced with a single pointer jump * [>>>] and [<<<] are merged into a skip instruction. * [>>+<<-] and [->>+<<] merged into a move instruction. + * [<+++++>-] is converted to a Multiply instruction. for performance comparison see no_optimisation branch. @@ -33,7 +34,7 @@ for performance comparison see no_optimisation branch. Options: -dump - dump parsed program + dump parsed program -eight eight bit execution -version diff --git a/parser/execute.go b/parser/execute.go index d916b9e..b1bf17e 100644 --- a/parser/execute.go +++ b/parser/execute.go @@ -65,6 +65,12 @@ func Execute[T Number](data []T, program []Instruction, reader io.ByteReader, wr destPtr := (operand + dataPtr) & DataMask data[destPtr] += data[dataPtr] data[dataPtr] = 0 + case opMulVal: + destPtr := (operand + dataPtr) & DataMask + factor := program[pc+1].operand + data[destPtr] += data[dataPtr] * T(factor) + data[dataPtr] = 0 + pc++ case opNoop: continue default: diff --git a/parser/execute_test.go b/parser/execute_test.go index 5ea158f..8da91f1 100644 --- a/parser/execute_test.go +++ b/parser/execute_test.go @@ -16,12 +16,14 @@ func TestExecuteSmall(t *testing.T) { {opAddVal, 5}, {opMove, 2}, {opAddDp, 2}, + {opMulVal, -1}, + {opNoop, 2}, } startdata := make([]int, 65536) outputBuf := bufio.NewWriter(os.Stdout) inputBuf := bufio.NewReader(strings.NewReader("no input.")) data := Execute(startdata, program, inputBuf, outputBuf)[:10] - want := []int{0, 0, 0, 0, 0, 0, 0, 5, 0, 0} + want := []int{0, 0, 0, 0, 0, 0, 10, 0, 0, 0} if !reflect.DeepEqual(data, want) { t.Errorf("got %v want %v", data, want) diff --git a/parser/instruction.go b/parser/instruction.go index d188a65..30d71a4 100644 --- a/parser/instruction.go +++ b/parser/instruction.go @@ -24,6 +24,7 @@ const ( opJmpNz opMove opSkip + opMulVal ) // String representation of Instruction @@ -39,6 +40,7 @@ func (inst Instruction) String() string { "jnz", "mov", "skp", + "mul", } return fmt.Sprintf("%s: %v", opName[inst.operator], inst.operand) } diff --git a/parser/instruction_test.go b/parser/instruction_test.go index ab18035..5c6cee3 100644 --- a/parser/instruction_test.go +++ b/parser/instruction_test.go @@ -44,6 +44,7 @@ func TestSameOp(t *testing.T) { opJmpNz, opMove, opSkip, + opMulVal, } for row, rval := range opsList { @@ -83,5 +84,4 @@ func TestComplement(t *testing.T) { }) } } - } diff --git a/parser/tokenise.go b/parser/tokenise.go index 448bcdf..265e469 100644 --- a/parser/tokenise.go +++ b/parser/tokenise.go @@ -36,7 +36,7 @@ func Tokenise(input io.ByteReader) (program []Instruction, err error) { program[pc-1].operand += instruction.operand program = program[:pc] pc-- - } else if program[pc-1].operator == opJmpNz { + } else if program[pc-1].SameOp(NewInstruction(']')) { operand := instruction.operand program = program[:pc] program = append(program, Instruction{opSetVal, operand}) @@ -51,25 +51,37 @@ func Tokenise(input io.ByteReader) (program []Instruction, err error) { jmpStack = jmpStack[:len(jmpStack)-1] program[pc].operand = jmpPc program[jmpPc].operand = pc - if pc-jmpPc == 2 && program[pc-1].operator == opAddVal { + if pc-jmpPc == 2 && program[pc-1].SameOp(NewInstruction('+')) { pc = jmpPc program = program[:pc] program = append(program, Instruction{opSetVal, 0}) - } else if pc-jmpPc == 2 && program[pc-1].operator == opAddDp { + } else if pc-jmpPc == 2 && program[pc-1].SameOp(NewInstruction('>')) { offset := program[pc-1].operand pc = jmpPc program = program[:pc] program = append(program, Instruction{opSkip, offset}) - } else if pc-jmpPc == 5 && + } else if pc-jmpPc == 5 && // [<<<+>>>-] or [-<<<+>>>] program[pc-4].Complement(program[pc-2]) && program[pc-3].Complement(program[pc-1]) { offset := program[pc-4].operand - if program[pc-3].operator == opAddDp { + if program[pc-3].SameOp(NewInstruction('>')) { offset = program[pc-3].operand } pc = jmpPc program = program[:pc] program = append(program, Instruction{opMove, offset}) + } else if pc-jmpPc == 5 && // [<<++++>>-] + program[pc-4].Complement(program[pc-2]) && + program[pc-3].SameOp(NewInstruction('+')) && + program[pc-1].SameOp(NewInstruction('-')) && + program[pc-1].operand == -1 { + offset := program[pc-4].operand + factor := program[pc-3].operand + pc = jmpPc + program = program[:pc] + program = append(program, Instruction{opMulVal, offset}) + pc++ + program = append(program, Instruction{opNoop, factor}) } } pc++ diff --git a/parser/tokenise_test.go b/parser/tokenise_test.go index eb62a2e..bcba2fc 100644 --- a/parser/tokenise_test.go +++ b/parser/tokenise_test.go @@ -27,6 +27,15 @@ func TestTokenise(t *testing.T) { {opAddDp, 2}, }, }, + { + "op_mul", + " [<++++++>-]", + []Instruction{ + Instruction{opNoop, 0}, + Instruction{opMulVal, -1}, // dest value pointer + Instruction{opNoop, 6}, // multiplication factor + }, + }, { "op_dp", ">>>>>>><<<<<<>",