соответствующие пары тегов в грамматике Treetop - PullRequest
2 голосов
/ 11 ноября 2010

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

Ответы [ 2 ]

5 голосов
/ 22 ноября 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
1 голос
/ 31 августа 2012

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

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

...