lua-users home
lua-l archive

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


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