Skip to content

RGarrido03/C-Project

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Relatório - tema PDraw, grupo pdraw-t02

Cadeira: Compiladores

Ano Letivo: 2023/2024

O presente projeto tem como objetivo construir um compilador e um interpretador para a linguagem PDraw e iPdraw, respetivamente. A linguagem PDraw compila os programas PDraw para Python. O programa compilado pode eventualmente executar um script iPdraw que será interpretado em tempo de execução. Ambas as linguagens permitem aos utilizadores a criação imagens e formas, proporcionando-lhes uma tela virtual. A linguagem segue a abstração da biblioteca python turtle.


Index

Relatório - tema PDraw, grupo pdraw-t02


1. Constituição do grupo e participação individual

NMec Nome Participação
112974 ANDRÉ PEDRO RIBEIRO 28.8%
68264 BRUNO RAFAEL DOS SANTOS LOPES 6.8%
108712 DIOGO ALEXANDRE MARQUES FALCÃO 6.8%
107927 RUBEN TAVARES GARRIDO 28.8%
113170 VIOLETA BATISTA RAMOS 28.8%

2. Como executar

Dar permissão para executar o script run.sh (workflow: antlr4-build,run,cria enviroment):

chmod +x ./run.sh
./run.sh [options] <filename>

Note

O script run.sh foi criado para facilitar a compilação e execução do pdraw.

3. Estrutura

Organização do repositório (diretórios):

├── doc
├── examples
│   └── self_made
├── scripts
└── src
    ├── compiler
    │   ├── st
    │   └── types
    └── generated_files
  • doc: Documentação e assets do projeto
  • examples: Exemplos de programas em PDraw
  • scripts: Scripts de apoio ao desenvolvimento
  • src: Código fonte do projeto
    • compiler: Código fonte do compilador
      • st: Código fonte dos templates StringTemplate
      • types: Código fonte dos tipos de dados
    • generated_files: Ficheiros gerados pelo ANTLR4

4. Pdraw

A linguagem PDraw é uma linguagem de programação compilada que compila programas para Python.

Todas as instruções são executadas em relação a uma caneta que é configurada com várias variáveis. Permite ter várias canetas numa determinada janela. As canetas são movidas para cima ou para baixo ('levantadas/colocadas do/no papel'), rodadas (clockwise ou anticlockwise) e deslizadas para a esquerda ou direita permitindo ao utilizador desenhar formas e imagens no ecrã.

Todas as instruções de atributos da caneta devem acabar com um ponto e vírgula e todas as linhas devem permitir a criação de comentários com o símbolo %.

4.1. Gramática

Em ANTLR4 ao definirmos uma gramática formulamos regras sintáticas(parser) e léxicas(lexer) gerando uma árvore sintática em que cada nó corresponde a um token. Neste projeto a gramática tem a seguinte estrutura.

Ficheiros Descricão
Elements.g4 Definição de expressões aritmétricas e comandos da caneta
Class.g4 Criação e configuração de Canvas e Pens
pgdraw Gramática Principal

O pgdraw.g4 importa a Elements.g4 e Class.g4 para ter maior abstração e uma melhor organização da gramática.

4.2. Visitors

Como já mencionado anteriormente, na árvore de análise sintática (parse tree) gerada pelo parser, pretendemos interagir com cada nó e é aqui que entra o Visitor. Com esta ferramenta podemos configurar com ações especifícas e personalizadas sobre a estrutura de objetos tornando o código mais modular, reutilizável e fácil manutenção.

Compiler e SemanticAnalysis são os Visitors que foram implementados neste projeto.

A seguir, demonstramos um exemplo de fluxo do projeto (caneta pode fazer up e down), passando pela gramática, depois pela análise semântica e acabando no compilador com o tipo StringTemplate.

Exemplo - InstructionPenAction

  1. Gramática
instruction:
	variable (move | rotate | pause | write)+	# InstructionMoveRotateAction
	| variable penAction						          # InstructionPenAction
	| variable '<-' arrowProps					      # InstructionArrowProps;

  1. Análise semântica
