Skip to content

Compiler implementation (lexical, syntactic, and semantic analysis) using Flex Windows (Lex and Yacc).

Notifications You must be signed in to change notification settings

alienXXVI/Compiler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Análise Léxica

Em analise_lexica.l é feita a inserção de tokens lidos do arquivo nas tabelas de símbolos e de palavras reservadas.


1. Expressões Regulares

Expressões Regulares são criadas para reconhecer padrões ou a construção de padrões de tokens, como STRING ou INT.

LETRA               [a-zA-Z]
DIGITO              [0-9]
IDENTIFICADOR       (_|{LETRA})(_|{LETRA}|{DIGITO})*

Tokens reconhecidos pela linguagem:

  • Palavras Reservadas de condição, repetição, etc.

    • IF
    • ELSE
    • WHILE
    • FOR
    • DO
    • RETURN
    • STRUCT
    • ENUM
    • DEFINE
    • INCLUDE
  • Palavras Reservadas para declaração de tipo.

    • INT
    • FLOAT
    • CHAR
    • VOID
    • STRING
  • Palavras Reservadas para operações.

    • SOMA
    • MULTIPLICAÇÃO
    • DIVISAO
    • SUBTRACAO
    • ATRIBUICAO
  • Símbolos.

    • IDENTIFICADOR
    • INTEIRO
    • REAL
    • CARACTER
    • CADEIA

Erros reconhecidos pela linguagem:

  • Erro 1 - reconhecimento de palavras reservadas mal formadas (if3, *while)
  • Erro 2 - identificadores mal formados, não seguem o padrão solicitado (90_aliana)
  • Erro 3 - operadores mal formados, duplicados ou "compostos" (++, +/)

2. Inserção de Tokens

Ao detectar um token, ele é inserido na tabela de símbolos ou de palavras reservadas, dependendo da sua natureza.

{IF}                {inserirReservada(yytext, R);}
{IDENTIFICADOR}     {inserirSimbolo(yytext, 0, T);}

Comentários e espaços em branco são ignorados.


3. Inicialização e Impressão das Tabelas

No main, as tabelas são inicializadas e após a varredura do arquivo, são printadas.



Estruturas de Dados e Métodos

Em hash_table.c e .h estão as estruturas de dados e métodos para tratar as tabelas hashing.


1. Estrutura de Símbolo

Um símbolo é armazenado em um "nó", que contém seu identificador, seu valor em string e sua categoria.

typedef struct noS {
    int id;
    char *lexema;
    Categoria categoria;
} Simbolo;

Este nó faz parte de um total da tabela hashing para símbolos.

typedef struct simbolos {
    Simbolo **tabela;
} TabelaSimbolo;

Um símbolo pode ter as seguintes categorias:

  • IDENTIFICADOR
  • INTEIRO
  • REAL
  • CARACTER
  • STRING

2. Estrutura de Palavra Reservada

Uma palavra reservada é armazenada em um "nó", que contém seu identificador e seu valor em string.

typedef struct noR {
    int id;
    char *lexema;
} Reservada;

Este nó faz parte de um total da tabela hashing para palavras reservadas.

typedef struct reservadas {
    Reservada **tabela;
} TabelaReservada;



Análise Sintática

Na fase de Análise Sintática (analise_sintatica.y) do compilador, em geral, é feita a verificação da relação entre tokens por meio das regras de uma gramática.


Estruturas Sintáticas

Ao serem reconhecidas, um valor (nome) associado àquela estrutura é inserido na árvore de derivação, de baixo para cima.

Programa

‘@’ = vazio; significa que aquela estrutura não precisa existir obrigatóriamente.


Sentenças Include
#include <nome_arquivo>
#includenome_arquivo”
@
  • Nome Arquivo:
arquivo.extensao

Sentenças Define
  • Sentenças Define

    #define identificador expressao
    @
    • Expressão
      • Operação

        operando op operando
        !operando
        • Op Aritmético

          +
          -
          *
          /
        • Op Relacional

          ==
          !=
          >
          <
          >=
          <=
        • Op Lógico

          &&
          ||
          !
      • Operando

        (operacao)
        literal
        • Literal

          inteiro, real, caractere, cadeia, identificador

Funções
  • Funções

    tipo_dado identificador ( parametros ) {
    	comandos
    }
    Tipo Dado
    int
    float
    char
    void
    string
    Parâmetros
    tipo_dado identificador
    tipo_dado identificador, ...
    @
    Comandos
    decl_var
    atribuicao
    sentenca_if
    sentenca_while
    sentenca_for
    sentenca_do
    sentenca_scan
    sentenca_print
    chamada_funcao
    sentenca_return
    sentenca_switch
    @
    Declaração Variável
    tipo_dado identificador
    tipo_dado atribuicao
    tipo_dado identificador, ...
    tipo_dado atribuicao, ...
    Tipo Dado
    int
    float
    char
    void
    string
    Atribuição
    identificador = expressao
    identificador = atribuicao
    Expressão
    • Operação

      operando op operando
      !operando
      • Op Aritmético

        +
        -
        *
        /
      • Op Relacional

        ==
        !=
        >
        <
        >=
        <=
      • Op Lógico

        &&
        ||
        !
    • Operando

      (operacao)
      literal
      • Literal

        inteiro, real, caractere, cadeia, identificador
    Atribuição
    identificador = expressao
    identificador = atribuicao
    Expressão
    • Operação

      operando op operando
      !operando
      • Op Aritmético

        +
        -
        *
        /
      • Op Relacional

        ==
        !=
        >
        <
        >=
        <=
      • Op Lógico

        &&
        ||
        !
    • Operando

      (operacao)
      literal
      • Literal

        inteiro, real, caractere, cadeia, identificador
    Sentença If
    if ( expressao ) {
    	comandos
    }
    
    if ( expressao ) {
    	comandos
    } else {
    	comandos
    }
    Expressão
    • Operação

      operando op operando
      !operando
      • Op Aritmético

        +
        -
        *
        /
      • Op Relacional

        ==
        !=
        >
        <
        >=
        <=
      • Op Lógico

        &&
        ||
        !
    • Operando

      (operacao)
      literal
      • Literal

        inteiro, real, caractere, cadeia, identificador
    Sentença While
    while ( expressao ) {
    	comandos
    }
    Expressão
    • Operação

      operando op operando
      !operando
      • Op Aritmético

        +
        -
        *
        /
      • Op Relacional

        ==
        !=
        >
        <
        >=
        <=
      • Op Lógico

        &&
        ||
        !
    • Operando

      (operacao)
      literal
      • Literal

        inteiro, real, caractere, cadeia, identificador
    Sentença For
    for ( parametros ) {
    	comandos
    }
    Parâmetros
    • Declaração Variável

      tipo_dado identificador
      tipo_dado atribuicao
      tipo_dado identificador, ...
      tipo_dado atribuicao, ...
      Tipo Dado
      int
      float
      char
      void
      string
      Atribuição
      identificador = expressao
      identificador = atribuicao
      Expressão
      • Operação

        operando op operando
        • Op Aritmético

          +
          -
          *
          /
        • Op Relacional

          ==
          !=
          >
          <
          >=
          <=
        • Op Lógico

          &&
          ||
          !
      • Operando

        (operacao)
        literal
        • Literal

          inteiro, real, caractere, cadeia, identificador
    • Expressão

      • Operação

        operando op operando
        !operando
        • Op Aritmético

          +
          -
          *
          /
        • Op Relacional

          ==
          !=
          >
          <
          >=
          <=
        • Op Lógico

          &&
          ||
          !
      • Operando

        (operacao)
        literal
        • Literal

          inteiro, real, caractere, cadeia, identificador
    Sentença Do
    do {
    	comandos
    } while ( expressao )
    Expressão
    • Operação

      operando op operando
      !operando
      • Op Aritmético

        +
        -
        *
        /
      • Op Relacional

        ==
        !=
        >
        <
        >=
        <=
      • Op Lógico

        &&
        ||
        !
    • Operando

      (operacao)
      literal
      • Literal

        inteiro, real, caractere, cadeia, identificador
    Sentença Scan
    scan ( parametros )
    Parâmetros
    identificador
    identificador,...
    Sentença Print
    print ( parametros )
    Parâmetros
    "string"
    identificador
    "string";...
    identificador;...
    Chamada Função
    identificador ( argumentos )
    Argumentos
    expressao
    expressao,...
    @
    Expressão
    • Operação

      operando op operando
      !operando
      • Op Aritmético

        +
        -
        *
        /
      • Op Relacional

        ==
        !=
        >
        <
        >=
        <=
      • Op Lógico

        &&
        ||
        !
    • Operando

      (operacao)
      literal
      • Literal

        inteiro, real, caractere, cadeia, identificador
    Sentença Return
    return ( valor )
    Valor
    expressão
    Sentença Switch
    switch ( valor ) {
    	case x:
    	break
    }
    Valor
    expressão

Alguns Erros Sintáticos Comuns

Além de reconhecer os erros léxicos, na fase do parser, quando é encontrado um erro sintático, este é exibido na tela. Por exemplo:

  1. Falta de tipo de retorno em definição de funções
funcao(float a, float b)
  1. Falta de palavra-chave de fechamento
if (x > 5) {
    print(x)
else {
    print("Erro")
  1. Falta de parênteses em chamadas de função
print "Hello"
funcao a, b

Árvore de Derivação

É gerado um arquivo de nome “arvore_nomeArquivo.txt” na pasta “arvores_geradas” com a árvore de derivação por onde o parser passou depois que uma “cadeia” (ou código fonte) é aceita.

Caso ocorra um erro, o arquivo não é criado e o erro é exibido.

A estrutura de um nó é dado por um valor (seu nome representativo), seu número de filhos e um ponteiro para a sua lista de filhos:

typedef struct No {
    char valor[MAX];
    int num_filhos;
    struct No** filhos;
} No;

No main, as tabelas de símbolos e de palavras reservadas continuam sendo impressas.


Compilação

Para compilar, é recomendado estar na pasta de caminho:

cd C:\Users\...\Trabalho\src

Primeiro, é feita a compilação do parser em “analise_sintatica.y”.

Em seguida, do scanner em “analise_lexica.l”.

Por fim, os códigos em .c são compilados e o executável é gerado, em “.\gçç.exe”

yacc -d analise_sintatica.y
lex analise_lexica.l
gcc (Get-ChildItem -Recurse -Path "C:\Users\...\Trabalho" -Filter "*.c").FullName -o gçç

Para testar um arquivo texto contendo um código fonte, basta chamar o executável “.\gçç” seguido do nome do arquivo (redirecionar para a pasta onde ele se encontra, se necessário).

.\gçç ..\codigos_teste\teste_yacc.txt

About

Compiler implementation (lexical, syntactic, and semantic analysis) using Flex Windows (Lex and Yacc).

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published