example bf interpreter
This commit is contained in:
parent
0c753dcc00
commit
bdac4fe7fc
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue