From 6dd617d8bd2961db09d438cac2869ad29e4d3a65 Mon Sep 17 00:00:00 2001 From: Tristan Morgan Date: Fri, 31 May 2024 14:20:46 +1000 Subject: [PATCH] Adding new OpDuplicate --- parser/execute.go | 7 +++++ parser/execute_test.go | 5 +++- parser/instruction.go | 1 + parser/instruction_test.go | 2 ++ parser/print.go | 9 +++--- parser/print_test.go | 6 +++- parser/tokenise.go | 58 +++++++++++++++++++++++++------------- parser/tokenise_test.go | 20 +++++++++---- 8 files changed, 77 insertions(+), 31 deletions(-) diff --git a/parser/execute.go b/parser/execute.go index b1bf17e..2b8792f 100644 --- a/parser/execute.go +++ b/parser/execute.go @@ -71,6 +71,13 @@ func Execute[T Number](data []T, program []Instruction, reader io.ByteReader, wr data[destPtr] += data[dataPtr] * T(factor) data[dataPtr] = 0 pc++ + case opDupVal: + firstPtr := (operand + dataPtr) & DataMask + secondPtr := (program[pc+1].operand + dataPtr) & DataMask + data[firstPtr] += data[dataPtr] + data[secondPtr] += data[dataPtr] + data[dataPtr] = 0 + pc++ case opNoop: continue default: diff --git a/parser/execute_test.go b/parser/execute_test.go index 01a58a6..54f4110 100644 --- a/parser/execute_test.go +++ b/parser/execute_test.go @@ -18,12 +18,15 @@ func TestExecuteSmall(t *testing.T) { {opAddDp, 2}, {opMulVal, -1}, {opNoop, 2}, + {opAddDp, -1}, + {opDupVal, -1}, + {opNoop, -2}, } startdata := make([]int, 65536) outputBuf := bufio.NewWriter(&bufferWriter{}) inputBuf := bufio.NewReader(strings.NewReader("no input.")) data := Execute(startdata, program, inputBuf, outputBuf)[:10] - want := []int{0, 0, 0, 0, 0, 0, 10, 0, 0, 0} + want := []int{0, 0, 0, 0, 10, 10, 0, 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 bad42fa..4045d18 100644 --- a/parser/instruction.go +++ b/parser/instruction.go @@ -21,6 +21,7 @@ const ( opMove opSkip opMulVal + opDupVal ) var instMap = map[byte]Instruction{ diff --git a/parser/instruction_test.go b/parser/instruction_test.go index 420c450..ae02f56 100644 --- a/parser/instruction_test.go +++ b/parser/instruction_test.go @@ -18,6 +18,7 @@ var opName = map[Opcode]string{ opMove: "mov", opSkip: "skp", opMulVal: "mul", + opDupVal: "dup", } func (inst Instruction) String() string { @@ -95,6 +96,7 @@ func TestSameOp(t *testing.T) { opMove, opSkip, opMulVal, + opDupVal, } for row, rval := range opsList { diff --git a/parser/print.go b/parser/print.go index d14d44d..7ff7af3 100644 --- a/parser/print.go +++ b/parser/print.go @@ -46,13 +46,14 @@ func instPrint(inst, lastInst Instruction) string { return "[" + repeatDirection("<", ">", inst.operand) + "]" case opMulVal: return "" + case opDupVal: + return "" case opNoop: if lastInst.operator == opMulVal { - multiplier := strings.Repeat("+", abs(inst.operand)) - if inst.operand < 0 { - multiplier = strings.Repeat("-", abs(inst.operand)) - } + multiplier := repeatDirection("-", "+", inst.operand) return "[-" + repeatDirection("<", ">", lastInst.operand) + multiplier + repeatDirection(">", "<", lastInst.operand) + "]" + } else if lastInst.operator == opDupVal { + return "[-" + repeatDirection("<", ">", lastInst.operand) + "+" + repeatDirection("<", ">", inst.operand-lastInst.operand) + "+" + repeatDirection(">", "<", inst.operand) + "]" } return "" default: diff --git a/parser/print_test.go b/parser/print_test.go index feb11e1..4c8d2a9 100644 --- a/parser/print_test.go +++ b/parser/print_test.go @@ -16,6 +16,10 @@ func TestPrint(t *testing.T) { {opMove, 2}, {opJmpZ, 7}, {opIn, 1}, + {opMulVal, 2}, + {opNoop, 2}, + {opDupVal, 1}, + {opNoop, 2}, {opJmpNz, 5}, {opAddDp, 2}, } @@ -23,7 +27,7 @@ func TestPrint(t *testing.T) { outputBuf := bufio.NewWriter(&buf) Print(program, outputBuf) got := buf.String() - want := " \n >>>>>\n [-]\n +++++\n [->>+<<]\n [\n\t ,\n ]\n >>\n" + want := " \n >>>>>\n [-]\n +++++\n [->>+<<]\n [\n\t ,\n\t [->>++<<]\n\t \n\t [->+>+<<]\n ]\n >>\n" if !reflect.DeepEqual(got, want) { t.Errorf("got %v want %v", got, want) diff --git a/parser/tokenise.go b/parser/tokenise.go index 7e4bd1c..d74ed20 100644 --- a/parser/tokenise.go +++ b/parser/tokenise.go @@ -73,32 +73,27 @@ func Tokenise(input io.ByteReader) (program []Instruction, err error) { program = program[:pc] program = append(program, Instruction{opSkip, offset}) case pc-jmpPc == 5: // looking for opMulVal and opMove - var factor, offset = 0, 0 - if program[pc-4].Complement(NewInstruction('+')) && - program[pc-3].Complement(program[pc-1]) && - program[pc-2].SameOp(NewInstruction('+')) { // open with minus + pointers, factors, ok := evalFactors(program[jmpPc+1 : pc]) - factor = program[pc-2].operand - offset = program[pc-3].operand - - } else if program[pc-1].Complement(NewInstruction('+')) && - program[pc-4].Complement(program[pc-2]) && - program[pc-3].SameOp(NewInstruction('+')) { // close with minus - - factor = program[pc-3].operand - offset = program[pc-4].operand - - } - if factor == 1 { + if ok && factors[0] == 1 { pc = jmpPc program = program[:pc] - program = append(program, Instruction{opMove, offset}) - } else if factor != 0 { + program = append(program, Instruction{opMove, pointers[0]}) + } else if ok && factors[0] != 0 { + pc = jmpPc + program = program[:pc] + program = append(program, Instruction{opMulVal, pointers[0]}) + pc++ + program = append(program, Instruction{opNoop, factors[0]}) + } + case pc-jmpPc == 7: //looking for opDupVal + pointers, factors, ok := evalFactors(program[jmpPc+1 : pc]) + if ok && factors[0] == 1 && factors[1] == 1 { pc = jmpPc program = program[:pc] - program = append(program, Instruction{opMulVal, offset}) + program = append(program, Instruction{opDupVal, pointers[0]}) pc++ - program = append(program, Instruction{opNoop, factor}) + program = append(program, Instruction{opNoop, pointers[1]}) } } } @@ -109,3 +104,26 @@ func Tokenise(input io.ByteReader) (program []Instruction, err error) { } return } + +func evalFactors(program []Instruction) (pointers, factors []int, ok bool) { + ok = false + collect := 0 + pointers = make([]int, 0) + factors = make([]int, 0) + for _, inst := range program { + if inst.SameOp(NewInstruction('>')) { + collect += inst.operand + } else if collect == 0 && inst.Complement(NewInstruction('+')) { + ok = true + } else if inst.SameOp(NewInstruction('-')) { + pointers = append(pointers, collect) + factors = append(factors, inst.operand) + } else { + return pointers, factors, false + } + } + if collect != 0 || !ok { + return pointers, factors, false + } + return +} diff --git a/parser/tokenise_test.go b/parser/tokenise_test.go index 7c0c37a..fb826a5 100644 --- a/parser/tokenise_test.go +++ b/parser/tokenise_test.go @@ -82,15 +82,25 @@ func TestTokenise(t *testing.T) { }, }, { - "op_jmp_z_nz", + "op_dup", ">[->>+>+<<<]", + []Instruction{ + {opNoop, 0}, + {opAddDp, 1}, + {opDupVal, 2}, + {opNoop, 3}, + }, + }, + { + "op_jmp_z_nz", + ">[->>,>+<<<]", []Instruction{ {opNoop, 0}, {opAddDp, 1}, {opJmpZ, 9}, {opAddVal, -1}, {opAddDp, 2}, - {opAddVal, 1}, + {opIn, 1}, {opAddDp, 1}, {opAddVal, 1}, {opAddDp, -3}, @@ -113,10 +123,10 @@ func TestTokenise(t *testing.T) { got, err := Tokenise(bufio.NewReader(strings.NewReader(v.code))) want := v.program - if !reflect.DeepEqual(got, want) { - t.Errorf("got %v want %v", got, want) - } else if err != nil { + if err != nil { t.Errorf("Error thrown %v", err) + } else if !reflect.DeepEqual(got, want) { + t.Errorf("got %v want %v", got, want) } }) }