Trabalho de Desenho de Linguagens de
Programa¸c˜
ao e de Compiladores
—
Mini Pascal
(cod. 11482)
Departamento de Inform´
atica
Universidade da Beira Interior
Ano lectivo 2015/2016
1
Introdu¸
c˜
ao
Este trabalho ´e parte constituinte da avalia¸c˜ao pr´atica da Unidade Curricular de c´odigo 11482 designada por Desenho de Linguagens de Programa¸c˜ao e de Compiladores, na sua edi¸c˜ao de 2015-2016.
O trabalho visa o exerc´ıcio dos conceitos e das t´ecnicas b´asicas de de-senho de linguagens de programa¸c˜ao e de compiladores expostos nas aulas da presente UC. Com tal este trabalho ´e estruturado nas v´arias fases que constituem um projecto desta natureza (espelhado pela pr´opria estrutura lectiva da UC). Estas diferentes fases visam ilustrar a utiliza¸c˜ao de t´ecnicas (e ferramentas computacionais associadas) de desenho de compiladores. Em particular as t´ecnicas de analises semˆantica, produ¸c˜ao de c´odigo m´aquina e optimiza¸c˜ao de c´odigo.
2
Descri¸
c˜
ao geral do trabalho
O objectivo geral ´e a defini¸c˜ao/extens˜ao formal de uma pequena linguagem de programa¸c˜ao, a linguagem Mini-Pascal (da autoria do Fran¸cois Pottier),
e a constru¸c˜ao do compilador correspondente, tendo por alvo a arquitectura x86-64.
Este trabalho est´a assim estruturado em duas fases.
A primeira fase consiste em entender a linguagem de base Mini-Pascal (cuja sintaxe abstracta e semˆantica a est´a descrito em anexo deste enunciado) e estendˆe-la. Esta fase dar´a lugar a primeira entrega dia 31 de Mar¸co de 2016.
A segunda fase consiste em desenhar e implementar o compilador para a extens˜ao definida da linguagem.
O trabalho completo, conclu´ıdo com a execu¸c˜ao da segunda fase, dever´a ser entregue no dia 26 de Maio 2016, e as defesas ter˜ao lugar nos primeiros dias da semana seguinte em calend´ario por definir e afixar na p´agina da UC. A entrega dever´a respeitar as modalidades de entrega descritas na sec¸c˜ao 4.
3
Trabalho Requerido
• Como intreg´avel para a primeira fase do trabalho, requer-se um do-cumento que apresenta a linguagem do ponto de vista da sua sintaxe abstracta, o seu sistema de tipo e a sua semˆantica.
• Como entreg´avel para a segunda fase, um compilador completo escrito em OCaml/menhir para a linguagem Mini-Pascal extendida (cujo n´ u-cleo de base de partida est´a descrita em anexo). Impreterivelmente, a arquitectura alvo considerada ´e a arquitetura x86-64 apresentada nas aulas.
O grupo de trabalho dever´a considerar extens˜oes que achar apropriadas e documentadas no relat´orio final. Estas extens˜oes dever˜ao ser discutidas com o regente da UC. Em jeito de sugest˜ao, as extens˜oes sugeridas s˜ao:
• novos tipos primitivos (float, character, string, etc,); • mecanismos de defini¸c˜ao de estruturas;
• mecanismos de defini¸c˜ao de tipos soma;
• mecanismos de defini¸c˜ao de tipos polim´orficos;
• mecanismos de declara¸c˜ao e utiliza¸c˜ao de apontadores/mem´oria dinˆ a-mica;
• introdu¸c˜ao de novos modos de passagem de parˆametros; • introdu¸c˜ao de novas primitivas;
• tec. ´
E esperado igualmente que o grupo reporte atempadamente `a equipa do-cente os eventuais entreg´aveis preliminares (a conclus˜ao incremental das fases de gera¸c˜ao c´odigo, como introduzido nas aulas) mas igualmente as dificulda-des ou quest˜oes encontradas.
4
Entrega do trabalho
O trabalho deve ser entregue num arquivo tar comprimido (nome.tgz ) em que nome ´e o identificador do vosso grupo. este arquivo deve conter todos os ficheiros fontes necess´arios `a compila¸c˜ao assim como um Makefile completo (as entradas all e clean devem estar presentes).
Este arquivo dever´a igualmente conter o relat´orio que descreve o trabalho feito, as escolhas (de desenho, etc.) tomadas, a documenta¸c˜ao do c´odigo e o manual do utilizador. ´E igualmente esperada que seja preparada uma apresenta¸c˜ao para a respectiva defesa.
5
Documentos auxiliares
Anexa-se a este enunciado os documentos que definam a linguagem alvo por compilar: a descri¸c˜ao da sintaxe abstracta e da semˆantica do core da lingua-gem Mini-Pascal. estes documentos s˜ao adapta¸c˜oes directas dos documentos fornecidos pelo Fran¸cois Pottier na sua UC de Desenho de Linguagens de Programa¸c˜ao e Compila¸c˜ao.
A
Sintaxe abstracta de Mini-Pascal
Nas seguintes defini¸c˜oes, a vari´avel b percorre o conjunto dos booleanos, ou seja {true, f alse}. A vari´avel n contempla os inteiros com sinal representados
com 32 bits (i.e. [−231..231−1]). A vari´avel x percorre o conjunto (numer´avel)
dos identificadores de vari´avel, a vari´avel f percorre o conjunto (numer´avel) dos identificadores de fun¸c˜oes e procedimentos.
Os tipos primitivos considerados s˜ao os tipos integer, boolean, array of τ onde τ ´e ele pr´oprio um tipo - que descreve os elementos do vector definido.
τ ::= tipos | integer inteiros | boolean booleanos | array of τ vectores
As constantes s˜ao booleanos ou inteiros. N˜ao h´a constantes de tipo vector : os vectores s˜ao alocados dinamicamente.
k ::= constantes | n constante inteira | b constante booleana
Os operadores un´arios e bin´arios que aparecem na sintaxe das express˜oes s˜ao as seguintes. Todas produzem um resultado de tipo integer, coma ex-cep¸c˜ao dos operadores de compara¸c˜ao que produzem um resultado de tipo boolean.
uop ::= operador un´ario | − nega¸c˜ao
bop ::= operador bin´ario | + adi¸c˜ao
| − subtrac¸c˜ao | × multiplica¸c˜ao | / divis˜ao | < | ≤ | > | ≥ | = | 6= compara¸c˜ao
As opera¸c˜oes primitivas, isto ´e, procedimentos e fun¸c˜oes predefinidas s˜ao as seguintes.
π ::= opera¸c˜oes primitivas | write escrita de um inteiro
| writeln escrita de um inteiro com mudan¸ca de linha | readln leitura de um inteiro
O alvo de uma chamada de um procedimento ou fun¸c˜ao ´e ou uma opera-¸c˜ao primitiva ou um procedimento/fun¸c˜ao definido pelo utilizador, a qual ´e designada pelo seu nome.
φ ::= alvo de uma chamada | π opera¸c˜ao primitiva
| f procedimento ou fun¸c˜ao definida pelo utilizador A sintaxe das express˜oes, condi¸c˜oes e instru¸c˜oes ´e a seguinte. e ::= express˜oes
| k constante | x vari´avel
| uop e aplica¸c˜ao de um operador un´ario | e bop e aplica¸c˜ao de um operador bin´ario | φ(e...e) chamada de fun¸c˜ao
| e[e] acesso a um elemento de vector | new array of τ [e] aloca¸c˜ao de um vector
c ::= condi¸c˜oes
| e express˜oes (com retorno de tipo boolean) | not c nega¸c˜ao
| c and c conjun¸c˜ao | c or c disjun¸c˜ao i ::= instru¸c˜oes
| φ(e...e) chamada de procedimento | x := e atribui¸c˜ao
| e[e] := e escrita num vector | if c then i else i condicional
| while c do i ciclo | i ... i sequˆencia
Uma defini¸c˜ao de procedimento ou de fun¸c˜ao ´e composta por um ca-be¸calho, por uma s´erie de declara¸c˜oes de vari´aveis locais e de um corpo. O cabe¸calho define o nome do procedimento ou da fun¸c˜ao, declara os seus parˆ a-metros formais, se se trata de uma fun¸c˜ao, indica qual o tipo do seu resultado. A nota¸c˜ao τ? indica um tipo opcional.
d ::= defini¸c˜ao de procedimentos/fun¸c˜oes | f (x : τ...x : τ ) : τ? cabe¸calho
var x : τ ... x : τ vari´aveis locais
i corpo
Um programa ´e composto de uma (eventual) sequˆencia de declara¸c˜ao de vari´aveis globais, de uma (eventual) sequˆencia de declara¸c˜ao de procedimen-tos/fun¸c˜oes e de um corpo.
p ::= programa | var x : τ ... x : τ vari´aveis globais
d .. d defini¸c˜oes de procedimentos/fun¸c˜oes
i corpo
B
Semˆ
antica formal de Mini-Pascal
Esta sec¸c˜ao introduz uma semˆantica operacional big-step
B.1
Valores
Os valores manipulados durante a execu¸c˜ao s˜ao booleanos, inteiros (com representa¸c˜ao sobre 32 bits), endere¸cos de vectores e igualmente a contante nil. Um vector ´e representado pelo seu endere¸co em mem´oria e n˜ao pela sequˆencia dos seus elementos. Esta distin¸c˜ao tem a sua importˆancia : ela significa, por exemplo, que ´e poss´ıvel para duas vari´aveis distintas de tipo “array of τ serem um alias uma da outra, isto ´e, conter o mesmo endere¸co e logo apontar para o mesmo vector. Significa igualmente que o conte´udo de uma vari´avel de tipo vector pode ser guardada nos registos, porque se trata de um endere¸co e n˜ao do vector em si. O vector ser´a arquivado na heap. O valor nil ´e o valor atribuido a vectores sem inicializa¸c˜ao.
cv ::= valores
| b constante booleana | n constante inteira | l endere¸co de vector | nil endere¸co inv´alido
No Mini-Pascal, quando declaramos uma vari´avel, damos o seu tipo τ , mas n˜ao indicamos o seu valor inicial. Nalgumas linguagens, como a linguagem
C, o valor inicial da vari´avel est´a ent˜ao indefinida : ´e prohibido aceder ao conte´udo desta vari´avel antes de uma inicializa¸c˜ao. Noutras linguagens, como em Java, as vari´aveis s˜ao inicializadas com um valor por omiss˜ao (que depende do tipo). Esta ser´a a abordagem seguida no Mini-Pascal. Assim define-se uma fun¸c˜ao def ault que atribu´ı a cada tipo o valor por omiss˜ao que lhe corresponde.
default (boolean) = false default (integer) = 0 default (array of τ ) = nil O ´ultimo caso justifica a existˆencia do valor nil.
B.2
Operadores
A semˆantica dos operadores un´arios ´e dada por uma fun¸c˜ao J.K que associa a todo o operador uop (recorde-se, este operador ´e pura sintaxe, ´e um nome) uma fun¸c˜ao parcial JuopK dos valores para os valores. Por exemplo, a se-mˆantica do operador de nega¸c˜ao ´e dada definindo J−K como sendo a fun¸c˜ao que a toda a constante inteira n associa a contante inteira −n normalizada no intervalo −231· · · 231− 1. ´E importante notar que a fun¸c˜ao
J−K n˜ao est´a definida para outros valores do que os valores inteiros : n˜ao se pode apli-car esta fun¸c˜ao sobre valores booleanos, nem a um endere¸co, nem ao valor nil. A semˆantica de um programa que aplicaria o operador da nega¸c˜ao sobre um vector, por exemplo, est´a ent˜ao sem defini¸c˜ao. Um tal programa ´e feliz-mente exclu´ıdo pelo sistema de tipos do Mini-Pascal, visto que o tipo inteiro ´
e incompat´ıvel com o tipo “array of τ ”.
De forma semelhante, a semˆantica de operadores bin´arios ´e dada por uma fun¸c˜aoJ.K que a todo o operador bop associa uma fun¸c˜ao bin´aria parcial JuopK dos pares de valores para os valores. A defini¸c˜ao exacta de cada um dos operadores ´e deixada em exerc´ıcio (por este n˜ao oferecer dificuldades particulares).
B.3
Ju´ızos
O conte´udo das vari´aveis globais ´e dada por um ambiente G que associa `as vari´aveis os valores que lhes correspondem. De igual forma, o conte´udo das vari´aveis locais ´e dado por um ambiente E. Finalmente o heap H associa aos endere¸cos sequˆencias finitas de valores.
A semˆantica de Mini-Pascal ´e definida por ju´ızos. A avalia¸c˜ao de uma express˜ao, de uma condi¸c˜ao, de uma instru¸c˜ao pode modificar as vari´aveis globais, as vari´aveis locais, assim como a heap. Os ju´ızos que descrevem a avalia¸c˜ao mencionam assim o estado inicial G, H, E e o estado resultante G0, H0, E0. No caso das express˜oes e das condi¸c˜oes, estes ju´ızos mencionam tamb´em um valor, que representa o resultado da avalia¸c˜ao. Os ju´ızos s˜ao assim da forma
G, H, E/e → G0, H0, E0/v G, H, E/c → G0, H0, E0/b G, H, E/i → G0, H0, E0
O primeiro caso destes ju´ızo lˆe-se : “no estado descrito por G, H, E, a avalia¸c˜ao da express˜ao e conduz ao estado descrito por G0, H0, E0 e produz o valor v”. O segundo e o terceiro caso lˆeem-se de forma semelhante.
Damo-nos a liberdade de escrever S para representar G, H, E.
Este estilo de semˆantica, como vismos nas aulas, ´e designada de semˆantica operacional de passos grandes (big-step). ´E assim designada porque estes ju´ızos ligam directamente as express˜oes e os seus resultados sem contemplar os eventuais passos interm´edios do calculo inerente.
A semˆantica das express˜oes ´e dada na figura 1. esta cont´em um conjunto de regras que definam o ju´ızo G, H, E/e → G0, H0, E0/v. Da mesma forma, os ju´ızos que descrevem das condi¸c˜oes e das instru¸c˜oes est˜ao definidos nas figuras 2 e 3. Na forma impl´ıcita de abuso de nota¸c˜ao, todas as regras est˜ao implicitamente parametrizadas por uma s´erie de defini¸c˜oes de fun¸c˜oes e pro-cedimentos que s˜ao consultadas pelas duas regras que descrevem a chamada de fun¸c˜oes e a chamada de procedimentos definidos pelo utilizador. Estas de-fini¸c˜oes de fun¸c˜oes e de procedimentos est˜ao definidas aquando a explora¸c˜ao de um programa p particular.
A semˆantica de um programa p particular ´e definida por um ju´ızo da forma
p →
Este ju´ızo p → lˆe-se “o programa p executa-se sem erro e termina”. A sua defini¸c˜ao ´e dada na figura 4.
Figura 1:
Figura 3: