First commit
This commit is contained in:
commit
3d68783535
25 files changed
+1751
No files matched your search
+103
@@ -0,0 +1,103 @@
|
||||
#include "micropascal-lexer/lexer.h"
|
||||
#include "micropascal-parser/parser.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* caminho;
|
||||
const char* modo;
|
||||
char* fonte;
|
||||
long tamanho = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Uso: micropascal <arquivo> [--tokens|--ast]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (strcmp(modo, "--tokens") == 0) {
|
||||
imprimirTokens(fonte);
|
||||
free(fonte);
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
#include "micropascal-lexer/lexer.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void lexerInicializar(Lexer* lexer, const char* fonte)
|
||||
{
|
||||
lexer->fonte = fonte;
|
||||
lexer->tamanho = strlen(fonte);
|
||||
lexer->posicao = 0;
|
||||
lexer->linha = 1;
|
||||
lexer->coluna = 1;
|
||||
lexer->houve_erro = 0;
|
||||
}
|
||||
|
||||
static int lexerAcabou(const Lexer* lexer)
|
||||
{
|
||||
return lexer->posicao >= lexer->tamanho;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int ehLetra(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
||||
}
|
||||
|
||||
static int ehDigito(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static Token lexerLerIdentificador(Lexer* lexer)
|
||||
{
|
||||
size_t inicio = lexer->posicao;
|
||||
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;
|
||||
}
|
||||
|
||||
static Token lexerLerNumero(Lexer* lexer)
|
||||
{
|
||||
size_t inicio = lexer->posicao;
|
||||
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);
|
||||
}
|
||||
|
||||
static Token lexerLerChar(Lexer* lexer)
|
||||
{
|
||||
size_t inicio = lexer->posicao;
|
||||
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);
|
||||
} else {
|
||||
return lexerErro(lexer, conteudo, linha, coluna);
|
||||
}
|
||||
} else if (ehLetra(conteudo) || ehDigito(conteudo)) {
|
||||
lexerAvancar(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);
|
||||
}
|
||||
|
||||
Token lexerProximoToken(Lexer* lexer)
|
||||
{
|
||||
size_t inicio;
|
||||
int linha;
|
||||
int coluna;
|
||||
char atual;
|
||||
Token token;
|
||||
|
||||
while (!lexerAcabou(lexer)) {
|
||||
atual = lexerEspiar(lexer, 0);
|
||||
if (atual == ' ' || atual == '\n' || atual == '\t' || atual == '\r') {
|
||||
lexerAvancar(lexer);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (lexerAcabou(lexer)) {
|
||||
token.kind = TOKEN_EOF;
|
||||
token.lexema = lexerCopiarIntervalo(lexer, lexer->posicao, lexer->posicao);
|
||||
token.linha = lexer->linha;
|
||||
token.coluna = lexer->coluna;
|
||||
return token;
|
||||
}
|
||||
|
||||
inicio = lexer->posicao;
|
||||
linha = lexer->linha;
|
||||
coluna = lexer->coluna;
|
||||
atual = lexerEspiar(lexer, 0);
|
||||
|
||||
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) == '=') {
|
||||
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);
|
||||
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_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) == '=') {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void tokenLiberar(Token* token)
|
||||
{
|
||||
if (token->lexema != NULL) {
|
||||
free(token->lexema);
|
||||
token->lexema = NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "micropascal-lexer/token.h"
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "micropascal-parser/ast.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void astLiberar(AstNo* no);
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
#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;
|
||||
}
|
||||
Reference in new issue
Block a user