Skip to content

Commit

Permalink
Pretty printer.
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanmorgan committed May 13, 2024
1 parent 460425c commit 0189856
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ for performance comparison see no_optimisation branch.
dump parsed program
-eight
eight bit execution
-print
pretty print parsed program
-version
display version

Expand Down
4 changes: 4 additions & 0 deletions cmd/bfg/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func main() {
version := flag.Bool("version", false, "display version")
eight := flag.Bool("eight", false, "eight bit execution")
dump := flag.Bool("dump", false, "dump parsed program")
print := flag.Bool("print", false, "pretty print parsed program")

flag.Usage = func() {
fmt.Printf("Usage:\n %s [option] source.bf [input]\n", os.Args[0])
Expand All @@ -35,6 +36,7 @@ func main() {
flag.Parse()
if *version {
fmt.Printf("Version: v%s%s\n", Version, VersionPrerelease)
fmt.Println("https://github.com/tristanmorgan/bfg\n")

Check failure on line 39 in cmd/bfg/main.go

View workflow job for this annotation

GitHub Actions / test

fmt.Println arg list ends with redundant newline
os.Exit(0)
}

Expand All @@ -61,6 +63,8 @@ func main() {
}
if *dump {
parser.Dump(program, outputBuf)
} else if *print {
parser.Print(program, outputBuf)
} else if *eight {
data := make([]byte, parser.DataSize)
parser.Execute(data, program, inputBuf, outputBuf)
Expand Down
83 changes: 83 additions & 0 deletions parser/print.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package parser

import (
"bufio"
"fmt"
"strings"
)

func abs(x int) int {
if x < 0 {
return -x
}
return x
}

func repeatDirection(neg, pos string, vect int) string {
if vect > 0 {
return strings.Repeat(pos, vect)
}
return strings.Repeat(neg, abs(vect))
}

func instPrint(inst, lastInst Instruction) string {
switch inst.operator {
case opAddDp:
return repeatDirection("<", ">", inst.operand)
case opAddVal:
return repeatDirection("-", "+", inst.operand)
case opSetVal:
prefix := "[-]"
if lastInst.IsZeroOp() && inst.operand != 0 {
prefix = ""
}
return prefix + repeatDirection("-", "+", inst.operand)
case opOut:
return "."
case opIn:
return ","
case opJmpZ:
return "["
case opJmpNz:
return "]"
case opMove:
return "[-" + repeatDirection("<", ">", inst.operand) + "+" + repeatDirection(">", "<", inst.operand) + "]"
case opSkip:
return "[" + repeatDirection("<", ">", inst.operand) + "]"
case opMulVal:
return ""
case opNoop:
if lastInst.operator == opMulVal {
multiplier := strings.Repeat("+", abs(inst.operand))
if inst.operand < 0 {
multiplier = strings.Repeat("-", abs(inst.operand))
}
if lastInst.operand > 0 {
return "[-" + strings.Repeat(">", lastInst.operand) + multiplier + strings.Repeat("<", lastInst.operand) + "]"
}
return "[-" + strings.Repeat("<", abs(lastInst.operand)) + multiplier + strings.Repeat(">", abs(lastInst.operand)) + "]"
}
return ""
default:
return ""
}
}

// Print pretty prints out the parsed program.
func Print(program []Instruction, writer *bufio.Writer) {
depth := 0
startLoop := NewInstruction('[')
endLoop := NewInstruction(']')
lastInst := NewInstruction('!')
for _, inst := range program {
if inst.SameOp(endLoop) {
depth--
}
fmt.Fprintln(writer, strings.Repeat("\t", depth), instPrint(inst, lastInst))
if inst.SameOp(startLoop) {
depth++
}
lastInst = inst
}
writer.Flush()
}
31 changes: 31 additions & 0 deletions parser/print_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package parser

import (
"bufio"
"bytes"
"reflect"
"testing"
)

func TestPrint(t *testing.T) {
program := []Instruction{
{opNoop, 0},
{opAddDp, 5},
{opSetVal, 0},
{opAddVal, 5},
{opMove, 2},
{opJmpZ, 7},
{opIn, 1},
{opJmpNz, 5},
{opAddDp, 2},
}
var buf bytes.Buffer
outputBuf := bufio.NewWriter(&buf)
Print(program, outputBuf)
got := buf.String()
want := " \n >>>>>\n [-]\n +++++\n [->>+<<]\n [\n\t ,\n ]\n >>\n"

if !reflect.DeepEqual(got, want) {
t.Errorf("got %v want %v", got, want)
}
}
3 changes: 3 additions & 0 deletions parser/tokenise.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ func Tokenise(input io.ByteReader) (program []Instruction, err error) {
pc--
} else if pc-jmpPc == 2 && program[pc-1].SameOp(NewInstruction('+')) {
pc = jmpPc
if program[jmpPc-1].SameOp(NewInstruction('+')) {
pc--
}
program = program[:pc]
program = append(program, Instruction{opSetVal, 0})
} else if pc-jmpPc == 2 && program[pc-1].SameOp(NewInstruction('>')) {
Expand Down
2 changes: 1 addition & 1 deletion parser/tokenise_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestTokenise(t *testing.T) {
}{
{
"small_prog",
">>>>>[-]zero+++++>+++++[->>+<<]move>>[>>+<<-]move",
">>>>>++[-]zero+++++>+++++[->>+<<]move>>[>>+<<-]move",
[]Instruction{
{opNoop, 0},
{opAddDp, 5},
Expand Down
2 changes: 1 addition & 1 deletion sample/rot13.bf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bf
,+[-[>>++++[>++++++++<-]<+<-[>+>+>-[>>>]<[[>+<-]>>+>]<<<<<-]]>>>[-]+>--
[-[<->+++[-]]]<[++++++++++++<[>-[>+>>]>[+[<+>-]>+>>]<<<<<-]>>[<+>-]>[-[
[-[<->[-]]]<[++++++++++++<[>-[>+>>]>[+[<+>-]>+>>]<<<<<-]>>[<+>-]>[-[
-<<[-]>>]<<[<<->>-]>>]<<[<<+>>-]]<[-]<.[-]<,+]

0 comments on commit 0189856

Please sign in to comment.