CSS / HSS Analisador em Treetop e Nested Regras de estilo
Pergunta
Eu sou novo para Treetop e tentando escrever um analisador CSS / HSS. HSS aumenta a funcionalidade básica do CSS com estilos aninhados, variáveis ??e um tipo de funcionalidade mixin.
Estou bastante perto - o analisador pode lidar com CSS - mas eu caio quando se trata de implementar um estilo em um estilo. por exemplo:
#rule #one {
#two {
color: red;
}
color: blue;
}
Eu tomei dois tiros nele, um que lida com espaços em branco e um que não o faz. Eu não consigo obter qualquer ao trabalho. A documentação copa de árvore é um pouco escassa e eu realmente sinto que estou perdendo algo fundamental. Esperemos que alguém pode me definir reta.
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
Código 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
Solução
Eu suponho que você está correndo em problemas recursão esquerda ? Se assim for, tenha em mente que TreeTop produz recursiva descida analisadores , e como tal, você pode' t realmente usar recursão esquerda em sua gramática. (Uma das principais razões que eu ainda preferem ocamlyacc / ocamllex sobre TreeTop apesar de sua aparência muito sexy.) Isso significa que você precisa para converter de forma recursiva esquerda para recursão direita. Desde você possui, sem dúvida, o Dragão Livro (certo?), I' vai direcioná-lo para seções 4.3.3, 4.3.4 e 4.4.1, que abrangem a questão. Como é típico, é difícil de entender, mas analisadores não obter a sua reputação de nada. Há também uma boa eliminação recursão esquerda tutorial que os caras ANTLR colocar-se sobre o assunto. É um pouco ANTLR / ANTLRworks específico, mas é um pouco mais fácil de entender do que o que está contido no Livro do dragão. Esta é uma daquelas coisas que simplesmente não sempre fazer um monte de sentido para alguém que não tenha feito isso, pelo menos algumas vezes antes.
Além disso, menor comentário, se você estiver indo para usar TreeTop, eu recomendo fazer isso em vez disso:
def ws
[\t ]*
end
Você não é provável que nunca precisa corresponder a um único espaço em branco, além de quase todas as regras da gramática vai precisar dele, por isso faz sentido para nomeá-la algo muito curto. Aliás, há são vantagens para um passo lexing separado. Este é um deles.
Outras dicas
Parece que alguém chegou antes de mim:
Apesar de eu perceber que eles usam expressões regulares e um eval () para analisar o arquivo de entrada, em vez de um analisador.
Edit: Agora eles usam TreeTop! É como se alguém fez todo o trabalho duro para mim.