2011-11-08 2 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'인수를 처리하려면 어떻게해야합니까? 그 일을 재귀 적으로 할 수있는 방법이 있습니까?

편집 :

가 나는 결과 트리에로의 인수가 필요하다는 사실을 강조하고 싶었다. 마찬가지로 :

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이 인수가없는 경우 루비 스타일 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

의견을 보내 주셔서 감사합니다. 그러나 인수는 Treetop 트리의 노드가되고 싶습니다. 귀하의 솔루션은 작동하지만 내 주장은 나무에 나타나지 않습니다. 어쨌든 고맙습니다. –

+0

성취하고자하는 목표에 더 가까워 지도록 편집되었습니다. –

0

더 좋은 방법은 재귀를 사용할 수 있습니다.

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

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