Não compreendo esta frase do artigo da Wikipedia sobre o problema de Dangling Else :
[O problema Dangling Else] é um problema que geralmente surge na construção do compilador, especialmente na análise sem scanner.
Alguém pode me explicar como as técnicas de análise sem scanner podem exacerbar esse problema? Parece-me que o problema está na gramática - já que é ambígua - e não na escolha da técnica de análise. o que estou perdendo?
if a then if b then s1 else s2
, a gramática é ambígua.Respostas:
Meu melhor palpite é que a frase no artigo da Wikipedia resulta de um mal-entendido do trabalho de E. Visser.
Gramáticas para analisadores sem scanner (isto é, gramáticas que descrevem um idioma como conjunto de seqüências de caracteres em vez de um conjunto de sequências de tokens com os tokens descritos separadamente como sequências de caracteres) tendem a ter muitas ambiguidades. Papel de E. Visser Os filtros de desambiguação para analisadores de LR generalizados sem scanner (*) propõem vários mecanismos para solucionar ambiguidades, um dos quais é útil para resolver o problema do outro pendente. Mas o artigo não afirma que a ambiguidade precisa denominada "problema do outro pendente" esteja relacionada a analisadores sem scanner (nem mesmo que o mecanismo seja especialmente útil para analisadores sem scanner).
O fato de propor um mecanismo para resolvê-lo não é uma declaração implícita, pois outro mecanismo de resolução de ambiguidade (prioridade e precedência do operador) também parece totalmente não relacionado à natureza sem scanner dos analisadores considerados (considere, por exemplo, que essas ambiguidades não podem ser presentes nas gramáticas regulares como resultado do aninhamento, enquanto os manipulados por uma regra de correspondência mais longa podem).
(*) Esse é provavelmente o artigo que serve de base ao artigo da Wikipedia sobre analisadores sem scanner, mesmo que eles façam referência a outro, também por E. Visser, Analisador de LR sem Scanner Generalizado .
fonte
Apenas para declarar o problema, o Dangling Else Problem é uma ambiguidade na especificação da sintaxe do código, onde pode não ser claro, nos casos de ifs e elses seguidos, o que mais pertence a qual if.
O exemplo mais simples e clássico:
Não está claro para quem não conhece as especificidades da especificação de idioma de cor, que
if
recebe oelse
(e esse trecho de código específico é válido em meia dúzia de idiomas, mas pode ter um desempenho diferente em cada um).A construção Dangling Else apresenta um problema em potencial para implementações de analisador sem scanner, porque a estratégia é reduzir o fluxo de arquivos um caractere de cada vez, até que o analisador veja que tem o suficiente para tokenizar (digerir no assembly ou no idioma intermediário que está compilando) . Isso permite que o analisador mantenha o estado mínimo; assim que achar que possui informações suficientes para gravar os tokens analisados no arquivo, isso será feito. Esse é o objetivo final de um analisador sem scanner; compilação rápida, simples e leve.
Supondo que novas linhas e espaços em branco antes ou depois da pontuação não tenham sentido (como na maioria dos idiomas do estilo C), essa declaração apareceria para o compilador como:
Perfeitamente analisável para um computador, então vamos ver. Eu recebo um personagem de cada vez até ter:
Ah, eu sei o que isso significa (em C #), significa "
push
condiçãoA na pilha de avaliação e, em seguida, chamobrfalse
para pular para a instrução após o próximo ponto e vírgula, se não for verdade". No momento, não vejo ponto e vírgula, portanto, por enquanto, definirei meu deslocamento de salto para o próximo espaço após esta instrução e aumentarei esse deslocamento à medida que insiro mais instruções até ver um ponto e vírgula. Continuando a analisar ...OK, isso analisa um par semelhante de operações de IL e segue imediatamente após a instrução que acabei de analisar. Como não vejo ponto-e-vírgula, aumentarei o deslocamento da minha declaração anterior pelo comprimento dos meus dois comandos (um para o push e outro para o break) e continuarei procurando.
Ok, é fácil. Isso é "
call
doFoo". E isso é um ponto e vírgula que eu vejo? Bem, isso é ótimo, esse é o fim da linha. Vou incrementar as compensações de pulo de meus dois blocos pelo comprimento desses dois comandos e esquecer que alguma vez me importei. OK, seguindo em frente ...... Uh-oh. Isso não é tão simples quanto parecia. OK, esqueci o que estava fazendo, mas isso
else
significa que há uma declaração de interrupção condicional em algum lugar que eu já vi, então deixe-me olhar para trás ... sim, aí estábrfalse
, logo após pressionar alguma "condiçãoB" em a pilha, o que quer que fosse. OK, agora eu preciso de um incondicionalbreak
como a próxima declaração. A declaração que virá depois disso agora é definitivamente o objetivo da minha interrupção condicional, por isso vou me certificar de que ela esteja certa e aumentarei a interrupção incondicional que eu introduzi. Seguindo em frente ...Isso é fácil. "
call
doBar". E há um ponto e vírgula, e eu nunca vi aparelho. Portanto, o incondicionalbreak
deve passar para a próxima declaração, seja ela qual for, e posso esquecer que alguma vez me importei.Então, o que temos ... (nota: são 22h e não tenho vontade de converter deslocamentos de bits em hexadecimal ou preencher o shell IL completo de uma função com esses comandos, então isso é apenas pseudo-IL usando números de linha onde normalmente haveria desvios de bytes):
Bem, isso realmente é executado corretamente, SE a regra (como na maioria das linguagens de estilo C) é
else
a mais próximaif
. Recuado para seguir o aninhamento da execução, ele seria executado assim, onde, se conditionA for false, o restante do snippet inteiro será ignorado:... mas o faz por acaso, porque a quebra associada à
if
instrução externa salta para abreak
instrução no final do internoif
, o que leva o ponteiro da execução além da instrução inteira. É um salto extra desnecessário e, se este exemplo for mais complexo, poderá não funcionar mais se analisado e tokenizado dessa maneira.Além disso, e se a especificação da linguagem disser que um dangling
else
pertence ao primeiroif
e se a condiçãoA for falsa, o doBar será executado, enquanto que se a condiçãoA for verdadeira, mas não a condiçãoB, nada acontecerá, como isso?O analisador havia esquecido o primeiro
if
que existia e, portanto, esse algoritmo simples de analisador não produzia o código correto, para não falar em código eficiente.Agora, o analisador pode ser inteligente o suficiente para lembrar os se
if
eelse
s por mais tempo, mas se a especificação do idioma indicar um únicoelse
depois de doisif
s corresponder ao primeiroif
, isso causará um problema com doisif
s comelse
s correspondentes :O analisador verá o primeiro
else
, corresponderá ao primeiroif
, depois verá o segundo e entrará em pânico no modo "que diabos eu estava fazendo de novo"? Nesse ponto, o analisador obteve bastante código em um estado mutável que preferiria já ter enviado para o fluxo de arquivos de saída.Existem soluções para todos esses problemas e what-ifs. Porém, o código necessário para ser inteligente aumenta a complexidade do algoritmo do analisador ou a especificação de idioma que permite que o analisador seja burro aumenta a verbosidade do código-fonte do idioma, como exigir instruções finais como
end if
parênteses indicando colchetes bloqueia se aif
instrução tiver umelse
(ambos os quais são comumente vistos em outros estilos de idioma).Este é apenas um exemplo simples de algumas
if
declarações, e observe todas as decisões que o compilador teve que tomar e onde ele poderia facilmente ter estragado tudo. Este é o detalhe por trás dessa declaração inócua da Wikipedia em sua pergunta.fonte