• Nenhum resultado encontrado

Compiladores (CC3001) Aula 9: Análise de tipos

N/A
N/A
Protected

Academic year: 2021

Share "Compiladores (CC3001) Aula 9: Análise de tipos"

Copied!
38
0
0

Texto

(1)

Compiladores (CC3001)

Aula 9: Análise de tipos

Pedro Vasconcelos

DCC/FCUP

(2)

Esta aula

Sistemas de Tipos Análise de Tipos Expressões Declarações e comandos Funções Extras

(3)

Re-lembrar: fases dum compilador

texto do programa ↓ Análise lexical ↓ sequência de tokens ↓ Análise sintática ↓

árvore sintática abstrata ↓

Análise semântica ↓

AST & tabela de símbolos

Geração de código ↓

código intermédio

Seleção de instruções ↓

código assembly simbólico ↓

Alocação de registos ↓

código assembly concreto ↓

Assembler & linker ↓

(4)

Sistemas de Tipos

Um sistema de tipos é um conjunto de regras lógicasda linguagem que todos os programas devem respeitar.

Exemplos de regras:

I +, -, *, / só operam sobre números I a condição de if deve ser um boleano

I numa atribuição var = expr a variável deve ser declarada com um tipo compatível com o da a expressão

(5)

Diferentes Sistemas de Tipos

Podemos classicar em dois eixos separados:

Estáticos vericação ocorreantes da execução do programa

vs.

Dinâmicos vericação ocorredurante a execuçãodo programa

Fortes operações com erros de tipos são proibidas

vs.

(6)

Diferentes Sistemas de Tipos (cont.)

Exemplos:

I Haskell, SML, Java: tipos estáticos e fortes

I Python, Scheme: tipos dinâmicos e fortes

I C: tipos estáticos e fracos

I Estas classicações são graduais e não absolutas

e.g. o sistema de tipos de Java é mais forte que o de C mas mais fraco que o de Haskell I A distinção estático/dinâmico deixa de fazer sentido para código máquina

(7)

Diferentes Sistemas de Tipos (cont.)

(8)

Porquê análise de tipos?

I Efetuar a análise de tipos durante a compilação (estática):

I evita vericações durante a execução do programa I permite gerar código mais eciente

(9)

Atributos

I A análise de tipos pode ser feita como uma (ou mais) travesia da AST

I Como as ASTs são estruturas recursivas, a travesia será implementada como funções recursivas

I As traversias constroem atributos; exemplos: I o tipo de cada sub-expressão;

I a tabela que associa cada identicador ao seu tipo (ambiente) I Atributos sintetizados: calculados das folhas da AST para a raiz

I Atributos herdados: passados da raiz da AST para as folhas

I Atributos sintetizados numa parte da AST podem ser herdados noutra

(10)

Expressões

I Uma linguagem com variáveis, expressões aritméticas e lógicas (comparações) I Dois tipos: int (números inteiros) e bool (valores lógicos)

Exemplos de expressões: 1+2*3

(1+2)<3

1+x*3 (válida se x for int)

(1+x)<y (válida se x for int e y for int)

Umerro de tipos(não podemos somar inteiros com valores lógicos): 1+(2<3)

(11)

Atributos sintetizados e herdados

Determinamos o tipo da expressão a partir dos tipos das sub-expressões (atributo sintetizado). < + 1 2 3 bool x     atributo sintetizado

Passamos um tabela de símbolos com os tipos da variáveis (atributo herdado). < + 1 x y atributo herdado {x 7→int, y 7→ int}     y

(12)

Implementação

data Expr = Num Int - 1, 2, 3 | Var Ident - x, y, z | Add Expr Expr - e1 + e2 | LessThan Expr Expr - e1 < e2 data Type = TyInt | TyBool

type TypeEnv = Map Ident Type - ambiente (tabela de símbolos) checkExpr :: TypeEnv -> Expr -> Type

- sintetizar o tipo de uma expressão

- argumentos: o ambiente (TypeEnv) e a expressão (Expr) - resultado: é um tipo (ou erro)

(13)

Atributos sintetizados vs. herdados

O tipo da expressão é propagado das folhas para a raiz (atributo sintetizado). checkExp env (Num n) = TyInt

...

checkExpr env (Add e1 e2) = let t1 = checkExpr env e1

t2 = checkExpr env e2

in if t1==TyInt && t2==TyInt then TyInt

(14)

Atributos sintetizados vs. herdados (cont.)

O ambiente (tabela de símbolos) é propagado da raiz para as folhas (atributo herdado). checkExpr env (Add e1 e2)

= let t1 = checkExpr env e1 t2 = checkExpr env e2

in if t1==TyInt && t2==TyInt then TyInt else error "type error in +"

(15)

