Analizador de árbol: sintaxis de definición de función - n argumentos

Actualmente estoy tratando de describir algo de gramática básica de Ruby, pero ahora estoy atascado con la definición de función. De hecho, no sé cómo manejar un argumento 'n'. Aquí está el código que uso para manejar funciones que contienen de 0 a 2 argumentos:

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

¿Cómo podría hacer para manejar 'n' argumento? ¿Hay alguna forma recursiva de hacer eso?

EDIT:

Quería resaltar el hecho de que necesito que los argumentos estén en el árbol de resultados. Igual que :

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

Así que necesito hacer una declaración de subclase cstom SyntaxNode, tal como lo hice para la regla function_definition, por ejemplo.

preguntado el 08 de noviembre de 11 a las 09:11

2 Respuestas

Quieres algo como (no probado):

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

(NB si este es un estilo rubí def entonces los parens también son opcionales en el caso de que no haya argumentos)

Edite para demostrar la extracción de los argumentos del árbol de análisis: aquí escupo el text_value de cada argumentoFunctionArg) nodo de sintaxis pero, por supuesto, podría hacer cualquier cosa:

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

Salida:

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

respondido 09 nov., 11:01

Gracias por tu comentario. Sin embargo, me gustaría que los argumentos fueran un nodo del árbol Treetop. Su solución funciona, pero mis argumentos no aparecen en el árbol. Muchas gracias de todos modos. - usuario740316

Editado para, con suerte, estar más cerca de lo que está tratando de lograr. - Martin carpintero

Un mejor método podría ser utilizar la recursividad.

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

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

Respondido 17 ago 15, 13:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.