Transparências do Capítulo 3 do livro-texto

Propaganda
Linguagens de Programação – Capítulo 3
Descrição da Sintaxe
Sintaxe –
Forma das
Semântica – Significado das
Expressões
Instruções
Unidades
Expressões
Instruções
Unidades
Exemplo: Comando if do C
Sintaxe:
if (<expressão>)
<instrução>
Semântica:
“Se o valor de expressão
for verdadeiro...”
Sintaxe: mais fácil de descrever que a semântica.
Existe uma notação concisa e universalmente aceita
para a descrição da sintaxe, mas não ainda para a
semântica
Página 1
Linguagens de Programação – Capítulo 3
Lexemas – Unidades sintáticas
Descrição dada por uma especificação léxica,
em nível mais baixo que a descrição sintática
Exemplo: Palavras reservadas, identificadores,
literais, operadores...
Tokens
Categorias de lexemas
Às vezes um token tem somente um lexema
possível, às vezes “infinitos”
Exemplo: index = 2*count + 17
“index” e “count” são lexemas que
pertencem à categoria “identificador”
Página 2
Linguagens de Programação – Capítulo 3
Formas de definir as linguagens, através de:
Reconhecedores de Linguagens
Dispositivos para verificar se certa sentença está
na linguagem
Geradores de Linguagens
Dispositivos para gerar sentenças da linguagem
BNF – Backus Naur Form
Notação mais usada para descrever formalmente
as linguagens de programação
“Metalinguagem ” ( linguagem usada para descrever
linguagens) para linguagens de programação
Gramática é o conjunto de regras que produz a
linguagem
Página 3
Linguagens de Programação – Capítulo 3
BNF
Exemplo: comando “if ” do Pascal
<if_stmt>
<if_stmt>
if <expr_lógica> then <stmt>
if <expr_lógica> then <stmt>
else<stmt>
ou
<if_stmt>
if <expr_lógica> then <stmt>
| if <expr_lógica> then <stmt>
else<stmt>
Exemplo: listas e recursividade
<lista_ident>
<ident>
<seq>
<letra>
<dígito>
<ident>
| <ident> , <lista_ident>
<letra> <seq> | <letra>
<letra> <seq> | <dígito><seq>
| <letra> | <dígito>
A|B|C ... |Z
0|1|2 ... |9
Página 4
Linguagens de Programação – Capítulo 3
Gramática para uma pequena linguagem
<programa>
begin <lista_stmt> end
<lista_stmt>
<stmt> | <stmt> ; <lista_stmt>
<stmt>
<var> := <expressão>
<expressão>
<var> + <var> | <var> - <var>
| <var>
<var>
A|B|C
Exemplo de derivação:
<programa>
begin <lista_stmt> end
begin <stmt> ; <lista_stmt> end
begin <var> := <expressão> ; <lista_stmt> end
begin A := <expressão> ; <lista_stmt> end
begin A := <var> + <var> ; <lista_stmt> end
begin A := B + <var> ; <lista_stmt> end
begin A := B + C ; <lista_stmt> end
begin A := B + C ; <stmt> end
begin A := B + C ; <var> := <expressão> end
begin A := B + C ; B := <expressão> end
begin A := B + C ; B := <var> end
begin A := B + C ; B := C end
Página 5
Linguagens de Programação – Capítulo 3
Gramática para instruções de atribuição
<atribuição>
<id>
<id> := <expressão>
A | B| C
<expressão>
<id> + <expressão>
| <id> * <expressão>
| ( <expressão> )
| <id>
Exemplo: derivar A := B * ( A + C )
<id> := <expressão>
A := <expressão>
A := <id> * <expressão>
A := B * <expressão>
A := B * ( <expressão> )
A := B * ( <id> + <expressão> )
A := B * ( A + <expressão> )
A := B * ( A + <id> )
<atribuição>
A := B * ( A + C )
Página 6
Linguagens de Programação – Capítulo 3
Árvores de Análise ( “Parse Trees” )
Exemplo: A := B * ( A + C )
<atribuição>
<id>
A
:=
<expressão>
<id>
B
* <expressão>
( <expressão> )
<id>
A
+
<expressão>
<id>
C
Página 7
Linguagens de Programação – Capítulo 3
Exemplo de Gramática Ambígua
<atribuição>
<id>
<id> := <expressão>
A | B| C
<expressão>
<expressão> + <expressão>
| <expressão> * <expressão>
| ( <expressão> )
| <id>
Exemplo: construir duas árvores diferentes para
A := B * ( A + C )
1º)
<atribuição>
<id>:=
<expressão>
A <expressão> + <expressão>
<id>
B
<expressão> * <expressão>
<id>
<id>
C
A
Página 8
Linguagens de Programação – Capítulo 3
2º)
<atribuição>
<id>:=
<expressão>
A <expressão> * <expressão>
<expressão> + <expressão> <id>
<id>
<id>
A
C
B
“Consertando” a Gramática
<atribuição>
<id>
A | B| C
<expressão>
<termo>
<fator>
<id> := <expressão>
<expressão> + <expressão>
| <termo>
<termo> * <fator>
| <fator>
( <expressão> )
| <id>
Página 9
Linguagens de Programação – Capítulo 3
Descrição da Sintaxe
Gramática não ambígua para expressões
<atribuição>
<id> := <expressão>
<id>
A | B| C
<expressão>
<expressão> + <expressão>
| <termo>
<termo>
<termo> * <fator>
| <fator>
<fator>
( <expressão> )
| <id>
Associatividade de operadores de mesma
precedência
<atribuição>
<id>:= <expressão>
Operador de adição
A <expressão>+<termo>
esquerdo mais baixo
que o direito.
É a ordem correta se
queremos associatividade
à esquerda
<expressão> + <termo> <fator>
<fator>
<termo>
<id>
<fator>
<id>
A
<id>
B
C
Página 10
Linguagens de Programação – Capítulo 3
Regra recursiva à esquerda
LHS aparece no início do RHS
( vide gramática anterior )
Regra recursiva à direita
LHS aparece no final do RHS
Exemplo: operador de exponenciação geralmente é
associativo à direita
<expressão> ^ <fator> | <expressão>
<fator>
<expressão>
<id>
( <expressão> ) | <id>
A | B| C
Exemplo: A ^ B ^ C = A ^ ( B ^C )
<fator>
<expressão> ^ <fator>
<id> <expressão> ^ <fator>
<expressão>
<id>
A
B
<id>
C
Página 11
Linguagens de Programação – Capítulo 3
Ambigüidade em if – then – else
<if_stmt>
<stmt>
if <exp_lógica> then <stmt>
| if <exp_lógica> then <stmt> else <stmt>
<if_stmt>
Árvore de análise I
<if_stmt>
if <exp_lógica> then <stmt> else <stmt>
<if_stmt>
if <exp_lógica> then <stmt>
if <exp>
then
if <exp>
then <stmt>
else <stmt>
Página 12
Linguagens de Programação – Capítulo 3
Árvore de análise II
<if_stmt>
if <exp_lógica> then <stmt>
<if_stmt>
if <exp_lógica> then <stmt> else <stmt>
if <exp>
then
if <exp>
then <stmt>
else <stmt>
Página 13
Linguagens de Programação – Capítulo 3
“Consertando” a Gramática
Regra Geral: o else pertence sempre ao then mais
próximo e entre um then-else, não pode haver
if sem else
<stmt>
<coincidente> | <livre>
<coincidente>
if <exp_lógica> then <coincidente>
else <coincidente>
| qualquer instrução não if
<livre>
if <exp_lógica> then <stmt>
| if <exp_lógica> then <coincidente>
else <livre>
É necessário ?
Sim!
Não é possível fazer
if <exp_lógica>
then
if <exp_lógica>
then <algo>
else <algo>
Fica obrigatório derivar
<stmt>
<livre>
if <exp_lógica> then
<stmt>
if <exp_lógica> then
<coincidente>
...
Página 14
Linguagens de Programação – Capítulo 3
BNF Estendida
Extensões não aumentam o poder descritivo da BNF
apenas melhoram sua legibilidade e capacidade de escrita
1) Denotar parte opcional dentro de colchetes em RHS
<seleção>
if ( <exp_lógica> ) <instrução>
[else <instrução>]
2) Uso de chaves em RHS para indicar que o que está
contido nelas pode ser: repetido indefinidamente
omitido completamente
a) <lista_iden>
<identificador> {, <identificador>}
b) <comp>
begin <stmt> {<stmt>} end
3) Lidar com opções de múltipla escolha
não são terminais
<for_stmt>
for <var> := <expressão> (to|downto)
<expressão> do <stmt>
Página 15
Linguagens de Programação – Capítulo 3
Comparação entre BNF e EBNF
BNF
<expr>
<termo>
<expr> + <termo>
| <expr> - <termo>
| <termo>
<termo> * <fator>
| <termo> / <fator>
| <fator>
EBNF
<expr>
<termo>
<termo> {(+ | -)<termo>}
<fator> {(* | /)<fator>}
Página 16
Linguagens de Programação – Capítulo 3
Grafo Sintático ( grafo de sintaxe)
Exemplo: Instrução if em ADA
<if_stmt>
if <condição> then <stmts> {<else_if>}
[else <stmts>] end_if
<else_if>
elsif <condição> then <stmts>
Legenda:
não-terminais
terminais
if_stmt
if
condição
then
stmts
end_if
else_if
else_if
else
elsif
condição
stmts
then
stmts
Página 17
Linguagens de Programação – Capítulo 3
Parsers – Analisadores sintáticos para
linguagens de programação
yacc: um dos mais usados (yet another compiler compiler)
Parsers:
top – down (descendente)
bottom – up (ascendente)
Análise Sintática Descendente Recursiva
Exemplo:
<expr>
<termo>
<fator>
<termo> {(+ | -)<termo>}
<fator> {(* | /)<fator>}
<id> | (<expr>)
Chama uma rotina para cada não terminal
void expr ( ){
termo ( );
while ( prox_token == “+” || prox_token == “-” ){
lexical ( );
termo ( );
lexical coloca o próximo
token de entrada em
}
prox_token( var global)
}
Página 18
Linguagens de Programação – Capítulo 3
void termo ( ){
fator ( );
while ( prox_token == “*” || prox_token == “/” ){
lexical ( );
fator ( );
}
}
void fator ( ){
if (prox_token == ident ){
lexical ( );
return;
}
else if (prox_token == “(” ){
lexical ( );
expr( );
if (prox_token ==“)”{
lexical( );
return;
}
else error ( );
}
else error( );
}
Página 19
Linguagens de Programação – Capítulo 3
Problema para parsers descendentes recursivos:
recursão à esquerda. Ex: < A >
<A> +< B >
(A discussão das características que autorizam o
uso de parsers descendentes recursivos para uma
gramática particular não será feita aqui)
Gramática de atributos
Dispositivos para descrever mais detalhes da
estrutura das linguagens de programação do que é
possível com (a BNF) uma gramática livre de contexto
Existem características da estrutura das linguagens
de programação difíceis/impossíveis de descrever com
A BNF
Exemplos:
“todas as variáveis devem ser declaradas
antes de serem referenciadas”
“end de uma subrotina em ADA seguido de
um nome deve coincidir com o nome da
subrotina”
Semântica Estática
Análise necessária para verificar essas
especificações. Pode ser feita em tempo de compilação
Mais relacionada ainda com a sintaxe
Página 20
Linguagens de Programação – Capítulo 3
Atributos
“Variáveis” associadas a símbolos gramaticais
Funções de computação de atributos
Associadas a regras para especificar como os
valores dos atributos são computados
Funções Predicadas
Símbolo gramatical X
A(X) = S(X)  H(X)
Conjunto de
atributos
associados a X
Atributos
Sintetizados 
Atributos
Herdados 
“Filhos” na árvore de análise
Regra: X0
X1 ... Xn
S(X0) = f ( A(X1),...,A(Xn) )
depende dos
filhos
H(Xj) = f ’ ( A(X0), A(X1),...,A(Xj-1) )
1 j  n
depende do
pai e irmãos
“menores”
Página 21
Linguagens de Programação – Capítulo 3
Função predicada: g ( A(X0),..., A(Xn) )
expressão
booleana
Se todos os valore de atributos em uma árvore de
análise tiverem sido computados
ela é
totalmente atribuída
Atributos intrínsecos
atributos sintetizados de
vértices folhas, cujos valores são calculados fora da
árvore de análise
usados para distinguir as 2
ocorrências do mesmo nãoExemplo: Ada
terminal
Regra sintática:
<def_proc>
procedure <nome_da_proc>[1]
<corpo_da_proc> end <nome_da_proc>[2]
Regra semântica:
<nome_da_proc>[1].string = <nome_da_proc>[2].string
Página 22
Linguagens de Programação – Capítulo 3
Exemplo: Compatibilidade de Tipos
<atribuição>
5
<expressão>
tipo_esperado
tipo_efetivo
:=
4
2
<var>
+
tipo_efetivo
string
A
<var> tipo_efetivo
string
1
<var>
string
A
3
B
3
tipo_efetivo
Legenda
Regra 1
Regra 2
Regra 3
Regra 4
1
2
3
4 5
Passos da construção
Página 23
Linguagens de Programação – Capítulo 3
Semântica Dinâmica
Semântica propriamente dita, significado das
expressões / instruções / unidades do programa
Operacional
Semântica
Axiomática
Denotacional
Semântica Operacional - descreve o significado de um
programa através da execução de suas instruções numa
máquina ( real ou simulada,virtual ). Alterações no
estado da máquina ao executar determinada instrução
definem o significado desta
Estado S
instrução
Estado S’
Estado  valores
de todos os registros
( células de memória )
Página 24
Linguagens de Programação – Capítulo 3
Qual computador usar ?
Hardware de um computador específico  interpretador
puro de sua linguagem de máquina
Complicado usar uma
máquina real específica
Usar um computador
de baixo nível, implementado
como uma simulação de software
Tradução para linguagem
De baixo nível
Semântica Operacional
Depende de algoritmos, não de
matemática
“Rodar” o programa na
máquina virtual
Exemplo: Instrução for do C
Semântica Operacional
for ( expr1 ; expr2 ; expr3 ){
...
}
expr1;
loop: if expr2 = 0 goto out
...
expr3;
goto loop;
out:
Página 25
Linguagens de Programação – Capítulo 3
Semântica Axiomática - baseia-se na lógica matemática
Associada a um método para provar. Correção de
programas que mostra a computação descrita por sua
especificação. ( limitada e de aplicação difícil )
Semântica Denotacional – dentre os métodos mais
empregados, é o de maior rigor matemático. Baseia-se
solidamente na teoria das funções recursivas.
Idéia: Associar para cada entidade da linguagem um
objeto matemático e uma função que os relacione
(entidade e objeto )
 Há maneiras rigorosas para manipular objetos
matemáticos, mas não construções de Linguagens de
Programação
 Os objetos denotam o significado das entidades
sintáticas que lhes correspondem
Exemplo:
<num_bin>
0
|1
| <num_bin> 0
| <num_bin> 1
Página 26
Linguagens de Programação – Capítulo 3
Árvore para 110 = 6
<num_bin>
<num_bin>
<num_bin>
‘1’
‘1’
6
‘0’
0
3
1
1
Função Semântica Mbin – associa os números binários
aos inteiros decimais não-negativos
Mbin ( ‘0’ ) = 0
Mbin ( ‘1’ ) = 1
Mbin ( <num_bin> ‘0’ ) = 2 * Mbin ( <num_bin> ) +
Mbin ( ‘0’ )
Mbin ( <num_bin> ‘1’ ) = 2 * Mbin ( <num_bin> ) +
Mbin ( ‘1’ )
Exemplo:
<num_dec>  0|1|2| ... |9
| <num_dec> (0|1|2| ... |9 )
Mbin ( ‘0’ ) = 0 ,... , Mbin ( ‘9’ ) = 9
Mbin ( <num_dec> ‘0’ ) = 10 * Mbin ( <num_bin> ) + 0
Mbin ( <num_dec> ‘9’ ) = 10 * Mbin ( <num_bin> ) + 9
...
Página 27
Linguagens de Programação – Capítulo 3
Estado de um programa
S = { <i1 , v1>,...,<in ,vn> }
ij  nome da variável j
vj  valor da variável j ( pode ser undef )
VARMAP ( i , j ) = vj
Me ( <expr> , s )  = devolve o valor de <expr> no
estado s ( Me ( <expr> , s )   {error} )
Ma ( x = E, s )  = devolve o estado do programa
após a execução da instrução x = E
Ms1 ( K, s )  = devolve o estado do programa
após a execução da lista de instruções K
lista de instruções
Página 28
Download