CSS / HSS Parser in Treetop und Nested Sheet-Regeln
Frage
Ich bin neu in Treetop und versuchen, einen CSS / HSS-Parser zu schreiben. HSS erweitert die Basisfunktionalität von CSS mit verschachtelten Formaten, Variablen und eine Art mixin Funktionalität.
Ich bin ziemlich nah - der Parser CSS umgehen kann - aber ich umfallen, wenn es um die Implementierung einer Art kommt in einen Stil. z:
#rule #one {
#two {
color: red;
}
color: blue;
}
Ich habe zwei Schüsse auf sie genommen, eine, die Leerzeichen behandelt und eine, die nicht der Fall ist. Ich kann nicht ganz bekommen entweder zu arbeiten. Die Baumwipfel Dokumentation ist ein wenig spärlich, und ich fühle mich wirklich wie ich grundlegende etwas fehlt bin. Hoffentlich kann mir jemand gerade eingestellt.
A:
grammar Stylesheet
rule stylesheet
space* style*
end
rule style
selectors space* '{' space* properties? space* '}' space*
end
rule properties
property space* (';' space* property)* ';'?
end
rule property
property_name space* [:] space* property_value
end
rule property_name
[^:;}]+
end
rule property_value
[^:;}]+
end
rule space
[\t ]
end
rule selectors
selector space* ([,] space* selector)*
end
rule selector
element (space+ ![{] element)*
end
rule element
class / id
end
rule id
[#] [a-zA-Z-]+
end
rule class
[.] [a-zA-Z-]+
end
end
B:
grammar Stylesheet
rule stylesheet
style*
end
rule style
selectors closure
end
rule closure
'{' ( style / property )* '}'
end
rule property
property_name ':' property_value ';'
end
rule property_name
[^:}]+
<PropertyNode>
end
rule property_value
[^;]+
<PropertyNode>
end
rule selectors
selector ( !closure ',' selector )*
<SelectorNode>
end
rule selector
element ( space+ !closure element )*
<SelectorNode>
end
rule element
class / id
end
rule id
('#' [a-zA-Z]+)
end
rule class
('.' [a-zA-Z]+)
end
rule space
[\t ]
end
end
Harness-Code:
require 'rubygems'
require 'treetop'
class PropertyNode < Treetop::Runtime::SyntaxNode
def value
"property:(#{text_value})"
end
end
class SelectorNode < Treetop::Runtime::SyntaxNode
def value
"--> #{text_value}"
end
end
Treetop.load('css')
parser = StylesheetParser.new
parser.consume_all_input = false
string = <<EOS
#hello-there .my-friend {
font-family:Verdana;
font-size:12px;
}
.my-friend, #is-cool {
font: 12px Verdana;
#he .likes-jam, #very-much {asaads:there;}
hello: there;
}
EOS
root_node = parser.parse(string)
def print_node(node, output = [])
output << node.value if node.respond_to?(:value)
node.elements.each {|element| print_node(element, output)} if node.elements
output
end
puts print_node(root_node).join("\n") if root_node
#puts parser.methods.sort.join(',')
puts parser.input
puts string[0...parser.failure_index] + '<--'
puts parser.failure_reason
puts parser.terminal_failures
Lösung
Ich nehme an, Sie laufen in Linksrekursion Probleme? Wenn ja, bedenken Sie, dass TreeTop produziert Rekursiver Abstieg , und als solche können Sie‘ t wirklich Linksrekursion in Ihrer Grammatik verwenden. (Einer der Hauptgründe, warum ich immer noch lieber ocamlyacc / ocamllex über TreeTop trotz seines sehr sexy Aussehen.) Das heißt, Sie müssen von links rekursive Formen nach rechts Rekursion konvertieren. Da Sie besitzen zweifellos die Drachen Buch (oder?), Ich ll leiten Sie zu den Abschnitten 4.3.3, 4.3.4 und 4.4.1, die das Thema abdecken. Wie typisch ist, ist es schwer zu verstehen, aber Parser nicht bekamen ihren Ruf für nichts. Es ist auch ein schönes Linksrekursion Beseitigung Tutorial dass die ANTLR Jungs setzen auf das Thema auf. Es ist etwas ANTLR / ANTLRWorks spezifisch, aber es ist etwas leichter zu verstehen als das, was in den Drachen Buch gefunden hat. Dies ist eines jener Dinge, die einfach nicht immer eine ganze Menge Sinn für jedermann machen, das es zumindest ein paar Mal, bevor nicht getan hat.
Auch kleinere Kommentar, wenn Sie TreeTop verwenden werden, empfehle, ich diese statt:
def ws
[\t ]*
end
Sie sind nicht wahrscheinlich jemals brauchen ein einzelnes Leerzeichen entsprechen, und fast jede Grammatikregel es brauchen wird, so macht es Sinn, es zu benennen etwas sehr kurz. Übrigens gibt sind Vorteile auf einen separaten lexing Schritt. Dies ist einer von ihnen.
Andere Tipps
Sieht aus wie jemand, mich zu schlagen es:
Auch wenn ich merke, dass sie reguläre Ausdrücke und ein eval () verwenden, um die Eingabedatei, anstatt ein Parser zu analysieren.
Edit: Jetzt benutzen sie TreeTop! Es ist wie jemand die ganze harte Arbeit für mich getan hat.