Análise Léxica
Num compilador, a análise linear é chamada de análise léxica ou esquadrinhamento (scanning). Por exemplo, na análise léxica, os caracteres no enunciado de atribuição:
montante := depósito_inicial + taxa_de_juros * 60
Poderiam ser agrupados nos seguintes tokens:
1. O identificador montante
2. O símbolo de atribuição :=
3. O identificador depósito_inicial
4. O sinal de adição
5. O identificador taxa_de_juros
6. O sinal de multiplicação
7. O número 60
Os espaços que separam os caracteres desses tokens seriam normalmente eliminados durante a análise léxica.
Análise Sintática
A análise hierárquica é chamada de análise gramatical ou análise sintática. Envolve o agrupamento dos tokens do programa fonte em frase gramaticais, que são usadas pelo compilador, a fim de sintetizar a saída.
Usualmente, as frases gramaticais do programa fonte são representadas por uma árvore gramatical, tala como a mostrada na Fig. 1.4.
Na expressão depósito_inicial + taxa_de_juros * 60, a frase taxa_de_juros * 60 é uma unidade lógica, porque as convenções usuais das expressões aritméticas nos dizem que a multiplicação é realizada antes da adição.
Como a expressão depósito_inicial + taxa_de_juros é seguida por um * não é agrupada numa única frase, na Fig. 1.4.
A estrutura hierárquica de um programa é usualmente expressa por regras recursivas. Por exemplo, poderíamos ter as seguintes regras como parte da definição de expressões:
1. Qualquer identificador é uma expressão.
2. Qualquer número é uma expressão.
3. Se expressão1 e expressão2 são expressões, então também o são:
expressão1 + expressão2
expressão1 * expressão2
(expressão1)
As regras 1 e 2 são as regras base (não recursivas), enquanto 3 define expressões em termos dos operadores aplicados às demais expressões.
Então, pela regra 1 depósito_inicial e taxa_de_juros são expressões. Pela regra 2, 60 é uma expressão, enquanto que, pela regra 3, podemos primeiro inferir que taxa_de_juros * 60 é uma expressão e, finalmente, que depósito_inicial + taxa_de_juros * 60 também o é.
Similarmente, muitas linguagens definem recursivamente enunciados tais como:
1. Se identificador, é um identificador e expressão2 uma expressão então:
identificador1 := expressão2
é um enunciado.
2. Se expressão1, é uma expressão e comando2 é um enunciado, então:
while(expressão1) do comando2
if(expressão1) then comando2
são enunciados.
A divisão entre a análise léxica e a sintática é um tanto arbitrária. Usualmente, escolhemos uma que simplifique a tarefa global de análise.
Um fator determinante na divisão é o de uma construção da linguagem fonte ser inerente recursiva ou não.
As construções léxicas não requerem recursão, enquanto as sintáticas frequentemente a exigem.
As gramáticas livres de contexto são uma formalização das regras recursivas que podem ser usadas para guiar a análise sintática.
Por exemplo, a recursão não é requerida para reconhecer identificadores, que são tipicamente cadeias de letras e dígitos, começando por uma letra.
Reconheceríamos normalmente os identificadores por um simples esquadrinhamento do fluxo de entrada, aguardando até que um caractere, que não uma letra ou um dígito, fosse encontrado, e agrupado, num token tipo identificador, todas as letras e dígitos coletados até aquele ponto.
Os caracteres, dessa forma agrupados, seriam registrados numa tabela, chamada tabela de símbolos, e removidos da entrada, de tal forma que o processamento do próximo token pudesse se iniciar.
Por outro lado, esse tipo de esquadrinhamento linear não é poderoso o suficiente para analisar expressões ou enunciados.
Por exemplo, não podemos fazer corresponder apropriadamente os parênteses nas expressões, ou o begin e o end nos enunciados, sem criar algum tipo de estrutura hierárquica ou aninhamento na entrada.
A árvore gramatical da Fig. 1.4 descreve a estrutura sintática da entrada. Uma representação interna mais comum dessa estrutura sintática é dada pela árvore sintática na Fig. 15(a).
Uma árvore sintática é uma representação condensada da árvore gramatical, na qual os operadores figuram como nós interiores e os operandos de um operador são os filhos do nó daquele operador.
Deixe um comentário