Como faço para implementar um scanner de duas passagens utilizando o Flex?
-
01-07-2019 - |
Pergunta
Como um projeto animal de estimação, eu gostaria de tentar implementar uma linguagem básica de meu próprio projeto que pode ser usado como uma linguagem de web-scripting. É trivial para executar um programa C ++ como um Apache CGI, então as mentiras reais de trabalho em como analisar um arquivo de entrada contendo não-código (HTML / CSS marcação) e código do lado do servidor.
No meu curso compilador graduação, usamos Flex e Bison para gerar um scanner e um analisador para uma linguagem simples. Foi-nos dada uma cópia da gramática e escreveu um analisador que traduziu a linguagem simples para uma simples reunião para uma máquina virtual. O scanner de flex tokenizes a entrada, e passa os sinais para o analisador Vega.
A diferença entre este eo que eu gostaria de fazer é que, como PHP, esta linguagem pode ter marcação HTML simples e a linguagem de script intercaladas como o seguinte:
<p>Hello,
<? echo "World ?>
</p>
Am I incorreta em assumir que seria eficiente para analisar o arquivo de entrada da seguinte forma:
- entrada de digitalização até que uma tag script de inicialização é encontrada ('
- segundo scanner tokenizes seção script do lado do servidor do arquivo de entrada (a partir da tag aberta: '') e passa o token para o analisador, que não tem necessidade de saber sobre a marcação no arquivo.
- O controle é retornado para o primeiro scanner que continua este padrão geral.
Basicamente, o primeiro aparelho apenas se diferencia entre Markup (que é retornada directamente para o navegador não modificada) e de código, que é passado para o segundo scanner, que por sua vez tokenizes o código e passa os sinais para o analisador.
Se isto é não um padrão de design sólido, como é que linguagens como PHP entrada alça de varredura e análise de código de forma eficiente?
Solução
Você quer olhar para as condições iniciais. Por exemplo:
"<?" { BEGIN (PHP); }
<PHP>[a-zA-Z]* { return PHP_TOKEN; }
<PHP>">?" { BEGIN (0); }
[a-zA-Z]* { return HTML_TOKEN; }
Você começa no estado 0, use a BEGIN macro para os estados de mudança. Para corresponder a um RE somente enquanto em um estado particular, prefixo do RE com o nome do estado cercado por ângulo de menor e maior.
No exemplo acima, "PHP" é o estado. "PHP_TOKEN" e "HTML_TOKEN" são _% token_s definida por seu arquivo yacc.
Outras dicas
PHP não diferencia entre a digitalização ea Markup. É simplesmente sai para o tampão, quando no modo de marcação, e em seguida muda para análise quando no modo de código. Você não precisa de um scanner de duas passagens, e você pode fazer isso com apenas um único lexer flex.
Se você está interessado em saber como o PHP em si funciona, baixar o código fonte (experimente a fonte PHP4 é muito mais fácil de entender). O que você quer olhar é no Diretório Zend, zend_language_scanner.l
.
Depois de ter escrito algo semelhante a mim mesmo, eu realmente recomendo repensar indo a rota Flex e Bison, e ir com algo moderno como Antlr . É muito mais fácil, mais fácil de entender (as macros empregadas em uma lex gramática ficar muito confuso e difícil de ler) e ele foi construído em um depurador ( AntlrWorks ) para que você não tem que passar horas olhando para 3 arquivos de depuração Meg. Ele também suporta muitas linguagens (Java, C #, C, Python, Actionscript) e tem um excelente livro e um site muito bom que deve ser capaz de chegar até você e funcionando em nenhum momento.