昨天我为我的新编程语言编写了翻译,并且我已经把它放在Github上了。在此之前,我做了一些简单的测试,它似乎工作,但现在当我想写一些例子 - 它根本没有工作!我真的很惊讶,我是怎么得到那个输出的。对于像这样的简单程序:
string Hello World!
locate 0
puts
效果非常好,显示输出' Hello World!'。更复杂的程序看起来像这样:
ADD 49
PUTCH
SUB 1
PUTCH
MUL 2
ADD 1
PUTCH
SUB 1
DIV 2
PUTCH
LOCATE 2
PUTD
LOCATE 0
SETV 10
PUTCH
SETV 0
LOCATE 0
STRING Hello World
LOCATE 0
PUTS
SETV 10
UNTILZERO
{
SUB 1
}
IFCC 10 == 10 {
LOCATE 0
SETV 0
STRING Ok!
LOCATE 0
PUTS
}
要理解这一点,您只需要了解Lua,C和Assembly。
如何运行上面的代码:./ lua start.lua test.txt -gencode 输出:
}UTSTE 0k! 10 {rld
local tape = {}
local pointer = 0
}UTSTE 0k! 10 {rldpe[pointer] + 49
(我不理解此invaild输出的任何部分)
所以实际上我的代码看起来像这样:
--[[
____ _ __ _ _ _
| _ \ (_) / _| | | _| || |_
| |_) |_ __ __ _ _ _ __ | |_ _ _ ___| | _|_ __ _|
| _ <| '__/ _` | | '_ \| _| | | |/ __| |/ /_| || |_
| |_) | | | (_| | | | | | | | |_| | (__| <|_ __ _|
|____/|_| \__,_|_|_| |_|_| \__,_|\___|_|\_\ |_||_|
Brainfuck# v 1.0. Copyright (C) by Krzysztof Szewczyk.
For more information check CONTRIB.MD and LICENSE.
Code is licensed under GPLv3.
--]]
output = "local tape = {}\nlocal pointer = 0\n" --We will use Lua 'eval'-like function.
brackets = 0
-- Parse command with parameters 'params', and parameter number
-- 'paramno'.
function parse(command,params,paramno)
if command == nil or params == nil or paramno == nil then return end
local cmd = string.upper(command)
if cmd == ";" then end
if cmd == "ADD" then
local amount = params[1]
output = output .. "tape[pointer] = tape[pointer] + " .. amount .. "\n"
end
if cmd == "SUB" then
local amount = params[1]
output = output .. "tape[pointer] = tape[pointer] - " .. amount .. "\n"
end
if cmd == "MUL" then
local amount = params[1]
output = output .. "tape[pointer] = tape[pointer] * " .. amount .. "\n"
end
if cmd == "DIV" then
local amount = params[1]
if amount == 0 then
print("[JIT] - Divide-by-zero error.")
end
output = output .. "tape[pointer] = tape[pointer] / " .. amount .. "\n"
end
if cmd == "ADDP" then
local amount = params[1]
output = output .. "pointer = pointer + " .. amount .. "\n"
end
if cmd == "SUBP" then
local amount = params[1]
output = output .. "pointer = pointer - " .. amount .. "\n"
end
if cmd == "MULP" then
local amount = params[1]
output = output .. "pointer = pointer * " .. amount .. "\n"
end
if cmd == "DIVP" then
local amount = params[1]
if amount == 0 then
print("[JIT] - Divide-by-zero error.")
end
output = output .. "pointer = pointer / " .. amount .. "\n"
end
if cmd == "LOCATE" then
local pos = params[1]
output = output .. "pointer = " .. pos .. "\n"
end
if cmd == "SETV" then
local val = params[1]
output = output .. "tape[pointer] = " .. val .. "\n"
end
if cmd == "STRING" then
local str = params[1]
for i = 1, #str do
local c = str:sub(i,i)
output = output .. "tape[pointer] = string.byte(\"" .. c .. "\")\n"
output = output .. "pointer = pointer + 1\n"
end
output = output .. "tape[pointer] = 0\n" --Remember to add null terminator (this can overwrite some of
--your crap stored in tape, so please have this in mind).
output = output .. "pointer = pointer + 1\n"
end
if cmd == "PUTCH" then
--Simply, no arguments
output = output .. "io.write(string.char(tape[pointer]))\n"
end
if cmd == "PUTD" then
--Simply, no arguments ^
output = output .. "io.write(tape[pointer])\n" --Just print integer (as integer, not character, for character see |)
end
if cmd == "PUTS" then
output = output .. "lastpntr=0\nwhile true do\nif tape[pointer] == 0 then break end\nio.write(string.char(tape[pointer]))\npointer = pointer + 1\nend\npointer=lastpntr\n" --I belive it's too complicated
--But it works.
end
if cmd == "GETCH" then
output = output .. "tape[pointer] = io.read()\n" --HACK: Any raw input is not possible in multiplatform way.
end
if cmd == "UNTILZERO" then
output = output .. "while tape[pointer]\n"
end
if cmd == "{" then
output = output .. "do\n"
brackets = brackets + 1;
end
if cmd == "}" then
output = output .. "end\n"
brackets = brackets - 1;
end
if cmd == "IUNTIL" then
local type = params[1]
local value = params[2]
output = output .. "while tape[pointer] " .. type .. value .. "\n"
brackets = brackets - 1;
end
if cmd == "TUNTIL" then
local type = params[1]
local value = params[2]
output = output .. "while tape[pointer] " .. type .. "tape[" .. value .. "]" .. "\n"
brackets = brackets - 1;
end
if cmd == "IFCC" then
local val1 = params[1];
local comp = params[2];
local val2 = params[3];
if params[4] == "{" then
output = output .. "if " .. val1 .. comp .. val2 .. " then\n"
else
print("[JIT]: IFCC needs starting bracket at 4th argument. Please pass it and don't forget to close it.")
end
end
if cmd == "IFCT" then
local val1 = params[1];
local comp = params[2];
local val2 = params[3];
if params[4] == "{" then
output = output .. "if " .. val1 .. comp .. "tape[" .. val2 .. "] then\n"
else
print("[JIT]: IFCC needs starting bracket at 4th argument. Please pass it and don't forget to close it.")
end
end
if cmd == "IFTT" then
local val1 = params[1];
local comp = params[2];
local val2 = params[3];
if params[4] == "{" then
output = output .. "if tape[" .. val1 .. "]" .. comp .. "tape[" .. val2 .. "] then\n"
else
print("[JIT]: IFCC needs starting bracket at 4th argument. Please pass it and don't forget to close it.")
end
end
end
-- Function to split strings. Any questions?
function string:split( inSplitPattern, outResults )
if not outResults then
outResults = { }
end
local theStart = 1
local theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
while theSplitStart do
table.insert( outResults, string.sub( self, theStart, theSplitStart-1 ) )
theStart = theSplitEnd + 1
theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart )
end
table.insert( outResults, string.sub( self, theStart ) )
return outResults
end
-- I create new function to ensure that variables
-- won't escape local context.
function main(filename,gencodeswitch)
local input = io.open(filename, "r")
if input then
--No error found while opening file
while true do
--First, read line.
local line = input:read()
--Now, let's check is it nil.
--If so, we can break out of this loop.
if line == nil then break end
--Else, we need to parse this instruction.
--So break it into main command and it's params.
local space = string.find(line, " ") --Find first space occurence (to divide
--command from it's arguments).
local params = string.sub(line, space+1) -- To get params just split string.
local command = string.sub(line, 0, space-1) -- To get command without trailing space.
--Actually, this space will get removed.
local paramTable = params:split(",")
local paramAmount = 0
-- HACK: Looks like ineffective solution, but who cares?
for i = 1, #paramTable do
paramAmount = paramAmount + 1;
end
print ("line:" .. line)
parse(command,paramTable,paramAmount)
end
--Done parsing. Generate code
if brackets ~= 0 then print("[JIT] Unbalanced brackets.") os.exit() end
if gencodeswitch == "-gencode" then print(output) end
--loadstring(output)()
else
--Oops, an error occured. Couldn't open file.
print("[JIT]: Please pass vaild filename.")
os.exit() --Bye, see ya later
end
end
if arg[1] == nil then
--User didn't pass any arguments.
print("Brainfuck# v 1.0")
print("Ussage:")
print(".\lua start.lua <input> [-print]")
print("Where:")
print(".\lua - lua executable")
print("start.lua - main module name");
print("<input> - input filename (non-optional!)")
print("[-print] - Optional, print source before execution.")
os.exit();
else
--User passed an argument
main(arg[1],arg[2])
end
我找不到任何错误,但一定有错误。 如果您想查看仓库is "fixed" in vbguest v0.15.0,但它不包含 除许可证,自述文件,构建和测试脚本之外的任何内容 我已经提出一些意见来理解这个破碎的代码 并试图更容易修复它。
有人能指出我在哪里犯了错误吗?
答案 0 :(得分:1)
我冒昧地完全修改你的代码,因为我看到了很多问题。 (它甚至没有编译,因为你发布它。)我想你是编程的新手。无论如何,还有更多的工作需要,但我会留给你剩下的。但是,它现在似乎确实适用于您的示例输入。
我将您的示例程序保存为sample.bf并使用该命令
brainfuck#.lua sample.bf -gencode | lua
获得Hello World!
作为输出。据我所知,这是正确的。
--[[
____ _ __ _ _ _
| _ \ (_) / _| | | _| || |_
| |_) |_ __ __ _ _ _ __ | |_ _ _ ___| | _|_ __ _|
| _ <| '__/ _` | | '_ \| _| | | |/ __| |/ /_| || |_
| |_) | | | (_| | | | | | | | |_| | (__| <|_ __ _|
|____/|_| \__,_|_|_| |_|_| \__,_|\___|_|\_\ |_||_|
Brainfuck# v 1.0. Copyright (C) by Krzysztof Szewczyk.
For more information check CONTRIB.MD and LICENSE.
Code is licensed under GPLv3.
--]]
output = [[
local tape = {}
local pointer = 0
]] --We will use Lua 'eval'-like function.
brackets = 0
-- Parse command with parameters 'params', and parameter number 'paramno'.
function parse(cmd,params,paramno)
if cmd == nil or params == nil or paramno == nil then return end
cmd = cmd:upper()
local amount
if cmd == ";" then
elseif cmd == "ADD" then
amount = params[1]
output = output .. "tape[pointer] = tape[pointer] + " .. amount .. "\n"
elseif cmd == "SUB" then
amount = params[1]
output = output .. "tape[pointer] = tape[pointer] - " .. amount .. "\n"
elseif cmd == "MUL" then
amount = params[1]
output = output .. "tape[pointer] = tape[pointer] * " .. amount .. "\n"
elseif cmd == "DIV" then
amount = params[1]
if amount == 0 then
print("[JIT] - Divide-by-zero error.")
end
output = output .. "tape[pointer] = tape[pointer] / " .. amount .. "\n"
elseif cmd == "ADDP" then
amount = params[1]
output = output .. "pointer = pointer + " .. amount .. "\n"
elseif cmd == "SUBP" then
amount = params[1]
output = output .. "pointer = pointer - " .. amount .. "\n"
elseif cmd == "MULP" then
amount = params[1]
output = output .. "pointer = pointer * " .. amount .. "\n"
elseif cmd == "DIVP" then
amount = params[1]
if amount == 0 then
print("[JIT] - Divide-by-zero error.")
end
output = output .. "pointer = pointer / " .. amount .. "\n"
elseif cmd == "LOCATE" then
local pos = params[1]
output = output .. "pointer = " .. pos .. "\n"
elseif cmd == "SETV" then
local val = params[1]
output = output .. "tape[pointer] = " .. val .. "\n"
elseif cmd == "STRING" then
local s = params[1]
for i = 1, #s do
local c = s:sub(i,i)
output = output .. "tape[pointer] = string.byte(\"" .. c .. "\")\n"
output = output .. "pointer = pointer + 1\n"
end
output = output .. "tape[pointer] = 0\n"
--Remember to add null terminator (this can overwrite some of your crap
--stored on tape, so please have this in mind).
output = output .. "pointer = pointer + 1\n"
elseif cmd == "PUTCH" then --Simply, no arguments
output = output .. "io.write(string.char(tape[pointer]))\n"
elseif cmd == "PUTD" then --Simply, no arguments ^
output = output .. "io.write(tape[pointer])\n" --Just print integer (as integer, not character, for character see |)
elseif cmd == "PUTS" then
output = output .. [[
lastpntr=0
while true do
if tape[pointer] == 0 then break end
io.write(string.char(tape[pointer]))
pointer = pointer + 1
end
pointer=lastpntr
]] --I believe it's too complicated but it works.
elseif cmd == "GETCH" then
output = output .. "tape[pointer] = io.read()\n" --HACK: Any raw input is not possible in multiplatform way.
elseif cmd == "UNTILZERO" then
output = output .. "while tape[pointer]\n"
elseif cmd == "{" then
output = output .. "do\n"
brackets = brackets + 1
elseif cmd == "}" then
output = output .. "end\n"
brackets = brackets - 1
elseif cmd == "IUNTIL" then
local type = params[1]
local value = params[2]
output = output .. "while tape[pointer] " .. type .. value .. "\n"
brackets = brackets - 1
elseif cmd == "TUNTIL" then
local type = params[1]
local value = params[2]
output = output .. "while tape[pointer] " .. type .. "tape[" .. value .. "]" .. "\n"
brackets = brackets - 1
elseif cmd == "IFCC" then
local val1 = params[1]
local comp = params[2]
local val2 = params[3]
if params[4] == "{" then
output = output .. "if " .. val1 .. comp .. val2 .. " then\n"
else
print("[JIT]: IFCC needs starting bracket at 4th argument. Please pass it and don't forget to close it.")
end
elseif cmd == "IFCT" then
local val1 = params[1]
local comp = params[2]
local val2 = params[3]
if params[4] == "{" then
output = output .. "if " .. val1 .. comp .. "tape[" .. val2 .. "] then\n"
else
print("[JIT]: IFCC needs starting bracket at 4th argument. Please pass it and don't forget to close it.")
end
elseif cmd == "IFTT" then
local val1 = params[1]
local comp = params[2]
local val2 = params[3]
if params[4] == "{" then
output = output .. "if tape[" .. val1 .. "]" .. comp .. "tape[" .. val2 .. "] then\n"
else
print("[JIT]: IFCC needs starting bracket at 4th argument. Please pass it and don't forget to close it.")
end
end
end
-- Function to split strings. Any questions?
function string:split( inSplitPattern, outResults )
outResults = outResults or {}
local theStart = 1
local theSplitStart, theSplitEnd = self:find(inSplitPattern, theStart)
while theSplitStart do
table.insert( outResults, self:sub(theStart, theSplitStart-1) )
theStart = theSplitEnd + 1
theSplitStart, theSplitEnd = self:find(inSplitPattern, theStart)
end
table.insert( outResults, self:sub(theStart) )
return outResults
end
-- I create new function to ensure that variables won't escape local context.
function main(filename,gencodeswitch)
local file = io.open(filename, "r")
if file == nil then
--Oops, an error occured. Couldn't open file.
print("[JIT]: Please pass valid filename.")
os.exit() --Bye, see ya later
return
end
--No error found while opening file
local space,params,command,paramTable,paramAmount
for line in file:lines() do
--We need to parse this instruction.
--So break it into main command and it's params.
space = (line..' '):find(" ") --Find first space occurence (to divide command from it's arguments).
params = line:sub(space+1) -- To get params just split string.
command = line:sub(1, space-1) -- To get command without trailing space.
--Actually, this space will get removed.
paramTable = params:split(',')
-- HACK: Looks like ineffective solution, but who cares?
--for i = 1, #paramTable do paramAmount = paramAmount + 1 end
paramAmount = #paramTable
print ('--' .. line)
parse(command,paramTable,paramAmount)
end
file:close()
--Done parsing. Generate code
if brackets ~= 0 then print("[JIT] Unbalanced brackets.") os.exit() end
if gencodeswitch == "-gencode" then print(output) end
--loadstring(output)()
end
if arg[1] == nil then
--User didn't pass any arguments.
print [[
Brainfuck# v 1.0
Usage:
.\lua start.lua <input> [-print]
Where:
.\lua - lua executable
start.lua - main module name
<input> - input filename (non-optional!)
[-print] - Optional, print source before execution.]]
os.exit()
else
--User passed an argument
main(arg[1],arg[2])
end