Add digilines support.

This commit is contained in:
Novatux 2013-07-06 20:41:50 +02:00
parent b0dbd68921
commit 6e0aab6bb7
7 changed files with 4663 additions and 4521 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
*~ *~
bit32.so

4
README
View File

@ -1,3 +1,7 @@
How to build How to build
Linux:
gcc bit32.c -shared -fpic -I../../src/lua/src -o bit32.so gcc bit32.c -shared -fpic -I../../src/lua/src -o bit32.so
Windows:
I don't know, sorry. I need someone to explain me that!

File diff suppressed because it is too large Load Diff

1
depends.txt Normal file
View File

@ -0,0 +1 @@
digilines

21
f.py
View File

@ -215,6 +215,27 @@ def compile_def(name, l, immed=False):
elif word == "QUIT": elif word == "QUIT":
squit.append(here) squit.append(here)
here += 2 here += 2
elif word == 'S"':
nw = l[i][:-1] #Remove trailing "
i += 1
setmemory(here, df["(branch)"])
here += 2
stack.append(here)
here += 2
stack.append(here)
for c in nw:
memory[here] = ord(c)
here += 1
k = stack.pop()
setmemory(stack.pop(), here)
setmemory(here, df["(lit)"])
here += 2
setmemory(here, k)
here += 2
setmemory(here, df["(lit)"])
here += 2
setmemory(here, len(nw))
here += 2
else: else:
setmemory(here, df[word]) setmemory(here, df[word])
here += 2 here += 2

View File

@ -80,6 +80,9 @@ ASSEMBLER
: WAIT 0x00 0x29 ; : WAIT 0x00 0x29 ;
: WAIT-INPUT 0x50 0x29 ; : WAIT-INPUT 0x50 0x29 ;
: LEAVE 0x11 0x11 0x11 0x1b 0x29 ; : LEAVE 0x11 0x11 0x11 0x1b 0x29 ;
: RECEIVE-AT 0x33 0x32 0x30 0x52 0x20 0x29 ;
: SET-CHANNEL 0x32 0x31 0x54 0x29 ;
: SEND 0x32 0x31 0x53 0x29 ;
FORTH FORTH
@ -106,6 +109,7 @@ FORTH
: CELL- 2 - ; : CELL- 2 - ;
: CHAR+ 1+ ; : CHAR+ 1+ ;
: CELLS 2* ; : CELLS 2* ;
: RECEIVE 0x80 RECEIVE-AT ;
: 2! SWAP OVER ! CELL+ ! ; : 2! SWAP OVER ! CELL+ ! ;
: 2@ DUP CELL+ @ SWAP @ ; : 2@ DUP CELL+ @ SWAP @ ;
: SOURCE (source) 2@ ; : SOURCE (source) 2@ ;
@ -119,7 +123,7 @@ FORTH
: NIP SWAP DROP ; : NIP SWAP DROP ;
: ABS DUP 0< IF NEGATE THEN ; : ABS DUP 0< IF NEGATE THEN ;
: (marker) LATEST ! (here) ! ; : (marker) LATEST ! (here) ! ;
: TYPE DUP 0> IF OVER + SWAP DO I C@ EMIT LOOP ELSE 2DROP THEN ; : TYPE DUP 0> IF OVER + SWAP ?DO I C@ EMIT LOOP ELSE 2DROP THEN ;
: RSTR 1+ DUP 2 + C@ 127 AND TUCK - SWAP ; : RSTR 1+ DUP 2 + C@ 127 AND TUCK - SWAP ;
: CR 10 EMIT ; : CR 10 EMIT ;
: SPACE 32 EMIT ; : SPACE 32 EMIT ;
@ -218,7 +222,7 @@ FORTH
: ?DO ['] (?do) , HERE 0 , HERE ; IMMEDIATE : ?DO ['] (?do) , HERE 0 , HERE ; IMMEDIATE
: LOOP ['] (loop) , , HERE SWAP ! ; IMMEDIATE : LOOP ['] (loop) , , HERE SWAP ! ; IMMEDIATE
: +LOOP ['] (+loop) , , HERE SWAP ! ; IMMEDIATE : +LOOP ['] (+loop) , , HERE SWAP ! ; IMMEDIATE
: ACCEPT WAIT-INPUT 0 @ MIN 16 -ROT MOVE ; : ACCEPT WAIT-INPUT 0 @ MIN TUCK 16 -ROT MOVE ;
: EXPECT ACCEPT SPAN ! ; : EXPECT ACCEPT SPAN ! ;
: QUERY 0 >IN ! 0 SOURCE-ID ! TIB DUP 80 ACCEPT SPACE (source) 2! ; : QUERY 0 >IN ! 0 SOURCE-ID ! TIB DUP 80 ACCEPT SPACE (source) 2! ;
: REFILL SOURCE-ID @ IF FALSE ELSE 0 >IN ! TIB DUP 80 ACCEPT SPACE (source) 2! TRUE THEN ; : REFILL SOURCE-ID @ IF FALSE ELSE 0 >IN ! TIB DUP 80 ACCEPT SPACE (source) 2! TRUE THEN ;
@ -230,4 +234,6 @@ FORTH
: DABS DUP 0< IF OVER NEGATE ROT IF SWAP INVERT ELSE SWAP NEGATE THEN THEN ; : DABS DUP 0< IF OVER NEGATE ROT IF SWAP INVERT ELSE SWAP NEGATE THEN THEN ;
: SM/REM OVER >R 2DUP XOR >R ABS >R DABS R> UM/MOD R> 0< IF NEGATE THEN SWAP R> 0< IF NEGATE THEN SWAP ; : SM/REM OVER >R 2DUP XOR >R ABS >R DABS R> UM/MOD R> 0< IF NEGATE THEN SWAP R> 0< IF NEGATE THEN SWAP ;
\ : KEY BEGIN RAWKEY DUP 31 > OVER 127 < AND IF EXIT THEN DROP AGAIN ; \ : KEY BEGIN RAWKEY DUP 31 > OVER 127 < AND IF EXIT THEN DROP AGAIN ;
: ON SET-CHANNEL S" on" SEND ;
: OFF SET-CHANNEL S" off" SEND ;
: COLD 82 EMIT 101 EMIT 97 EMIT 100 EMIT 121 EMIT QUIT ; : COLD 82 EMIT 101 EMIT 97 EMIT 100 EMIT 121 EMIT QUIT ;