Atributos sintetizados vs. herdados (cont.)

O ambiente será determinada na chamada de topo (raiz da AST):

> checkExpr (Map.fromList [("x",TyInt)]) (Add (Var "x") (Num 1)) TyInt

Esta expressão teria um erro de tipo num outro ambiente:

> checkExp (Map.fromList [("x", TyBool)] (Add (Var "x") (Num 1)))

type error in +

(16)

Denição completa

checkExpr env (Num n) = TyInt

checkExpr env (Var x) = case Map.lookup x env of Nothing -> error "undeclared var"

Just t -> t

checkExpr env (Add e1 e2) = let t1 = checkExpr env e1

t2 = checkExpr env e2

in if t1==TyInt && t2==TyInt then TyInt else error "type error in +"

checkExpr env (LessThan e1 e2) = let t1 = checkExpr env e1 t2 = checkExpr env e2

in if t1==TyInt && t2==TyInt then TyBool else error "type error in <"

(17)

Declarações e comandos

I Vamos acrescentar denições para declações de variáveisecomandos

I Acrescentamos novos denições na sintaxe abstrata e funções para fazer a análise de tipos

(18)

Declarações e comandos (cont.)

data Stm = Assign Ident Expr - var := expr

| If Expr Stm Stm - if expr then stm1 else stm2 | While Expr Stm - ciclo while

| Block [Decl] [Stm] - bloco: declarações e comandos

| Skip - comando vazio

deriving Show

(19)

Exemplos

if (x<y) x=y; else x=0; If (LessThan (Var "x") (Var "y"))(Assign "x" (Var "y")) (Assign "x" (Num 0))

(20)

Exemplos (cont.)

n = 1; while(n < 10) n = n+1; Block [] [ Assign "n" (Num 1)

, While (LessThan (Var "n") (Num 10)) (Assign "n" (Add (Var "n") (Num 1))) ]

(21)

Exemplos (cont.)

if (x<y) { int temp; temp = x; x = y; y = temp; }

If (LessThan (Var "x") (Var "y")) (Block [("temp",TyInt)]

[ Assign "temp" (Var "x") , Assign "x" (Var "y") , Assign "y" (Var "temp") ])

(22)

Regras de tipos para comandos

Atribuição (var := expr) a variável e a expressão devem ter o mesmo tipo

Condição (if exp then stm1 else stm2)

1. a expressão deve ter tipo bool

2. os dois comandos devem estar corretamente tipados

Ciclo (while exp stm)

1. a expressão deve ter tipo bool

2. o corpo deve estar corretamente tipado

Bloco extendemos o ambiente com declarações e vericamos se todos os comandos estão bem tipados

(23)

Análise de tipos para comandos

checkStm :: TypeEnv -> Stm -> Bool

I Tal como para expressões vamos passar um ambiente como atributo herdado

I O resultado de analizar dum comando será um boleano I True se ocomando respeita as regras de tipos

I ou lança um erro1 com uma mensagem apropriada I Nos blocos: necessitamos deextender o ambiente

(Ver demonstração.)

(24)

Analisar if/else

checkStm env (If cond stm1 stm2) = let t0 = checkExpr env cond

in if t0 == TyBool then checkStm env stm1 && checkStm env stm2 else error "type error: condition must be bool"

(25)

Analisar blocos

checkStm env (Block decls stms) = let env' = extendEnv env decls

in checkAll env' stms

-- funções auxiliares: extender um ambiente extendEnv :: TypeEnv -> [Decl] -> TypeEnv extendEnv env [] = env

extendEnv env ((v,t):rest) = extendEnv (Map.insert v t env) rest -- verificar tipos de uma lista de comandos

checkAll env [] = True

(26)

Análise de tipos para funções

I Vamos extender a linguagem comdeclarações e chamada de funções

I Simplicação: denições comuma só expressão (e não comandos)

I Um programapode ter:

I declarações de uma ou mais funções;

(27)

Análise de tipos para funções (cont.)

data Expr = ...

| FunCall Ident [Expr] - chamada f(e1, e2, ...)

data FunDef = FunDef Ident Type [(Ident,Type)] Expr - t f(x1:t1,..., xn:tn) = expr

data Prog = Prog [FunDef] Stm

(28)

Exemplo

int incr(int x) { return x+1; } int main() { int x, y; x = 2; y = incr(x+1); } Prog

