Home
Reading
Searching
Subscribe
Sponsors
Statistics
Posting
Contact
Spam
Lists
Links
About
Hosting
Filtering
Features Download
Marketing
Archives
FAQ
Blog
 
Gmane
From: Philippe Lhoste <PhiLho <at> GMX.net>
Subject: Re: Trace debugger for lpeg
Newsgroups: gmane.comp.lang.lua.general
Date: Tuesday 29th May 2012 13:25:18 UTC (over 5 years ago)
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
--  --  --  --  --  --  --  --  --  --  --  --  --  --
 
CD: 3ms