141
init.lua
View File

@ -1,5 +1,6 @@
CYCLES_PER_STEP = 1000 local CYCLES_PER_STEP = 1000
MAX_CYCLES = 100000 local MAX_CYCLES = 100000
local MAX_LINE_LENGHT = 42
local modpath = minetest.get_modpath("forth_computer") local modpath = minetest.get_modpath("forth_computer")
package.cpath = modpath.."/?.so;"..modpath.."/?.dll;"..package.cpath; package.cpath = modpath.."/?.so;"..modpath.."/?.dll;"..package.cpath;
@ -37,6 +38,15 @@ function lines(str)
return t return t
end end
local function hashpos(pos)
return tostring(pos.x).."\n"..tostring(pos.y).."\n"..tostring(pos.z)
end
local function dehashpos(str)
local l = lines(str)
return {x = tonumber(l[1]), y = tonumber(l[2]), z = tonumber(l[3])}
end
function newline(text, toadd) function newline(text, toadd)
local f = lines(text) local f = lines(text)
table.insert(f, toadd) table.insert(f, toadd)
@ -90,7 +100,7 @@ local function emit(pos, c, cptr)
local ll = ls[#ls] local ll = ls[#ls]
if s=="\n" or s=="\r" then if s=="\n" or s=="\r" then
meta:set_string("text", newline(text,"")) meta:set_string("text", newline(text,""))
elseif string.len(ll)>=52 then elseif string.len(ll)>=MAX_LINE_LENGHT then
meta:set_string("text", newline(text, s)) meta:set_string("text", newline(text, s))
else else
meta:set_string("text", text..s) meta:set_string("text", text..s)
@ -98,14 +108,52 @@ local function emit(pos, c, cptr)
cptr.fmodif = true cptr.fmodif = true
end end
local function string_at(cptr, addr, len)
local l = {}
for k=1, len do
local i = u16(addr+k-1)
local s = cptr[i]
l[k] = string.char(s)
end
return table.concat(l, "")
end
local function receive(cptr, caddr, clen, raddr)
local channel = string_at(cptr, caddr, clen)
local event = cptr.digiline_events[channel]
if event and type(event)=="string" then
if string.len(event)>80 then
event = string.sub(event,1,80)
end
for i=1,string.len(event) do
cptr[u16(raddr-1+i)] = string.byte(event,i)
end
cptr.X = string.len(event)
else
cptr.X = 0
end
end
local function set_channel(cptr, caddr, clen)
local channel = string_at(cptr, caddr, clen)
cptr.channel = channel
end
local function send_message(pos, cptr, maddr, mlen)
local msg = string_at(cptr, maddr, mlen)
cptr.digiline_events[cptr.channel] = msg
digiline:receptor_send(pos, digiline.rules.default, cptr.channel, msg)
end
local function run_computer(pos,cptr) local function run_computer(pos,cptr)
cptr.cycles = math.max(MAX_CYCLES,cptr.cycles+CYCLES_PER_STEP) cptr.cycles = math.max(MAX_CYCLES,cptr.cycles+CYCLES_PER_STEP)
while 1 do while 1 do
instr = cptr[cptr.PC] instr = cptr[cptr.PC]
local f = ITABLE[instr]
if f == nil then return end
--print("Instr: "..tostring(instr).." PC: "..tostring(cptr.PC).." SP: "..tostring(cptr.SP).." RP: "..tostring(cptr.RP).." X: "..tostring(cptr.X).." Y: "..tostring(cptr.Y).." Z: "..tostring(cptr.Z).." I: "..tostring(cptr.I)) --print("Instr: "..tostring(instr).." PC: "..tostring(cptr.PC).." SP: "..tostring(cptr.SP).." RP: "..tostring(cptr.RP).." X: "..tostring(cptr.X).." Y: "..tostring(cptr.Y).." Z: "..tostring(cptr.Z).." I: "..tostring(cptr.I))
cptr.PC = bit32.band(cptr.PC+1, 0xffff) cptr.PC = bit32.band(cptr.PC+1, 0xffff)
local f = ITABLE[instr] setfenv(f, {cptr = cptr, pos=pos, emit=emit, receive=receive, set_channel=set_channel, send_message=send_message, u16=u16, u32=u32, s16=s16, s32=s32, read=read, write=write, readC=readC, writeC=writeC, push=push, pop=pop, rpush=rpush, rpop=rpop, bit32=bit32, math=math})
setfenv(f, {cptr = cptr, pos=pos, emit=emit, u16=u16, u32=u32, s16=s16, s32=s32, read=read, write=write, readC=readC, writeC=writeC, push=push, pop=pop, rpush=rpush, rpop=rpop, bit32=bit32, math=math})
f() f()
cptr.cycles = cptr.cycles - 1 cptr.cycles = cptr.cycles - 1
if cptr.paused or cptr.cycles == 0 then if cptr.paused or cptr.cycles == 0 then
@ -126,6 +174,8 @@ local function create_cptr()
cptr.SP = 0x200 cptr.SP = 0x200
cptr.paused = false cptr.paused = false
cptr.has_input = false cptr.has_input = false
cptr.digiline_events = {}
cptr.channel = ""
cptr.cycles = 0 cptr.cycles = 0
return cptr return cptr
end end
@ -222,10 +272,46 @@ ITABLE_RAW = {
[0x50] = "if cptr.has_input then\ncptr.has_input = false\nelse\ncptr.paused = true\ncptr.PC = u16(cptr.PC-1)\nend", [0x50] = "if cptr.has_input then\ncptr.has_input = false\nelse\ncptr.paused = true\ncptr.PC = u16(cptr.PC-1)\nend",
[0x51] = "emit(pos, cptr.X, cptr)", [0x51] = "emit(pos, cptr.X, cptr)",
[0x52] = "receive(cptr, cptr.X, cptr.Y, cptr.Z)", -- Digiline receive
[0x53] = "send_message(pos, cptr, cptr.X, cptr.Y)", -- Digiline send
[0x54] = "set_channel(cptr, cptr.X, cptr.Y)", -- Digiline set channel
} }
ITABLE = {} ITABLE = {}
local formspec_close_table = {}
local function on_formspec_close(name, func)
formspec_close_table[name] = {func=func}
end
minetest.register_globalstep(function(dtime)
for name, t in pairs(formspec_close_table) do
local player = minetest.get_player_by_name(name)
if player == nil then
t.func()
formspec_close_table[name] = nil
return
end
local pitch = player:get_look_pitch()
local yaw = player:get_look_yaw()
local pos = player:getpos()
if t.pitch ~= nil then
if pitch~=t.pitch or yaw~=t.yaw or pos.x~=t.x or pos.y~=t.y or pos.z~=t.z then
t.func()
formspec_close_table[name] = nil
return
end
else
t.pitch = pitch
t.yaw = yaw
t.x = pos.x
t.y = pos.y
t.z = pos.z
end
end
end)
for i, v in pairs(ITABLE_RAW) do for i, v in pairs(ITABLE_RAW) do
ITABLE[i] = loadstring(v) ITABLE[i] = loadstring(v)
end end
@ -248,24 +334,42 @@ end
local cptrs = read_file(wpath.."/forth_computers") local cptrs = read_file(wpath.."/forth_computers")
local on_digiline_receive = function (pos, node, channel, msg)
local cptr = cptrs[hashpos(pos)].cptr
if cptr == nil then return end
cptr.digiline_events[channel] = msg
end
minetest.register_node("forth_computer:computer",{ minetest.register_node("forth_computer:computer",{
description = "Computer", description = "Computer",
tiles = {"computer.png"}, tiles = {"computer.png"},
groups = {cracky=3}, groups = {cracky=3},
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
digiline =
{
receptor = {},
effector = {action = on_digiline_receive},
},
on_construct = function(pos) on_construct = function(pos)
local meta=minetest.get_meta(pos) local meta=minetest.get_meta(pos)
meta:set_string("text","\n\n\n\n\n\n\n\n\n\n") meta:set_string("text","\n\n\n\n\n\n\n\n\n\n")
cptrs[minetest.serialize(pos)] = {pos=pos, cptr=create_cptr(), fmodif=false} cptrs[hashpos(pos)] = {pos=pos, cptr=create_cptr(), fmodif=false}
end, end,
on_destruct = function(pos) on_destruct = function(pos)
cptrs[minetest.serialize(pos)] = nil cptrs[hashpos(pos)] = nil
end, end,
on_rightclick = function(pos, node, clicker) on_rightclick = function(pos, node, clicker)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local name = clicker:get_player_name() local name = clicker:get_player_name()
cptrs[minetest.serialize(pos)].cptr.pname = name if cptrs[hashpos(pos)] == nil then
minetest.show_formspec(name,"computer"..minetest.serialize(pos),create_formspec(meta:get_string("text"))) cptrs[hashpos(pos)] = {pos=pos, cptr=create_cptr(), fmodif=false}
end
cptrs[hashpos(pos)].cptr.pname = name
on_formspec_close(name, function()
local c = cptrs[hashpos(pos)]
if c~= nil then c.cptr.pname = nil end
end)
minetest.show_formspec(name,"computer"..hashpos(pos),create_formspec(meta:get_string("text")))
end, end,
}) })
@ -276,7 +380,7 @@ minetest.register_globalstep(function(dtime)
i.cptr.fmodif=false i.cptr.fmodif=false
if i.cptr.pname~=nil then if i.cptr.pname~=nil then
local meta = minetest.get_meta(i.pos) local meta = minetest.get_meta(i.pos)
minetest.show_formspec(i.cptr.pname,"computer"..minetest.serialize(i.pos),create_formspec(meta:get_string("text"))) minetest.show_formspec(i.cptr.pname,"computer"..hashpos(i.pos),create_formspec(meta:get_string("text")))
end end
end end
end end
@ -290,12 +394,16 @@ minetest.register_on_shutdown(function()
write_file(wpath.."/forth_computers",cptrs) write_file(wpath.."/forth_computers",cptrs)
end) end)
function escape(x)
return string.gsub(string.gsub(string.gsub(x,";","\\;"), "%]", "\\]"), "%[", "\\[")
end
function create_formspec(text) function create_formspec(text)
local f = lines(text) local f = lines(text)
s = "size[5,4.5;" s = "size[5,4.5;"
i = -0.25 i = -0.25
for _,x in ipairs(f) do for _,x in ipairs(f) do
s = s.."]label[0,"..tostring(i)..";"..minetest.formspec_escape(x) s = s.."]label[0,"..tostring(i)..";"..escape(x)--minetest.formspec_escape(x)
i = i+0.3 i = i+0.3
end end
s = s.."]field[0.3,"..tostring(i+0.4)..";4.4,1;f;;]" s = s.."]field[0.3,"..tostring(i+0.4)..";4.4,1;f;;]"
@ -305,20 +413,21 @@ end
minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname:sub(1,8)~="computer" then return end if formname:sub(1,8)~="computer" then return end
if fields["f"]==nil or fields["f"]=="" then return end if fields["f"]==nil or fields["f"]=="" then return end
local pos = minetest.deserialize(formname:sub(9,-1)) local pos = dehashpos(formname:sub(9,-1))
local c = cptrs[minetest.serialize(pos)] local c = cptrs[hashpos(pos)]
if c==nil then return end if c==nil then return end
local cptr=c.cptr local cptr=c.cptr
cptr.has_input = true cptr.has_input = true
if string.len(fields["f"])>52 then if string.len(fields["f"])>MAX_LINE_LENGHT then
fields["f"] = string.sub(fields["f"],1,52) fields["f"] = string.sub(fields["f"],1,MAX_LINE_LENGHT)
end end
for i=1,string.len(fields["f"]) do for i=1,string.len(fields["f"]) do
cptr[15+i] = string.byte(fields["f"],i) cptr[15+i] = string.byte(fields["f"],i)
end end
write(cptr, 0, string.len(fields["f"])) write(cptr, 0, string.len(fields["f"]))
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local ntext = newline(meta:get_string("text"),fields["f"]) --local ntext = newline(meta:get_string("text"),fields["f"])
local ntext = meta:get_string("text")..fields["f"]
meta:set_string("text",ntext) meta:set_string("text",ntext)
minetest.show_formspec(player:get_player_name(),formname,create_formspec(ntext)) minetest.show_formspec(player:get_player_name(),formname,create_formspec(ntext))
end) end)