@Override
  public Boolean visitInstructionPenAction(
    pdrawParser.InstructionPenActionContext ctx
  ) {
    String variable = ctx.variable().getText();
    if (!symbolTable.containsKey(variable)) {
    // if variable (pen) is not in the Symbol Table.
      ErrorHandling.printError(
        ctx,
        String.format("Variable %s not defined", variable)
      );
      return false;
    }
    // variable is Type PEN. We only allow for the words "down" and "up". If so, the return value is true and it passes the semantic analysis.
    Type type = symbolTable.get(variable).getType();
    if (type instanceof PenTAD) {
      Boolean penAction =
        ctx.penAction().getText().equals("down") ||
        ctx.penAction().getText().equals("up");
      if (penAction) {
        return true;
      }
      ErrorHandling.printError(ctx, "Instructions are not valid");
      return false;
    }
    ErrorHandling.printError(
      ctx,
      String.format("Variable %s is not a pen", variable)
    );
    return false;
  }
  1. String template
instruction(variable, action, value, fontsize) ::= "<variable>.<action>(<value><if(fontsize)>, <fontsize><endif>)"
  1. Compiler
  @Override
  public ST visitInstructionPenAction(
    pdrawParser.InstructionPenActionContext ctx
  ) {
    // add tokens in StringTemplate
    ST res = pdrawTemplate.getInstanceOf("instruction");
    res.add("variable", visit(ctx.variable()));
    res.add("action", ctx.penAction().getText());
    return res;
  }

4.3. Variáveis, métodos, operadores e tipos de dados

Variáveis e métodos

As variáveis em PDraw são declaradas com o tipo de dados e o nome da variável. Atributos podem ser definidos para as variáveis e as Strings têm de ser concatenadas.

int add = 3 + 1;
int sub = 3 - 1;
int mul = 3 * 1;
real div = 3 / 1;
int dre = 3 // 1;
int pow = 3 ^ 2;
int par = (3 + 2) * 4;
par = sub--;
par = add++;
mult++;
string word = "Love" "C"; % Concatenation
int i,x,t; % Default value
int k=0, w=0;
pen p = new PenType1;

As variáveis também podem ser declaradas com input.

int x = int(stdin "x: ");
int y = int(stdin "y: ");
string w = stdin stdin "Choose your stdin name: ";

Por último, podemos dar print de variáveis.

p2 -> stdout;
"\n" -> stdout;
"FALHOU" -> stderr;

Operadores

Operador Descrição
+ Adição
++ Incremento
-- Decremento
- Subtração
/ Divisão
// Divisão inteira
* Multiplicação
^ Potência
== Igual
!= Diferente
< Menor que
<= Menor ou igual a
> Maior que
>= Maior ou igual a
and E lógico
or Ou lógico
up Levanta a caneta
down Baixa a caneta
pause Pausa o programa por microsegundos

Note

A árvore sintática não está a fazer a verificação da precedência para os operadores and, or, *, ^,/,//, no entanto, inferimos as regras do python e por isso não criámos regras novas. Por isso, o and precede o or. No caso == (igual), criámos regras para que este tenha menor precedência do que as setas.

Tipos de dados

Tipos (Type):

  • Angle
  • Bool
  • Canvas
  • Function
  • Int
  • PenTAD
  • Pen
  • Point
  • Real
  • String
  • Symbol
  • Tuple

O cast de tipos de dados também é possível:

int i = 5;
string s = string(i);

string t = "5";
t = string(8);

real r = 5.0;
r = real(1);
r = real("1");

4.4 Caneta

Existem 2 formas de criar uma caneta em PDraw:

  1. Caneta com atributos: A caneta com atributos é criada com atributos específicos. A declaração da caneta é feita com a definição dos atributos.
define pen PenType1 {
  color = green;
  position = ( 10 , 10 ) ;
  orientation = 45º;
  thickness = 10 ;
  pressure = −1;
}

pen p1 = new PenType1;
  1. Caneta por defeito: A caneta herdada por defeito é herdada com os atributos anteriormente definidos.
pen p1 = new PenType1;

ou com valores por defeito

