-
Notifications
You must be signed in to change notification settings - Fork 255
/
bf.scala
113 lines (95 loc) · 2.73 KB
/
bf.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import scala.collection.mutable.ArrayBuffer
sealed abstract class Op
case class Inc(v: Int) extends Op
case class Move(v: Int) extends Op
case class Loop(loop: Array[Op]) extends Op
case object Print extends Op
class Tape() {
private var tape: Array[Int] = Array(0)
private var pos: Int = 0
def get = tape(pos)
def inc(x: Int) = tape(pos) += x
def move(x: Int) = {
pos += x
while (pos >= tape.length) {
tape = Array.copyOf(tape, tape.length * 2)
}
}
}
class Printer(val quiet: Boolean) {
private var sum1: Int = 0
private var sum2: Int = 0
def write(n: Int) = {
if (quiet) {
sum1 = (sum1 + n) % 255
sum2 = (sum2 + sum1) % 255
} else {
print(n.toChar)
}
}
def checksum = (sum2 << 8) | sum1
}
class Program(text: String, p: Printer) {
val ops: Array[Op] = parse(text.iterator)
def parse(iterator: Iterator[Char]) : Array[Op] = {
val res = ArrayBuffer[Op]()
while (iterator.hasNext) {
iterator.next() match {
case '+' => res += Inc(1)
case '-' => res += Inc(-1)
case '>' => res += Move(1)
case '<' => res += Move(-1)
case '.' => res += Print
case '[' => res += Loop(parse(iterator))
case ']' => return res.toArray
case _ =>
}
}
res.toArray
}
def run = _run(ops, new Tape())
def _run(program: Array[Op], tape: Tape): Unit = {
for (op <- program) op match {
case Inc(x) => tape.inc(x)
case Move(x) => tape.move(x)
case Loop(loop) => while (tape.get > 0) _run(loop, tape)
case Print => p.write(tape.get)
}
}
}
object BrainFuck {
def notify(msg: String): Unit = {
scala.util.Using((new java.net.Socket("localhost", 9001)).getOutputStream()) {
_.write(msg.getBytes())
}
}
def verify = {
val text = """++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>
---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."""
val pLeft = new Printer(true)
new Program(text, pLeft).run
val left = pLeft.checksum
val pRight = new Printer(true)
for (c <- "Hello World!\n") {
pRight.write(c)
}
val right = pRight.checksum
if (left != right) {
System.err.println(s"${left} != ${right}")
System.exit(1)
}
}
def main(args: Array[String]): Unit = {
val text = scala.util.Using(scala.io.Source.fromFile(args(0))) { _.mkString }.get
val p = new Printer(sys.env.get("QUIET").isDefined)
notify(s"Scala\t${ProcessHandle.current().pid()}")
val s = System.nanoTime
new Program(text, p).run
val elapsed = (System.nanoTime - s) / 1e9
notify("stop")
System.err.println(s"time: $elapsed s")
if (p.quiet) {
System.out.println(s"Output checksum: ${p.checksum}");
}
}
}