12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- def scan(source)
- source
- .chars
- .filter { |c| "+-<>[].,".include?(c) }
- .map(&:to_sym)
- end
-
- def parse(tokens)
- position = 0
- tree = Array.new
-
- parse_node = Proc.new do |token|
- case token
- when :+, :-, :>, :<, :'.', :'.', :','
- position += 1
- token
- when :"["
- position += 1
- body = Array.new
-
- while position < tokens.size && tokens[position] != :"]"
- body << parse_node.call(tokens[position])
- end
-
- raise "Unexpected EOF; expected ]" if position == tokens.size
- position += 1 if tokens[position] == :"]"
-
- body
- else
- raise "Unrecognized token #{token}"
- end
- end
-
- while position < tokens.size
- tree << parse_node.call(tokens[position])
- end
-
- tree
- end
-
- def interpret(tree)
- stack = Array.new(100) { 0 }
- position = 0
- pointer = 0
-
- interpret_node = Proc.new do |node|
- case node
- when :+
- stack[pointer] += 1
- when :-
- stack[pointer] -= 1
- when :>
- raise "Out of bounds" if pointer >= 30_000
- pointer += 1
- when :<
- raise "Below zero" if pointer <= 0
- pointer -= 1
- when :'.'
- STDOUT.write stack[pointer].chr
- when :','
- char = STDIN.getc
- stack[pointer] = char.ord
- when Array
-
- while stack[pointer] > 0
- node.each { |subnode| interpret_node.call(subnode) }
- end
-
- else
- raise "Unexpected node #{node}"
- end
- end
-
- while position < tree.length
- interpret_node.call(tree[position])
- position += 1
- end
-
- STDOUT.print("\n")
- end
-
- interpret(parse(scan(ARGV.first))).inspect
|