Files
micro-pascal/src/micropascal-parser/parser.c
T
2026-10-06 23:05:44 +00:00

505 lines
12 KiB
C

#include "micropascal-parser/parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}
static void parserAvancar(Parser* parser)
{
tokenLiberar(&parser->atual);
parser->atual = lexerProximoToken(parser->lexer);
}
void parserInicializar(Parser* parser, Lexer* lexer)
{
parser->lexer = lexer;
parser->atual.kind = TOKEN_EOF;
parser->atual.lexema = NULL;
parser->atual.linha = 0;
parser->atual.coluna = 0;
parser->houve_erro = 0;
parser->total_erros = 0;
parser->silencioso = 0;
parserAvancar(parser);
}
void parserSilenciarErros(Parser* parser, int silenciar)
{
parser->silencioso = 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);
}
}
static int parserVerificar(Parser* parser, TokenKind kind)
{
return parser->atual.kind == kind;
}
static int parserConsumir(Parser* parser, TokenKind kind)
{
if (parserVerificar(parser, kind)) {
parserAvancar(parser);
return 1;
}
return 0;
}
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;
}
}
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;
}
}
static AstNo* parserAnalisarDeclVar(Parser* parser)
{
AstNo* decl = parserCriarNo(AST_DECL_VAR, NULL);
AstNo* ultimo = NULL;
AstNo* identificador;
AstNo* tipo;
if (!parserEsperar(parser, TOKEN_IDENTIFICADOR)) {
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;
}
if (!parserEsperar(parser, TOKEN_DOIS_PONTOS)) {
return decl;
}
tipo = parserAnalisarTipo(parser);
decl->direita = tipo;
if (!parserEsperar(parser, TOKEN_PONTO_VIRGULA)) {
return decl;
}
return decl;
}
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;
}
}
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);
novo = parserCriarNo(AST_EXPRESSAO_BINARIA, operador);
novo->esquerda = esquerda;
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);
novo = parserCriarNo(AST_EXPRESSAO_BINARIA, operador);
novo->esquerda = esquerda;
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);
novo = parserCriarNo(AST_EXPRESSAO_BINARIA, operador);
novo->esquerda = esquerda;
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);
novo = parserCriarNo(AST_EXPRESSAO_BINARIA, operador);
novo->esquerda = esquerda;
novo->direita = direita;
esquerda = novo;
}
return esquerda;
}
static AstNo* parserAnalisarExpressao(Parser* parser)
{
return parserAnalisarExpOrAnd(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;
}
}
static AstNo* parserAnalisarBloco(Parser* parser)
{
AstNo* bloco = parserCriarNo(AST_BLOCO, NULL);
AstNo* lista = parserCriarNo(AST_LISTA_COMANDOS, NULL);
AstNo* ultimo = NULL;
if (!parserEsperar(parser, TOKEN_BEGIN)) {
astLiberar(bloco);
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;
}
AstNo* parserAnalisarPrograma(Parser* parser)
{
AstNo* programa = parserCriarNo(AST_PROGRAMA, NULL);
if (!parserEsperar(parser, TOKEN_PROGRAM)) {
astLiberar(programa);
return NULL;
}
if (parserVerificar(parser, TOKEN_IDENTIFICADOR)) {
free(programa->valor);
programa->valor = (char*)malloc(strlen(parser->atual.lexema) + 1);
strcpy(programa->valor, parser->atual.lexema);
parserAvancar(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;
}