Você está na página 1de 1

Editado por Aleardo Manacero Jr.

Captulo 2 - Analisador Lxico


1. 2. 3. 4. Expresses regulares Autmatos de estado finito AEF's e expresses regulares Implementao do analisador lxico

O compilador tem no seu analisador lxico o primeiro componente a entrar em contato com o cdigo fonte. Sua funo basica identificar os tokens presentes no cdigo fonte e passar essa informao para o parser. Isso significa que ele vai ocupar uma grande parte do tempo de execuo do compilador, obrigando-nos a implement-lo de modo bastante eficiente para que o processo de compilao possa ocorrer de forma rpida. O procedimento de anlise lxica consiste em ler os caracteres de entrada e agrupa-los em conjuntos que tenham sentido para os demais componentes do compilador. Estes conjuntos so os tokens da linguagem e na realidade so os identificadores e smbolos especiais de uma linguagem de computao. A seguir trataremos das expresses regulares e dos autmatos de estado finito, para depois estudarmos como os AEF's podem ser construdos automaticamente a partir de uma gramtica regular e como os analisadores lxicos podem ser representados atravs de um AEF.

1. Expresses regulares
Expresso regular uma forma compacta de denotar todos os possveis strings que compe uma determinada linguagem, usando para isso a chamada notao estrela (*) de Kleene para representar a ocorrncia de zero ou mais instncias de um determinado smbolo ou conjunto de smbolos terminais. O que a notao * de Kleene faz apenas indicar que uma sequncia de um determinado caracter "c" expressa pelo smbolo "c*", representando uma sequncia de pelo menos zero ocorrncias do caracter "c". Assim, um nmero inteiro pode ser representado por "dd*", em que "d" representa um dos algarismos entre 0 e 9. Da mesma forma, um identificador em pascal ou modula-2 pode ser representado por "a(a|d)*", em que "a" representa uma letra entre a e z enquanto "d" um algarismo entre 0 e 9. Uma expresso regular pode ser expressa atravs de uma gramtica livre de contexto da seguinte forma: gramtica ER = ( {'|', '(', ')', '*', '+', '?', \sigma}, {ExpReg, Termo, Fator, Primario}, ExpReg, P ) Na qual P: 1. ExpReg -> ExpReg '|' Termo (alternao) 2. ExpReg -> Termo 3. Termo -> Termo Primario (concatenao) 4. Termo -> Primario 5. Primario -> Fator '*' (iterao) 6. Primario -> Fator 7. Fator -> '(' ExpReg ')' (agrupamento) 8. Fator -> \sigma Observaes: \lambda 1. '(', ')', '*', '|', '+' e '?' so chamados meta-smbolos. 2. O meta-smbolo '+' significa que o Fator associado a ele pode ser repetido uma ou mais vezes. Logo, "a+" = "aa*" 3. O meta-smbolo '?' significa que o Fator associado a ele pode ser repetido zero ou uma vez. Logo, "a?" = a |

1.1 lgebra de expresses regulares


Uma vez definida uma expresso regular, temos que saber como manipula-la de modo a torna-la o mais legvel possvel, isto , como uma expresso regular define todos os strings de uma linguagem, gostaramos de poder ler atravs dela quais so os strings admissveis para a dada linguagem sem muitos transtornos. Isto possvel atravs de manipulaes algbricas feitas a partir de propriedades do tipo associativa, comutativa, distributiva e de identidade aplicadas s expresses regulares. Por exemplo, fica fcil de perceber que a propriedade comutativa pode ser aplicada sobre uma alternao pois r|s = s|r e no sobre uma concatenao pois rs != sr. A seguir temos uma lista das propriedades algbricas para expresses regulares. 1. r|s = s|r 2. r|(s|t) = (r|s)|t 3. r(st) = (rs)t 4. r|r = r 5. r(s|t) = rs|rt 6. (r|s)t = rt|st 7. r \lambda = \lambda r = r 8. r*r* = r* 9. r* = \lambda | r | rr | ... 10.(r*)* = r* 11.rr* = r*r = r+ 12.(r*|s*)* = (r*s*)* 13.(r*s*)* = (r|s)* 14.(rs)*r = r(sr)* 15.(r|s)* = (r*s)*r* (comutativa para alternao) (associativa para alternao) (associativa para concatenao) (absoro para alternao) (distributiva a esquerda) (distributiva a direita) (identidade para concatenao) (absoro de fechamento) (fechamento de Kleene)

