passenden Tag-Paare in Baumwipfel Grammatik
Frage
Ich will nicht eine Wiederholung von die Antwort Cthulhu, aber ich möchte Paare Öffnung zusammenpassen und mit Treetop HTML-Tags zu schließen. Mit diese Grammatik , kann ich öffnenden Tags und End-Tags entsprechen , aber jetzt möchte ich eine Regel, sie beide zusammen zu binden. Ich habe die folgende versucht, aber mit diesem macht mein Parser für immer weitergehen (Endlosschleife):
rule html_tag_pair
html_open_tag (!html_close_tag (html_tag_pair / '' / text / newline /
whitespace))+ html_close_tag <HTMLTagPair>
end
Ich habe versucht, diese aus dem rekursiven Klammern Beispiels zu stützen und das negative Vorschau Beispiel auf der Treetop Github Seite . Die anderen Regeln Ich habe verwiesen wird, sind wie folgt:
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
Ich weiß, ich werde zum Anpassen einzelnes Öffnens oder Schließen-Tags erlauben müssen, aber wenn ein Paar von HTML-Tags vorhanden ist, würde ich sie gerne als Paar zusammen zu bekommen. Es schien, saubersten, dies zu tun, indem sie mit meiner Grammatik übereinstimmt, aber vielleicht gibt es einen besseren Weg?
Lösung
Sie können nur diese für jedes HTML-Tag-Paar entweder eine separate Regel unter Verwendung tun, oder eine semantische Prädikat verwendet wird. Das heißt, durch das Starttag speichern (in einem sempred), dann akzeptieren (in einem anderen sempred) einen schließenden Tag nur, wenn es den gleiche Tag ist. Das ist viel schwieriger, in Treetop zu tun, als es sein sollte, weil es kein geeigneter Ort ist, den Kontext zu speichern und Sie können den Parser-Stack nicht spähen, aber es ist möglich.
BTW, tritt das gleiche Problem MIME Grenzen beim Parsen (und in Markdown). Ich habe überprüft nicht Mikel Implementierung in Action (wahrscheinlich er verwendet einen verschachtelten Mime-Parser für die), aber es ist möglich, in Treetop.
http://github.com/cjheath /activefacts/blob/master/lib/activefacts/cql/parser.rb ich speichern Kontext in einem gefälschten Eingabestrom - können Sie sehen, welche Methoden es zur Unterstützung hat - weil „Eingang“ auf allen SyntaxNodes zur Verfügung steht. Ich habe eine andere Art des Grundes für sempreds dort verwenden, aber einige der Techniken anwendbar sind.
Andere Tipps
Hier ist eine wirklich einfache Grammatik, die ein semantisches Prädikat verwendet, um den Start-Tag das Schließschild zu entsprechen.
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