99 lines
2.3 KiB
Nim
99 lines
2.3 KiB
Nim
import os, strutils
|
|
|
|
type
|
|
Tape = ref object
|
|
cells: array[30_000, uint8]
|
|
head: int
|
|
|
|
Token = enum
|
|
IncrementHead, DecrementHead
|
|
IncrementCell, DecrementCell
|
|
Print, Read
|
|
LoopStart, LoopEnd
|
|
|
|
CommandKind = enum
|
|
Do, Loop
|
|
|
|
Command = object
|
|
case kind: CommandKind
|
|
of Do:
|
|
tk: Token
|
|
of Loop:
|
|
cs: seq[Command]
|
|
|
|
proc incrementHead(t: Tape) =
|
|
t.head.inc
|
|
|
|
proc decrementHead(t: Tape) =
|
|
t.head.dec
|
|
|
|
proc incrementCell(t: Tape) =
|
|
t.cells[t.head].inc
|
|
|
|
proc decrementCell(t: Tape) =
|
|
t.cells[t.head].dec
|
|
|
|
proc print(t: Tape) =
|
|
stdout.write(chr(t.cells[t.head]))
|
|
|
|
proc read(t: Tape) =
|
|
stdout.write("Enter a char: ")
|
|
t.cells[t.head] = uint8(parseInt(stdin.readLine()))
|
|
|
|
func getData(t: Tape): uint8 =
|
|
return t.cells[t.head]
|
|
|
|
proc tokenize(data: string): seq[Token] =
|
|
var tokens: seq[Token]
|
|
for c in data:
|
|
case c:
|
|
of '>': tokens.add(IncrementHead)
|
|
of '<': tokens.add(DecrementHead)
|
|
of '+': tokens.add(IncrementCell)
|
|
of '-': tokens.add(DecrementCell)
|
|
of '.': tokens.add(Print)
|
|
of ',': tokens.add(Read)
|
|
of '[': tokens.add(LoopStart)
|
|
of ']': tokens.add(LoopEnd)
|
|
else: discard
|
|
return tokens
|
|
|
|
proc parse(tokens: seq[Token], index: int): (seq[Command], int) =
|
|
var commands: seq[Command]
|
|
var index = index
|
|
while index < tokens.len:
|
|
case tokens[index]:
|
|
of LoopStart:
|
|
let res = parse(tokens, index+1)
|
|
index = res[1]
|
|
let loop = Command(kind: Loop, cs: res[0])
|
|
commands.add(loop)
|
|
of LoopEnd:
|
|
return (commands, index)
|
|
else:
|
|
let command = Command(kind: Do, tk: tokens[index])
|
|
commands.add(command)
|
|
index.inc
|
|
return (commands, index)
|
|
|
|
proc run(program: seq[Command], tape: Tape) =
|
|
for command in program:
|
|
case command.kind:
|
|
of Do:
|
|
case command.tk:
|
|
of IncrementHead: tape.incrementHead()
|
|
of DecrementHead: tape.decrementHead()
|
|
of IncrementCell: tape.incrementCell()
|
|
of DecrementCell: tape.decrementCell()
|
|
of Print: tape.print()
|
|
of Read: tape.read()
|
|
else: discard
|
|
of Loop:
|
|
while tape.getData() != 0:
|
|
run(command.cs, tape)
|
|
|
|
when isMainModule:
|
|
let brainfuck = paramStr(1).readFile()
|
|
let program = tokenize(brainfuck).parse(0)[0]
|
|
let tape = Tape()
|
|
run(program, tape)
|