[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: LPEG: fold capture
- From: Sean Conner <sean@...>
- Date: Sun, 19 Aug 2018 18:18:30 -0400
It was thus said that the Great Александр Машин once stated:
> Deal all,
>
> as far as I understand the documentation on fold captures in LPEG
> (http://www.inf.puc-rio.br/~roberto/lpeg/#cap-f), the folding function
> should be called if there is at least one capture in the pattern passed
> to lpeg.Cf ().
The text is dense, but it does state when the function is called:
This capture assumes that patt should produce at least one capture
with at least one value (of any type), which becomes the initial
value of an accumulator.
So you need at least one capture, but the function isn't called at this
point.
For each subsequent capture, LPeg calls func with this accumulator
as the first argument and all values produced by the capture as
extra arguments; the first result from this call becomes the new
value for the accumulator. The final value of the accumulator
becomes the captured value.
It's only when there are two or more captures is the function called.
> The following code
>
> tostring (lpeg.P{'sum'
> , sum = lpeg.Cf ( lpeg.V'operand' * lpeg.Cg (
> lpeg.V'operator' * lpeg.V'operand' ) ^ 0, function
> (arg1, op, arg2)
> if op == '+' then
> return arg1 + arg2
> elseif op == '-' then
> return arg1 - arg2
> elseif op == nil then -- Special case: there is
> only one number in the expression:
> return 0
> end
> end )
> , operand = lpeg.C ( lpeg.R'09' ^ 1 / tonumber)
> , operator = lpeg.C (lpeg.S'+-')
> }:match '4') returns '4' (the whole line) rather than '0' whivh it
> is supposed to return if the string consists of only one number without
> arithmetc signs, which means that the folding function was never called.
How do you determine if you have:
4
versus?
4-4
One way might be:
-- omitting the leading 'lpeg.'
operand = R'09'^1 / tonumber -- returns a capture, lpeg.C() no needed
operator = C(S"+-")
sum_calc = Cf(
operand * Cg(operator * operand)^0,
function(arg1,op,arg2)
if op == '+' then
return arg1 + arg2
else -- op MUST be -
return arg1 - arg2
end
end
)
sum = #(operand * operator * operand) * sum_calc
+ Cc(false) -- or 0 or whatever you want to indicate an error
print(sum:match "4-4")
print(sum:match "4+4")
print(sum:match "4")
'#patt' matches a pattern but does not consume the input, so here we have
sum looking ahead for at least one "full expression" before going into the
folding capture; if it doesn't find a "full expression" it will return an
error (whatever value you want---also, for so simple a production, you don't
need a full grammar).
To avoid the look ahead, you can make the following changes:
sum_calc = Cf(
operand * Cg(operator * operand)
* Cg(operator * operand)^0,
function(arg1,op,arg2)
if op == '+' then
return arg1 + arg2
else -- op MUST be -
return arg1 - arg2
end
end
)
sum = sum_calc
+ Cc(false) -- or 0 or whatever you want to indicate an error
This one avoid the excessive look-ahead but does one "full expression" and
carries on from there.
-spc