lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 29/05/2012 14:48, Roberto Ierusalimschy wrote:
Here is my version:

   [...]
       local enter = lpeg.P(function (s, p, ...) print("ENTER", k) return true end)
       local leave = lpeg.P(function (s, p, ...) print("LEAVE", k) return false end)

I minor detail:  These two functions do not need parameters:
   "lpeg.P(function () print(..."

Yes, I kept them from the original code, partly because it was documenting the function capture...

Actually, meanwhile I made some other improvements, giving more information on the process, and indenting the output for better understanding. I was about to post here, and seeing your message, I just removed the parameters where I really don't use them. :-)

function trace(grammar, withIndent)
  local level = 0
  local lastTry = {}
  for k, r in pairs(grammar) do
    if type(k) == "number" then
      -- Doesn't work with grammar only defined with numerical indexes,
      -- but I feel they aren't common...
      if type(r) ~= "pattern" and type(r) ~= "userdata" then
        print("Initial rule: " .. r)
      end
    else
      -- Indentation, if asked, with number of spaces
      -- corresponding to the nesting level
      local prefix = function (info)
        if withIndent then
          return string.rep(" ", level) .. info
        else
          return info
        end
      end
      local try = lpeg.P(function (s, p, ...)
          print(prefix"TRY", k, "AT", p, "WITH", "'" .. s:sub(p, p) .. "'")
          level = level + 1
          lastTry[level] = p
          return true
        end)
      local fail = lpeg.P(function (s, p, ...)
          level = level - 1
          print(prefix"FAIL", k)
          return false
        end)
      grammar[k] = lpeg.Cmt(try * r + fail,
        function (s, p, ...)
          local lt = lastTry[level]
          level = level - 1
          print(prefix"MATCH", k, "UP TO", p, "=", "'" .. s:sub(lt, p-1) .. "'")
          print("-->", "'" .. s:sub(1, p-1) .. "'")
          return true
        end)
    end
  end
  return grammar
end

With a little grammar for testing: parsing something similar to Lua tables.

local test = [[ { a, { b, c, { d }, e, } ; f, {}, { { g, h } } ; i, { { j }, k, } } ]]
local P, S, C, Ct, V = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.V
local OpenBrace = P'{'
local CloseBrace = P'}'
local Separator = S',;'
local Spaces = S" \r\n"^0
local grammar =
{
  "Start";
  Start = Spaces * V"Table",
  Table = OpenBrace * Spaces * V"Elements"^-1 * CloseBrace * Spaces,
  Elements = V"Element" *
      (Separator * Spaces * V"Element")^0 *
      Separator^-1 * Spaces,
  Element = V"Table" + V"Unit",
  -- Primitive, not fully conform to Lua syntax, but OK for this test
  Unit = (1 - Separator - OpenBrace - CloseBrace)^1 * Spaces,
}
print(P(trace(grammar, true)):match(test))

The definition of the grammar is important for proper debugging...
In my initial version, I have put the Spaces before the items. It was working, but was mostly showing these spaces instead of interesting chars...

Also I defined the base patterns outside of the grammar for performance, but if they are included in the grammar, they can give more information.

--
Philippe Lhoste
--  (near) Paris -- France
--  http://Phi.Lho.free.fr
--  --  --  --  --  --  --  --  --  --  --  --  --  --