问题描述:

I've written a small Ruby library that lets me generate parsers using the parsing expression grammar formalism but with a few extra extensions. Currently I can compose/generate parsers dynamically at runtime by using a pretty simple API, e.g.

g = Grammar.rules do

rule :start, m('abc')

end

The above grammar will match the string "abc" and return an object representing the matched results. There are the obvious ways of composing parsers with sequencing (>), alternation (|), negative/positive lookahead (!/+), semantic actions (>>), etc. Most of these parsers can be "compiled" in advance in an obvious way by simply compiling the component parsers and then gluing them together with the proper control flow. As a concrete example,

g = Grammar.rules do

rule :start, m('abc') > m('def')

end

can be compiled to

class CompiledGrammar

def self.start(context)

seq1 = match('abc', context)

if seq1.nil?

return nil

end

seq2 = match('def', context)

if seq2.nil?

return nil

end

return [seq1, seq2]

end

end

Similar expressions work for alternation, positive/negative lookahead, and semantic actions but there is one extension that I'm not quite sure how to compile. The extension deals with using information from the current parsing process to generate another parser on the fly, e.g.

g = Grammar.rules do

rule :start, m('a').many[:a] > dynamic(->(context) {

m('b' * context[:a].length)

})

end

The above grammar will match as many 'a's as possible and then will match an equal number of 'b's by dynamically generating a parser that has just the right number of 'b's.

I know that I can make this work if I include the entire library in the compiled output but is there a better way to do this that does not involve falling back on the existing runtime?

相关阅读:
Top