|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
lcode.e - 2002sep29
Summary: one way to implement a Forth-like language on top of Lua is
to write an inner interpreter that runs code stored in a Lua array;
the cells of that array can be used to store arbitrary Lua values, not
just integers in a certain range, and I can start with a very simple
interpreter that runs "L-code" consisting mainly of strings and Lua
functions... then I can gradually change it into something that runs
"real bytecodes" that can be reimplemented in C. This file contains
some notes about that.
"mem" in flua: there's an array "mem" where numbered positions
correspond to "memory positions" - "cells", whose content is generally
a number, or a string (that gets translated to a number).
There's another dictionary that associates names -> numbers (for
compilation); when we define a dictionary function from interpretation
mode it gets an entry in that dictionary, and another that is a
function that when executed in interp mode will call the "compiled
version".
Implementar um array "nameof" pra eu poder mostrar funções e outros
baratinhos mais facilmente. Aliás, ele não precisa ser sempre um
array... não, não vou complicar tanto por enquanto (Lua não é Forth!),
ele vai ser um array sim. Depois eu mudo, se for o caso.
Sobre a compilação: um array "mem"; um certo número de estados, cada
um dado por uma função (em princípio só tenho os estados "head" e
"forth"; ou melhor, state_head e state_forth); o interpretador
simplesmente "while state do state() done".
#*
mylua -e '
push = function( stack, val ) tinsert(stack, 1, val) end
pop = function( stack ) return tremove(stack, 1) end
mem = {}
rstack = {}
rpush = function( val ) push(rstack, val) end
rpop = function( ) return pop(rstack) end
dstack = {}
dpush = function( val ) push(dstack, val) end
dpop = function( ) return pop(dstack) end
state_forth = function( )
local what_to_run = mem[ip]
ip = ip + 1
if type(what_to_run) == "number" then
state = state_head
rpush(ip)
ip = what_to_run
else
what_to_run() -- non-numbers are "primitives".
end
end
state_head = function( )
local what_to_run = mem[ip]
ip = ip + 1
what_to_run() -- all my heads are primitives right now
end
f_exit = function( ) ip = pop(rstack); if ip == nil then state = nil end end
f_lit = function( ) dpush(mem[ip]); ip = ip + 1 end
f_dup = function( ) local v = dpop(); dpush(v); dpush(v) end
f_star = function( ) dpush(dpop()*dpop()) end
f_dot = function( ) p(dpop()) end
h_forth = function( ) state = state_forth end
set_many = function( table, start, ... )
for i = 1,getn(arg) do
table[start] = arg[i]
start = start + 1
end
end
f_square = 0
set_many(mem, f_square, h_forth, f_dup, f_star, f_exit)
f_cube = f_square + 4
set_many(mem, f_cube, h_forth, f_dup, f_square, f_star, f_exit)
f_demo = f_cube + 5
set_many(mem, f_demo, h_forth, f_lit, 5, f_cube, f_dot, f_exit)
ip = f_demo
state = state_head
while state do state() end
'
#*
-- (find-luanode "Table Constructors")
-- (find-luanode "Function Definitions")
-- (find-luanode "For Statement")
Próximos passos: adicionar um rstack e uns demos com variáveis (a l
Forth) e outros baratos; modificar o asText pra ele aceitar um
dicionário (ou uma função dicionário) que converta alguns carinhas de
modo especial, e fazer com que o tratamento dele de índices string não
bugue em strings com chars estranhos; criar um "dicionário para o modo
de compilação", em que cada string (um word) esteja associado ao
código que o compile; i.e., "." -> function( ) mem[here] = f_dot; here
= here + 1 end, etc.
# (find-angg "miniforth/macro2.lua")
# (find-angg "miniforth/")
# (find-angg "miniforth/miniforth1.lua")
# (find-angg "miniforth/crim/")
# (find-luanode "")
# (find-luanode "Lua Stand-alone")
# (find-luanode "type")
mylua -e 'print(type(function () end))' ;# "function"
mylua -e 'print(type("foo"))' ;# "string"
mylua -e 'print(type(22))' ;# "number"
mylua -e 'print(type(22.57))' ;# "number"
mylua -e 'p(push)'
# (find-angg ".zshrc" "lua")