On Wed, Nov 21, 2012 at 11:54:53PM -0800, Long Nguyen wrote: > Hello everyone, > > I was very impressed with Val Schorre's META-II paper that Dr. Kay gave me > to read, so I built a version of it for C; the metacircular part of which > can fit in a half of a sheet of A4 or Letter paper. Here it is:
So, here is my version for Lua. I came up with it independently (I deliberately did _not_ look at your work), except for 2 details: - Of course '*' is for repetition and '$' for variable recall. Schorres's convention is backwards, how could I have missed it? - At first, I used exclusively functions. Then your `do {} while()` loops reminded me that `(function() ... end)()` might be less readable than `repeat ... until true` for those who don't know about first class functions. I swear the removal of this horrendous `.OUT()` syntax is convergent evol... err, design. The version I present here is not the first working one, but it is the first one I'm happy with. It was build from previous versions, which were build from... and the infinite regress was solve by hand compiling. By the way: Hand. Compiling. Sucks. But I was too proud to bootstrap from Long's compiler. So, here is my meta-compiler: The metacircular part is below, the rest (runtime support and bootstrap code) is attached. I'm pretty sure there is no bug, though like Long's version, there is no error reporting either. You need Lua5.1 to run it. Older versions will miss `string.match()` Loup. .syntax program output = '{' * ( '$' {'io.write(_input)'} | .string {'io.write(' $ ')'}) '}' {'io.write("\\n")' }; primary = .id { $ '()' } | .string {'_run.testSTR(' $ ')' } | '.id' {'local _input = _run.parseID()' } | '.number' {'local _input = _run.parseNUM()'} | '.string' {'local _input = _run.parseSTR()'} | '.empty' {'_switch = true' } | '(' choice ')' | '*' {'repeat' } primary {'until not _switch' } {'_switch = true' }; sequence = {'repeat' } (primary {'if not _switch then break end'} | output) * (primary {'if not _switch then error() end'} | output) {'until true'}; choice = {'repeat' } sequence * ('|' {'if _switch then break end'} sequence) {'until true'}; rule = .id {'function ' $ '()'} '=' choice ';' {'end'}; program = '.syntax' .id {'local _run = require("runtime")'} * rule '.end' {$ '()' }; .end
local input = io.read("*all") -- should take place at module call time local loc = 1 -- beginning of the input local function forward(n) loc = loc + n end local function getchar(String, i) return string.sub(String, i, i) end -- Tries to extract the next token. If found, returns it and advances past it local function read(finder) -- skip leading whitespace first while string.find(" \t\n\r", getchar(input, loc), 1, true) do if loc >= string.len(input) then error("End of input") end forward(1) end local token = finder() -- extract the token with the finder if token then forward(string.len(token)) -- token fond => advance past it _switch = true else _switch = false end return token -- returns the token or nil end local function match(pattern) return function() return string.match(input, pattern, loc) end end function test_prefix(String) return function() local prefix = string.sub(input, loc, loc + string.len(String) - 1) return prefix == String and prefix or nil end end local function testSTR (String) return read(test_prefix(String)) end local function parseID () return read(match("^%a[%a%d]*")) end local function parseNUM() return read(match("^%d+") ) end local function parseSTR() return read(match("^'[^']*'") ) end local M = {} -- public interface M.testSTR = testSTR M.parseID = parseID M.parseNUM = parseNUM M.parseSTR = parseSTR return M
local _run = require("runtime") function output() repeat -- choice -- repeat -- sequence -- _run.testSTR('{') if not _switch then break end repeat -- repetition -- repeat -- choice -- repeat -- sequence -- _run.testSTR('$') if not _switch then break end io.write('io.write(_input)') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- local _input = _run.parseSTR() if not _switch then break end io.write('io.write(') io.write(_input) io.write(')') io.write("\n") until true -- sequence (end) until true -- choice (end) until not _switch -- repetition (end) _switch = true if not _switch then error() end _run.testSTR('}') if not _switch then error() end io.write('io.write("\\n")') io.write("\n") until true -- sequence (end) until true -- choice (end) end -- (output) function primary() repeat -- choice -- repeat -- sequence -- local _input = _run.parseID() if not _switch then break end io.write(_input) io.write('()') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- local _input = _run.parseSTR() if not _switch then break end io.write('_run.testSTR(') io.write(_input) io.write(')') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- _run.testSTR('.id') if not _switch then break end io.write('local _input = _run.parseID()') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- _run.testSTR('.number') if not _switch then break end io.write('local _input = _run.parseNUM()') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- _run.testSTR('.string') if not _switch then break end io.write('local _input = _run.parseSTR()') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- _run.testSTR('.empty') if not _switch then break end io.write('_switch = true') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- _run.testSTR('(') if not _switch then break end choice() if not _switch then error() end _run.testSTR(')') if not _switch then error() end until true -- sequence (end) if _switch then break end repeat -- sequence -- _run.testSTR('*') if not _switch then break end io.write('repeat') io.write("\n") primary() if not _switch then error() end io.write('until not _switch') io.write("\n") io.write('_switch = true') io.write("\n") until true -- sequence (end) until true -- choice (end) end -- (primary) function sequence() repeat -- choice -- repeat -- sequence -- io.write('repeat') io.write("\n") repeat -- choice -- repeat -- sequence -- primary() if not _switch then break end io.write('if not _switch then break end') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- output() if not _switch then break end until true -- sequence (end) until true -- choice (end) if not _switch then error() end repeat -- repetition -- repeat -- choice -- repeat -- sequence -- primary() if not _switch then break end io.write('if not _switch then error() end') io.write("\n") until true -- sequence (end) if _switch then break end repeat -- sequence -- output() if not _switch then break end until true -- sequence (end) until true -- choice (end) until not _switch -- repetition (end) _switch = true if not _switch then error() end io.write('until true') io.write("\n") until true -- sequence (end) until true -- choice (end) end -- (sequence) function choice() repeat -- choice -- repeat -- sequence -- io.write('repeat') io.write("\n") sequence() if not _switch then error() end repeat -- repetition -- repeat -- choice -- repeat -- sequence -- _run.testSTR('|') if not _switch then break end io.write('if _switch then break end') io.write("\n") sequence() if not _switch then error() end until true -- sequence (end) until true -- choice (end) until not _switch -- repetition (end) _switch = true if not _switch then error() end io.write('until true') io.write("\n") until true -- sequence (end) until true -- choice (end) end -- (choice) function rule() repeat -- choice -- repeat -- sequence -- local _input = _run.parseID() if not _switch then break end io.write('function ') io.write(_input) io.write('()') io.write("\n") _run.testSTR('=') if not _switch then error() end choice() if not _switch then error() end _run.testSTR(';') if not _switch then error() end io.write('end') io.write("\n") until true -- sequence (end) until true -- choice (end) end -- (rule) function program() repeat -- choice -- repeat -- sequence -- _run.testSTR('.syntax') if not _switch then break end local _input = _run.parseID() if not _switch then error() end io.write('local _run = require("runtime")') io.write("\n") repeat -- repetition -- rule() until not _switch -- repetition (end) _switch = true if not _switch then error() end _run.testSTR('.end') if not _switch then error() end io.write(_input) io.write('()') io.write("\n") until true -- sequence (end) until true -- choice (end) end -- (program) program()
_______________________________________________ fonc mailing list fonc@vpri.org http://vpri.org/mailman/listinfo/fonc