pen psec = new;
Variável Descricão
color Cor da caneta que pode ser uma palvra ou um valor hexadecimal
position Posição inicial representada por um ponto (tuplo)
orientation Ângulo em graus da orientação da caneta
thickness Espessura da caneta
pressure Pressão com que a caneta está a ser usada
speed Velocidade da caneta a desenhar

Podemos também adicionar/subtrair pontos à caneta (o que resulta na alteração da posição da caneta):

pen p1 = new PenType1;
p1 = p1 + (5,5);

4.5 Canvas

A canvas é a tela virtual onde são desenhadas as figuras. Por predifinição, a canvas tem 500x500 de tamanho, sem nome e branco. Porém, pode ser alterada:

define canvas Canvas1 "Example 1" (100,100);

Canvas

Canvas2 background red;

Podemos também definir qual a canvas ativa:

set Canvas1;

4.6 Setas de atributos

As setas de atributos são usadas quando queremos alterar um atributo de uma caneta. Por exemplo, se quisermos alterar a cor de uma caneta, podemos fazer:

p1 <- color = red;

Assim como se quisermos mudar a posição da caneta (tendo o x e y já anteriormente definidos):

p1 <-position (x,y);
p1 <-speed 100+x;

4.7 Instruções condicionais e loops

If

Para o if, tivemos que tomar em atenção as operações lógicas e aritméticas, assim como elifs e else, para além disso também tivemos em atenção o scope dos ifs, variáveis definidas no if só estão disponiveis no if.

if (myStringVar == "Hello") {
    "Hello bestie" -> stdout;
} else if (myStringVar == "Hi") {
    "Hi bestie" -> stdout;
} else {
    "Bye bestie" -> stdout;
};

For

Para o for, tivemos que tomar em atenção a inicialização, condição, incremento e scope.

for (int i = 0; i < 5; i++) {
   i -> stdout;
};

While/Until

Exemplo de um until:

until (done) {
   length = int(stdin "length: ");
   angle = real(stdin "rotation angle (degrees): ") / 180 * PI;
   string t = stdin "finish (y/N)?: ";
   done = t;
};

Pipeline de comandos

Exemplo de uma Pipeline:

p1 forward 10 right 144º forward 10 right 144º;
p1 forward 20 right 100º pause 1000 forward 10 pause 2000 right 144º;

4.8 StringTemplates (ST)

Como StringTemplates divimos também em três secções para ser mais legível de leitura e compreensão.

Por exemplo temos a Class.stg:

createPenClass(className, classProps) ::= <<
class <className>(Pen):
    def __init__(self) -> None:
        super().__init__()
        <classProps; separator="\n">
>>

classProps(prop, expression) ::= "self.<prop> = <expression>"

Temos a pdraw.stg:

assignment(assignVar, assignPen, reassignVar, variable, object, expression, type) ::= <%
<if(assignVar)>
<variable>: <type> = <expression>
<elseif(assignPen)>
<object>
<elseif(reassignVar)>
<variable> = <expression>
<endif>
%>

e por último a Elements.stg:

tuple(e1, e2) ::= "(<e1>,<e2>)"

A utilização destes templates vai permitir gerar código ou texto de saída durante a compilação.

4.9 Funções

As funções em PDraw são definidas com o tipo de retorno, o nome da função e os argumentos. A função tem de ser chamada com os argumentos necessários e com o tipo correto. Todas as variáveis definidas dentro da função são locais e não podem ser acedidas fora da função.

Exemplo de uma função que desenha um círculo:

def int recursiveWithPen(pen p, int i){
    if (i < 100){
        p left (360 / 100) deg;
        p forward 10 * PI;
        return recursiveWithPen(p,i+1);
    };
    return 0;
};

4.10 Pipeline de comandos

A pipeline de comandos é uma sequência de comandos que são executados em sequência. Cada comando é separado por um espaço.

p1 forward 10 right 144º forward 10 right 144º;
p1 forward 20 right 100º pause 1000 forward 10 pause 2000 right 144º;

4.11 Escrever texto no ecrã

Para escrever texto no ecrã, usamos a função write. Esta função recebe uma string e escreve-a no ecrã.

