Skip to content
Eduardo Dantas edited this page Aug 23, 2019 · 20 revisions

Introdução

Compiladores são programas complexos que visam a modificação de um código fonte escrito em alto nível (entendível por humanos) para linguagem de máquina. Para fazer isso eles trabalham em diversas etapas na transformação do código original. As etapas se desdobram na criação de um parser em conjunto com uma tabelas de símbolos, criação de uma arvore de análise sintática (ADA), conversão desta para uma Árvore de Análise Semântica (ASA), modificação das expressões para a Notação Polonesa (NP), geração de código intermediário (GCI), geração de código objeto (GCO), otimização e por fim, a interpretação desse código objeto por uma p-code machine, que é capaz de gerar os comandos em assembler interpretados pela máquina.

Este projeto se foca na criação de um analisador léxico, sintático e semântico com o auxilio de Flex, Bison, e posterior impressão de uma árvore sintática n-ária.

O Analisador Léxico

A análise léxica (scanner) trata-se de analisar a entrada de caracteres e com isso produzir uma sequência de símbolos chamados tokens que podem ser manipulados pelo parser (um leitor). Esta é uma forma de verificar se existe algum caractere que não faz parte do alfabeto definido por nós e também de reconhecer palavras reservadas, constantes e outras palavras pertencentes à linguagem de programação.

O alfabeto

Pode-se definir tokens que serão reconhecidos durante a análise léxica. Os tokens nada mais são que uma sequência de caracteres (strings) os quais podem ser manipulados por um analisador sintático, fornecendo significado a eles.

Análise Sintática

A análise sintática parsing determina se uma cadeia de símbolos léxicos pode ser gerada por uma gramática, transformando a cadeia em uma estrutura de dados, usualmente uma árvore.

Análise Semântica

Terceira etapa no processo de compilação, essa análise é responsável por apontar expressões que quebram a gramática definida. A semântica de uma sentença seria o significado assumido por ela em um determinado contexto.

A linguagem de base

A linguagem C é uma linguagem de programação de proposito geral, estruturada, imperativa e procedural. Escolhemos C devido a familiaridade de comandos e conhecida experiência com a mesma, facilitando a adaptação ao código necessário e para uso dos tokens.

Definições da linguagem C

Tipos de dados:

  • char
  • int
  • float
  • double

Podemos alcançar as variantes desses tipos adicionando modificadores unsigned long e short antes da definição do tipo.

Operadores:

Operador Função
'+' Adição
'-' Subtração
'*' Multiplicação
'/' Divisão

Operadores unários

Operador Função
'++' Adição
'--' Subtração

Operadores relacionais

Operador Função
'>' Maior que
'>=' Maior ou igual
'<' Menor que
'<=' Menor ou igual
'==' Igual
'!=' Diferente

Operadores lógico

Operador Função
'&&' AND
'
'!' NOT

Condicionais

if(exp){} else{}
switch(exp){} case: break;

Repetição

while, for, do while

O Projeto

Nosso analisador léxico

Utilizamos Flex para gerar as regras de reconhecimento de tokens através do comando flex analisador.l O arquivo analisador.l importa como biblioteca os arquivos gerados pelo parser do bison, assim temos como saída um arquivo lex.yy.c.

Nosso analisador Sintático

Através do uso de Bison no arquivo parser.y via comando bison -d parser.y o mesmo gera dois arquivos parser.tab.h e parser.tab.c, que contém a tabela de símbolos referentes ao nosso código fonte e demais funções.

Nosso analisador semântico

Afim de definir regras para que a construção da árvore de sintaxe fosse feita respeitando as precedências, como multiplicação e soma, e as operações determinadas, definimos uma gramática.