1.2 Transformaes entre gramticas e expresses regulares


Uma linguagem regular pode ser definida ou atravs de uma gramtica regular ou atravs de uma expresso regular. Ambas as formas so suficientes, isto , definindo-se uma delas a linguagem fica automaticamente definida tambm. As diferenas entre a gramtica e a expresso que definem uma linguagem regular se devem ao formato em que definimos estas duas entidades. Enquanto uma gramtica usa o conjunto de produes para reescrever o smbolo inicial nos strings da linguagem, a expresso regular vai descrever os mesmos strings atravs de uma nica sentena na forma descrita em 2.1. Portanto a descrio de uma linguagem atravs de uma expresso regular permite uma identificao mais clara dos strings que compem a dada linguagem, enquanto que a gramtica mais til no momento de se formular as regras de formao da linguagem. Logo, interessante que tenhamos alguma estratgia para converter uma gramtica numa expresso regular e vice-versa, para que tenhamos como definir as regras e visualizar a linguagem nas formas adequadas para ambos os casos. A) Converso de expresso regular para gramtica: Dada a expresso regular \omega: 1. Cria-se a "produo" S -> \omega 2. Aplica-se uma das regras a seguir at no existirem produes vazias nem meta-smbolos Regra Para as produes R1 R2 R3 R4 R5 R6 A -> xy A -> x*y A -> x | y A -> B e e B -> x B -> xA A -> \lambda Criam-se as produes A -> xB A -> xB | y y A -> x A -> x B -> xA e e B -> y B -> xB |

e A -> y e B -> x e B -> x

S -> \lambda (S o smbolo inicial)

G -> \lambdaG -> S

Exemplo: a(a|d)* ==> S -> a(a|d)* (R1) S -> aA A -> (a|d)*

A -> (a|d)* <=> A -> (a|d)*\lambda (R2) (R3) (R3) A -> (a|d)B | \lambda B -> (a|d)B | \lambda A -> (a|d)B A -> aB B -> (a|d)B B -> aB A -> \lambda A -> dB B -> \lambda B -> dB

Com isso temos: S -> aA A -> aB A -> dB A -> \lambda B -> aB B -> dB B -> \lambda Eliminando-se as produes vazias e fazendo as simplificaes necessrias temos a gramtica final dada por: S -> aA S -> a A -> aA A -> dA A -> a A -> d B) Converso de gramtica para expresso regular: A converso neste sentido tambm simples, bastando fazer o procedimento inverso ao anterior usando para tanto as regras dadas a seguir: R1 Produes da gramtica B -> y A -> y Expresso regular A -> xy A -> x*y A -> x|y

R1 A -> xB R2 A -> xA | y R3 A -> x

Exemplo: A partir da gramtica G abaixo teremos: S-> aA S -> a A -> aA A -> a A -> dA A -> d

===>

a(a|d)*(a|d)|a

===>

a(a|d)*

2. Autmatos de estado finito


Como foi dito no captulo anterior, um autmato uma entidade capaz de reconhecer se uma string est ou no corretamente definida dentro de uma dada gramtica. Pela classificao de Chomsky vimos tambm que uma gramtica regular pode ser reconhecida pelo que chamamos de autmato de estado finito (AEF), o qual descrito pelos cinco objetos discriminados a seguir: M = (\SIGMA, Q, \DELTA, q0, F) Em que \SIGMA o alfabeto compreendido pelo autmato, Q o conjunto de estados definidos para o autmato, \DELTA o seu conjunto de regras de transio, q0 o seu estado inicial e F o conjunto de estados finais para o autmato. Um autmato pode ter suas regras de transio representadas de forma grfica ou tabular. Na forma grfica temos tambm a representao visual dos estados do AEF, o que facilita o entendimento de como o autmato passa de um estado a outro. J a forma tabular se presta bem ao armazenamento das transies num computador, o que vai ser muito interessante durante o projeto de um analisador lxico. A figura a seguir ilustra a representao grfica de um AEF, enquanto que a tabela depois da figura representa as transies do mesmo autmato em sua forma tabular.

