From 02ef7c706cf9850b97c85ef260e98a6adb0fa3b4 Mon Sep 17 00:00:00 2001 From: Marcel Guinhos Date: Tue, 6 Oct 2026 23:05:44 +0000 Subject: [PATCH] First commit --- AUTORES.txt | 2 + Makefile | 6 +- README.md | 6 + src/main.c | 18 +++ src/micropascal-lexer/lexer.c | 181 +++++++++++++++++++-------- src/micropascal-lexer/token.c | 172 +++++++++++++------------- src/micropascal-parser/ast.c | 73 ++++++----- src/micropascal-parser/parser.c | 212 ++++++++++++++++++++++---------- 8 files changed, 427 insertions(+), 243 deletions(-) create mode 100644 AUTORES.txt diff --git a/AUTORES.txt b/AUTORES.txt new file mode 100644 index 0000000..853e9d1 --- /dev/null +++ b/AUTORES.txt @@ -0,0 +1,2 @@ +Marcel Guinhos de Menezes Feitosa (00000855041) +Aloisio diff --git a/Makefile b/Makefile index 837cd77..7abe650 100644 --- a/Makefile +++ b/Makefile @@ -41,9 +41,7 @@ TEST_SRCS := tests/test_main.c tests/test_lexer.c tests/test_parser.c $(LIB_SRCS ARGS ?= examples/testaparidade.pas -.PHONY: all help build run test clean - -all: build +.PHONY: help all build run test clean help: @echo "micro-Pascal - alvos disponiveis" @@ -53,6 +51,8 @@ help: @echo " make test compila e executa a suite de testes" @echo " make clean remove o diretorio build" +all: build + build: $(BIN) $(BIN): $(APP_SRCS) diff --git a/README.md b/README.md index 2a60e0f..9a7ce6e 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,12 @@ micro-pascal/ Todos os arquivos de cabecalho residem em include/. +## Requisitos de compilacao + +- Compilador C99 (gcc/cc ou clang). +- GNU Make. +- Alvos suportados: Linux e Windows. + ## Uso ``` diff --git a/src/main.c b/src/main.c index 85de655..a135bd8 100644 --- a/src/main.c +++ b/src/main.c @@ -9,24 +9,30 @@ static char* lerArquivo(const char* caminho, long* tamanho) { FILE* arquivo = fopen(caminho, "rb"); char* conteudo; + if (arquivo == NULL) { return NULL; } + fseek(arquivo, 0, SEEK_END); *tamanho = ftell(arquivo); fseek(arquivo, 0, SEEK_SET); conteudo = (char*)malloc((size_t)(*tamanho) + 1); + if (conteudo == NULL) { fclose(arquivo); return NULL; } + if (fread(conteudo, 1, (size_t)(*tamanho), arquivo) != (size_t)(*tamanho)) { free(conteudo); fclose(arquivo); return NULL; } + conteudo[*tamanho] = '\0'; fclose(arquivo); + return conteudo; } @@ -34,18 +40,24 @@ static void imprimirTokens(const char* fonte) { Lexer lexer; Token token; + lexerInicializar(&lexer, fonte); + do { token = lexerProximoToken(&lexer); + if (token.kind == TOKEN_ERRO) { tokenLiberar(&token); break; } + printf("%s [%s]\n", tokenKindNome(token.kind), token.lexema); + if (token.kind == TOKEN_EOF) { tokenLiberar(&token); break; } + tokenLiberar(&token); } while (1); } @@ -64,11 +76,13 @@ int main(int argc, char** argv) caminho = argv[1]; modo = "--ast"; + if (argc >= 3) { modo = argv[2]; } fonte = lerArquivo(caminho, &tamanho); + if (fonte == NULL) { printf("Nao foi possivel abrir o arquivo [%s]\n", caminho); return 1; @@ -84,20 +98,24 @@ int main(int argc, char** argv) Lexer lexer; Parser parser; AstNo* programa; + lexerInicializar(&lexer, fonte); parserInicializar(&parser, &lexer); programa = parserAnalisarPrograma(&parser); tokenLiberar(&parser.atual); + if (parser.houve_erro) { astLiberar(programa); free(fonte); return 1; } + printf("Analise sintatica concluida com sucesso.\n"); astImprimir(programa, 0); astLiberar(programa); } free(fonte); + return 0; } diff --git a/src/micropascal-lexer/lexer.c b/src/micropascal-lexer/lexer.c index 5b165b6..90201d5 100644 --- a/src/micropascal-lexer/lexer.c +++ b/src/micropascal-lexer/lexer.c @@ -23,22 +23,27 @@ static int lexerAcabou(const Lexer* lexer) static char lexerEspiar(const Lexer* lexer, size_t deslocamento) { size_t indice = lexer->posicao + deslocamento; + if (indice >= lexer->tamanho) { return '\0'; } + return lexer->fonte[indice]; } static char lexerAvancar(Lexer* lexer) { char atual = lexer->fonte[lexer->posicao]; + lexer->posicao++; + if (atual == '\n') { lexer->linha++; lexer->coluna = 1; } else { lexer->coluna++; } + return atual; } @@ -56,21 +61,26 @@ static char* lexerCopiarIntervalo(const Lexer* lexer, size_t inicio, size_t fim) { size_t comprimento = fim - inicio; char* resultado = (char*)malloc(comprimento + 1); + if (resultado == NULL) { return NULL; } + memcpy(resultado, lexer->fonte + inicio, comprimento); resultado[comprimento] = '\0'; + return resultado; } static Token lexerCriarToken(const Lexer* lexer, TokenKind kind, size_t inicio, int linha, int coluna) { Token token; + token.kind = kind; token.lexema = lexerCopiarIntervalo(lexer, inicio, lexer->posicao); token.linha = linha; token.coluna = coluna; + return token; } @@ -79,72 +89,93 @@ static TokenKind lexerPalavraReservada(const char* lexema) if (strcmp(lexema, "program") == 0) { return TOKEN_PROGRAM; } + if (strcmp(lexema, "if") == 0) { return TOKEN_IF; } + if (strcmp(lexema, "then") == 0) { return TOKEN_THEN; } + if (strcmp(lexema, "else") == 0) { return TOKEN_ELSE; } + if (strcmp(lexema, "while") == 0) { return TOKEN_WHILE; } + if (strcmp(lexema, "do") == 0) { return TOKEN_DO; } + if (strcmp(lexema, "repeat") == 0) { return TOKEN_REPEAT; } + if (strcmp(lexema, "until") == 0) { return TOKEN_UNTIL; } + if (strcmp(lexema, "integer") == 0) { return TOKEN_INTEGER; } + if (strcmp(lexema, "real") == 0) { return TOKEN_REAL; } + if (strcmp(lexema, "char") == 0) { return TOKEN_CHAR; } + if (strcmp(lexema, "begin") == 0) { return TOKEN_BEGIN; } + if (strcmp(lexema, "end") == 0) { return TOKEN_END; } + if (strcmp(lexema, "write") == 0) { return TOKEN_WRITE; } + if (strcmp(lexema, "var") == 0) { return TOKEN_VAR; } + if (strcmp(lexema, "div") == 0) { return TOKEN_DIV; } + if (strcmp(lexema, "and") == 0) { return TOKEN_AND; } + if (strcmp(lexema, "or") == 0) { return TOKEN_OR; } + if (strcmp(lexema, "not") == 0) { return TOKEN_NOT; } + return TOKEN_IDENTIFICADOR; } static Token lexerErro(Lexer* lexer, char caractere, int linha, int coluna) { Token token; + lexer->houve_erro = 1; token.kind = TOKEN_ERRO; printf("Erro léxico no caracter [%c]\n", caractere); token.lexema = lexerCopiarIntervalo(lexer, lexer->posicao, lexer->posicao); token.linha = linha; token.coluna = coluna; + return token; } @@ -154,11 +185,14 @@ static Token lexerLerIdentificador(Lexer* lexer) int linha = lexer->linha; int coluna = lexer->coluna; Token token; + while (!lexerAcabou(lexer) && (ehLetra(lexerEspiar(lexer, 0)) || ehDigito(lexerEspiar(lexer, 0)))) { lexerAvancar(lexer); } + token = lexerCriarToken(lexer, TOKEN_IDENTIFICADOR, inicio, linha, coluna); token.kind = lexerPalavraReservada(token.lexema); + return token; } @@ -168,23 +202,30 @@ static Token lexerLerNumero(Lexer* lexer) int linha = lexer->linha; int coluna = lexer->coluna; TokenKind kind = TOKEN_INTEIRO_LITERAL; + if (lexerEspiar(lexer, 0) == '.') { lexerAvancar(lexer); + while (!lexerAcabou(lexer) && ehDigito(lexerEspiar(lexer, 0))) { lexerAvancar(lexer); } + return lexerCriarToken(lexer, TOKEN_REAL_LITERAL, inicio, linha, coluna); } + while (!lexerAcabou(lexer) && ehDigito(lexerEspiar(lexer, 0))) { lexerAvancar(lexer); } + if (lexerEspiar(lexer, 0) == '.' && ehDigito(lexerEspiar(lexer, 1))) { kind = TOKEN_REAL_LITERAL; lexerAvancar(lexer); + while (!lexerAcabou(lexer) && ehDigito(lexerEspiar(lexer, 0))) { lexerAvancar(lexer); } } + return lexerCriarToken(lexer, kind, inicio, linha, coluna); } @@ -194,13 +235,18 @@ static Token lexerLerChar(Lexer* lexer) int linha = lexer->linha; int coluna = lexer->coluna; char conteudo; + lexerAvancar(lexer); + if (lexerAcabou(lexer)) { return lexerErro(lexer, '\'', linha, coluna); } + conteudo = lexerEspiar(lexer, 0); + if (conteudo == '\\') { char escapado = lexerEspiar(lexer, 1); + if (escapado == 'n' || escapado == 't') { lexerAvancar(lexer); lexerAvancar(lexer); @@ -212,10 +258,13 @@ static Token lexerLerChar(Lexer* lexer) } else { return lexerErro(lexer, conteudo, linha, coluna); } + if (lexerEspiar(lexer, 0) != '\'') { return lexerErro(lexer, lexerEspiar(lexer, 0), linha, coluna); } + lexerAvancar(lexer); + return lexerCriarToken(lexer, TOKEN_CHAR_LITERAL, inicio, linha, coluna); } @@ -229,10 +278,12 @@ Token lexerProximoToken(Lexer* lexer) while (!lexerAcabou(lexer)) { atual = lexerEspiar(lexer, 0); + if (atual == ' ' || atual == '\n' || atual == '\t' || atual == '\r') { lexerAvancar(lexer); continue; } + break; } @@ -241,6 +292,7 @@ Token lexerProximoToken(Lexer* lexer) token.lexema = lexerCopiarIntervalo(lexer, lexer->posicao, lexer->posicao); token.linha = lexer->linha; token.coluna = lexer->coluna; + return token; } @@ -252,75 +304,96 @@ Token lexerProximoToken(Lexer* lexer) if (ehLetra(atual)) { return lexerLerIdentificador(lexer); } + if (ehDigito(atual)) { return lexerLerNumero(lexer); } + if (atual == '\'') { return lexerLerChar(lexer); } + if (atual == '.' && ehDigito(lexerEspiar(lexer, 1))) { return lexerLerNumero(lexer); } switch (atual) { - case '<': - lexerAvancar(lexer); - if (lexerEspiar(lexer, 0) == '=') { + case '<': lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_MENOR_IGUAL, inicio, linha, coluna); - } - if (lexerEspiar(lexer, 0) == '>') { + + if (lexerEspiar(lexer, 0) == '=') { + lexerAvancar(lexer); + return lexerCriarToken(lexer, TOKEN_MENOR_IGUAL, inicio, linha, coluna); + } + + if (lexerEspiar(lexer, 0) == '>') { + lexerAvancar(lexer); + return lexerCriarToken(lexer, TOKEN_DIFERENTE, inicio, linha, coluna); + } + + return lexerCriarToken(lexer, TOKEN_MENOR, inicio, linha, coluna); + case '>': lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_DIFERENTE, inicio, linha, coluna); - } - return lexerCriarToken(lexer, TOKEN_MENOR, inicio, linha, coluna); - case '>': - lexerAvancar(lexer); - if (lexerEspiar(lexer, 0) == '=') { + + if (lexerEspiar(lexer, 0) == '=') { + lexerAvancar(lexer); + return lexerCriarToken(lexer, TOKEN_MAIOR_IGUAL, inicio, linha, coluna); + } + + return lexerCriarToken(lexer, TOKEN_MAIOR, inicio, linha, coluna); + case '=': lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_MAIOR_IGUAL, inicio, linha, coluna); - } - return lexerCriarToken(lexer, TOKEN_MAIOR, inicio, linha, coluna); - case '=': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_IGUAL, inicio, linha, coluna); - case '+': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_MAIS, inicio, linha, coluna); - case '-': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_MENOS, inicio, linha, coluna); - case '*': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_MULTIPLICACAO, inicio, linha, coluna); - case '/': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_DIVISAO, inicio, linha, coluna); - case ':': - lexerAvancar(lexer); - if (lexerEspiar(lexer, 0) == '=') { + + return lexerCriarToken(lexer, TOKEN_IGUAL, inicio, linha, coluna); + case '+': lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_ATRIBUICAO, inicio, linha, coluna); - } - return lexerCriarToken(lexer, TOKEN_DOIS_PONTOS, inicio, linha, coluna); - case '(': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_ABRE_PARENTESES, inicio, linha, coluna); - case ')': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_FECHA_PARENTESES, inicio, linha, coluna); - case ',': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_VIRGULA, inicio, linha, coluna); - case ';': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_PONTO_VIRGULA, inicio, linha, coluna); - case '.': - lexerAvancar(lexer); - return lexerCriarToken(lexer, TOKEN_PONTO, inicio, linha, coluna); - default: - lexerAvancar(lexer); - return lexerErro(lexer, atual, linha, coluna); + + return lexerCriarToken(lexer, TOKEN_MAIS, inicio, linha, coluna); + case '-': + lexerAvancar(lexer); + + return lexerCriarToken(lexer, TOKEN_MENOS, inicio, linha, coluna); + case '*': + lexerAvancar(lexer); + + return lexerCriarToken(lexer, TOKEN_MULTIPLICACAO, inicio, linha, coluna); + case '/': + lexerAvancar(lexer); + + return lexerCriarToken(lexer, TOKEN_DIVISAO, inicio, linha, coluna); + case ':': + lexerAvancar(lexer); + + if (lexerEspiar(lexer, 0) == '=') { + lexerAvancar(lexer); + return lexerCriarToken(lexer, TOKEN_ATRIBUICAO, inicio, linha, coluna); + } + + return lexerCriarToken(lexer, TOKEN_DOIS_PONTOS, inicio, linha, coluna); + case '(': + lexerAvancar(lexer); + + return lexerCriarToken(lexer, TOKEN_ABRE_PARENTESES, inicio, linha, coluna); + case ')': + lexerAvancar(lexer); + + return lexerCriarToken(lexer, TOKEN_FECHA_PARENTESES, inicio, linha, coluna); + case ',': + lexerAvancar(lexer); + + return lexerCriarToken(lexer, TOKEN_VIRGULA, inicio, linha, coluna); + case ';': + lexerAvancar(lexer); + + return lexerCriarToken(lexer, TOKEN_PONTO_VIRGULA, inicio, linha, coluna); + case '.': + lexerAvancar(lexer); + + return lexerCriarToken(lexer, TOKEN_PONTO, inicio, linha, coluna); + default: + lexerAvancar(lexer); + + return lexerErro(lexer, atual, linha, coluna); } } diff --git a/src/micropascal-lexer/token.c b/src/micropascal-lexer/token.c index d6c546c..bb7e5ba 100644 --- a/src/micropascal-lexer/token.c +++ b/src/micropascal-lexer/token.c @@ -3,91 +3,91 @@ const char* tokenKindNome(TokenKind kind) { switch (kind) { - case TOKEN_EOF: - return "EOF"; - case TOKEN_IDENTIFICADOR: - return "IDENTIFICADOR"; - case TOKEN_INTEIRO_LITERAL: - return "INTEIRO_LITERAL"; - case TOKEN_REAL_LITERAL: - return "REAL_LITERAL"; - case TOKEN_CHAR_LITERAL: - return "CHAR_LITERAL"; - case TOKEN_MENOR: - return "MENOR"; - case TOKEN_MAIOR: - return "MAIOR"; - case TOKEN_MENOR_IGUAL: - return "MENOR_IGUAL"; - case TOKEN_MAIOR_IGUAL: - return "MAIOR_IGUAL"; - case TOKEN_IGUAL: - return "IGUAL"; - case TOKEN_DIFERENTE: - return "DIFERENTE"; - case TOKEN_MAIS: - return "MAIS"; - case TOKEN_MENOS: - return "MENOS"; - case TOKEN_MULTIPLICACAO: - return "MULTIPLICACAO"; - case TOKEN_DIVISAO: - return "DIVISAO"; - case TOKEN_DIV: - return "DIV"; - case TOKEN_AND: - return "AND"; - case TOKEN_OR: - return "OR"; - case TOKEN_NOT: - return "NOT"; - case TOKEN_ATRIBUICAO: - return "ATRIBUICAO"; - case TOKEN_ABRE_PARENTESES: - return "ABRE_PARENTESES"; - case TOKEN_FECHA_PARENTESES: - return "FECHA_PARENTESES"; - case TOKEN_VIRGULA: - return "VIRGULA"; - case TOKEN_PONTO_VIRGULA: - return "PONTO_VIRGULA"; - case TOKEN_PONTO: - return "PONTO"; - case TOKEN_DOIS_PONTOS: - return "DOIS_PONTOS"; - case TOKEN_PROGRAM: - return "PROGRAM"; - case TOKEN_IF: - return "IF"; - case TOKEN_THEN: - return "THEN"; - case TOKEN_ELSE: - return "ELSE"; - case TOKEN_WHILE: - return "WHILE"; - case TOKEN_DO: - return "DO"; - case TOKEN_REPEAT: - return "REPEAT"; - case TOKEN_UNTIL: - return "UNTIL"; - case TOKEN_INTEGER: - return "INTEGER"; - case TOKEN_REAL: - return "REAL"; - case TOKEN_CHAR: - return "CHAR"; - case TOKEN_BEGIN: - return "BEGIN"; - case TOKEN_END: - return "END"; - case TOKEN_WRITE: - return "WRITE"; - case TOKEN_VAR: - return "VAR"; - case TOKEN_ERRO: - return "ERRO"; - default: - return "DESCONHECIDO"; + case TOKEN_EOF: + return "EOF"; + case TOKEN_IDENTIFICADOR: + return "IDENTIFICADOR"; + case TOKEN_INTEIRO_LITERAL: + return "INTEIRO_LITERAL"; + case TOKEN_REAL_LITERAL: + return "REAL_LITERAL"; + case TOKEN_CHAR_LITERAL: + return "CHAR_LITERAL"; + case TOKEN_MENOR: + return "MENOR"; + case TOKEN_MAIOR: + return "MAIOR"; + case TOKEN_MENOR_IGUAL: + return "MENOR_IGUAL"; + case TOKEN_MAIOR_IGUAL: + return "MAIOR_IGUAL"; + case TOKEN_IGUAL: + return "IGUAL"; + case TOKEN_DIFERENTE: + return "DIFERENTE"; + case TOKEN_MAIS: + return "MAIS"; + case TOKEN_MENOS: + return "MENOS"; + case TOKEN_MULTIPLICACAO: + return "MULTIPLICACAO"; + case TOKEN_DIVISAO: + return "DIVISAO"; + case TOKEN_DIV: + return "DIV"; + case TOKEN_AND: + return "AND"; + case TOKEN_OR: + return "OR"; + case TOKEN_NOT: + return "NOT"; + case TOKEN_ATRIBUICAO: + return "ATRIBUICAO"; + case TOKEN_ABRE_PARENTESES: + return "ABRE_PARENTESES"; + case TOKEN_FECHA_PARENTESES: + return "FECHA_PARENTESES"; + case TOKEN_VIRGULA: + return "VIRGULA"; + case TOKEN_PONTO_VIRGULA: + return "PONTO_VIRGULA"; + case TOKEN_PONTO: + return "PONTO"; + case TOKEN_DOIS_PONTOS: + return "DOIS_PONTOS"; + case TOKEN_PROGRAM: + return "PROGRAM"; + case TOKEN_IF: + return "IF"; + case TOKEN_THEN: + return "THEN"; + case TOKEN_ELSE: + return "ELSE"; + case TOKEN_WHILE: + return "WHILE"; + case TOKEN_DO: + return "DO"; + case TOKEN_REPEAT: + return "REPEAT"; + case TOKEN_UNTIL: + return "UNTIL"; + case TOKEN_INTEGER: + return "INTEGER"; + case TOKEN_REAL: + return "REAL"; + case TOKEN_CHAR: + return "CHAR"; + case TOKEN_BEGIN: + return "BEGIN"; + case TOKEN_END: + return "END"; + case TOKEN_WRITE: + return "WRITE"; + case TOKEN_VAR: + return "VAR"; + case TOKEN_ERRO: + return "ERRO"; + default: + return "DESCONHECIDO"; } } diff --git a/src/micropascal-parser/ast.c b/src/micropascal-parser/ast.c index 59c14a6..0202e39 100644 --- a/src/micropascal-parser/ast.c +++ b/src/micropascal-parser/ast.c @@ -11,38 +11,38 @@ void astImprimir(const AstNo* no, int profundidade); static const char* astKindNome(AstKind kind) { switch (kind) { - case AST_PROGRAMA: - return "Programa"; - case AST_SECAO_VAR: - return "SecaoVar"; - case AST_DECL_VAR: - return "DeclVar"; - case AST_TIPO: - return "Tipo"; - case AST_BLOCO: - return "Bloco"; - case AST_LISTA_COMANDOS: - return "ListaComandos"; - case AST_ATRIBUICAO: - return "Atribuicao"; - case AST_ITERACAO: - return "Iteracao"; - case AST_DECISAO: - return "Decisao"; - case AST_ESCRITA: - return "Escrita"; - case AST_EXPRESSAO_BINARIA: - return "ExpressaoBinaria"; - case AST_EXPRESSAO_UNARIA: - return "ExpressaoUnaria"; - case AST_EXPRESSAO_PARENTESES: - return "ExpressaoParenteses"; - case AST_EXPRESSAO_LITERAL: - return "ExpressaoLiteral"; - case AST_EXPRESSAO_IDENTIFICADOR: - return "ExpressaoIdentificador"; - default: - return "Desconhecido"; + case AST_PROGRAMA: + return "Programa"; + case AST_SECAO_VAR: + return "SecaoVar"; + case AST_DECL_VAR: + return "DeclVar"; + case AST_TIPO: + return "Tipo"; + case AST_BLOCO: + return "Bloco"; + case AST_LISTA_COMANDOS: + return "ListaComandos"; + case AST_ATRIBUICAO: + return "Atribuicao"; + case AST_ITERACAO: + return "Iteracao"; + case AST_DECISAO: + return "Decisao"; + case AST_ESCRITA: + return "Escrita"; + case AST_EXPRESSAO_BINARIA: + return "ExpressaoBinaria"; + case AST_EXPRESSAO_UNARIA: + return "ExpressaoUnaria"; + case AST_EXPRESSAO_PARENTESES: + return "ExpressaoParenteses"; + case AST_EXPRESSAO_LITERAL: + return "ExpressaoLiteral"; + case AST_EXPRESSAO_IDENTIFICADOR: + return "ExpressaoIdentificador"; + default: + return "Desconhecido"; } } @@ -51,13 +51,16 @@ void astLiberar(AstNo* no) if (no == NULL) { return; } + astLiberar(no->esquerda); astLiberar(no->direita); astLiberar(no->terceiro); astLiberar(no->proximo); + if (no->valor != NULL) { free(no->valor); } + free(no); } @@ -65,20 +68,26 @@ void astImprimir(const AstNo* no, int profundidade) { int i; const AstNo* atual; + if (no == NULL) { return; } + for (i = 0; i < profundidade; i++) { printf(" "); } + printf("%s", astKindNome(no->kind)); + if (no->valor != NULL) { printf(" (%s)", no->valor); } + printf("\n"); astImprimir(no->esquerda, profundidade + 1); astImprimir(no->direita, profundidade + 1); astImprimir(no->terceiro, profundidade + 1); + for (atual = no->proximo; atual != NULL; atual = atual->proximo) { astImprimir(atual, profundidade); } diff --git a/src/micropascal-parser/parser.c b/src/micropascal-parser/parser.c index 9c7609b..42af1c8 100644 --- a/src/micropascal-parser/parser.c +++ b/src/micropascal-parser/parser.c @@ -7,17 +7,21 @@ static AstNo* parserCriarNo(AstKind kind, const char* valor) { AstNo* no = (AstNo*)malloc(sizeof(AstNo)); + no->kind = kind; + if (valor != NULL) { no->valor = (char*)malloc(strlen(valor) + 1); strcpy(no->valor, valor); } else { no->valor = NULL; } + no->esquerda = NULL; no->direita = NULL; no->terceiro = NULL; no->proximo = NULL; + return no; } @@ -37,6 +41,7 @@ void parserInicializar(Parser* parser, Lexer* lexer) parser->houve_erro = 0; parser->total_erros = 0; parser->silencioso = 0; + parserAvancar(parser); } @@ -48,11 +53,14 @@ void parserSilenciarErros(Parser* parser, int silenciar) static void parserErro(Parser* parser) { const char* lexema = parser->atual.lexema; + if (lexema == NULL) { lexema = ""; } + parser->houve_erro = 1; parser->total_erros++; + if (!parser->silencioso) { printf("Erro de sintaxe no token [%s]\n", lexema); } @@ -69,6 +77,7 @@ static int parserConsumir(Parser* parser, TokenKind kind) parserAvancar(parser); return 1; } + return 0; } @@ -77,43 +86,50 @@ static int parserEsperar(Parser* parser, TokenKind kind) if (parserConsumir(parser, kind)) { return 1; } + parserErro(parser); + return 0; } static int parserEmInicioDeComando(Parser* parser) { switch (parser->atual.kind) { - case TOKEN_BEGIN: - case TOKEN_IDENTIFICADOR: - case TOKEN_WHILE: - case TOKEN_REPEAT: - case TOKEN_IF: - case TOKEN_WRITE: - return 1; - default: - return 0; + case TOKEN_BEGIN: + case TOKEN_IDENTIFICADOR: + case TOKEN_WHILE: + case TOKEN_REPEAT: + case TOKEN_IF: + case TOKEN_WRITE: + return 1; + default: + return 0; } } static AstNo* parserAnalisarBloco(Parser* parser); static AstNo* parserAnalisarComando(Parser* parser); static AstNo* parserAnalisarExpressao(Parser* parser); + static AstNo* parserAnalisarTipo(Parser* parser) { switch (parser->atual.kind) { - case TOKEN_INTEGER: - parserAvancar(parser); - return parserCriarNo(AST_TIPO, "integer"); - case TOKEN_REAL: - parserAvancar(parser); - return parserCriarNo(AST_TIPO, "real"); - case TOKEN_CHAR: - parserAvancar(parser); - return parserCriarNo(AST_TIPO, "char"); - default: - parserErro(parser); - return NULL; + case TOKEN_INTEGER: + parserAvancar(parser); + + return parserCriarNo(AST_TIPO, "integer"); + case TOKEN_REAL: + parserAvancar(parser); + + return parserCriarNo(AST_TIPO, "real"); + case TOKEN_CHAR: + parserAvancar(parser); + + return parserCriarNo(AST_TIPO, "char"); + default: + parserErro(parser); + + return NULL; } } @@ -128,15 +144,18 @@ static AstNo* parserAnalisarDeclVar(Parser* parser) astLiberar(decl); return NULL; } + identificador = parserCriarNo(AST_EXPRESSAO_IDENTIFICADOR, NULL); decl->esquerda = identificador; ultimo = identificador; while (parserVerificar(parser, TOKEN_VIRGULA)) { parserAvancar(parser); + if (!parserEsperar(parser, TOKEN_IDENTIFICADOR)) { return decl; } + ultimo->proximo = parserCriarNo(AST_EXPRESSAO_IDENTIFICADOR, NULL); ultimo = ultimo->proximo; } @@ -144,11 +163,14 @@ static AstNo* parserAnalisarDeclVar(Parser* parser) if (!parserEsperar(parser, TOKEN_DOIS_PONTOS)) { return decl; } + tipo = parserAnalisarTipo(parser); decl->direita = tipo; + if (!parserEsperar(parser, TOKEN_PONTO_VIRGULA)) { return decl; } + return decl; } @@ -156,69 +178,85 @@ static AstNo* parserAnalisarSecaoVar(Parser* parser) { AstNo* secao = parserCriarNo(AST_SECAO_VAR, NULL); AstNo* ultimo = NULL; + if (!parserEsperar(parser, TOKEN_VAR)) { astLiberar(secao); return NULL; } + while (parserVerificar(parser, TOKEN_IDENTIFICADOR)) { AstNo* decl = parserAnalisarDeclVar(parser); + if (decl == NULL) { break; } + if (ultimo == NULL) { secao->esquerda = decl; } else { ultimo->proximo = decl; } + ultimo = decl; } + return secao; } static AstNo* parserAnalisarExprBasica(Parser* parser) { AstNo* no; + switch (parser->atual.kind) { - case TOKEN_ABRE_PARENTESES: - parserAvancar(parser); - no = parserCriarNo(AST_EXPRESSAO_PARENTESES, NULL); - no->esquerda = parserAnalisarExpressao(parser); - parserEsperar(parser, TOKEN_FECHA_PARENTESES); - return no; - case TOKEN_NOT: - parserAvancar(parser); - no = parserCriarNo(AST_EXPRESSAO_UNARIA, "not"); - no->esquerda = parserAnalisarExprBasica(parser); - return no; - case TOKEN_INTEIRO_LITERAL: - no = parserCriarNo(AST_EXPRESSAO_LITERAL, parser->atual.lexema); - parserAvancar(parser); - return no; - case TOKEN_REAL_LITERAL: - no = parserCriarNo(AST_EXPRESSAO_LITERAL, parser->atual.lexema); - parserAvancar(parser); - return no; - case TOKEN_CHAR_LITERAL: - no = parserCriarNo(AST_EXPRESSAO_LITERAL, parser->atual.lexema); - parserAvancar(parser); - return no; - case TOKEN_IDENTIFICADOR: - no = parserCriarNo(AST_EXPRESSAO_IDENTIFICADOR, parser->atual.lexema); - parserAvancar(parser); - return no; - default: - parserErro(parser); - return NULL; + case TOKEN_ABRE_PARENTESES: + parserAvancar(parser); + no = parserCriarNo(AST_EXPRESSAO_PARENTESES, NULL); + no->esquerda = parserAnalisarExpressao(parser); + parserEsperar(parser, TOKEN_FECHA_PARENTESES); + + return no; + case TOKEN_NOT: + parserAvancar(parser); + no = parserCriarNo(AST_EXPRESSAO_UNARIA, "not"); + no->esquerda = parserAnalisarExprBasica(parser); + + return no; + case TOKEN_INTEIRO_LITERAL: + no = parserCriarNo(AST_EXPRESSAO_LITERAL, parser->atual.lexema); + parserAvancar(parser); + + return no; + case TOKEN_REAL_LITERAL: + no = parserCriarNo(AST_EXPRESSAO_LITERAL, parser->atual.lexema); + parserAvancar(parser); + + return no; + case TOKEN_CHAR_LITERAL: + no = parserCriarNo(AST_EXPRESSAO_LITERAL, parser->atual.lexema); + parserAvancar(parser); + + return no; + case TOKEN_IDENTIFICADOR: + no = parserCriarNo(AST_EXPRESSAO_IDENTIFICADOR, parser->atual.lexema); + parserAvancar(parser); + + return no; + default: + parserErro(parser); + + return NULL; } } static AstNo* parserAnalisarExpMul(Parser* parser) { AstNo* esquerda = parserAnalisarExprBasica(parser); + while (parser->atual.kind == TOKEN_MULTIPLICACAO || parser->atual.kind == TOKEN_DIVISAO || parser->atual.kind == TOKEN_DIV) { char operador[8]; AstNo* direita; AstNo* novo; + strcpy(operador, parser->atual.lexema); parserAvancar(parser); direita = parserAnalisarExprBasica(parser); @@ -227,16 +265,19 @@ static AstNo* parserAnalisarExpMul(Parser* parser) novo->direita = direita; esquerda = novo; } + return esquerda; } static AstNo* parserAnalisarExpAd(Parser* parser) { AstNo* esquerda = parserAnalisarExpMul(parser); + while (parser->atual.kind == TOKEN_MAIS || parser->atual.kind == TOKEN_MENOS) { char operador[8]; AstNo* direita; AstNo* novo; + strcpy(operador, parser->atual.lexema); parserAvancar(parser); direita = parserAnalisarExpMul(parser); @@ -245,16 +286,19 @@ static AstNo* parserAnalisarExpAd(Parser* parser) novo->direita = direita; esquerda = novo; } + return esquerda; } static AstNo* parserAnalisarExpRel(Parser* parser) { AstNo* esquerda = parserAnalisarExpAd(parser); + while (parser->atual.kind == TOKEN_IGUAL || parser->atual.kind == TOKEN_DIFERENTE || parser->atual.kind == TOKEN_MENOR || parser->atual.kind == TOKEN_MAIOR || parser->atual.kind == TOKEN_MENOR_IGUAL || parser->atual.kind == TOKEN_MAIOR_IGUAL) { char operador[8]; AstNo* direita; AstNo* novo; + strcpy(operador, parser->atual.lexema); parserAvancar(parser); direita = parserAnalisarExpAd(parser); @@ -263,16 +307,19 @@ static AstNo* parserAnalisarExpRel(Parser* parser) novo->direita = direita; esquerda = novo; } + return esquerda; } static AstNo* parserAnalisarExpOrAnd(Parser* parser) { AstNo* esquerda = parserAnalisarExpRel(parser); + while (parser->atual.kind == TOKEN_OR || parser->atual.kind == TOKEN_AND) { char operador[8]; AstNo* direita; AstNo* novo; + strcpy(operador, parser->atual.lexema); parserAvancar(parser); direita = parserAnalisarExpRel(parser); @@ -281,6 +328,7 @@ static AstNo* parserAnalisarExpOrAnd(Parser* parser) novo->direita = direita; esquerda = novo; } + return esquerda; } @@ -292,82 +340,98 @@ static AstNo* parserAnalisarExpressao(Parser* parser) static AstNo* parserAnalisarAtribuicao(Parser* parser) { AstNo* no = parserCriarNo(AST_ATRIBUICAO, parser->atual.lexema); + parserAvancar(parser); + if (!parserEsperar(parser, TOKEN_ATRIBUICAO)) { return no; } + no->esquerda = parserAnalisarExpressao(parser); parserEsperar(parser, TOKEN_PONTO_VIRGULA); + return no; } static AstNo* parserAnalisarIteracao(Parser* parser) { AstNo* no; + if (parser->atual.kind == TOKEN_WHILE) { parserAvancar(parser); no = parserCriarNo(AST_ITERACAO, "while"); no->esquerda = parserAnalisarExpressao(parser); parserEsperar(parser, TOKEN_DO); no->direita = parserAnalisarComando(parser); + return no; } + parserAvancar(parser); no = parserCriarNo(AST_ITERACAO, "repeat"); no->esquerda = parserAnalisarComando(parser); parserEsperar(parser, TOKEN_UNTIL); no->direita = parserAnalisarExpressao(parser); parserEsperar(parser, TOKEN_PONTO_VIRGULA); + return no; } static AstNo* parserAnalisarDecisao(Parser* parser) { AstNo* no; + parserAvancar(parser); no = parserCriarNo(AST_DECISAO, NULL); no->esquerda = parserAnalisarExpressao(parser); parserEsperar(parser, TOKEN_THEN); no->direita = parserAnalisarComando(parser); + if (parserVerificar(parser, TOKEN_ELSE)) { parserAvancar(parser); no->terceiro = parserAnalisarComando(parser); } + return no; } static AstNo* parserAnalisarEscrita(Parser* parser) { AstNo* no; + parserAvancar(parser); no = parserCriarNo(AST_ESCRITA, NULL); parserEsperar(parser, TOKEN_ABRE_PARENTESES); no->esquerda = parserAnalisarExpressao(parser); parserEsperar(parser, TOKEN_FECHA_PARENTESES); parserEsperar(parser, TOKEN_PONTO_VIRGULA); + return no; } static AstNo* parserAnalisarComando(Parser* parser) { switch (parser->atual.kind) { - case TOKEN_BEGIN: { - AstNo* bloco = parserAnalisarBloco(parser); - parserEsperar(parser, TOKEN_PONTO_VIRGULA); - return bloco; - } - case TOKEN_IDENTIFICADOR: - return parserAnalisarAtribuicao(parser); - case TOKEN_WHILE: - case TOKEN_REPEAT: - return parserAnalisarIteracao(parser); - case TOKEN_IF: - return parserAnalisarDecisao(parser); - case TOKEN_WRITE: - return parserAnalisarEscrita(parser); - default: - parserErro(parser); - return NULL; + case TOKEN_BEGIN: { + AstNo* bloco = parserAnalisarBloco(parser); + + parserEsperar(parser, TOKEN_PONTO_VIRGULA); + + return bloco; + } + case TOKEN_IDENTIFICADOR: + return parserAnalisarAtribuicao(parser); + case TOKEN_WHILE: + case TOKEN_REPEAT: + return parserAnalisarIteracao(parser); + case TOKEN_IF: + return parserAnalisarDecisao(parser); + case TOKEN_WRITE: + return parserAnalisarEscrita(parser); + default: + parserErro(parser); + + return NULL; } } @@ -382,20 +446,26 @@ static AstNo* parserAnalisarBloco(Parser* parser) astLiberar(lista); return NULL; } + while (parserEmInicioDeComando(parser)) { AstNo* comando = parserAnalisarComando(parser); + if (comando == NULL) { break; } + if (ultimo == NULL) { lista->esquerda = comando; } else { ultimo->proximo = comando; } + ultimo = comando; } + parserEsperar(parser, TOKEN_END); bloco->esquerda = lista; + return bloco; } @@ -407,6 +477,7 @@ AstNo* parserAnalisarPrograma(Parser* parser) astLiberar(programa); return NULL; } + if (parserVerificar(parser, TOKEN_IDENTIFICADOR)) { free(programa->valor); programa->valor = (char*)malloc(strlen(parser->atual.lexema) + 1); @@ -415,14 +486,19 @@ AstNo* parserAnalisarPrograma(Parser* parser) } else { parserErro(parser); } + parserEsperar(parser, TOKEN_PONTO_VIRGULA); + if (parserVerificar(parser, TOKEN_VAR)) { programa->esquerda = parserAnalisarSecaoVar(parser); } + programa->direita = parserAnalisarBloco(parser); parserEsperar(parser, TOKEN_PONTO); + if (!parserVerificar(parser, TOKEN_EOF)) { parserErro(parser); } + return programa; }