Как закодировать триггер действия с верхушкой дерева?

Я пытаюсь запускать некоторый фрагмент кода каждый раз, когда синтаксический анализатор распознает токен.

скажем

grammar FooBar

  rule start
    (foo "\n")+
  end

  rule foo
    stuff_i_want:([a-z]+) {
       puts "Hi there I found: #{stuff_i_want.text_value}"
     }
  end

end

Идея состоит в том, чтобы это действие puts выполнялось каждый раз, когда будет найден токен foo. Закодированный как есть, он не работает, так как запускается только один раз (во время загрузки класса) и, конечно, stuff_i_want.text_value тогда не существует.

Есть идеи? Это вообще возможно? Отсутствие документации по библиотеке не позволяет легко сказать.


person The Mighty Rubber Duck    schedule 08.08.2013    source источник


Ответы (2)


Ну, я не уверен, что я сделал, чтобы заслужить отрицательный голос.

Во всяком случае, вот решение, которое я использовал:

node_extension.rb

module Crawlable

  def crawl *args
    continue = true
    continue = action(*args) if respond_to? :action

    return if !continue || elements.nil?

    elements.each do |elt|
      elt.crawl(*args)
    end
  end

end

# reopen the SyntaxNode class and include the module to add the functionality
class Treetop::Runtime::SyntaxNode

  include Crawlable

end

затем остается только определить метод action(*args) на каждом узле, на котором вы хотите вызвать эффект, и начать сканирование на верхнем узле синтаксического анализатора (тот, который возвращается вызовом синтаксического анализа

parse_tree = FooBarParser.new.parse "mycontent"
parse_tree.crawl # add optional parameters for context/state

Необязательные параметры передаются каждому методу action. Вы также можете вернуть ложное значение (false или nil) в действии, чтобы остановить сканирование поддерева.

grammar FooBar

  rule start
    (foo "\n")+
  end

  rule foo
    stuff_i_want:([a-z]+) {
       def action
         puts "Hi there I found: #{stuff_i_want.text_value}"

         false
       end
     }
  end

end
person The Mighty Rubber Duck    schedule 09.08.2013

Это может быть более простым решением, чем то, с которым вы можете столкнуться. Я не понимаю, зачем вам нужно открывать класс SyntaxNode, чтобы получить желаемую функциональность. Все, что вам нужно сделать, это еще немного пройтись по узлам (если только я не понимаю, чего вы пытаетесь достичь).

Вот пример:

require 'treetop'

Treetop.load_from_string DATA.read

parser = FooBarParser.new

parser.parse("hello\nok\nmorestuff\n").action

__END__
grammar FooBar
  rule start
     (foo "\n")+
     {
        def action
           elements.each {|e| e.elements[0].action }
        end
     }
  end

  rule foo
    stuff_i_want:([a-z]+)
    {
       def action
          puts "Hi there I found: #{stuff_i_want.text_value}"
       end
    }
  end
end

# => Hi there I found: hello
#    Hi there I found: ok
#    Hi there I found: morestuff
person Josh Voigts    schedule 09.08.2013
comment
Хороший вопрос, это может быть очень просто. Однако файлы, с которыми я работаю, имеют много промежуточных синтаксических узлов, которые требуют рекурсивного вызова action, что приводит к большому дублированию кода. Я считаю, что мое решение немного более гибкое. Но спасибо за ваш вклад :) - person The Mighty Rubber Duck; 11.08.2013
comment
Имеет смысл, это своего рода умный способ справиться с этим. - person Josh Voigts; 14.08.2013