CSS / HSS Parser in Cima e nidificati regole del foglio di stile
Domanda
Sono nuovo di Cima di albero e il tentativo di scrivere un CSS / HSS parser. HSS aumenta le funzionalità di base di CSS con stili nidificati, variabili e una sorta di funzionalità mixin.
Sono abbastanza vicino - il parser in grado di gestire i CSS - ma cado giù quando si tratta di attuare uno stile di nel uno stile. per esempio:
#rule #one {
#two {
color: red;
}
color: blue;
}
Ho preso due colpi a esso, quella che gestisce gli spazi e uno che non lo fa. Non riesco a ottenere sia al lavoro. La documentazione cima d'albero è un po 'scarsa e mi sento come se mi manca qualcosa di fondamentale. Speriamo che qualcuno mi può impostare dritto.
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
Codice Harness:
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
Soluzione
Presumo si sta eseguendo in sinistra problemi di ricorsività ? In tal caso, tenere a mente che produce TreeTop parser discesa ricorsiva , e come tale, si puo' t davvero usare la ricorsione sinistra nella tua grammatica. (Una delle principali ragioni per cui continuo a preferire ocamlyacc / ocamllex sopra TreeTop nonostante il suo aspetto molto sexy.) Questo significa che è necessario convertire da forme ricorsive sinistra a destra ricorsione. Dal momento che senza dubbio possiede il Drago libro (giusto?), I' ll dirigete alle sezioni 4.3.3, 4.3.4 e 4.4.1 che coprono il problema. Come è tipico, è difficile da capire, ma parser non ha ottenuto la loro reputazione per niente. C'è anche una bella sinistra esercitazione eliminazione ricorsione che i ragazzi ANTLR mettere sull'argomento. E 'un po ANTLR / ANTLRworks specifica, ma è leggermente più facile da capire di quello che ha trovato nel Libro Drago. Questa è una di quelle cose che proprio non mai fare un sacco di senso a chi non l'ha fatto almeno un paio di volte prima.
Inoltre, commento minore, se avete intenzione di utilizzare TreeTop, vi consiglio di fare questo, invece:
def ws
[\t ]*
end
Non è molto probabile che mai bisogno di indicare un singolo carattere di spazio, oltre a quasi ogni regola grammaticale sta per bisogno, quindi ha senso chiamarlo qualcosa di molto breve. Per inciso, ci vantaggi ad un passo lexing separato. Questo è uno di loro.
Altri suggerimenti
Sembra che qualcuno mi ha battuto ad esso:
Anche se mi accorgo che usano le espressioni regolari e un eval () per analizzare il file di input, piuttosto che un parser.
Edit: Ora usano TreeTop! E 'come se qualcuno ha fatto tutto il lavoro duro per me.