Documente Academic
Documente Profesional
Documente Cultură
Computabilidade
Unidade I
Todos os direitos reservados. Nenhuma parte desta obra pode ser reproduzida ou transmitida por qualquer forma e/ou
quaisquer meios (eletrnico, incluindo fotocpia e gravao) ou arquivada em qualquer sistema ou banco de dados sem
permisso escrita da Universidade Paulista.
Apresentao
Unidade I
das novas arquiteturas de computador. Capacitlo no desenvolvimento de ferramentas de gerao de
programas para avaliao e apoio aos processos de engenharia de software, interpretadores e processadores
de dados estruturados e tambm no desenvolvimento de novas linguagens e paradigmas de programao.
Plano de ensino
1. Introduo
1.1. Descrio do processo realizado pelo computador a partir da codificao de um algoritmo pelo
programador at a sua execuo em um computador
1.2. Caracterizao das linguagens quanto ao nvel de abstrao
1.3. Identificao e diferenciao dos elementos do domnio
1.3.1. Linguagemfonte, de implementao e alvo
1.3.2. Compiladores, tradutores, montadores e interpretadores
1.3.3. IDEs, debuggers, editores grficos de interface e demais ferramentas de apoio
1.4. Modelos para a construo de compiladores
1.4.1. As etapas de transformao do cdigo
1.4.2. Compiladores de uma passagem e de mltiplas passagens
1.4.3. O modelo de Anlise e Sntese
2. Anlise Lxica
2.1. A transformao de fluxo de caracteres em lista de tokens
2.2. Autmatos finitos para reconhecimento e classificao de tokens
2.3. Identificao de erros lxicos
3. Anlise Sinttica
3.1. Produes (das Gramticas Livres de Contexto) e rvores de derivao
3.2. Descendente (topdown): Descendente Recursiva e LL
3.3. Ascendente (bottomup): LR e LALR
4
Unidade I
Compiladores e Computabilidade
Unidade I
Introduo
Da codificao execuo de um programa
Algumas perguntas importantes de serem respondidas j de incio so: o que ocorre desde a
codificao de um algoritmo por um programador at a sua execuo em um computador? Quais
so os elementos envolvidos? O que compete a cada um deles neste processo?
Programador Cdigofonte [Prprocessador] Cdigofonte sem macros
[Compilador] Cdigoobjeto (.obj) [Linker] Cdigo de mquina realocvel (.exe)
[Carregador] Cdigo de mquina absoluto
Podemos descrever esse processo da seguinte maneira:
O programador codifica o algoritmo utilizando uma linguagem de programao (linguagemfonte)
e o salva em um arquivo texto (cdigofonte). Antes de ser compilado, o cdigo submetido a um
prprocessamento para a remoo de macros e, ento, pode ser passado ao compilador para ser
transformado em cdigo de mquina (cdigoobjeto), de acordo com a plataformaalvo.
Neste novo arquivo criado pelo compilador, habitualmente com extenso.obj, temos apenas o
cdigo referente s instrues e funes definidas por este programador, faltando ainda juntlo
com o cdigo de mquina relativo s funes das bibliotecas. Para que isso seja feito, um programa
realiza a ligao entre os diversos arquivosobjetos e acrescenta os cabealhos necessrios ao sistema
operacional para identificlos como um arquivo executvel (cdigo de mquina realocvel).
Quando, ento, desejamos executar o programa, o carregador ou loader do sistema operacional
aloca o cdigo em alguma poro de memria em que caiba e que esteja disponvel, resolvendo
os endereos das variveis estticas e de entrada de funo at o momento sob a forma de
deslocamentos, por isso sendo chamado de cdigo de mquina absoluto.
Caracterizao das linguagens quanto ao nvel de abstrao
certo dizer que qualquer problema pode ser codificado usando qualquer linguagem, afinal
todo e qualquer programa , de fato, um conjunto de instrues dadas em linguagem de mquina;
mas a questo : ser que isso conveniente?
As linguagens de programao podem ser classificadas de acordo com o grau de abstrao
que oferecem, ou seja, o quo permissivas so para que o programador se concentre nos aspectos
essenciais, ignorando caractersticas menos importantes ou mincias operacionais.
7
Unidade I
Desse modo, as linguagens com um alto grau de abstrao, geralmente mais prximo da
linguagem humana, so chamadas de linguagem de alto nvel, enquanto aquelas mais prximas
das caractersticas e cdigo de mquina, em que o conhecimento de detalhes relativos arquitetura
e organizao so fundamentais, so ditas linguagens de baixo nvel.
Identificao e diferenciao dos elementos do domnio
Compiladores e Computabilidade
construdo; e a sntese, em que o cdigo correspondente traduo ser efetivamente
produzido de acordo.
A anlise lxica (ou scanner) a primeira etapa do processo de compilao e sua funo varrer
o cdigofonte, caractere por caractere, compondo os elementos que de fato formam o programa
e que so chamados de tokens ou lexemas. Adicionalmente, elementos tais como espaos em
branco, tabulaes, marcas de formatao de texto, comentrios ou quaisquer outros que sejam
irrelevantes ao processo de compilao so eliminados. Desse modo, dizemos que o analisador
lxico responsvel por transformar o fluxo de caracteres em um fluxo de tokens.
Garantida a produo de uma sequncia coerente de lexemas, precisamos ainda verificar a
adequao da estrutura gramatical do programa. A prxima subfase a anlise sinttica, em que se
busca determinar se uma sequncia de smbolos lxicos (cadeia) pode ser gerada pela gramtica que
define a linguagem em questo. Essa tarefa consiste em construir a rvore de derivao correspondente.
Resta ainda verificar o significado ou a semntica do programa, tarefa executada pela ltima
etapa da anlise, a chamada anlise semntica. de sua responsabilidade verificar certos aspectos
que no foram investigados anteriormente por impossibilidade ou inadequao de propsito, tais
como questes relativas a escopo, regras de visibilidade e compatibilidade entre tipos.
Uma vez garantido que o cdigofonte vlido e coerente, podese passar ao processo de
sntese. durante a gerao de cdigo que efetivamente ocorre a produo do cdigo equivalente
ao programa original. Dado o nvel de dificuldade inerente diferena entre os nveis de abstrao,
uma primeira tentativa pode ser realizada e seu produto passa por uma fase de otimizao, cujo
objetivo melhorar o cdigo gerado e eliminar redundncias, aumentando o desempenho.
Leitura recomendada:
Unidade I
a) Em que aspectos os comentrios podem ser verdadeiros?
a) Linguagemfonte e objeto;
Resp.: Linguagem de alto nvel a linguagem mais prxima da linguagem natural e apresenta
como principais caractersticas portabilidade, segurana, legibilidade e uso de abstraes. Linguagem
de baixo nvel a linguagem mais prxima do hardware e apresenta como principais caractersticas
dependncia da arquitetura, baixa legibilidade, baixa segurana e pouco ou nenhum suporte para
o uso de abstraes.
10
Compiladores e Computabilidade
c) Linguagem de montagem e de mquina;
Resp.: Linguagensfonte e linguagensobjeto podem ser tanto de alto quanto de baixo nvel.
Conforme a particular combinao, nomeiase o processador de linguagens como compilador,
tradutor, filtro, montador etc. Linguagens de alto nvel e de baixo nvel podem ser tanto
linguagensfonte quanto linguagensobjeto, dependendo de serem, respectivamente, entrada ou
sada de processadores de linguagens.
Anlise Lxica
Unidade I
Reconhecer e validar sequncias numricas, quer sejam inteiros, reais ou outra base suportada
pela linguagem (e.g.: hexadecimal);
Reconhecer e validar elementos de definio pelo programador e utilizados como
identificadores;
Prover um mecanismo para controle de erros amigvel, haja vista que o analisador lxico
quem varre o cdigofonte e, portanto, o nico que tem referncia da localidade em que um
determinado token ocorre (e.g.: mensagem de erro relativa ao elemento E da linha N).
Como fazlo?
Os tokens possuem uma estrutura sinttica e, desse modo, podemos descrever cada um dos
itens da linguagem (palavras reservadas, operadores, delimitadores etc.) atravs de regras de
produo, tais como:
identif = letra {letra|dgito}
nmero = dgito {dgito}
if = if
igual = ==
Pensando nisso, inevitavelmente surge a pergunta: por que o analisador lxico no uma parte
do analisador sinttico?
Observe alguns aspectos que justificam essa diviso de fases:
1. Isso deixaria o analisador sinttico mais complicado de ser construdo, a citar a dificuldade
para distinguir palavras reservadas e identificadores. Por exemplo, uma regra sinttica que poderia
ser escrita assim:
Statement ::= ident = Expr ; |
if ( Expr )...
precisaria ser reescrita desta forma, para que fosse possvel tratar as duas tarefas simultaneamente:
Statement ::= i ( f ( Expr )... | notF {letter | digit} = Expr ; ) |
notI {letter | digit} = Expr ;.
12
Compiladores e Computabilidade
2. O scanning deve eliminar brancos, tabulaes, fins de linha e comentrios. Considerando que
esses caracteres podem ocorrer em qualquer lugar do cdigo, teramos de especificar gramticas
mais complexas. Exemplo:
Statement ::= if {Blank} ( {Blank} Expr {Blank} ) {Blank}....
Blank ::= | \r | \n | \t | Comment.
3. Tokens podem ser descritos por gramticas regulares, que so mais simples e mais eficientes
que as gramticas livres de contexto. A maioria das estruturas lxicas so regulares:
Nomes ::= letra { letra | dgito }
Nmeros ::= dgito { dgito }
Strings ::= \ { qqCaractereExcetoAspas } \
Palavras reservadas ::= letra { letra }
Operadores ::= > | = | + |...
4. Gramticas regulares no podem lidar com estruturas aninhadas, pois no so capazes de manipular
recurso central. Esse tipo de construo importante na maioria das linguagens de programao.
Expresses aninhadas Expr ... ( Expr )...
Comandos aninhados Comando do Comando while ( Expr )
Classes aninhadas
Os autmatos finitos podem reconhecer linguagens regulares. Assim, podemos definir o scanner
como um AFD que reconhea os elementos da linguagemfonte.
O processamento de cada caractere obtido ser regido pelas transies previstas pelo autmato,
de modo que o AFD ter reconhecido uma sentena:
Se a entrada tiver sido consumida totalmente; ou
Se no for possvel realizar uma transio com o prximo smbolo da entrada e o autmato
encontrarse em um estado final.
Veja um exemplo no esquema a seguir:
13
Unidade I
Leitura recomendada:
Resp.: Apenas um caractere de espao necessrio para separar uma palavra de outra, ento
ocorrncias consecutivas so desnecessrias para esse propsito. Mas at mesmo esse nico espao
perde sua utilidade aps a identificao do trmino do token em formao e, consequentemente,
tambm pode ser descartado aps cumprir com o seu propsito.
Anlise Sinttica (Introduo)
Viso geral do processo
14
Compiladores e Computabilidade
Dada uma gramtica livre de contexto G e uma sentena s, aqui representada pelo
programafonte, o analisador sinttico tem o propsito de verificar se s pertence linguagem
gerada por G. Em outras palavras, a partir dos tokens fornecidos pelo analisador lxico, tentar
construir a rvore de derivao para s segundo as regras de produo dadas pela gramtica G. Se
esta tarefa for possvel, o programa considerado sintaticamente correto.
Tarefas que lhe so pertinentes:
Em geral, programas contm erros. Assim, um bom compilador deve, na medida do possvel,
detectar todos os erros ocorridos, avisar o usurio de suas ocorrncias e recuperarse deles, de
modo que seja possvel analisar o restante do cdigofonte.
A implementao de um bom mecanismo de deteco e recuperao de erros muitas vezes
depende de a questo ser considerada desde o incio do projeto da linguagem.
Modo pnico ou desespero
Param imediatamente diante do primeiro erro ou, identificado um erro, o analisador sinttico
descarta smbolos de entrada, at que seja encontrado um token pertencente ao subconjunto de
15
Unidade I
tokens de sincronizao (e.g.: ponto e vrgula, delimitadores etc.).
Recuperao de frases
Ao descobrir um erro, o analisador sinttico pode tentar uma recuperao realizando uma
correo local na entrada restante, substituindoa por alguma cadeia que permita que a anlise
prossiga. Por exemplo, substituir uma vrgula inadequada por um ponto e vrgula, ou ainda remover
um sinal de : excedente.
Produes de erro
Modificar a gramtica incluindo regras de produo estratgicas, de modo a acomodar os erros
mais comuns. Assim, sempre que uma produo de erro for identificada pelo analisador, possvel
conduzir o tratamento mais adequado quela situao em especial.
Correo global
Em geral, emprega algoritmos que escolhem, entre possveis solues, aquela que apresenta
uma sequncia mnima de mudanas para que se obtenha uma correo global do programa, e
no dos erros individualmente.
Alguns dados interessantes que devem ser considerados quando se pensa em quo eficiente
deve ser o mtodo de tratamento e recuperao de erros versus o tempo demandado para que
opere de modo satisfatrio:
Cerca de 60% dos programas so compilados de modo correto sinttica e semanticamente. Entre
os que apresentam erros: cerca de 80% dos enunciados apresentam apenas um erro e 13% apresentam
apenas dois erros. Em aproximadamente 90% dos casos, os erros envolvem um nico token.
Anlise sinttica descendente e ascendente
Os mtodos de anlise sinttica podem ser classificados segundo a maneira pela qual a rvore
de derivao da cadeia analisada x construda:
Nos mtodos descendentes, a rvore de derivao correspondente a x construda de cima para
baixo, ou seja, da raiz (o smbolo inicial S) para as folhas, onde se encontra x.
Nos mtodos ascendentes, a rvore de derivao correspondente a x construda de baixo para
cima, ou seja, das folhas, onde se encontra x, para a raiz, onde se encontra o smbolo inicial S.
Nos mtodos descendentes (topdown), temos de decidir qual a regra A a ser aplicada a
um n rotulado por um no terminal A. A expanso de A feita criando ns filhos rotulados com
os smbolos de .
Nos mtodos ascendentes (bottomup), temos de decidir quando a regra A deve ser aplicada
e devemos encontrar ns vizinhos rotulados com os smbolos de . A reduo pela regra A
consiste em acrescentar rvore um n A, cujos filhos so os ns correspondentes aos smbolos de .
16
Compiladores e Computabilidade
Mtodos descendentes e ascendentes constroem a rvore da esquerda para a direita. A razo para isso
que a escolha das regras deve se basear na cadeia a ser gerada, que lida da esquerda para a direita (seria
muito estranho um compilador que comeasse a partir do fim do programa em direo ao incio).
Exemplo:
Considere a cadeia x = a + a * a e a gramtica:
1.
EE+T
2.
ET
3.
TT*F
4.
TF
5.
F(E)
6.
Fa
17
Unidade I
Note que as regras so consideradas na ordem 1 2 4 6 3 4 6 6, a mesma ordem em que as regras
so usadas na derivao esquerda:
E E+T T+T a+T a+T*F a+F*F a+a*F a+a*a
Porm, se usarmos um mtodo de anlise ascendente, as regras so identificadas na ordem 6 4
2 6 4 6 3 1, e os passos de construo da rvore podem ser vistos na figura a seguir:
Embora a rvore de derivao seja usada para descrever os mtodos de anlise, na prtica ela
nunca efetivamente construda. s vezes, se necessrio, construmos rvores sintticas, que
guardam alguma semelhana com a rvore de derivao, mas ocupam um espao de memria
significativamente menor. A nica estrutura de dados necessria para o processo de anlise uma
pilha, que guarda informao sobre os ns da rvore de derivao relevantes em cada fase do processo.
No caso da anlise descendente, os ns relevantes so aqueles ainda no expandidos; no caso
da anlise ascendente, so as razes das rvores que ainda no foram reunidas em rvores maiores.
Tipos de Analisadores Sintticos:
Compiladores e Computabilidade
Mtodos ascendentes (bottomup): constroem a rvore sinttica de baixo para cima
Analisadores SR
Analisadores LR
Analisadores LALR
Leitura recomendada:
Captulo 4, sees 4.1 e 4.2 do livro Compiladores: princpios, tcnicas e ferramentas (Livro do Drago).
Captulo 3, seo 3.1 do livro Implementao de linguagens de programao: compiladores.
Exerccios resolvidos:
19
Unidade I
2. Considere a gramtica abaixo, sobre o alfabeto = {(, ), a, ,}: L (S)
S I,S | I
Ia|L
a) Mostre os movimentos de um reconhecedor ascendente na anlise da sentena (a, (a), (a,a));
b) Mostre os movimentos de um reconhecedor descendente na anlise da sentena (a, (a), (a,a));
c) Obtenha o esboo de um reconhecedor recursivo descendente para a linguagem por ela definida.
20
Compiladores e Computabilidade
Anlise Sinttica I Anlise Descendente
Neste mtodo, a escolha da regra a ser usada durante o processo de anlise descendente se d atravs
de duas informaes: o no terminal A a ser expandido e o primeiro smbolo a do resto da entrada.
21
Unidade I
Uma tabela M indexada por estas duas entradas nos fornece a regra a ser utilizada: M[A, a].
Vale ressaltar que essa tcnica s pode ser empregada para uma classe restrita de gramticas, as
chamadas gramticas LL(1).
O nome LL(1) indica que:
A cadeia de entrada examinada da esquerda para a direita (L=lefttoright);
O analisador procura construir uma derivao esquerda (L=leftmost);
Exatamente 1 smbolo do resto da entrada examinado.
Exemplo Suponha a gramtica a seguir:
1. E T E
2. T F T
3. F ( E )
4. F a
5. E + T E
6. E
7. T * F T
8. T
Essa gramtica LL(1) e, assim, a sua tabela de anlise M ser:
(
22
1 1
2 2
3 4
5 6
Compiladores e Computabilidade
Nessa tabela, a entrada M[S, k] correspondente ao no terminal S e ao terminal k tem o nmero
da regra que deve ser usada para expanso de S. As entradas indicadas por correspondem a
erros, ou seja, so combinaes que no podem ocorrer durante a anlise de cadeias da linguagem.
Para analisar a cadeia a + a * a, teremos as seguintes configuraes:
Pilha
E
Entrada
a+a*a
Escolha da regra
M[E, a] = 1
TE
FTE
aTE
TE
a+a*a
a+a*a
a+a*a
+a*a
M[T, a] = 2
M[F, a] = 4
M[T, +] = 8
E
+TE
TE
FTE
aTE
TE
*FTE
FTE
aTE
TE
E
+a*a
+a*a
a*a
a*a
a*a
*a
*a
A
A
M[E, +] = 5
M[T, a] = 2
M[F, a] = 4
M[T, *] = 7
M[F, a] = 4
M[T, $] = 8
M[E, $] = 6
Vamos, agora, mostrar como construir M, a tabela de anlise LL(1). No caso mais simples, o
smbolo a (o primeiro do resto da entrada) o primeiro smbolo derivado do no terminal a ser
expandido A e faz parte de First(A). Nesse caso, a deve pertencer a First(), em que A uma
das alternativas de regra para A. Como ilustrao, podemos ver que, no exemplo acima, a regra F
(E) foi usada com o smbolo (.
Outra possibilidade a de que no seja A o no terminal responsvel pela gerao do smbolo a, mas sim
algum outro no terminal encontrado depois de A. Neste caso, devemos ter a pertencendo ao Follow(A).
Como ilustrao, podemos ver que, no exemplo acima, a regra T foi usada com o smbolo +.
Para construir a tabela M, vamos examinar todas as regras da gramtica:
Para cada regra i: A, temos M[A, a]=i, para cada a em First().
Para cada regra i: A, se *, temos M[A, a]=i, para cada a em Follow(A).
Se a gramtica LL(1), cada entrada de M receber no mximo um valor. As entradas de M que
no receberem nenhum valor devem ser marcadas como entradas de erro. Caso alguma entrada de
23
Unidade I
M seja definida mais de uma vez, dizemos que houve um conflito e que a gramtica no LL(1).
Exemplo Considere a gramtica dada no exemplo anterior. Essa gramtica LL(1), e a tabela
de anlise M pode ser construda como indicado. Temos, para cada regra:
1. E TE
2. T FT
3. F (E)
4. F a
5. E +TE
6. E
7. T *FT
8. T
First(TE) = { (, a }
First(FT) = { (, a }
First((E)) ={ ( }
First(a) = { a }
First(+TE) = { + }
Follow(E) = { $, ) }
First(*FT) = { *}
Follow(T) = { $, +, )}
M[E, (] = 1 e M[E, a] = 1
M[T, (] = 2 e M[T, a] = 2
M[F, (] = 3
M[F, a] = 4
M[E, +] = 5
M[E, $] = 6 e M[E, )] = 6
M[T,* ] = 7
M[T, $] = 8, M[T, +] = 8 e M[T, )] = 8
First(E+T)= { (, a }
First(T)= { (, a }
First(T?F)= { (, a }
First(F)= { (, a }
First((E))= { ( }
First(a)= { a }
M[E, (] = 1 e M[E, a] = 1
M[E, (] = 2 e M[E, a] = 2
M[T, (] = 3 e M[T, a] = 3
M[T, (] = 4 e M[T, a] = 4
M[F, (] = 5
M[F, a] = 6
Se uma gramtica permite uma derivao A * A, para algum no terminal A e para alguma
cadeia no vazia , a gramtica dita recursiva esquerda.
No caso mais simples, existe na gramtica uma regra AA responsvel diretamente pela
derivao mencionada. Para que A no seja um no terminal intil, deve existir na gramtica (pelo
menos) uma regra da forma A, sem recurso esquerda.
A combinao dessas duas regras faz com que First(A) e, portanto, First(A) contenham todos
os smbolos de First(), e isso leva necessariamente a um conflito. A eliminao da recurso
esquerda pode ser tentada, procurando transformar a gramtica em uma gramtica LL(1).
24
Compiladores e Computabilidade
Observar que a combinao:
A A
A
permite a gerao de cadeias da forma e que essas mesmas cadeias podem ser
geradas de outra maneira. Por exemplo:
A A
A A
A
Essa outra forma de gerao usa recurso direita, que no cria problemas.
Prefixos comuns
Tratase do caso em que duas regras comeam com o mesmo smbolo ou conjunto de smbolos
(prefixo), isto , regras como A e A, com First(). Neste caso, existe uma interseo
entre First() e First(), e a gramtica no pode ser LL(1).
Isso acontece porque no possvel decidir, olhando apenas o primeiro smbolo derivado de ,
qual a regra correta. A soluo simples e envolve a fatorao.
Suponha as regras abaixo:
A
A
Podemos reescrever essas regras em equivalentes, de modo a colocar o prefixo em uma regra e
adiar a deciso entre e para quando o primeiro smbolo derivado de ou de estiver visvel.
A A
A
A
Essas duas tcnicas permitem transformar algumas gramticas em gramticas LL(1). Entretanto,
vale ressaltar que algumas gramticas livres de contexto GLC no tm gramticas equivalentes
LL(1). Nesse caso, a aplicao dessas tcnicas ou mesmo de outras poder no ter sucesso.
25
Unidade I
Exemplo Considere a gramtica a seguir:
1. E E + T | T
2. T T * F | F
3. F ( E ) | a
Essa gramtica apresenta duas situaes de recurso esquerda. Fazendo as substituies
indicadas, temos:
1. E T E
2. E + T E |
3. T F T
4. T * F T |
5. F ( E ) | a
E essa gramtica LL(1), como j foi visto anteriormente.
Exemplo Suponha transformar a gramtica abaixo em uma gramtica LL(1) equivalente:
1. L L ; S | S
2. S if E th L el L fi | if E th L fi | s
3. E e
Temos recurso esquerda nas regras de L e possibilidade de fatorao nas regras de S. Uma
transformao dessa gramtica em LL(1) teria o seguinte resultado:
1. L SL
2. L ; S L |
3. S if E th L S | s
4. S el L fi | fi
5. E e
Novamente, podemos verificar que essa uma gramtica LL(1).
26
Compiladores e Computabilidade
Leitura recomendada:
Captulo 4, seo 4.4 do livro Compiladores: princpios, tcnicas e ferramentas (Livro do Drago).
Captulo 3, seo 3.2 do livro Implementao de linguagens de programao: compiladores.
Exerccios resolvidos:
Considere a gramtica abaixo:
S aXb | aYc | aaZd
X bX | bc
Y cY | cb
Z dZ |
a) Essa gramtica LL(1)? Prove a sua resposta.
b) Caso a gramtica acima no seja LL(1), obtenha uma gramtica equivalente que seja LL(1) e
prove que a nova gramtica , de fato, LL(1).
Resp. item a: No, pois os conjuntos First no so disjuntos. Em todas as regras encontramos prefixos
iguais para as possveis derivaes de cada regra, quer de maneira direta ou indireta. Note que isso se
reflete diretamente nos valores includos nos conjuntos First e Follow, conforme dados abaixo:
First (aXb) = {a}, First (aYc) = {a}, First (aaZd) = {a}
First (bX) = {b}, First (bc) = {b}
First (cY) = {c}, First (cb) = {c}
First (dZ) = {d}, follow (Z) = {d}
Resp. item b: Eliminando recurses e fazendo substituies dos smbolos nas construes dadas
por S, teremos: S ab*bcb | ac*cbc | aad*d. Fatorando as trs diferentes possibilidades de derivao
para o smbolo S, ficaramos com a seguinte regra: S a(b*bcb | c*cbc | ad*d)
possvel observar que essa gramtica no apresenta recurses esquerda, uma vez que
deriva diretamente de sentenas compostas apenas de smbolos terminais. Alm disso, tambm
se nota que os prefixos para cada uma das possveis derivaes aps o primeiro smbolo a so
diferentes para os trs casos possveis. Esses aspectos podem ser confirmados quando calculamos
os conjuntos First para cada uma das trs possibilidades de derivao apresentadas para o smbolo
27
Unidade I
S: First (b*bcb) = {b}; First (c*cbc) = {c} e First (aad*d) = {a}
2. Obtenha o esboo de um reconhecedor, atravs do mtodo recursivo descendente, para a
linguagem definida pela expresso:
(+||)(d+(|.|.d*)|.d+)(e(+||)d+|)
So exemplos de sentenas pertencentes a essa linguagem: 123, 45.312, +.76, 5.44e2,
+0.88e35.
28