Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Marcus Vinicius Araujo Martins Universidade Estadual de Feira de Santana (UEFS) Feira de Santana BA Brasil
{viniciusfsa@gmail.com}
Resumo: Este relatrio visa descrever um projeto de analisador sinttico para um compilador baseado na produo de uma gramtica desenvolvida em etapa anterior, usando a notao EBNF. Aqui sero tratadas as principais tcnicas de anlise sinttica, destacando vantagens e desvantagens de cada uma, bem como tambm salientado o processo de tratamento de erros sintticos e breve descrio do projeto prtico.
1 - Fundamentao terica
1.1 - O analisador sinttico
O analisador sinttico tem por funo receber uma cadeia ou conjunto de tokens proveniente do analisador lxico e verificar se a mesma pode ser gerada pela gramtica da linguagem fonte [1]. Neste sentido, a gramtica quem d as diretrizes para construo de um analisador capaz de reconhecer expresses que so aceitas em suas regras. O analisador sinttico tem o papel ainda de se recuperar dos erros que ocorram, no intuito de continuar a processar toda entrada de tokens, e no apenas at encontrar o primeiro erro. Quando falado aqui em erros sintticos, no mais se est preocupado com erros de escrita ou tipos mal formados. Isso foi um papel do analisador lxico que, no poder de suas atribuies, pde localizar e classificar a ocorrncia de cada token dentro do cdigo, bem como relatar possveis erros lxicos presentes no corpo de cdigo do programador. Passada essa fase, subtende-se que a tabela de smbolos mantm um conjunto de valores que precisam agora ser vistos como unidades e, desta forma, seu contedo, se formado por dgitos ou letras, no mais o objetivo. Aqui, vistos de forma atmica, os tokens precisam passar por uma etapa onde sua ordem verificada, se um identificador vem imediatamente antes de um operador ou se um tipo primitivo antecede um identificador, numa declarao, por exemplo, no poder de construo definido na gramtica. Nesse contexto, a construo do analisador sinttico a ser apresentada se baseia nas construes definidas na gramtica, em etapa anterior, baseando-se na notao EBNF. As possveis estratgias da anlise so esplanadas no tpico 1.2, bem como tambm apresentado os critrios de escolha de determinada estratgia, a partir de decises tericas e de projeto.
produo antes definida seja trocada, por uma segunda produo, o que torna o mtodo bastante exaustivo. O mtodo recursivo preditivo desenvolvido sem retrocesso. Nesse mtodo, o smbolo sob o cabeote de leitura determina exatamente qual produo deve ser aplicada na expanso de cada no terminal. Esse foi o mtodo implementado para o analisador em questo, aproveitando que ele exige que a gramtica no tenha recursividade esquerda, que a gramtica seja fatorada esquerda e que, para os noterminais com mais de uma regra de produo, os primeiros terminais derivveis sejam capazes de identificar, univocamente,a produo que deve ser aplicada para cada momento da anlise sinttica [2]. Esse tipo de anlise se baseia no princpio de que cada no terminal identificado como uma funo ou procedimento. Funciona como um grafo onde toda regra da gramtica mapeada[3], Toda ocorrncia de um terminal x corresponde ao seu reconhecimento na cadeia de entrada e a leitura do prximo smbolo dessa cadeia. O exemplo de gramtica da figura 1 em correspondncia com seu procedimento implementado na figura 2 descrevem esse princpio.
Figura 1 Exemplo de gramtica
O cdigo descrito na figura 2 corresponde a implementao do procedimento apresentado na figura 1. Caso o no-terminal <F> seja invocado, esse procedimento executado. Na produo especfica, F deriva a ou b ou o no terminal <E> entre parnteses (<E>). A partir disso ele analisa primeiramente se (. Se sim, o procedimento chama prximo token e passa a responsabilidade para o procedimento <E>, no apresentada aqui sua estrutura de procedimento. Genericamente, caso o contedo depois do ( seja realmente pertencente a produo <E>, ou seja, caso <E> retorne um valor verdadeiro, <F> continuar seu processamento. Assim, ele analisa se o prximo token ). Se sim, ele chama o prximo token, deixando o ponteiro ou cabea do cabeote pronto para prxima anlise, e finaliza o procedimento. Se inicialmente o primeiro token no fosse (, ento o procedimento verificaria se era a ou se era b. Se no fosse nenhum desses, lanado um erro ou um valor falso, indicando que aquela produo no corresponde. Sendo a ou b, o procedimento finalizado, sem ocorrncia de erros. A terceira estratgia top-down a tabular preditiva. Essa forma de anlise chegou ser verificada, mas no foi implementada, devido principalmente a sua complexidade. Esse mtodo utiliza uma tabela que faz relao entre os smbolos no
terminais e os smbolos de entrada. Para construo da tabela, se faz necessrio saber dois conjuntos, denominados Primeiro e Seguinte. O conjunto Primeiro para um simbolo T, por exemplo, o conjunto de smbolos terminais que iniciam as cadeias derivadas de T, onde T qualquer cadeia de smbolos da gramtica[2]. O Seguinte de T o conjunto de terminais a que podem aparecer imediatamente direita de T em alguma forma sentencial[2]. Embora o mtodo tabular no tenha sido implementado, a construo desses dois conjuntos foi necessria no tratamento de erros, descrita no tpico 1.4.
lxico, controlando o processo de criao da tabela de tokens, pelo analisador lxico, e a repassando para o analisador sinttico. Os mtodos da classe ProductionRules.java so quase que exclusivamente procedimentos dos smbolos no terminais, como descrito no tpico 1.3. Todavia, ela possui um mtodo start() que faz com que uma tabela de smbolos passada por uma instancia da classe controladora ParsingControl.java, seja transferida numa ordem inversa para uma pilha de tokens, no intuito de pegar os tokens na forma correta. Fazendo isso, os tokens so buscados sempre nessa pilha. Aps isso, o primeiro token retirado da pilha e o primeiro procedimento chamado, o procedimento programa(). A figura 3 mostra o incio da execuo.
O procedimento programa() relaciona a estrutura geral de como deve ser o cdigo. Por deciso de projeto, ele deve comear com zero, uma ou mais declaraes de biblioteca, seguido de zero ou mais declaraes globais e seguido obrigatoriamente por declaraes de variveis e funes, na obrigatoriedade de existir pelo menos o mtodo main() no cdigo do programador. Isso corresponde na prtica que o cdigo do programador deve manter uma estrutura iniciada por <Declarao de Bibliotecas>, depois por <TypeDef> ou <Declarao de Struct> ou <Declarao Const>, depois por <Varveis Globais>* e <Declarao de Funes> e depois por <Principal>, que o mtodo main(). A implementao dos procedimentos se baseou nas seguintes tcnicas, analisando a produo de cada no terminal na gramtica. a) quando houver uma concatenao if's encadeados b) quando houver uma escolha ou else if ... pra cada derivao c) quando houver uma repetio do while. d) quando houver uma repetio do do-while com flag. tem de comparar na seqncia com '|' na derivao, utiliza-se um if tipo { } (0 ou mais) utiliza-se o tipo { }+ (1 ou mais) utiliza-se o
A forma de tratamento de erros se baseou na construo dos conjuntos Primeiro e Seguinte, para cada procedimento, conforme descrito na sesso 1.4. Para o procedimento declaracaoConst() por exemplo, seus seguintes foram levantados e definidos no escopo do prprio mtodo, conforme figura 4.
Ocorrendo algum erro dentro do procedimento declaracaoConst(), como por exemplo a ausncia do smbolo = depois de um identificador, lanado um erro sinttico com a chamada ao procedimento matchError(smbolo,seguinte). Os parmetros dessa chamada correspondem respectivamente ao smbolo que era esperado e o conjunto de seguintes do procedimento. O mtodo matchError() quando recebe
esses parmetros, adiciona numa lista de erros esse novo erro e faz um loop para saber se o prximo token equivale a algum possvel seguinte a construo declaraConst(). O lanamento de erros com a chamada a matchError() no pode ser feito em qualquer procedimento que falhe; deve ser chamada apenas quando a falha for numa anlise de em um smbolo terminal. Em outros casos, apenas um valor falso retornado, fazendo com que o no terminal que o invocou busque outra produo possvel para ele. A construo do analisador no se deu obedecendo exatamente as construes da gramtica, visto que na mesma ainda pde ser encontrada algumas ambigidades nas produes. Problemas como esse foram resolvidos diretamente dentro do cdigo, ao invs de fazer alteraes na gramtica primeiramente. Um exemplo disso o caso de aceitao de ifs sem elses. Na verdade isso no o problema. O problema que quando aconteciam de se ter dois ifs e um else, estava ambguo, na gramtica, a qual IF o else pertencia. A soluo para isso foi a obrigatoriedade de todo IF acompanhar um else.
3 - Referncias
[1] AHO, Alfred V.; SETHI, Ravi; ULLMAN, Jeffrey D. Compiladores, principios, tecnicas
e ferramentas. Rio de Janeiro: Guanabara Koogan, c1995.
[2] PRICE, Ana Maria de Alencar; TOSCANI, Simao Sirineo. Implementacao de linguagens
de programacao : compiladores. 3. ed. Porto Alegre: Sagra Luzatto, 2005.
[3] Compiladores - Profa. Helena Caseli, disponvel em: http://www2.dc.ufscar.br/~helenacaseli/comp/trabalhos/Trabalho2/Trabalho2.pdf ltimo acesso: 23/12/09