树顶解析器:函数定义语法 - n个参数

问题描述 投票:3回答:2

我目前正在尝试描述一些基本的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子类声明,就像我为函数定义规则所做的那样。

ruby parsing treetop
2个回答
1
投票

你想要(未经测试)的东西:

'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"]

0
投票

更好的方法可能是使用递归。

rule function_definition
  'def' space identifier space? '(' space? argList? space? ')' block 'end'
end

rule argList
   identifier space? ',' space? argList
   / identifier
end
© www.soinside.com 2019 - 2024. All rights reserved.