Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
8

Where is the mistake in this parser? [closed]

Asked by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
8 years ago

I have begun on a PEG parser.

The goal is to build a grammar out of trees of combinators using sequence and either. I have some mistake in my sequence implementation, because I get false as the output from this instead of an empty stream.

-- <library>

-- Forward declare helper
local wrap

-- e: function | string
-- return: Parser (Stream -> Stream?)
function expect(e)
    local x = e
    if type(e) == "string" then
        x = function(n) return n == e end
    end
    return wrap(function(stream)
        if x( stream:first() ) then
            return stream:rest(), stream:first()
        else
            return false
        end
    end)
end

-- a, b: Parser
-- return: Parse (Stream -> Stream?)
function seq(a, b)
    return wrap(function(stream)
        local u = a(stream)
        if u then
            return b(stream)
        else
            return false
        end
    end)
end

-- wrappedCall(w, ...) is the same as w(...) for a value that has been
-- `wrap`pped
function wrappedCall(w, ...)
    return w["function"](...)
end

-- Allows + and * to be used as aliases for `either` and `sequence`.
-- function -> function+*
function wrap(f)
    local t = {["function"] = f}
    setmetatable(t, {

        __mul = seq,
        __call = wrappedCall})
    return t
end

-- Stream<element> -> element
function streamFirst(list)
    return list[1]
end

-- Stream -> Stream
function streamRest(list)
    local t = {unpack(list)}
    table.remove(t, 1)
    return Stream(t)
end

-- string -> Stream
function Stream(list)
    local s = {unpack(list)}
    s.first = streamFirst
    s.rest = streamRest
    return s
end

-- </library>
-- <client>

-- string -> boolean
function isLetter(s)
    return s:sub(1, 1):lower() ~= s:sub(1, 1):upper()
end

local name = expect(isLetter)
local open, close = expect("<"), expect(">")

local void = open * name * close 
local tokens = Stream {"<", "img", ">"}

print( void(tokens) )
-- I expect this to print `table: ABCDEF`, but I get `false`
-- </client>

Does anyone else have an idea of where I made a mistake? I regret not testing more incrementally...

0
that needs a bluetaslem answer! oh, wait a minute... unmiss 337 — 8y
0
Try & remake it but more incrementally. Redbullusa 1580 — 8y
0
According to the Studio, you have not defined 'either' on line 46 (This may not be the main problem, but I thought to point it out anyway). :) TheeDeathCaster 2368 — 8y
2
b(stream) = false and as said before, "either" was never defined for __add = either Validark 1580 — 8y
0
I took out the definition of either because it wasn't used meaningfully in this script, forgot it was in the metatable -- that's not the problem. Edit the code to fix that BlueTaslem 18071 — 8y

Locked by Avigant

This question has been locked to preserve its current state and prevent spam and unwanted comments and answers.

Why was this question closed?

1 answer

Log in to vote
4
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
8 years ago

I found the bug -- it was a little mistake in this line:

        local u = a(stream)
        if u then
            return b(stream)

Looking at it, the definition of local u is suspicious, since u is only used in the condition.

It should have been this:

    local u = a(stream)
    if u then
        return b(u)

so that the rest of the stream after what a takes it put into b.

0
Yes, good answer, oh, great BlueTaslem! Redbullusa 1580 — 8y
2
I'm calling this one! Look at my other comment and I pointed out the error in "b(stream)" Validark 1580 — 8y
0
wow, he answered his own quesito. User#5978 25 — 8y
Ad