News : The level of daily SPAM has reached insane proportions, all registrations are now manual. I ask you to send me an e-mail (john (at) murga (dot) org), to confirm that you want me to create an account for you.


Post Reply  Post Thread 
Interactive Fish interpreter
Author Message
jpjacobs
Member
***


Posts: 113
Group: Registered
Joined: Jul 2007
Status: Offline
Reputation: 0
Post: #1
RE: Interactive Fish interpreter

I've been coding this interactive fish interpreter, because it's a really nice language (http://esolangs.org/wiki/Fish). I'm almost there, but I can't get the output window to redraw when using the run button (which goes into a loop calling the main coroutine). So I can't see the individual characters being printed.

Using the step button (which just resumes the coroutine once) does work.

Any Ideas? This is the code:

Code:
-- configuration --
demo=[["hello, world"r> ?o?<;]]
size=10
font=fltk.FL_SCREEN
def_delay=500
-- end config --

-- parsing different commands
z=table
p=z.insert    -- push
P=z.remove    -- pop
W=function(...) win.output_buffer:append(...) end
t="><^v/\\|_#x+-*,%=)(!?:~$@&r}{gponi;[].mX"        -- all tokens
C=t.char
B=t.byte
F=t.match
M=setmetatable
f={
"s.dx,s.dy=1,0","s.dx,s.dy=-1,0","s.dx,s.dy=0,-1","s.dx,s.dy=0,1",
"s.dx,s.dy=-s.dy,-s.dx","s.dx,s.dy=s.dy,s.dx","s.dx=-s.dx","s.dy=-s.dy","s.dx,s.dy=-s.dx,-s.dy",
"z=math.random(1,4)f[('><^v'):sub(z,z)]()",
"p(s.s,P(s.s)+P(s.s))","p(s.s,-P(s.s)+P(s.s))","p(s.s,P(s.s)*P(s.s))",
"z=P(s.s)if z~=0 then p(s.s,P(s.s)/z)else error'Div by 0'end","y=P(s.s)z=P(s.s)p(s.s,z%y)", -- div
"p(s.s,P(s.s)==P(s.s) and 1 or 0)",
"p(s.s,P(s.s)>P(s.s) and 1 or 0)",
"p(s.s,P(s.s)<P(s.s) and 1 or 0)",
"s.x,s.y=s.x+s.dx,s.y+s.dy",
"if #s.s==0 or s.s[#s.s]==0 then f['!'](s) end",
"p(s.s,s.s[#s.s])",
"P(s.s)",
"z=#s.s s.s[z],s.s[z-1]=s.s[z-1],s.s[z]",
"z=#s.s s.s[z],s.s[z-1],s.s[z-2]=s.s[z-1],s.s[z-2],s.s[z]",
"if s.r then p(s.s,s.r)s.r=nil else s.r=P(s.s)end",
"if s.s==s.l then z=s.l s.l={}s.s=s.l else z=S S={}s.s=S end for k=1,#z do s.s[#z-k+1]=z[k]end",
"p(s.s,1,P(s.s))",
"p(s.s,P(s.s,1))",
"z=P(s.s) p(s.s,c[P(s.s)][z])",
"z,w=P(s.s),P(s.s) c[w][P(s.s)]=z",
"W(C(P(s.s)))",
"W(P(s.s))",
"z=io.read(1) if not z then p(s.s,4)else while z:match'%s'do z=io.read(1)if not z then z='\\4'end end p(s.s,B(z))end",
"fltk.fl_message('Fish program quit')step=coroutine.create(function()return end) coroutine.resume(step)", --"os.exit()", -- TODO modify!
"T.nt=true",
"P(T,s.id)for k=s.id,#T do T[k].id=k end", -- update self.id after removing a thread.
"s.s = s.s==S and s.l or S",
"z= s.s==S and s.l or S for k=#s.s,1,-1 do p(z,P(s.s,1))end",
"dbg(s)",
}
function dbg(s)
    print""
    print("Current Stack:",s.s==s.l and "Local Stack" or "Global Stack")
    print("Local stack:")
    for k,v in pairs(s.l) do print("",k,v,v>=0 and string.char(v) or "NEG") end
    print("Global stack:")
    for k,v in pairs(S) do print("",k,v,v>=0 and string.char(v) or "NEG") end
    print("Register: ",s.r)
    print("Codebox:")
    for k=0,#c do
        io.write(string.format("%0"..#tostring(#c).."i",k),": ")
        for l=0,#c[k] do
            io.write(string.char(c[k][l]))
        end
        io.write"\n"
    end
end

-- Linking commands to functions
z=1
for k in t:gmatch"." do -- will contain the tokens
    --TODO setfenv / setmetatable to avoid all indexing in functions.
    f[k]=assert(loadstring("s=...;"..f[z]))
    z=z+1
end

T={        -- table of threads
    --nt = new thread to be created.
    }
c={}    -- codebox IP wraps around
S={}    -- global stack
-- codebox layout
--     -----> +x
--  @  |line of text            -- wrap around to second line
--     |second line of text.    -- negative indices can be used for variables
--     |
--     V +Y

-- y first coord, x second
-- wrap around rows if nil row
-- wrap around cols if nil char.
function T.n(T,x,y,dx,dy) -- New thread function
    z={
    id=#T+1,                    -- keep number id
    l={},                    -- local stack
    dx=dx or 1,                    -- 1 for +x, -1 for -x, 0 for y/-y
    dy=dy or 0,                    -- 1 for +y, -1 for -y, 0 for x/-x
    x=x or 0,                    -- X of IP
    y=y or 0,                    -- Y of IP
    -- i,                    -- will contain type of quote when reading in a string
    -- r,                    -- registry
    }
    z.m=function(s)
        s.x,s.y=s.x+s.dx,s.y+s.dy
        if s.y > #c then
            s.y=0
        elseif s.y<0 then
            s.y=#c
        end
        if s.x>#c[s.y] and s.dx==1 then
            s.x=0
        elseif s.x<0 then
            s.x=#c[s.y]
        end
    end
    z.s=z.l -- current stack is local stack
    T[z.id]=z    -- add at next index
end
T:n(-1)

function run()
-- compile to codebox
--fh= arg[1] and io.open(arg[1]) or io.stdin    -- use file or stdin
-- Todo: find a way to "lock" the editor.
y=0;pos=0
while pos<=win.edt_buffer:length() do
    c[y]=M({},{__index=function()return 32 end})--default to space
    local l = win.edt_buffer:line_text(pos)
    for k=1,#l do
        local z=l:sub(k,k)
        if not i then        -- normal mode
            if F(z,"['\"]") then i=z end
            if F(z,"[^\n\r]")then --filter out only newlines
                c[y][k-1]=B(z)
            end -- any spacing allowed.
        else                -- verbatim string mode
            if z==i then i=nil end
            c[y][k-1]=B(z)
        end
    end
    pos=win.edt_buffer:line_end(pos)+1
    y=y+1
end

while #T>0 do
    for id=1,#T do --TODO make that f[q] uses the correct stacks etc.
        s=T[id]
        s:m()                                        -- move the IP
        n,o=s.dx,s.dy -- keep old directions for new thread detection
        q=C(c[s.y][s.x])
        if s.i then                        -- stringparsing mode        
            if F(q,"['\"]") then        -- end-quote
                s.i=nil
            else
                p(s.s,c[s.y][s.x])    -- push contents of box, then advance
            end
        else                             -- not in string parsing mode
            if F(q,"['\"]") then        -- start-quote
                s.i=q
            elseif F(q,"%x") then        -- parsing a number
                p(s.s,tonumber(q,16))
            elseif F(q,"[^ ]") then
                assert(f[q])
                f[q](s)    -- call, feed with state/thread
            end
        end
    end
    if T.nt and (n~=s.dx or o~=s.dy) then
        -- create new thread
        T:n(s.x,s.y,s.dx,s.dy)
        T.nt=nil
        s.dx,s.dy=n,o        -- restore directions of parent
    end
    coroutine.yield()
end
end

step = coroutine.create(run)

win = {}
  win.window = fltk:Fl_Double_Window(334, 210, 565, 355, "Fish interpreter")
  do
    win.edt_buffer = fltk:Fl_Text_Buffer()
    win.edt = fltk:Fl_Text_Editor(25, 25, 260, 280)
    win.edt:buffer(win.edt_buffer)
    win.edt:textfont(font)
    win.edt:textsize(size)
    win.edt:selection_color(fltk.FL_BLACK)

    win.output_buffer = fltk:Fl_Text_Buffer()
    win.output = fltk:Fl_Text_Display(285, 25, 260, 280)
    win.output:buffer(win.output_buffer)
    win.output:textfont(font)
    win.output:textsize(size)
    win.output:selection_color(fltk.FL_BLACK)

    win.rol = fltk:Fl_Roller(105, 320, 45, 25, "Delay")
    win.rol_output = fltk:Fl_Value_Output(160, 320, 50, 25)
    win.rol:align(4)
    win.rol:step(100)
    win.rol:bounds(0,10000)
    win.rol:value(500)
    win.rol:callback(function() win.rol_output:value(win.rol:value()) end)

    local o = fltk:Fl_Button(215, 320, 70, 25, "Back")
    o:callback( function() print"Back button not implemented" end)
    local o = fltk:Fl_Button(285, 320, 70, 25, "Step")
    o:callback( function() coroutine.resume(step) end)
    local o = fltk:Fl_Return_Button(355, 320, 70, 25, "Run")
    o:callback(function()
        stat=1
        while coroutine.status(step)~="dead" do
            print("step, sleeping for "..win.rol_output:value())
            coroutine.resume(step) win.window:show() win.output:redraw()
            murgaLua.sleepMilliseconds(win.rol_output:value())
        end
    end)
  end
  fltk.Fl_End()
  win.window:show()
  win.edt_buffer:text(demo)
Fl:run()


Regards,

Jan-Pieter

05-06-2011 01:36 AM
Find all posts by this user Quote this message in a reply
Post Reply  Post Thread 

Messages In This Thread
Interactive Fish interpreter - jpjacobs - 04-21-2011, 08:09 PM
RE: Texteditor - mikshaw - 04-22-2011, 12:43 AM
RE: Texteditor - jpjacobs - 04-22-2011, 08:14 PM
RE: Interactive Fish interpreter - jpjacobs - 05-06-2011 01:36 AM
RE: Interactive Fish interpreter - mikshaw - 05-06-2011, 11:23 PM

View a Printable Version
Send this Thread to a Friend
Subscribe to this Thread | Add Thread to Favorites

Forum Jump: