Explorar E-books
Categorias
Explorar Audiolivros
Categorias
Explorar Revistas
Categorias
Explorar Documentos
Categorias
Sintaxe Simples
• Apresenta de forma resumida boa parte do
assunto que veremos em detalhes no
restante do curso
• Dá uma visão geral do processo de
compilação
Um compilador simples
• Objetivo: traduzir expressões infixas em
posfixas
9–5+2Æ95–2+
• Aplicabilidade: computação baseda em
pilha (por exemplo, gerador de código para
.NET e JVM)
Front-end de um compilador
Programa fonte
Analisador léxico
tokens
Tabela de
Parser
Símbolos
árvore sintática
Three-address code
Definição de uma linguagem
• Linguagem = sintaxe + semântica
• Sintaxe = forma
• Semântica = significado
Definição de uma linguagem
• Especificação da sintaxe:
– gramática livre de contexto, BNF, eBNF
(Backus-Naur Form)
• Especificação da Semântica:
– normalmente informal (textual)
– formal: uso de semântica operacional,
denotacional, de ações, etc.
Exemplo: if-else
digit g 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Exemplo 1a
digit g 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Exemplo 2
call g id ( optparams )
optparams g params | ε
params g params , param | param
Derivações
• Uma gramática deriva strings a partir do seu
símbolo inicial e repetidamente substituindo
não-terminais pelo corpo de sua produção
• As sequencias de terminais produzidas desta
forma geram a linguagem definida pela
gramática
• Exemplos: 9, 9 - 5, 9 - 5 + 2
Parsing
• Problema de pegar uma string de terminais
e verificar como derivá-la a partir do
símbolo inicial da gramática; caso não seja
possível, reportar erros de sintaxe.
X Y Z
Parse Trees
• A raiz é o símbolo inicial
• Cada folha é um terminal ou ε
• Cada nó interior é um não-terminal
• Se A é um não-terminal e X1, X2,...,Xn são
labels de filhos deste nó, tem que haver uma
produção A g X1 X2 ... Xn
Exemplo
• 9–5+2 list
list digit
list digit
digit
9 - 5 + 2
Ambiguidade
• Parse-tree gera uma string, mas uma string
pode possuir várias parse-trees, se a
gramática for ambígua.
• Solução: usar sempre gramáticas não-
ambíguas, ou gramáticas ambíguas com
informações adicionais sobre como resolver
ambiguidades.
Ambiguidade - Exemplo
string
+ string string - string
traduza expr1;
traduza term;
trate + ;
Conceito: Atributo
• Um valor associado a um construtor do
programa.
• Exemplos:
– Tipo em uma expressão;
– Número de instruções geradas;
– Endereço da primeira instrução gerada para
uma construção.
Conceito: Esquema de tradução
(dirigida pela sintaxe)
• Notação para associar trechos de programa
a produções de uma gramática
• Os trechos de programa são executados
quando a produção é usada durante a análise
sintática
• O resultado da execução desses trechos de
programa, na ordem criada pela análise
sintática, produz a tradução desejada do
programa fonte
Notação pós-fixada
• Se E é uma variável ou constante, sua notação
pós-fixada é ela mesma;
• Se E é uma expressão da forma E1 op E2, então
sua notação pós fixada é E1’ E2’ op, onde E1’ e
E2’ são as notações pós-fixadas de E1 e E2
respectivamente;
• Se E é uma expressão com parênteses da forma
( E1 ), então sua notação pós-fixada é a mesma
notação pós-fixada de E1.
Exemplo
• (9-5)+2 95-2+
• 9-(5+2) 952+-
• 9-(5+2)*3 952+-3*
Definição dirigida por sintaxe
• Definição dirigida por sintaxe associa a
cada símbolo um conjunto de atributos;
• e a cada produção, regras semânticas para
computar os valores dos atributos
(Gramática de atributos)
Definição dirigida por sintaxe
1 Dada uma string x, construa uma parse tree
para ela;
2 Aplique as regras semânticas para avaliar
os atributos em cada nó.
Exemplo – valores dos atributos
nos nós de uma parse tree
expr.t = 95-2+
expr.t = 9 term.t = 5
term.t = 9
9 - 5 + 2
Tipos de Atributos
• Atributos sintetizados: seus valores são
obtidos a partir dos filhos de um
determinado nó;
Podem ser calculados através de uma
travessia bottom-up;
• Atributos herdados: têm seus valores
definidos a partir do próprio nó, de seus
pais ou seus irmãos.
Exemplo – Definição dirigida por
sintaxe
• Produção Regra semântica
expr g expr1 + term expr.t = expr1.t || term.t || ‘+’
expr g expr1 – term expr.t = expr1.t || term.t || ‘-’
expr g term expr.t = term.t
term g 0 term.t = ‘0’
term g 1 term.t = ‘1’
…
term g 9 term.t = ‘9’
Travessias
• Travessia em profundidade (depth-first)
rest
expr
expr term
+
expr - term
2
term
5
9
Ações traduzindo 9-5+2 em 95-2+
expr
expr term
+ {print(‘+’)}
expr {print(‘-’)}
- term
2 {print(‘2’)}
term
5 {print(‘5’)}
9 {print(‘9’)}
Exemplo 2: Ações de tradução
para notação pós-fixada
• expr g expr + term { print (‘+’) }
expr g expr - term { print (‘-’) }
expr g term
term g 0 { print (‘0’) }
term g 1 { print (‘1’) }
…
term g 9 { print (‘9’) }
Parsing
• Processo de determinar como uma string de
terminais pode ser gerada por uma
gramática
• Conceitualmente é a construção da parse
tree
• Mas a parse tree pode não ser efetivamente
construída durante a compilação.
Parsing
• Para gramáticas livres de contexto sempre é
possível construir um parser com
complexidade O(n3) para fazer o parsing de
n tokens.
• Na prática, o parsing de linguagens de
programação normalmente pode ser feito
linearmente.
• Travessia linear da esquerda para a direita,
olhando um token de cada vez.
Top-down ou bottom-up parsers
• Refere-se à ordem em que os nós da parse
tree são criados.
• Top-down: mais fáceis de escrever “à mão”
• Bottom-up: suportam uma classe maior de
gramáticas e de esquemas de tradução;
são frequentemente usados/gerados pelas
ferramentas de geração automática de
parsers.
Exemplo
• stmt g expr ;
| if (expr ) stmt
| for ( optexpr ; optexpr ; optexpr ) stmt
| other
optexpr g expr
|ε
Exemplo
stmt
void optexpr( ) {
if (lookahead == expr) match (expr) ;
}
Exemplo – predictive parsing (cont.)
void stmt( ) {
switch (lookahead) {
case expr: match(expr); match(‘;’); break;
case if: match(if); match(‘(‘);
match(expr);match(‘)’); stmt(); break;
case for: match(for); match(‘(‘);
optexpr(); match(‘;‘);
optexpr(); match(‘;‘); optexpr();
match(‘)‘); stmt(); break;
case other: match(other); break;
default: report(“syntax error”);
}
}
Predictive parsing - Problema
• Recursão à esquerda leva a loop em
predictive parsers:
A g Aα | ε
Predictive parsing - Solução
• Reescrever produções tornando-as
recursivas à direita:
A g Aα | β
reescrever para
A g βR
R g αR | ε
• Exemplo: expressão “βαααα”
Sintaxe abstrata x Sintaxe
concreta
• Sintaxe abstrata: ignora distinções
superficiais de forma, irrelevantes para o
processo de tradução.
list +
list -
digit 2
list digit 9 5
digit
9 - 5 + 2
Sintaxe abstrata x Sintaxe
concreta (cont.)
• Na árvore sintática abstrata os nós são
construções do programa, enquanto que na
parse tree os nós são não-terminais.
A g Aa | Ab | c | d
A g cR|dR
R g aR | bR | ε
Reescrevendo a gramática de
expressões (cont.)
A = expr
a = + term {print(‘+’)}
b = - term {print(‘-’)}
c = term
Reescrevendo a gramática de
expressões (cont.)
expr g term rest
rest g + term {print (‘+’) } rest
| - term {print (‘-’) } rest
|ε
term g 0 {print (‘0’) }
…
term g 9 {print (‘9’) }
Exemplo: 9-5+2
Tradutor em C
void expr () {
term(); rest();
}
Tradutor em C
void term () {
if (isdigit(lookahead)) {
t = lookahead; match(lookahead); print(t);
}
else report(“syntax error”);
}
Tradutor em C (cont.)
void rest()
{ if (lookahead == ‘+’) {
match(‘+’); term(); print(‘+’); rest();
}
else if (lookahead ==‘-’) {
match(‘-’); term(); print(‘-’); rest();
}
else { };
}
Otimizações
void rest ()
{ while (true) {
if (lookahead == ‘+’) {
match(‘+’); term(); print(‘+’); continue;
}
else if (lookahead ==‘-’) {
match(‘-’); term(); print(‘-’); continue;
}
break;
}
}
Usando um analisador léxico
• Facilita o tratamento de lexemas ao invés de
caracteres:
– Tratamento de espaços em branco
– Tratamento de número maiores que 9
(constantes)
– Reconhecimento de identificadores e palavras-
chave.
Estendendo para identificadores e
números maiores que 9
expr g expr + term {print (‘+’) }
| expr – term {print (‘-’) }
| term
term g term * factor {print (‘*’) }
| term / factor {print (‘/’) }
| factor
factor g ( expr )
| num {print (num.value) }
| id {print (id.lexeme) }
Class Token
class Token
int tag
• Representações lineares:
e.g. three-address code
Construção da Syntax tree
• Classes para representar a hierarquia de
construções da Linguagem:
after
L-values e R-values
• i = 5;
i = i + 1;
Lexical Analyser
if 1: t1 = (int) ‘\n’
2: ifFalse peek == t1 goto 4
eq assign 3: line = line + 1
4:
peek (int) line +
‘\n’ line 1