example bf interpreter

This commit is contained in:
prod2 2022-02-03 22:28:25 +01:00
parent 0c753dcc00
commit bdac4fe7fc
5 changed files with 140 additions and 4 deletions

112
examples/bf.nds Normal file
View File

@ -0,0 +1,112 @@
{
// source
var src = ">++++++++++>+>+[
[+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[
[-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
[>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>>
]<<<
]";
var pos = 0;
var len = #src;
var char;
var depth = 0;
// input
var input = "";
var inppos = 0;
// tape
var tape = @[];
var ptr = 0;
var ptrmax = 30000 - 1;
var i = 0;
while (i < ptrmax) {
tape[i] = 0;
i = i + 1;
};
{ @mainloop
while (pos < len) {
char = src[pos];
if (char == "<")
if (ptr > 0)
ptr = ptr - 1
else
ptr = ptrmax
;
if (char == ">")
if (ptr < ptrmax)
ptr = ptr + 1
else
ptr = 0
;
if (char == "+")
if (tape[ptr] < 255)
tape[ptr] = tape[ptr] + 1
else
tape[ptr] = 0
;
if (char == "-")
if (tape[ptr] > 0)
tape[ptr] = tape[ptr] - 1
else
tape[ptr] = 255
;
if (char == ".")
print(chr(tape[ptr]))
;
if (char == ",") {
tape[ptr] = int(input[inppos]);
inppos = inppos + 1;
};
if (char == "[") {
if (tape[ptr] == 0) {
depth = depth + 1;
while (depth > 0) {
pos = pos + 1;
char = src[pos];
depth = depth +
if (char == "[")
1
else if (char == "]")
-1
else
0
;
};
};
};
if (char == "]") {
if (tape[ptr] != 0) {
depth = depth + 1;
while (depth > 0) {
pos = pos - 1;
char = src[pos];
depth = depth +
if (char == "]")
1
else if (char == "[")
-1
else
0
;
};
};
};
pos = pos + 1;
};
};
};

View File

@ -7,7 +7,7 @@ type
OpCode* = enum
opReturn, opCall, opCheckArity, opFunctionDef, # functions
opPop, opPopSA, opPopA # pop
opPrint, # print
opPrint, # print TODO move to native func
opNegate, opNot # unary
opAdd, opSubtract, opMultiply, opDivide, # math
opEqual, opGreater, opLess, # comparison
@ -18,6 +18,7 @@ type
opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop, # jumps
opCreateList, opCreateTable, # collection creation
opLen, opSetIndex, opGetIndex, # collection operators
opChr, opInt, # temporary opcodes for the brainfuck interpreter TODO move to native funcs
Chunk* = object
code*: seq[uint8]
@ -82,6 +83,7 @@ const simpleInstructions = {
opEqual, opGreater, opLess,
opTrue, opFalse, opNil,
opLen, opSetIndex, opGetIndex,
opChr, opInt,
}
const constantInstructions = {
opConstant,

View File

@ -469,10 +469,16 @@ proc unary(comp: Compiler) =
comp.writeChunk(0, opNegate)
of tkBang:
comp.writeChunk(0, opNot)
of tkInt:
comp.writeChunk(0, opInt)
of tkChr:
comp.writeChunk(0, opChr)
else:
discard # unreachable
tkBang.genRule(unary, nop, pcNone)
tkInt.genRule(unary, nop, pcNone)
tkChr.genRule(unary, nop, pcNone)
proc binary(comp: Compiler) =
let opType = comp.previous.tokenType

View File

@ -19,6 +19,7 @@ type
tkIdentifier, tkString,
tkNumber, tkAnd, tkElse, tkFalse, tkFor, tkFunct, tkGoto, tkIf, tkNil,
tkOr, tkPrint, tkLabel, tkBreak, tkTrue, tkVar, tkWhile,
tkChr, tkInt,
tkError, tkEof
Token* = object
@ -124,7 +125,9 @@ const keywords = {
"print": tkPrint,
"true": tkTrue,
"var": tkVar,
"while": tkWhile
"while": tkWhile,
"int": tkInt,
"chr": tkChr,
}.toTable
proc canStartIdent(chr: char): bool =

View File

@ -157,7 +157,7 @@ proc run*(chunk: Chunk): InterpretResult =
runtimeError(res.msg)
break
of opPrint:
echo $stack.peek()
write stdout, $stack.peek()
of opDefineGlobal:
let name = readConstant().asString()
let existed = globals.tableSet(name.fromNdString(), stack.pop())
@ -264,7 +264,20 @@ proc run*(chunk: Chunk): InterpretResult =
if not res.ok:
runtimeError(res.msg)
break
of opChr:
let val = stack.pop()
if not val.isFloat() or val.asFloat() > 255f or val.asFloat() < 0f:
runtimeError("chr on not float or float out of range")
break
let chr = val.asFloat().int().char()
stack.push(($chr).fromNimString())
of opInt:
let val = stack.pop()
if not val.isString():
runtimeError("int on non string")
break
let code = ($val.asString())[0].int().float()
stack.push(code.fromFloat())
when profileInstructions:
durations[ins] += getMonoTime() - startTime