CSS / HSS Parser dans les règles arboricoles et emboîtés Stylesheet
Question
Je suis nouveau à arboricole et de tenter d'écrire un analyseur CSS / HSS. HSS augmente la fonctionnalité de base de CSS avec des styles imbriqués, variables et une sorte de fonctionnalité mixin.
Je suis assez proche - l'analyseur peut gérer CSS - mais je tombe quand il s'agit de mettre en œuvre un style dans les un style. par exemple:
#rule #one {
#two {
color: red;
}
color: blue;
}
J'ai pris deux coups de feu à elle, celui qui gère les espaces et qui ne fonctionne pas. Je ne peux pas tout à fait obtenir soit pour travailler. La documentation de la cime des arbres est un peu clairsemée et je me sens vraiment comme si je manque quelque chose de fondamental. Espérons que quelqu'un peut me détromper.
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
Code de harnais:
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
La solution
Je suppose que vous êtes en cours d'exécution dans gauche problèmes de récursion? Si oui, gardez à l'esprit que TreeTop produit parseurs descente récursive , et en tant que tel, vous pouvez » t vraiment utiliser la récursivité gauche dans votre grammaire. (L'une des principales raisons pour lesquelles je préfère encore ocamlyacc / ocamllex sur TreeTop malgré son apparence très sexy.) Cela signifie que vous devez convertir les formes récursives à gauche récursion droite. Puisque vous possédez sans doute le dragon Livre (droit?), Je ll vous direct aux sections 4.3.3, 4.3.4 et 4.4.1 qui couvrent la question. Comme il est typique, il est difficile à comprendre, mais parseurs n'a pas obtenu leur réputation pour rien. Il y a aussi une belle gauche tutoriel d'élimination de récursion que les gars ANTLR mettre en place sur le sujet. Il est un peu ANTLR / ANTLRworks spécifique, mais il est un peu plus facile à comprendre que ce qui se trouve dans le Dragon Book. C'est une de ces choses qui ne font pas tout simplement jamais beaucoup de sens pour quelqu'un qui n'a pas fait au moins quelques fois.
En outre, un commentaire mineur, si vous allez utiliser TreeTop, je recommande de faire ceci:
def ws
[\t ]*
end
Vous n'êtes pas susceptible de jamais besoin de faire correspondre un seul caractère d'espace blanc, plus presque toutes les règles de la grammaire va en avoir besoin, il est donc logique de le nommer quelque chose de très court. Soit dit en passant, il y a sont des avantages à une étape de lexing séparée. C'est l'un d'entre eux.
Autres conseils
On dirait que quelqu'un me devança:
Bien que je remarque qu'ils utilisent des expressions régulières et un eval () pour analyser le fichier d'entrée plutôt que d'un analyseur.
Edit: Maintenant, ils utilisent TreeTop! Il est comme quelqu'un l'a fait tout le travail pour moi.