Forma grfica para representao de um AEF. a b c A B B C B C B C A - D D - - Forma tabular para representao das transies num AEF. Um autmato reconhece ou aceita um string para uma dada linguagem se, ao final do string, parar num estado pertencente ao conjuntode estados finais F. Caso isso no ocorra diz-se que o autmato rejeita o string. Alm disso, diz-se que um autmato aceita uma linguagem se e somente se todos os strings definidos para aquela linguagem so aceitos pelo autmato, isto , para qualquer string pertencente linguagem o autmato ir parar num de seus estados finais. Partindo da definio da aceitao de uma linguagem podemos comparar dois autmatos sobre suas condies de equivalncia, isomorfismo, etc. Assim, diz-se que dois autmatos so EQUIVALENTES quando eles aceitam a mesma linguagem. J quando, alm de aceitarem a mesma linguagem, eles tambm tiverem os mesmos estados, diz-se que eles so ISOMORFOS. Por outro lado, quando um autmato tem o menor nmero de estados entre todos os seus equivalentes dizemos que ele REDUZIDO. Um AEF ainda pode ser classificado segundo o tipo de regras de transio que o mesmo apresenta. Por este critrio ele pode ser determinstico ou no-determinstico. Um AEF no-deterministico aquele em que pode ocorrer a transio vazia, que aquela em que o AEF pode passar de um estado a outro sem que ocorra a entrada de um caracter do string. Alm disso, num AEF no-determinstico podem ocorrer indeterminaes na ao do AEF, isto , determinados estados podem ter mais do que uma transio possvel para um dado caracter. O AEF determinstico aquele em que transies vazias no ocorrem e tambm em que no existam indeterminismos no momento de transitar de um estado a outro aps a leitura de um caracter, ou seja, todo aquele que no for no-determinstico.

2.2.1 Transformao de uma gramtica regular num AEF


Como um AEF um dispositivo capaz de reconhecer os strings de uma linguagem e uma gramtica um meio formal de definir uma linguagem, devemos ter mecanismos para a partir de uma gramtica especificar o AEF que reconhea tal linguagem. Isto feito de forma bastante simples, seguindo-se as regras a seguir: GRAMTICA alfabeto \SIGMA Para todo smbolo no-terminal em N S Para toda produo A -> xB Para toda produo A -> x AEF alfabeto \SIGMA cria-se um estado q pertencente a Q cria-se um estado final qf q0 cria-se uma transio B cria-se uma transio qf \delta(A,x) = \delta(A,x) =

3 AEF's e expresses regulares


Como j vimos, gramticas e expresses regulares so apenas duas formas distintas de representar uma linguagem. Logo, tambm podemos construir um AEF partindo-se de uma expresso regular. Uma forma bastante simples de se fazer isto atravs da representao grfica de um AEF, em que uma expresso regular ER seria colocada dentro de uma caixa-preta com um estado de entrada A e outro de sada B, como mostrado a seguir:

A seguir acrescentaria-se um estado inicial S e outro final F, quando teramos as transies \delta(S,\lambda) = A e \delta(B,\lambda) = F. A partir da seguiramos com a transformao usando as cinco regras a seguir, at que no existam mais caixas-pretas. REGRAS:

Exerccio: Encontre o AEF que reconhea a expresso \omega = a(a|d)*

Como se pode observar, o nmero de transies vazias no AEF encontrado bastante elevado, o que nos faz pensar em reduzir o nmero destas ocorrncias. Entretanto, bastante perigoso fazer isso sem um critrio muito bem definido, pois podemos acabar alterando a linguagem reconhecida por um AEF se retirarmos expresses vazias que fossem realmente necessrias. O exemplo a seguir ilustra bem este problema.

