我目前正在尝试描述一些基本的Ruby语法,但我现在仍然坚持使用函数定义。实际上,我不知道如何处理'n'论证。这是我用来处理包含0到2个args的函数的代码:
rule function_definition
'def' space? identifier space? '(' space? expression? space? ','? expression? space? ')'
block
space? 'end' <FunctionDefinition>
end
我怎么能处理'n'论证?有没有递归方式呢?
编辑:
我想突出一个事实,即我需要参数在结果树中。喜欢 :
Argument offset=42, "arg1"
Argument offset=43, "arg2"
Argument offset=44, "arg3"
所以我需要做一个自定义的SyntaxNode子类声明,就像我为函数定义规则所做的那样。
你想要(未经测试)的东西:
'def' space? identifier space? '(' space? ( expression ( space? ',' expression )* )? space? ')'
(注意如果这是一个红宝石风格的def
那么在没有参数的情况下,parens也是可选的)
编辑以演示从解析树中提取参数 - 这里我吐出每个参数(text_value
)语法节点的FunctionArg
但你当然可以做任何事情:
foo.rb:
# Prepend current directory to load path
$:.push('.')
# Load treetop grammar directly without compilation
require 'polyglot'
require 'treetop'
require 'def'
# Classes for bespoke nodes
class FunctionDefinition < Treetop::Runtime::SyntaxNode ; end
class FunctionArg < Treetop::Runtime::SyntaxNode ; end
# Some tests
[
'def foo() block end',
'def foo(arg1) block end',
'def foo(arg1, arg2) block end',
'def foo(arg1, arg2, arg3) block end',
].each do |test|
parser = DefParser.new
tree = parser.parse( test )
raise RuntimeError, "Parsing failed on line:\n#{test}" unless tree
puts test
puts "identifier=#{tree.function_identifier}"
puts "args=#{tree.function_args.inspect}"
puts
end
得分.天天:
grammar Def
# Top level rule: a function
rule function_definition
'def' space identifier space? '(' space? arg0 more_args space? ')' space block space 'end' <FunctionDefinition>
{
def function_identifier
identifier.text_value
end
def function_args
arg0.is_a?( FunctionArg ) ? [ arg0.text_value ] + more_args.args : []
end
}
end
# First function argument
rule arg0
argument?
end
# Second and further function arguments
rule more_args
( space? ',' space? argument )*
{
def args
elements.map { |e| e.elements.last.text_value }
end
}
end
# Function identifier
rule identifier
[a-zA-Z_] [a-zA-Z0-9_]*
end
# TODO Dummy rule for function block
rule block
'block'
end
# Function argument
rule argument
[a-zA-Z_] [a-zA-Z0-9_]* <FunctionArg>
end
# Horizontal whitespace (htab or space character).
rule space
[ \t]
end
end
输出:
def foo() block end
identifier=foo
args=[]
def foo(arg1) block end
identifier=foo
args=["arg1"]
def foo(arg1, arg2) block end
identifier=foo
args=["arg1", "arg2"]
def foo(arg1, arg2, arg3) block end
identifier=foo
args=["arg1", "arg2", "arg3"]
更好的方法可能是使用递归。
rule function_definition
'def' space identifier space? '(' space? argList? space? ')' block 'end'
end
rule argList
identifier space? ',' space? argList
/ identifier
end