[FunDef "incr" TyInt [("x",TyInt)] (Add (Var "x") (Num 1))] [Block [("x", TyInt), ("y",TyInt)]

[ Assign "x" (Num 2)

, Assign "y" (FunCall "incr" [Add (Var "x") (Num 1)]) ]

(29)

Tipos de funções

(t1, t2, . . . , tn) → r

I t1, t2, . . . , tn são ostipos dos argumentos I r é otipo do resultado

data Type = ...

(30)

Vericação de chamadas

Para vericar uma chamada f (e1, . . . , en)

1. Procurar f no ambiente e obter um tipo (t1, . . . , tn) → r 2. Recursivamente vericar tipos de e1, . . . , en

3. Se os tipos são iguais a t1, . . . , tn então retornar o tipo do resultado (r); caso

(31)

Vericação de chamadas (cont.)

Uma nova equação na função checkExpr: checkExpr env (FunCall f args)

= case Map.lookup f env of

Just (TyFun argTypes result) ->

if map (checkExpr env) args == argTypes then result else error "invalid argument types"

(32)

Vericação de denições

Para vericar f (x1 : t1, . . . , xn: tn) : r = e

1. Extendemos o ambiente com {x1 7→ t1, . . . , xn7→ tn} 2. No ambiente extendido: vericamos o tipo de e

3. Se o tipo resultante for igual a r retornamos um novo ambiente com {f 7→ (t1, . . . , tn) → r }

Caso contrário: erro.

(33)

Vericação de denições (cont.)

checkFunDef :: TypeEnv -> FunDef -> TypeEnv checkFunDef env (FunDef f decls result expr)

= let env' = extendEnv decls env texpr = checkExpr env' expr in if texpr == result then

let args = map snd decls

in extendEnv [("f",TyFun args result)] env else error "wrong result type"

-- função auxiliar (já era usada para blocos) extendEnv :: TypeEnv -> [Decl] -> TypeEnv extendEnv env [] = env

(34)

Recursão

I A vericação de funções não permite usos recursivos da função, e.g.

int f(int x) = if x > 0 then x*f(x-1) else 1

I A extensão para recursão é simples: basta acresentar uma entrada para f ao ambiente usado para tipar o corpo da função2

I Mas só seria útil combinada com a extensão para comandos ou expressões if/else

(caso contrário não há forma de terminar a recursão. . .)

(35)

Overloading e coerção

Overloading utilizar o mesmo operador para operações em tipos diferentes (e.g. + em inteiros e fracionários)

1 + 2 -- int 1.0 + 2.5 -- float

Coercão conversão implícita ou explícita de tipos int x = ...;

(float)x + 2.5 -- conversão explícita x + 2.5 -- conversão implícita

(36)

Overloading e coerção (cont.)

I A vericação para tipos e operadores pré-denidos é simples (e.g. C, Pascal)

I Consideravelmente mais complexa se o programador pode denir operadores sobre tipos novos (e.g. C++, Haskell,. . . )

(37)

Polimorsmo

polimórco (adjetivo): que se apresenta sob diversas formas.

Dicionário Online Priberam Em programação: a possibilidade de escrevercódigo que opera sobre diferentes tipos.

polimorsmo paramétrico SML/Haskell ou generics em Java/C# reverse :: [t] -> [t] -- em Haskell void reverse(List<T> list); // em Java

polimorsmo ad-hoc overloading, interfaces, herança. . .

(Tópicos abordados em Fundamentos de Linguagens e Tópicos de Programação Funcional Avançada.)

(38)

Inferência

I Para alguns sistemas é possível inferir os tipos automaticamente em vez de apenas

vericar declarações

I As linguagens funcionais fortemente tipadas usam inferência baseada no algoritmo Damas-Milner (com extensões)

Referências

Documentos relacionados

Outras alterações típicas nos portadores desta síndrome e que geralmente não se encontram em portadores de displasia cleidocraniana são: presença de glaucoma

A partir da leitura do livro Macunaíma, de Mário de Andrade, publicado em 1928, e do filme homônimo, de Joaquim Pedro de Andrade, lançado em 1969, intenta-se compreender como a

Para a autora parte da elite católica que ocupava os quadros da Ação Integralista Brasileira, não divulgavam o racismo por razões da doutrina cristã, mas mesmo assim, afirmavam

O presente capítulo apresenta as proposições que compõem o PAE, no intuito de solucionar o problema da presente pesquisa, cuja questão é aqui retomada: “De que maneira a

Três devotos, uma fé, nenhum milagre: Nitheroy Revista Brasiliense de Ciências e Artes, São Paulo: Fundação Editora da UNESP, 1998; SQUEFF, Letícia Coelho “A Reforma Pedreira

Neste panorama, o principal objetivo desse estudo é entender a importância da competitividade de destinos turísticos pontuando quais políticas tem sido adotadas

Em ambos os processos foi possível obter macarrões instantâneos com um teor de amido resistente significativo (acima de 3 % para todos os ensaios). Na análise de textura,

Quando utilizar um computador com o Windows instalado, inicie o EasyMP Multi PC Projection e selecione o adaptador de rede que está a utilizar na opção Mudar LAN de Definir opções.