Exemplo (exerccio): 1. Construa o AEF para a expresso \omega = (a*b)* usando as regras dadas anteriormente. 2. Aps isso repita a construo do AEF, porm trocando a regra R3 pela regra F3 dada a seguir. Verifique que neste segundo caso possvel a aceitao do string "a", que no aceita por \omega.

3.1 - Obteno de um AEF determinstico a partir de um no-determinstico


A reduo do nmero de transies vazias num AEF, bem como a eliminao de transies ambguas, pode ser feita de forma segura quando se faz a reduo de um AEF no-determinstico para um determinstico. Este processo realizado em quatro etapas, "remoo de ciclos vazios", "eliminao de transies vazias", "remoo de no-determinismos" e "reduo do autmato", que esto descritas a seguir. 1. Remoo de ciclos vazios: O primeiro passo na obteno do AEF determinstico identificar ciclos nos quais, partindo-se de um dado estado pode-se chegar ao mesmo passando apenas por transies vazias. Como se percebe, tais ciclos implicam em que os estados intermedirios no necessariamente precisam ser percorridos, desde que se garanta a manuteno das transies no-vazias ligadas aos estados do ciclo. Para eliminarmos estes ciclos sem que haja prejuzo de consistncia ao AEF basta que se crie um novo estado que ir assumir o lugar de todos os estados que fazem parte do ciclo. As transies de entrada do novo estado so as transies de entrada de cada um dos estados do ciclo, enquanto que as transies de sada so todas as transies de sada dos estados em substituio. Nesse processo, caso um dos estados do ciclo for final, ento o novo estado tambm ser final. Efetuar isto de forma grfica possvel, bastando tomar cuidado para, a cada passo, no deixar de lado nenhuma transio dos estados que compe o ciclo. Entretanto, quando estamos fazendo isso de forma automatizada fica difcil conseguir um algoritmo que trabalhe de forma visual eficientemente. O que se faz usar a forma tabular de representao das transies do AEF, passando ento a ser necessrio um algoritmo de deteo de ciclos vazios na tabela em questo. Fica como exerccio a especificao dos algoritmos para a eliminao dos ciclos vazios no AEF no-determinstico, o que significa um algoritmo para a deteo do ciclo e outro para a unio dos estados pertencentes ao ciclo. 2. Eliminao de transies vazias: Aps a eliminao dos ciclos vazios ainda teremos transies vazias que no pertenciam a nenhum ciclo. A eliminao de tais transies pode ser feita de forma semelhante eliminao dos ciclos vazios, isto , atravs da unio dos estados envolvidos numa transio vazia, tanto de forma grfica quanto de forma algoritmica atravs da tabela de transies. No caso da eliminao de transies vazias, o que se faz copiar o estado destino da transio vazia sobre o estado origem da mesma, sem remover o estado destino entretanto. No processo o que se faz copiar todas as transies que partem do estado destino para o estado origem, pois so estas as transies que passam a ser possveis quando partindo do estado origem com a transio vazia para o estado destino, no qual teramos as novas transies de partida possveis. Aqui tambm, o novo estado (aquele do qual partia a transio vazia) passar a ser final caso o estado destino seja final. Na forma tabular, teramos algo como nas tabelas seguintes, nas quais estamos eliminando a transio vazia \delta(A, \lambda) = B. a b \lambda a b \lambda S B A S B A A B A A,B F G B A,B F G B A,B F G F ===> F G F H,J G F H,J H F H F J A J A Observem que o algoritmo pode ser otimizado se forarmos com que o processo se inicie a partir de um estado destino que no tenha transies vazias entre as suas transies de partida, pois assim eliminamos a possibilidade de ter que eliminar transies recursivamente. 3. Remoo de no-determinismos: Como se pode ver das tabelas apresentadas no passo 2 ainda teremos indeterminismos em algumas transies, como por exemplo \delta(A, a) = A ou \delta(A, a) = B. O ltimo passo para a obteno de um AEF determinstico a eliminao de tais transies, o que pode ser feito atravs da alterao dos estados do autmato. Muito embora isso tambm possa ser feito de forma grfica, apenas realizamos este passo pela forma tabular, uma vez que a complexidade da alterao dos estados tal que seria muito fcil cometer pequenos enganos no processo, o que levaria a uma linguagem diferente da original. O processo pela forma tabular o seguinte: 1. partindo-se do estado inicial, para cada transio com mltiplas opes cria-se um novo estado, cujo nome a unio dos nomes dos estados destinos da transio. 2. Cria-se uma nova linha na tabela, com o novo estado, em que as transies so dadas pela unio entre as transies de cada um dos estados agora aglutinados. 3. Repete-se o processo at que no existam mais estados a serem aglutinados. 4. Reduo do autmato: Muito embora o autmato obtido no passo 3 j seja determinstico, o mesmo contm muitos estados que poderiam ser eliminados por um processo de reduo no tamanho do autmato. Esta reduo se d pela identificao dos estados equivalentes em classe, que so os estados para os quais se aceitariam as mesmas strings caso eles fossem os estados iniciais para as strings. Uma vez identificados os estados de uma classe de equivalncia, os mesmos so substituidos por apenas uma instncia, alterando-se o seu nome e atualizando a tabela de transies para conter este novo nome. O processo se repete at que no seja mais possvel identificar novas classes de equivalncia, o que significa que o autmato dado pela tabela atual o autmato reduzido para a linguagem em questo. O algoritmo a seguir deixa explcito o processo de minimizao dos estados de um autmato determinstico: 1. Dividir os estados em duas classes, uma contendo todos os estados que sejam finais e outra contendo os no-finais. 2. Em qualquer das classes, separar tambm os estados que bloqueiam num determinado caracter do alfabeto numa nova classe. 3. Estados dentro de uma mesma classe que levem at estados em diferentes classes para um mesmo caracter, tambm podem ser divididos em duas classes. 4. O processo continua at que mais nenhuma nova classe possa ser criada. Nesse momento, cada uma das classes pode ser considerada como sendo um estado nico. A aplicao desse processo no autmato a seguir mostra bem como isso pode ser feito:

Ou seja, de incio separamos os estados finais dos no-finais. Depois, vemos que os estados B e BE bloqueiam para o caracter "a" e devem, portanto, serem separados do estado A. A seguir, vemos que o estado CF leva ao estado A, numa classe diferente da classe a que pertence o estado CF, enquanto que os demais estados levam ao estado BE, que est numa classe diferente de A. Assim, podemos separar o estado CF numa classe diferente da que pertencem os outros estados finais. A seguir, no teramos mais classes para separar, quando ento poderamos juntar todos os estados de uma dada classe num estado nico, resultando no autmato indicado na ltima tabela da sequncia.

3.2- Transformao de AEF's em gramticas regulares


O processo aqui bastante simples, bastando fazer a aplicao das regras de transformao de forma reversa, isto , para toda transio \delta(A,x) = B acrescenta-se a produo A -> xB e para todo estado final "F" acrescenta-se a produo F -> \lambda Aps a criao de todas as produes deve-se fazer a eliminao das produes vazias atravs dos mecanismos apresentados anteriormente. Portanto percebe-se que a transformao trivial, levando-nos a conseguir mais uma passagem entre as vrias formas de se representar a gramtica para um analisador lxico.

3.3- Gramtica linear a esquerda


Quando examinamos o processo de transformao de uma gramtica num AEF construmos todas as regras baseando-nos numa gramtica linear a direita, isto , com produes do tipo A -> xB e A -> x. Entretanto, nem sempre temos uma gramtica deste tipo em mos. Uma forma de se obter tal gramtica usar expresses regulares como uma forma intermediria no processo de transformao de uma gramtica linear a esquerda em outra a direita. Como j temos as regras de transformao entre ER's e gramticas lineares a direita, resta-nos apenas determinar as regras de transformao entre gramtica linear a esquerda e expresses regulares. As regras de produo so as seguintes: Produes: A -> Bx A -> Ax A -> x e B -> y Expresso regular: A -> yx A -> yx* A -> x | y e A -> y e A -> y

