FACULDADE ANGLO AMERICANO – FOZ DO IGUAÇU Curso de Ciência da Computação – 7º Periodo Disciplina: Compiladores Prof. Erinaldo Sanches Nascimento Análise Sintática Descendente Recursivo com retrocesso Recursivo preditivo Tabular preditivo Definição • Esse método constroi a árvore de derivação para a cadeia de entrada de cima para baixo. – Da raiz para as folhas. – Cria nós em pré-ordem (da esquerda para a direita). – Produz uma derivação mais à esquerda para uma cadeia de entrada. http://erinaldosn.wordpress.com 2 • Analisadores sintáticos descendentes – Com retrocesso (backtracking) – Preditivos • Algoritmos – Descendentes recursivos – LL(1) http://erinaldosn.wordpress.com 3 Exemplo • Gramática http://erinaldosn.wordpress.com 4 • Análise sintática descendente para a entrada id+id*id http://erinaldosn.wordpress.com 5 http://erinaldosn.wordpress.com 6 http://erinaldosn.wordpress.com 7 Análise Sintática Descendente Recursiva • Consiste em um conjunto de procedimentos, um para cada não-terminal da gramática. • Pode exigir retrocesso (voltar atrás no reconhecimento) • A regra gramatical para um A não-terminal é vista como uma definição de procedimento para reconhecer um A. • O lado direito da regra gramatical especifica a estrutura do código para esse procedimento. http://erinaldosn.wordpress.com 8 • Considere a regra gramatical para um fator na gramática de expressões: void fator(){ switch (marca) case ‘(‘ : casamento((); exp; casamento()); case numero : casamento(numero); default erro; } http://erinaldosn.wordpress.com 9 • Procedimento casamento que casa a marca seguinte com seu parâmetro. void casamento(marcaEsperada){ if marca = marcaEsperada capturaMarca; else erro; } http://erinaldosn.wordpress.com 10 • Funcionamento de um analisador descendente com retrocesso. – Considere a sentença [a] derivada a partir da gramática abaixo, a qual gera listas: S a | [L] L S; L | S http://erinaldosn.wordpress.com 11 • O reconhecimento de [ é bem sucedido. • A derivação de L é efetuada usando S ; L. • S é expandido novamente, obtendo-se sucesso. http://erinaldosn.wordpress.com 12 • A comparação seguinte (] com ;) falha. • O analisador deve retroceder para o ponto em que estava por ocasião da opção pela primeira alternativa de L. • É aplicada a segunda alternativa, L S. • A derivação final é obtida aplicando-se a produção Sa. http://erinaldosn.wordpress.com 13 Pseudocódigo • Programa principal main(){ token = Letoken(); if S if token = ‘$’ write (‘Sucesso’); else write (‘Erro’); } http://erinaldosn.wordpress.com 14 • Função S S(){ if token = ‘a’{ token = Letoken(); return true; } else if token = ‘[‘{ token = Letoken(); if L if token = ‘]’{ token = Letoken(); return true; } else return false; else return false } else return false; } http://erinaldosn.wordpress.com 15 • Função L. L(){ Marca_Ponto(); if S if token = ‘;’{ token = Letoken(); if L return true; else return false; } else { Retrocede(); if S return true; else return false; } else return false; } http://erinaldosn.wordpress.com 16 • A função Letoken() retorna um token lido a partir da sentença de entrada. • Marca_Ponto() marca, na sentença de entrada, um ponto de possível reinício da análise. • Retrocede() volta o ponteiro de leitura para o último ponto marcado. http://erinaldosn.wordpress.com 17 • Função L sem backtracking (retrocesso) L(){ if S if token = ‘;’{ if L return true; else return false; } else return true; else return false; } http://erinaldosn.wordpress.com 18 Exercício • Considere a gramática: ScAd Aab|a • Construa uma árvore de derivação descendente para a cadeia w = cad • Crie um algoritmo para reconhecimento dessa gramática. • Implemente o algoritmo em C, Java ou Pascal. http://erinaldosn.wordpress.com 19 FIRST e FOLLOW • Conjunto de verificação à frente Primeiro e de Sequência. • Permitem escolher qual produção aplicar, com base no próximo símbolo da entrada. http://erinaldosn.wordpress.com 20 FIRST( ) • é qualquer cadeia de símbolos da gramática – Conjunto de símbolos terminais que iniciam as cadeias derivadas de . • Se * , então a palavra vazia também faz parte do conjunto. http://erinaldosn.wordpress.com 21 • Considere as duas produções-A: A | • Onde FIST( ) e FIRST( ) são conjunto disjuntos • Podemos escolher uma dessas alternativas de A examinando o próximo símbolo de entrada a, desde que a só possa estar em FIRST( ) ou FIRST( ) http://erinaldosn.wordpress.com 22 FOLLOW(A) • É definida para símbolos não-terminais. • A é um não-terminal. • FOLLOW(A) é o conjunto de terminais a que podem aparecer imediatamente à direita de A em alguma forma sentencial – O conjunto de terminais a, tal que existe uma derivação da forma S * Aa para e quaisquer. http://erinaldosn.wordpress.com 23 Algoritmo para calcular FIRST(X) Para calcular o FIRST(X) de todos os símbolos S da gramática, aplique as regras a seguir até que não haja mais terminais ou que possam ser acrescentados a algum dos conjuntos FIRST. http://erinaldosn.wordpress.com 24 1. Se X é um símbolo terminal, então FIRST(X)={X}. 2. Se X é um símbolo não-terminal e X Y1Y2...Yk é uma produção para algum k 1, então acrescente a a FIRST(X) se, para algum i, a estiver em FIRST(Yi), e estiver em todos os FIRST(Yi),...,FIRST(Yi-1). Se está em FIRST(Yj) para todo j=1,2,...,k, então adicione a FIRST(X). 3. Se X é uma produção, então acrescente a FIRST(X). http://erinaldosn.wordpress.com 25 for (cada não-terminal A) First(A) = {}; while houver alterações em algum FIRST(A){ for (cada escolha de produção A X1,X2...Xn){ k = 1; continue = true; while (continue == true && k<=n){ acrescente First(Xk)-{ } a First(A); if ( não pertencer a First(Xk){ continue = false; k = k+1; } } if (continue = true) acrescente a First(A); http://erinaldosn.wordpress.com 26 • Algoritmo simplificado for (cada não-terminal A) First(A) = {}; while (houver alterações em algum First(A)) for (cada escolha de produção A X1X2...Xn) acrescente FIRST(X1) a First(A); http://erinaldosn.wordpress.com 27 Algoritmo para calcular FOLLOW(X) Para calcular o FOLLOW(X) para todos os nãoterminais A, aplique as regras a seguir até que nada possa ser acrescentado a nenhum dos conjuntos FOLLOW. http://erinaldosn.wordpress.com 28 1. Coloque $ em FOLLOW(S), onde S é o símbolo inicial da gramática, e $ é o marcador de fim da entrada ou fim de arquivo. 2. Se houver uma produção X B , então tudo em FIRST( ) exceto está em FOLLOW(A). 3. Se houver uma produção X B, ou uma produção X B , onde FIRST( ) contém , então inclua FOLLOW(X) em FOLLOW(A). http://erinaldosn.wordpress.com 29 • Algoritmo para computação de conjuntos FOLLOW. Follow(símbolo-inicial) = {$}; for (cada não-terminal S # símbolo-inicial) Follow(S) = {}; while (houver alterações em algum conjunto Follow) for(cada produção S A1A2...An) for (cada Xi não-terminal){ adicione First(Ai+1aAi+2...An) – { } a Follow(A) if ( estiver em First(Ai+1Ai+2...An)) adicione Follow(S) a Follow(A) } http://erinaldosn.wordpress.com 30 Observe • A palavra vazia jamais fará parte de algum conjunto FOLLOW. • Os conjuntos FOLLOW são formados apenas por símbolos terminais • não é símbolo terminal. http://erinaldosn.wordpress.com 31