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")