4. Implementao do analisador lxico


Um analisador lxico pode ser implementado ou atravs do AEF que o representa ou atravs de sua gramtica regular. Embora o resultado de ambas as tcnicas deva ser o mesmo, estas formas tem diferenas fundamentais quanto implementao. Se partirmos do AEF para a implementao do scanner, o trabalho de manipulao maior do que se partirmos de sua gramtica regular, que um processo que pode ser feito de forma automtica. A seguir descrevemos estas duas abordagens, apresentando tambm os problemas envolvidos na especificao do analisador lxico, tais como a implementao da tabela de smbolos, tamanho do alfabeto de entrada e tratamento da passagem de valores (tokens) ao analisador sinttico, entre outros.

4.1 Implementao via AEF


A implementao do scanner atravs de um AEF bastante simples. Basicamente o que feito usar um par de comandos do tipo CASE (switch em C) para representar os estados e os caracteres sendo lidos pelo autmato. Assim, por exemplo, um primeiro CASE faz sua deciso a partir do estado atual do autmato (que est guardado numa varivel atualizada a cada transio), enquanto que o segundo CASE tomar a sua deciso a partir do caracter que acaba de ser lido. A ordem em que estes dois cases so realizados pode ser alterada segundo a convenincia do processo de busca, isto , caso seja mais conveniente primeiro selecionar pelo caracter de entrada e depois pelo estado, podemos faz-lo assim sem maiores complicaes. A deciso sobre qual ordem a ser adotada deixada ento a cargo do implementador. Como pode ser visto, uma vez definido o AEF temos que a sua implementao trivial se o mesmo puder ser expresso por um conjunto reduzido de estados e de caracteres de entrada. Entretanto isso no o que ocorre num compilador, fazendo com que a implementao do AEF se torne trabalhosa devido ao grande nmero de estados e do tamanho do alfabeto existentes numa gramtica regular real. A soluo para este problema o uso de geradores automticos de scanners, tais como o lex ou o flex presentes no ambiente UNIX.

4.2 Implementao via gramtica


O scanner pode ser implementado usando-se um gerador automtico, tal como o lex. Para tanto, usamos gramticas reescritas na forma de expresses regulares, que devidamente arranjadas segundo a sintaxe do lex podem gerar de forma automtica o cdigo do scanner. Esta abordagem tem enormes vantagens com relao implementao direta a partir do autmato pois, como a gramtica (e as expresses regulares que a representam) tem que ser definida de qualquer maneira, uma vez que a partir dela que sabemos quais so os strings permitidos para a dada linguagem, torna-se desinteressante tranformarmos a gramtica num autmato que teria que ser implementado manualmente, se sabemos que existem geradores automticos de scanners a partir das produes da prpria gramtica. Entretanto, em ambos casos existem problemas que precisam ser resolvidos para que a implementao seja funcional, tanto quanto sua correo como quanto sua eficincia. A seo seguinte faz um tratamento destes problemas.

4.3 Problemas de implementao


