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

Reply via email to