pen p1 = new PenType1;
p1 down;
% pen write texto, fontsize;
p1 write "ola", 30;

5. iPdraw

A linguagem iPdraw é uma linguagem de programação interpretada que executa programas iPdraw. A linguagem iPdraw permite todas as operações que a linguagem PDraw permite (com exceção de funções) com a adição de manipulação de arrays, no entanto, apenas permite a execução de comandos para uma Pen.

5.1. Gramática

A gramática do iPdraw é muito semelhante à gramática do PDraw. No entanto, a gramática do iPdraw é mais simples e não permite a definição de funções e permite a criação/manipulação de arrays.

5.2. Visitors

O visitor interpreter.py é responsável por interpretar o código iPdraw e fazer a verificação semântica comando a comando que é feita em execution time.

5.3 Variáveis, Loops, Conditional Structures, Pipeline de comandos,Escrever texto no ecrã

Todas as estruturas desta secção são declaradas exatamente da mesma forma que em PDraw.

5.4 Arrays

A linguagem iPdraw permite a criação e manipulação de arrays.

int arr =[10,20, 30,40,50,60,70,80,90,100,110,120,140];

arr[0]=20;
arr[10]=30;

arr[0] -> stdout;
len arr -> stdout;
del arr[1];
len arr -> stdout;

int j;

while (j lt len arr){
    arr[j] -> stdout;
    j++;
};

6. Exemplos

Como mencionado anteriormente o p1.ipdraw, p1.pdraw , p2.pdraw, p3.pdraw, p4.pdraw e exemplos criados personalizados para cada ocasião onde é testada cada operação para efeitos de testes. Os exemplos criados por nós estão na pasta self_made

examples
├── p1.ipdraw
├── p1.pdraw
├── p2.pdraw
├── p3.pdraw
├── p4.pdraw
└── self_made
    ├── test_addpoint.pdraw
    ├── test_assignment.pdraw
    ├── test_atributtesarrows.pdraw
    ├── test_canvas_background.pdraw
    ├── test_casts.pdraw
    ├── test_compiler_definepen.pdraw
    ├── test_compiler_onevar.pdraw
    ├── test_compiler_vars_defines.pdraw
    ├── test_create_canvas.pdraw
    ├── test_definepen_assignpen.pdraw
    ├── test_for.pdraw
    ├── test_function.pdraw
    ├── test_if.pdraw
    ├── test_ipdraw.ipdraw
    ├── test_multiple_ass_one_line.pdraw
    ├── test_operation.pdraw
    ├── test_pdraw3_addpoint.pdraw
    ├── test_pipeline.pdraw
    ├── test_stdin.pdraw
    ├── test_while.pdraw
    └── test_write.pdraw

7. Contribuições

Funcionalidade Scope Autor
Arrays Interpretador André e Violeta
Casts entre tipos de dados Compilador Diogo e Rúben
Interpretador André e Violeta
Constants Compilador Rúben
Interpretador André e Violeta
Escrita de texto no canvas Compilador e Interpretador André e Violeta
Escrita de texto no stdout Compilador Rúben
Executar interpretador Compilador Rúben
for loop Compilador Rúben
Interpretador André e Violeta
Funções Compilador André e Violeta
if condition Compilador Rúben
Interpretador André e Violeta
Increment / Decrement Compilador Rúben
Interpretador André e Violeta
Instrução de pausa Compilador Rúben
Leitura de texto do stdin Compilador Rúben
Interpretador André e Violeta
Mudança de atributos de canetas Compilador Diogo
Interpretador André e Violeta
Movimento de canetas Compilador Bruno
Compilador André e Violeta
Operações de relação e igualdade Compilador Rúben
Interpretador André e Violeta
Pipelines de canetas Compilador Rúben
Interpretador André e Violeta
Relatório Outros Todos
Script de execução Outros André e Rúben
Somar pontos a canetas Compilador André, Bruno e Violeta
Variáveis sem valor inicial Compilador e Interpretador André, Rúben e Violeta
Verificação semântica de tipos Compilador e Interpretador André e Violeta
while & until loops Compilador Rúben
Interpretador André e Violeta

About

Project for "Compiladores", 2023/2024

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •