совпадающие пары тегов в грамматике Treetop

Я не хочу повторения Ктулху answer, но я хочу сопоставить пары открывающих и закрывающих тегов HTML с помощью Treetop. Используя эту грамматику, я могу сопоставлять открывающие и закрывающие теги , но теперь я хочу правило, чтобы связать их вместе. Я пробовал следующее, но использование этого заставляет мой парсер работать вечно (бесконечный цикл):

rule html_tag_pair
  html_open_tag (!html_close_tag (html_tag_pair / '' / text / newline /
    whitespace))+ html_close_tag <HTMLTagPair>
end

Я пытался взять за основу пример с рекурсивными круглыми скобками и пример отрицательного просмотра вперед на странице Treetop Github . Другие правила, на которые я ссылался, следующие:

rule newline
  [\n\r] {
    def content
      :newline
    end
  }
end

rule tab
  "\t" {
    def content
      :tab
    end
  }
end

rule whitespace
  (newline / tab / [\s]) {
    def content
      :whitespace
    end
  }
end

rule text
  [^<]+ {
    def content
      [:text, text_value]
    end
  }
end

rule html_open_tag
  "<" html_tag_name attribute_list ">" <HTMLOpenTag>
end

rule html_empty_tag
  "<" html_tag_name attribute_list whitespace* "/>" <HTMLEmptyTag>
end

rule html_close_tag
  "</" html_tag_name ">" <HTMLCloseTag>
end

rule html_tag_name
  [A-Za-z0-9]+ {
    def content
      text_value
    end
  }
end

rule attribute_list
  attribute* {
    def content
      elements.inject({}){ |hash, e| hash.merge(e.content) }
    end
  }
end

rule attribute
  whitespace+ html_tag_name "=" quoted_value {
    def content
      {elements[1].content => elements[3].content}
    end
  }
end

rule quoted_value
  ('"' [^"]* '"' / "'" [^']* "'") {
    def content
      elements[1].text_value
    end
  }
end

Я знаю, что мне нужно будет разрешить сопоставление отдельных открывающих или закрывающих тегов, но если существует пара HTML-тегов, я хотел бы собрать их вместе как пару. Казалось, что проще всего сделать это, сопоставив их с моей грамматикой, но, возможно, есть лучший способ?


person Sarah Vessels    schedule 11.11.2010    source источник
comment
должен ли быть "+" между <html_open_tag> и (!html_close_tag(etc? Кроме того (и я признаю, что просмотр вперед в Treetop смущает Кнута из меня), кажется, что отрицательный просмотр вперед будет для несопоставленных тегов (например, ‹br /›, и положительный просмотр для совпадающих тегов).   -  person philosodad    schedule 11.11.2010
comment
Хм, кажется, что + не должно быть, так как все правило рекурсивно, поэтому в нем уже может быть несколько открытых тегов, потому что в нем есть другие пары тегов.   -  person Sarah Vessels    schedule 11.11.2010


Ответы (2)


Это можно сделать только с помощью отдельного правила для каждой пары HTML-тегов или семантического предиката. То есть, сохраняя открывающий тег (в семпреде), затем принимая (в другом семпреде) закрывающий тег, только если это тот же самый тег. В Treetop это сделать намного сложнее, чем должно быть, потому что нет удобного места для сохранения контекста и нельзя заглянуть в стек парсера, но это возможно.

Кстати, та же проблема возникает при анализе границ MIME (и в Markdown). Я не проверял реализацию Микеля в ActionMailer (вероятно, он использует для этого вложенный парсер Mime), но это возможно в Treetop.

В http://github.com/cjheath/activefacts/blob/master/lib/activefacts/cql/parser.rb Я сохраняю контекст в поддельном входном потоке — вы можете видеть, какие методы он должен поддерживать — потому что «ввод» доступен на всех SyntaxNodes. У меня есть другая причина использовать семпреды, но некоторые методы применимы.

person Clifford Heath    schedule 31.08.2012

Вот действительно простая грамматика, которая использует семантический предикат для сопоставления закрывающего тега с начальным тегом.

grammar SimpleXML
  rule document
    (text / tag)*
  end

  rule text
    [^<]+
  end

  rule tag
    "<" [^>]+ ">" (text / tag)* "</" [^>]+ &{|seq| seq[1].text_value == seq[5].text_value } ">"
  end
end
person munchbit    schedule 22.11.2012