blob: 74f5abe7e4ef6019cb14cfa728b2ce1d20f92209 (
plain)
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
|
#!/usr/bin/ruby -w
# Simple BF interpretor.
#
# This works by translating input code into ruby and evaluating the
# translated ruby code. Doing it this way runs much faster than
# interpreting BF on our own.
#
# There is no error reporting whatsoever. A malformed input may result in
# a syntax error at run time, but good luck in finding where it came from.
# Setup empty tape and initial pointer position. Note that tape size is
# fixed. We can make it infinite by initializing it to "[]" here and
# adding some nil checks in the generated code, but avoiding those checks
# makes the program run ~10% faster.
$code = "t=Array.new(30000,0); p=0;"
# Counters for pending add or shift operations. We buffer incoming +-<>
# operators and output a single merged operation when we encounter a
# different operator.
$buffered_add = 0
$buffered_shift = 0
# Flush pending add operations, if any.
def flush_add
if $buffered_add != 0
$code += "t[p]+=#{$buffered_add};"
$buffered_add = 0
end
end
# Flush pending shift operations, if any.
def flush_shift
if $buffered_shift != 0
$code += "p+=#{$buffered_shift};"
$buffered_shift = 0
end
end
def flush_pending_ops
flush_add
flush_shift
end
# Convert input characters to ruby.
ARGF.each_char{|c|
case c
when '+'
flush_shift
$buffered_add += 1
when '-'
flush_shift
$buffered_add -= 1
when '<'
flush_add
$buffered_shift -= 1
when '>'
flush_add
$buffered_shift += 1
when ','
flush_pending_ops
$code += "if c=STDIN.getc;" +
"t[p]=c.ord;" +
"else;" +
"t[p]=-1;" + # EOF is interpreted as -1.
"end;"
when '.'
flush_pending_ops
$code += "print t[p].chr;"
when '['
flush_pending_ops
$code += "while t[p]!=0;"
when ']'
flush_pending_ops
$code += "end;"
end
}
flush_pending_ops
# Evaluate converted code.
eval $code
|