3

現在、いくつかの基本的な 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"

そのため、たとえば function_definition ルールで行ったのと同じように、cstom SyntaxNode サブクラス宣言を行う必要があります。

4

2 に答える 2

1

あなたは(未テスト)のようなものが欲しい:

'def' space? identifier space? '(' space? ( expression ( space? ',' expression )* )? space?  ')'

(注: これがルビ スタイルdefの場合、引数がない場合は括弧もオプションです)

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

def.tt:

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"]
于 2011-11-08T11:17:33.133 に答える
0

より良い方法は、再帰を使用することです。

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

rule argList
   identifier space? ',' space? argList
   / identifier
end
于 2015-08-17T10:28:41.490 に答える