1. Tamanho do alfabeto de entrada: Como o autmato usa dois cases aninhados, em que um deles decidido pelos diferentes caracteres do alfabeto de entrada, torna-se necessrio que o alfabeto no seja muito extenso, uma vez que em geral temos cerca de 50 estados diferentes na gramtica de um compilador normal. O alfabeto ASCII tem 128 caracteres (muitos no imprimveis), logo se o estamos usando, precisamos de algo para reduzir o seu tamanho. Uma ttica usar subconjuntos que tenham uma caracterstica em comum para que possam ser representados por apenas um nico smbolo, tais como todas as letras (maisculas e minsculas) serem representadas pelo conjunto [A-Za-z]. 2. Critrios de parada: Um outro problema a determinao de quando uma certa sequncia de entrada representa um token vlido ou no. Por exemplo, para expresso regular d*d* fica impossvel determinar se a sequncia de entrada 12345 representa os strings "1" e "2345" ou "123" e "45". Para este problema temos duas solues. Na primeira a estratgia antecipar sempre a leitura do prximo caracter quando estivermos trabalhando com um dado caracter. Assim, se estivermos num estado final que tenha transies de sada, usamos o prximo caracter para decidir se ele permite uma transio ou no. A outra soluo simplesmente ignora os estados finais at que o autmato bloqueie. Neste caso ele verifica se o bloqueio ocorreu num estado final. Caso isso seja verdade ele aceita o token, caso contrrio o token rejeitado. Nos dois casos o scanner reinicia seu funcionamento a partir do caracter que causou o seu bloqueio. 3. Eliminao de espaos e comentrios: Outro aspecto a ser cuidado a eliminao de espaos em branco e de comentrios da sequncia de entrada. A finalidade de sua existncia dar mais clareza ao texto fonte mas, durante a compilao, no existe mais nenhuma razo para que os mesmos sejam mantidos, uma vez que o scanner j separa todos os tokens a serem trabalhados pelo analisador sinttico. Alis, se os espaos e comentrios fossem mantidos aps a passagem pelo scanner, teramos que aumentar a quantidade de tokens aceitveis pela linguagem do parser, o que o tornaria muito mais complexo. Assim, temos que fazer com que o scanner reconhea espaos e comentrios e os descarte aps detectar algo diferente de espao ou comentrio, o que obtido modificando a sua gramtica de forma que suas expresses regulares incluam agora espaos e comentrios. 4. Passagem de valores: Como o scanner existe apenas para fazer a separao dos tokens de entrada do parser (que quem ativa o scanner), temos que encontrar uma forma de faz-lo passar valores para o parser. Uma forma elegante de fazer isso atravs da adio de aes semnticas s produes da gramtica regular. Uma ao semntica simplesmente uma atribuio de valor de retrno que o scanner faria no instante em que chegasse em um bloqueio num estado final. Isto pode ser implementado de vrias formas, mas a mais simples atravs de atribuies diretas dentro dos comandos case criados (tanto manualmente como de forma automtica) para fazer a anlise lxica. No caso do uso do lex isto feito diretamente em cada expresso regular. 5. Tabela de smbolos: Dentro do processo de identificao de tokens da gramtica surge o problema de como identificar individualmente cada varivel ou constante definida no programa. Essa tarefa resolvida pelo uso de uma tabela de smbolos, em que so armazenadas todas as informaes sobre cada varivel (tratada aqui como um smbolo), tais como seu nome, seu escopo, endereo lgico, tipo, etc. Um grande problema envolvido na implementao do scanner a forma em que a tabela de smbolos criada e manipulada. Isto se deve ao fato de que a tabela de smbolos tem que ser consultada, e atualizada, cada vez que um token identificado. Logo, temos que ter mecanismos que faam isso de forma bastante eficiente. Dentre as possveis estratgias temos a implementao da tabela como sendo uma tabela hash, em que atravs de uma funo hash pudessemos encontrar smbolos dentro da tabela de forma bastante rpida. Esta forma ao mesmo tempo eficiente e econmica em termos de memria, desde que dentro de cada posio da tabela no tenhamos que percorrer listas extensas para identificar um token de forma nica. Uma possvel melhoria obtida ao custo de um aumento no espao ocupado na memria, fazendo-se com que cada caracter de cada token ocupe um n de uma rvore de busca. Tal rvore chamada "trie" (de re"trie"val) e consiste basicamente em fazer com que cada n seja um vetor que aponte para n possveis caracteres que seguiriam ao n em questo. Para efeito de comparao temos a seguir uma tabela apresentando o espao ocupado e tempo de busca para tabelas de smbolos implementadas atravs de busca linear, tabela hash e rvore trie: Tamanho da tabela (bytes) 50 ident. Busca linear Tabela Hash rvore trie 600 1400 5720 500 ident. 6000 10400 36000 Tempo de scan 50 ident. 2960 250 250 500 ident. 29600 540 250

Algoritmo

Você também pode gostar