2011-11-08 9 views
3

現在、基本的なRuby文法について説明しようとしていますが、現在は関数定義に固執しています。確かに、私は 'n'引数を扱う方法を知らない。 0から2までの引数を含む関数を処理するために使用するコードを次に示します。Treetopパーサ:関数定義構文-n引数

rule function_definition 
    'def' space? identifier space? '(' space? expression? space? ','? expression? space? ')' 
     block 
    space? 'end' <FunctionDefinition> 
    end 

'n'引数を処理するにはどうすればよいですか?それを行う再帰的な方法はありますか?

EDIT:

私は引数が結果ツリーにする必要があるという事実を強調したかったです。同様に:

Argument offset=42, "arg1" 
Argument offset=43, "arg2" 
Argument offset=44, "arg3" 

は、だから、私はインスタンスのfunction_definitionルールのためにやったように、cstom SyntaxNodeのサブクラスの宣言を行う必要があります。

答えて

1

あなたが(未テスト)のような何かをしたい:

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

(NBこれはRubyのスタイルdefであるならば、括弧は引数がない場合にもオプションです)

編集実証します解析ツリーからの引数を抽出する - ここで私は、構文のノード(FunctionArg)各引数のtext_valueを吐き出すていますが、もちろん何もすることができます:

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"] 
+0

ご意見ありがとうございます。しかし、私は引数がツリートップツリーのノードであることを望んでいます。あなたの解決策は機能しますが、私の議論はツリーに現れません。とにかくありがとうございました。 –

+0

あなたが達成しようとしているものに近づくように編集されました。 –

0

より良い方法は、再帰を使用するかもしれません。

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

rule argList 
    identifier space? ',' space? argList 
/identifier 
end