Update talents + beasts
This commit is contained in:
356
tools/lpeg/lpprint.lua
Normal file
356
tools/lpeg/lpprint.lua
Normal file
@ -0,0 +1,356 @@
|
||||
--[[
|
||||
LPEGLJ
|
||||
lpprint.lua
|
||||
Tree, code and debug print function (only for debuging)
|
||||
Copyright (C) 2014 Rostislav Sacek.
|
||||
based on LPeg v1.0 - PEG pattern matching for Lua
|
||||
Lua.org & PUC-Rio written by Roberto Ierusalimschy
|
||||
http://www.inf.puc-rio.br/~roberto/lpeg/
|
||||
|
||||
** Permission is hereby granted, free of charge, to any person obtaining
|
||||
** a copy of this software and associated documentation files (the
|
||||
** "Software"), to deal in the Software without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Software, and to
|
||||
** permit persons to whom the Software is furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be
|
||||
** included in all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**
|
||||
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
|
||||
--]]
|
||||
|
||||
local ffi = require"ffi"
|
||||
local band, rshift, lshift = bit.band, bit.rshift, bit.lshift
|
||||
|
||||
ffi.cdef[[
|
||||
int isprint ( int c );
|
||||
]]
|
||||
|
||||
local RuleLR = 0x10000
|
||||
local Ruleused = 0x20000
|
||||
|
||||
-- {======================================================
|
||||
-- Printing patterns (for debugging)
|
||||
-- =======================================================
|
||||
|
||||
local TChar = 0
|
||||
local TSet = 1
|
||||
local TAny = 2 -- standard PEG elements
|
||||
local TTrue = 3
|
||||
local TFalse = 4
|
||||
local TRep = 5
|
||||
local TSeq = 6
|
||||
local TChoice = 7
|
||||
local TNot = 8
|
||||
local TAnd = 9
|
||||
local TCall = 10
|
||||
local TOpenCall = 11
|
||||
local TRule = 12 -- sib1 is rule's pattern, sib2 is 'next' rule
|
||||
local TGrammar = 13 -- sib1 is initial (and first) rule
|
||||
local TBehind = 14 -- match behind
|
||||
local TCapture = 15 -- regular capture
|
||||
local TRunTime = 16 -- run-time capture
|
||||
|
||||
local IAny = 0 -- if no char, fail
|
||||
local IChar = 1 -- if char != aux, fail
|
||||
local ISet = 2 -- if char not in val, fail
|
||||
local ITestAny = 3 -- in no char, jump to 'offset'
|
||||
local ITestChar = 4 -- if char != aux, jump to 'offset'
|
||||
local ITestSet = 5 -- if char not in val, jump to 'offset'
|
||||
local ISpan = 6 -- read a span of chars in val
|
||||
local IBehind = 7 -- walk back 'aux' characters (fail if not possible)
|
||||
local IRet = 8 -- return from a rule
|
||||
local IEnd = 9 -- end of pattern
|
||||
local IChoice = 10 -- stack a choice; next fail will jump to 'offset'
|
||||
local IJmp = 11 -- jump to 'offset'
|
||||
local ICall = 12 -- call rule at 'offset'
|
||||
local IOpenCall = 13 -- call rule number 'offset' (must be closed to a ICall)
|
||||
local ICommit = 14 -- pop choice and jump to 'offset'
|
||||
local IPartialCommit = 15 -- update top choice to current position and jump
|
||||
local IBackCommit = 16 -- "fails" but jump to its own 'offset'
|
||||
local IFailTwice = 17 -- pop one choice and then fail
|
||||
local IFail = 18 -- go back to saved state on choice and jump to saved offset
|
||||
local IGiveup = 19 -- internal use
|
||||
local IFullCapture = 20 -- complete capture of last 'off' chars
|
||||
local IOpenCapture = 21 -- start a capture
|
||||
local ICloseCapture = 22
|
||||
local ICloseRunTime = 23
|
||||
|
||||
local Cclose = 0
|
||||
local Cposition = 1
|
||||
local Cconst = 2
|
||||
local Cbackref = 3
|
||||
local Carg = 4
|
||||
local Csimple = 5
|
||||
local Ctable = 6
|
||||
local Cfunction = 7
|
||||
local Cquery = 8
|
||||
local Cstring = 9
|
||||
local Cnum = 10
|
||||
local Csubst = 11
|
||||
local Cfold = 12
|
||||
local Cruntime = 13
|
||||
local Cgroup = 14
|
||||
|
||||
|
||||
-- number of siblings for each tree
|
||||
local numsiblings = {
|
||||
[TRep] = 1,
|
||||
[TSeq] = 2,
|
||||
[TChoice] = 2,
|
||||
[TNot] = 1,
|
||||
[TAnd] = 1,
|
||||
[TRule] = 2,
|
||||
[TGrammar] = 1,
|
||||
[TBehind] = 1,
|
||||
[TCapture] = 1,
|
||||
[TRunTime] = 1,
|
||||
}
|
||||
local names = {
|
||||
[IAny] = "any",
|
||||
[IChar] = "char",
|
||||
[ISet] = "set",
|
||||
[ITestAny] = "testany",
|
||||
[ITestChar] = "testchar",
|
||||
[ITestSet] = "testset",
|
||||
[ISpan] = "span",
|
||||
[IBehind] = "behind",
|
||||
[IRet] = "ret",
|
||||
[IEnd] = "end",
|
||||
[IChoice] = "choice",
|
||||
[IJmp] = "jmp",
|
||||
[ICall] = "call",
|
||||
[IOpenCall] = "open_call",
|
||||
[ICommit] = "commit",
|
||||
[IPartialCommit] = "partial_commit",
|
||||
[IBackCommit] = "back_commit",
|
||||
[IFailTwice] = "failtwice",
|
||||
[IFail] = "fail",
|
||||
[IGiveup] = "giveup",
|
||||
[IFullCapture] = "fullcapture",
|
||||
[IOpenCapture] = "opencapture",
|
||||
[ICloseCapture] = "closecapture",
|
||||
[ICloseRunTime] = "closeruntime"
|
||||
}
|
||||
|
||||
local function printcharset(st)
|
||||
io.write("[");
|
||||
local i = 0
|
||||
while i <= 255 do
|
||||
local first = i;
|
||||
while band(st[rshift(i, 5)], lshift(1, band(i, 31))) ~= 0 and i <= 255 do
|
||||
i = i + 1
|
||||
end
|
||||
if i - 1 == first then -- unary range?
|
||||
io.write(("(%02x)"):format(first))
|
||||
elseif i - 1 > first then -- non-empty range?
|
||||
io.write(("(%02x-%02x)"):format(first, i - 1))
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
io.write("]")
|
||||
end
|
||||
|
||||
local modes = {
|
||||
[Cclose] = "close",
|
||||
[Cposition] = "position",
|
||||
[Cconst] = "constant",
|
||||
[Cbackref] = "backref",
|
||||
[Carg] = "argument",
|
||||
[Csimple] = "simple",
|
||||
[Ctable] = "table",
|
||||
[Cfunction] = "function",
|
||||
[Cquery] = "query",
|
||||
[Cstring] = "string",
|
||||
[Cnum] = "num",
|
||||
[Csubst] = "substitution",
|
||||
[Cfold] = "fold",
|
||||
[Cruntime] = "runtime",
|
||||
[Cgroup] = "group"
|
||||
}
|
||||
|
||||
local function printcapkind(kind)
|
||||
io.write(("%s"):format(modes[kind]))
|
||||
end
|
||||
|
||||
local function printjmp(p, index)
|
||||
io.write(("-> %d"):format(index + p[index].offset))
|
||||
end
|
||||
|
||||
local function printrulename(p, index, rulenames)
|
||||
if rulenames and rulenames[index + p[index].offset] then
|
||||
io.write(' ', rulenames[index + p[index].offset])
|
||||
end
|
||||
end
|
||||
|
||||
local function printinst(p, index, valuetable, rulenames)
|
||||
local code = p[index].code
|
||||
if rulenames and rulenames[index] then
|
||||
io.write(rulenames[index], '\n')
|
||||
end
|
||||
io.write(("%04d: %s "):format(index, names[code]))
|
||||
if code == IChar then
|
||||
io.write(("'%s'"):format(string.char(p[index].val)))
|
||||
elseif code == ITestChar then
|
||||
io.write(("'%s'"):format(string.char(p[index].val)))
|
||||
printjmp(p, index)
|
||||
printrulename(p, index, rulenames)
|
||||
elseif code == IFullCapture then
|
||||
printcapkind(band(p[index].val, 0x0f));
|
||||
io.write((" (size = %d) (idx = %s)"):format(band(rshift(p[index].val, 4), 0xF), tostring(valuetable[p[index].offset])))
|
||||
elseif code == IOpenCapture then
|
||||
printcapkind(band(p[index].val, 0x0f))
|
||||
io.write((" (idx = %s)"):format(tostring(valuetable[p[index].offset])))
|
||||
elseif code == ISet then
|
||||
printcharset(valuetable[p[index].val]);
|
||||
elseif code == ITestSet then
|
||||
printcharset(valuetable[p[index].val])
|
||||
printjmp(p, index);
|
||||
printrulename(p, index, rulenames)
|
||||
elseif code == ISpan then
|
||||
printcharset(valuetable[p[index].val]);
|
||||
elseif code == IOpenCall then
|
||||
io.write(("-> %d"):format(p[index].offset))
|
||||
elseif code == IBehind then
|
||||
io.write(("%d"):format(p[index].val))
|
||||
elseif code == IJmp or code == ICall or code == ICommit or code == IChoice or
|
||||
code == IPartialCommit or code == IBackCommit or code == ITestAny then
|
||||
printjmp(p, index);
|
||||
if (code == ICall or code == IJmp) and p[index].aux > 0 then
|
||||
io.write(' ', valuetable[p[index].aux])
|
||||
else
|
||||
printrulename(p, index, rulenames)
|
||||
end
|
||||
end
|
||||
io.write("\n")
|
||||
end
|
||||
|
||||
|
||||
local function printpatt(p, valuetable)
|
||||
local ruleNames = {}
|
||||
for i = 0, p.size - 1 do
|
||||
local code = p.p[i].code
|
||||
if (code == ICall or code == IJmp) and p.p[i].aux > 0 then
|
||||
local index = i + p.p[i].offset
|
||||
ruleNames[index] = valuetable[p.p[i].aux]
|
||||
end
|
||||
end
|
||||
for i = 0, p.size - 1 do
|
||||
printinst(p.p, i, valuetable, ruleNames)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function printcap(cap, index, valuetable)
|
||||
printcapkind(cap[index].kind)
|
||||
io.write((" (idx: %s - size: %d) -> %d\n"):format(valuetable[cap[index].idx], cap[index].siz, cap[index].s))
|
||||
end
|
||||
|
||||
|
||||
local function printcaplist(cap, limit, valuetable)
|
||||
io.write(">======\n")
|
||||
local index = 0
|
||||
while cap[index].s and index < limit do
|
||||
printcap(cap, index, valuetable)
|
||||
index = index + 1
|
||||
end
|
||||
io.write("=======\n")
|
||||
end
|
||||
|
||||
-- ======================================================
|
||||
|
||||
|
||||
|
||||
-- {======================================================
|
||||
-- Printing trees (for debugging)
|
||||
-- =======================================================
|
||||
|
||||
local tagnames = {
|
||||
[TChar] = "char",
|
||||
[TSet] = "set",
|
||||
[TAny] = "any",
|
||||
[TTrue] = "true",
|
||||
[TFalse] = "false",
|
||||
[TRep] = "rep",
|
||||
[TSeq] = "seq",
|
||||
[TChoice] = "choice",
|
||||
[TNot] = "not",
|
||||
[TAnd] = "and",
|
||||
[TCall] = "call",
|
||||
[TOpenCall] = "opencall",
|
||||
[TRule] = "rule",
|
||||
[TGrammar] = "grammar",
|
||||
[TBehind] = "behind",
|
||||
[TCapture] = "capture",
|
||||
[TRunTime] = "run-time"
|
||||
}
|
||||
|
||||
|
||||
local function printtree(tree, ident, index, valuetable)
|
||||
for i = 1, ident do
|
||||
io.write(" ")
|
||||
end
|
||||
local tag = tree[index].tag
|
||||
io.write(("%s"):format(tagnames[tag]))
|
||||
if tag == TChar then
|
||||
local c = tree[index].val
|
||||
if ffi.C.isprint(c) then
|
||||
io.write((" '%c'\n"):format(c))
|
||||
else
|
||||
io.write((" (%02X)\n"):format(c))
|
||||
end
|
||||
elseif tag == TSet then
|
||||
printcharset(valuetable[tree[index].val]);
|
||||
io.write("\n")
|
||||
elseif tag == TOpenCall or tag == TCall then
|
||||
io.write((" key: %s\n"):format(tostring(valuetable[tree[index].val])))
|
||||
elseif tag == TBehind then
|
||||
io.write((" %d\n"):format(tree[index].val))
|
||||
printtree(tree, ident + 2, index + 1, valuetable);
|
||||
elseif tag == TCapture then
|
||||
io.write((" cap: %s n: %s\n"):format(modes[bit.band(tree[index].cap, 0xffff)], valuetable[tree[index].val]))
|
||||
printtree(tree, ident + 2, index + 1, valuetable);
|
||||
elseif tag == TRule then
|
||||
local extra = bit.band(tree[index].cap, RuleLR) == RuleLR and ' left recursive' or ''
|
||||
extra = extra .. (bit.band(tree[index].cap, Ruleused) ~= Ruleused and ' not used' or '')
|
||||
io.write((" n: %d key: %s%s\n"):format(bit.band(tree[index].cap, 0xffff) - 1, valuetable[tree[index].val], extra))
|
||||
printtree(tree, ident + 2, index + 1, valuetable);
|
||||
-- do not print next rule as a sibling
|
||||
elseif tag == TGrammar then
|
||||
local ruleindex = index + 1
|
||||
io.write((" %d\n"):format(tree[index].val)) -- number of rules
|
||||
for i = 1, tree[index].val do
|
||||
printtree(tree, ident + 2, ruleindex, valuetable);
|
||||
ruleindex = ruleindex + tree[ruleindex].ps
|
||||
end
|
||||
assert(tree[ruleindex].tag == TTrue); -- sentinel
|
||||
else
|
||||
local sibs = numsiblings[tree[index].tag] or 0
|
||||
io.write("\n")
|
||||
if sibs >= 1 then
|
||||
printtree(tree, ident + 2, index + 1, valuetable);
|
||||
if sibs >= 2 then
|
||||
printtree(tree, ident + 2, index + tree[index].ps, valuetable)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- }====================================================== */
|
||||
|
||||
return {
|
||||
printtree = printtree,
|
||||
printpatt = printpatt,
|
||||
printcaplist = printcaplist,
|
||||
printinst = printinst
|
||||
}
|
Reference in New Issue
Block a user