First commit

This commit is contained in:
mguinhos committed 2026-10-06 22:12:02 +00:00
commit 3d68783535
25 files changed
+1751

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
build/
*.o
*.obj
*.exe
*.out
*.stackdump
.DS_Store
Thumbs.db
desktop.ini
*.swp
*~
+51
View File
@@ -0,0 +1,51 @@
# Instruções de Implementação do Projeto Mini Pascal em C
spawna um subagente para implementar isso em C usando a estrutura micro-pascal/src/ micro-pascal/include/ e /build e Makefile use estilo K&R use typedefs para nomes dos tipos, use enums para os TokenKinds. use também AstKind e KeywordKind (enums).
prefiro que ponteiros se foram usados fiquem colados no nome do tipo, assim: Ponteiro* nome_da_variavel;
nomes de variaveis precisam ser snake_case, nomes de funções camel case e nomes de tipos PascalCase.
adicione tests/ também
os artefatos de testes ficam em build/<nome-da-arquitetura|x8|arm|etc>/.tests/...
e o build normal:
build/<nome-da-arquitetura|x86|arm|etc>/bin
o Makefile deve suportar windows e linux.
O Makefile deve ter help. build, run, test.
coloque os exemplos em examples/
lembrando que o src tem que estar bonitinho:
src/main.c
src/micropascal-lexer/...
src/micropascal-parser/...
...
o include tmb:
include/micropascal-lexer/...
src/micropascal-parser/...
.gitignore
Quando terminar e estiver funcionando, remova todos os comentários e em dashes e utf-8 do código, dos readmes, dos .gitignores e .gitkeeps.
Não se coloque como coautor, coloque a mim como autor: mguinhos@gmail.com (Marcel Guinhos; https://mguinhos.github.io/ ; https://github.com/mguinhos ; meu RA (Registro Academico) da UNICAP é 00000855041 meu email academico é marcel.00000855041@unicap.br
A disciplina é 2026.2-MINF-0203-CONSTRUCAO DE COMPILADORES-MANHÃ (SEMESTRE-TURMA-NOME DA DISCIPLINA) o nome do professor é Robinson Lins.
certifique-se de que todos os .h estão em include/
Dê um git init. nome do branch deve ser main
Dê um git commit -m "First commit"
Adicione LICENSE.md MIT
e Adicione README.md
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Marcel Guinhos
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+73
View File
@@ -0,0 +1,73 @@
ifeq ($(OS),Windows_NT)
DETECTED_OS := Windows
RM := del /Q
RMDIR := rmdir /S /Q
ARCH_RAW := $(PROCESSOR_ARCHITECTURE)
BIN_EXT := .exe
MKDIR_P = if not exist "$(1)" mkdir "$(1)"
RUN_PREFIX :=
else
DETECTED_OS := $(shell uname -s)
RM := rm -f
RMDIR := rm -rf
ARCH_RAW := $(shell uname -m)
BIN_EXT :=
MKDIR_P = mkdir -p "$(1)"
RUN_PREFIX := ./
endif
ifneq (,$(filter x86_64 amd64 AMD64 x86 i386 i486 i586 i686,$(ARCH_RAW)))
ARCH := x86
else ifneq (,$(filter aarch64 arm64 ARM64 armv7l armv6l arm,$(ARCH_RAW)))
ARCH := arm
else ifneq (,$(filter ppc64 ppc64le powerpc,$(ARCH_RAW)))
ARCH := powerpc
else
ARCH := $(ARCH_RAW)
endif
CC ?= cc
CFLAGS ?= -std=c99 -Wall -Wextra -Iinclude
BUILD_DIR := build/$(ARCH)
BIN_DIR := $(BUILD_DIR)/bin
TEST_DIR := $(BUILD_DIR)/.tests
BIN := $(BIN_DIR)/micropascal$(BIN_EXT)
TEST_BIN := $(TEST_DIR)/micropascal-tests$(BIN_EXT)
LIB_SRCS := $(wildcard src/micropascal-lexer/*.c) $(wildcard src/micropascal-parser/*.c)
APP_SRCS := src/main.c $(LIB_SRCS)
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
help:
@echo "micro-Pascal - alvos disponiveis"
@echo " make help mostra esta ajuda"
@echo " make build compila o compilador em $(BIN)"
@echo " make run compila e executa em uma amostra (ARGS=arquivo)"
@echo " make test compila e executa a suite de testes"
@echo " make clean remove o diretorio build"
build: $(BIN)
$(BIN): $(APP_SRCS)
@$(call MKDIR_P,$(BIN_DIR))
$(CC) $(CFLAGS) $(APP_SRCS) -o $(BIN)
$(TEST_BIN): $(TEST_SRCS)
@$(call MKDIR_P,$(TEST_DIR))
$(CC) $(CFLAGS) $(TEST_SRCS) -o $(TEST_BIN)
run: build
$(RUN_PREFIX)$(BIN) $(ARGS)
test: $(TEST_BIN)
$(RUN_PREFIX)$(TEST_BIN)
clean:
$(RMDIR) build
Binary file not shown.
+77
View File
@@ -0,0 +1,77 @@
# micro-Pascal
Analisadores lexico e sintatico de um compilador para a linguagem micro-Pascal,
uma versao simplificada de Pascal, implementados em C.
## Contexto academico
- Disciplina: 2026.2-MINF-0203-CONSTRUCAO DE COMPILADORES-MANHA
- Professor: Robinson Lins
- Universidade Catolica de Pernambuco (UNICAP)
## Autor
- Marcel Guinhos
- Site: https://mguinhos.github.io/
- GitHub: https://github.com/mguinhos
- RA UNICAP: 00000855041
- Email academico: marcel.00000855041@unicap.br
## Estrutura do projeto
```
micro-pascal/
include/
micropascal-lexer/ cabecalhos do lexer (token.h, lexer.h)
micropascal-parser/ cabecalhos do parser (ast.h, parser.h)
micropascal-tests/ cabecalho auxiliar dos testes
src/
main.c ponto de entrada
micropascal-lexer/ implementacao do lexer
micropascal-parser/ implementacao do parser e da AST
tests/ codigo dos testes automatizados
examples/ programas de exemplo em micro-Pascal
Makefile build para Linux e Windows
```
Todos os arquivos de cabecalho residem em include/.
## Uso
```
make help mostra a ajuda
make build compila o compilador
make run compila e executa em examples/testaparidade.pas
make test compila e executa a suite de testes
make clean remove o diretorio build
```
Os binarios ficam em build/<arquitetura>/bin e os artefatos de teste em
build/<arquitetura>/.tests.
Para usar outro programa de entrada:
```
make run ARGS=examples/somaimpares.pas
```
Para imprimir apenas a sequencia de tokens:
```
build/x86/bin/micropascal examples/testaparidade.pas --tokens
```
## Escopo
- Analise lexica completa, com todos os tokens da especificacao.
- Analise sintatica por descida recursiva, com a precedencia e a
associatividade definidas na especificacao.
Mensagens de erro:
- Léxico: Erro léxico no caracter [x]
- Sintático: Erro de sintaxe no token [lexema]
## Licenca
MIT. Veja LICENSE.md.
+9
View File
@@ -0,0 +1,9 @@
program Contador;
var
i : integer;
begin
i := 0;
repeat
i := i + 1;
until i >= 10;
end.
+6
View File
@@ -0,0 +1,6 @@
program Erro;
var
x : integer
begin
x := 1;
end.
+14
View File
@@ -0,0 +1,14 @@
program Logica;
var
a, b, c : integer;
begin
a := 1;
b := 2;
c := 3;
if not a = b and c <> a or a <= c then
write('o')
;
while a < b do
a := a + 1
;
end.
+17
View File
@@ -0,0 +1,17 @@
program SomaImpares;
var
n : integer;
i, proximoImpar, soma : integer;
begin
n := 4;
i := 0;
soma := 0;
while i < n do
begin
proximoImpar := 2*i + 1;
soma := soma + proximoImpar;
i := i + 1;
end;
write(soma);
write('\n');
end.
+12
View File
@@ -0,0 +1,12 @@
program TestaParidade;
var
n : integer;
begin
n := 2 * 13 + 5;
if n = (n div 2)*2 then
write('p')
;
else
write('i')
;
end.
+15
View File
@@ -0,0 +1,15 @@
program Tipos;
var
a, b : integer;
c : real;
d : char;
begin
a := 1;
b := 2;
c := 1.5 + 2.5 * 2.0;
d := 'x';
write(a);
write(b);
write(c);
write(d);
end.
+19
View File
@@ -0,0 +1,19 @@
#ifndef MICROPASCAL_LEXER_LEXER_H
#define MICROPASCAL_LEXER_LEXER_H
#include "micropascal-lexer/token.h"
typedef struct Lexer {
const char* fonte;
size_t tamanho;
size_t posicao;
int linha;
int coluna;
int houve_erro;
} Lexer;
void lexerInicializar(Lexer* lexer, const char* fonte);
Token lexerProximoToken(Lexer* lexer);
void tokenLiberar(Token* token);
#endif
+60
View File
@@ -0,0 +1,60 @@
#ifndef MICROPASCAL_LEXER_TOKEN_H
#define MICROPASCAL_LEXER_TOKEN_H
#include <stddef.h>
typedef enum TokenKind {
TOKEN_EOF,
TOKEN_IDENTIFICADOR,
TOKEN_INTEIRO_LITERAL,
TOKEN_REAL_LITERAL,
TOKEN_CHAR_LITERAL,
TOKEN_MENOR,
TOKEN_MAIOR,
TOKEN_MENOR_IGUAL,
TOKEN_MAIOR_IGUAL,
TOKEN_IGUAL,
TOKEN_DIFERENTE,
TOKEN_MAIS,
TOKEN_MENOS,
TOKEN_MULTIPLICACAO,
TOKEN_DIVISAO,
TOKEN_DIV,
TOKEN_AND,
TOKEN_OR,
TOKEN_NOT,
TOKEN_ATRIBUICAO,
TOKEN_ABRE_PARENTESES,
TOKEN_FECHA_PARENTESES,
TOKEN_VIRGULA,
TOKEN_PONTO_VIRGULA,
TOKEN_PONTO,
TOKEN_DOIS_PONTOS,
TOKEN_PROGRAM,
TOKEN_IF,
TOKEN_THEN,
TOKEN_ELSE,
TOKEN_WHILE,
TOKEN_DO,
TOKEN_REPEAT,
TOKEN_UNTIL,
TOKEN_INTEGER,
TOKEN_REAL,
TOKEN_CHAR,
TOKEN_BEGIN,
TOKEN_END,
TOKEN_WRITE,
TOKEN_VAR,
TOKEN_ERRO
} TokenKind;
typedef struct Token {
TokenKind kind;
char* lexema;
int linha;
int coluna;
} Token;
const char* tokenKindNome(TokenKind kind);
#endif
+31
View File
@@ -0,0 +1,31 @@
#ifndef MICROPASCAL_PARSER_AST_H
#define MICROPASCAL_PARSER_AST_H
typedef enum AstKind {
AST_PROGRAMA,
AST_SECAO_VAR,
AST_DECL_VAR,
AST_TIPO,
AST_BLOCO,
AST_LISTA_COMANDOS,
AST_ATRIBUICAO,
AST_ITERACAO,
AST_DECISAO,
AST_ESCRITA,
AST_EXPRESSAO_BINARIA,
AST_EXPRESSAO_UNARIA,
AST_EXPRESSAO_PARENTESES,
AST_EXPRESSAO_LITERAL,
AST_EXPRESSAO_IDENTIFICADOR
} AstKind;
typedef struct AstNo {
AstKind kind;
char* valor;
struct AstNo* esquerda;
struct AstNo* direita;
struct AstNo* terceiro;
struct AstNo* proximo;
} AstNo;
#endif
+21
View File
@@ -0,0 +1,21 @@
#ifndef MICROPASCAL_PARSER_PARSER_H
#define MICROPASCAL_PARSER_PARSER_H
#include "micropascal-lexer/lexer.h"
#include "micropascal-parser/ast.h"
typedef struct Parser {
Lexer* lexer;
Token atual;
int houve_erro;
int total_erros;
int silencioso;
} Parser;
void parserInicializar(Parser* parser, Lexer* lexer);
void parserSilenciarErros(Parser* parser, int silenciar);
AstNo* parserAnalisarPrograma(Parser* parser);
void astLiberar(AstNo* no);
void astImprimir(const AstNo* no, int profundidade);
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifndef MICROPASCAL_TESTS_TESTES_H
#define MICROPASCAL_TESTS_TESTES_H
#include <stdio.h>
typedef struct ResultadoTeste {
int total;
int passaram;
int falharam;
} ResultadoTeste;
void runLexerTests(ResultadoTeste* resultado_testes);
void runParserTests(ResultadoTeste* resultado_testes);
#define TESTE_ASSERT(resultado_testes, condicao, descricao) \
do { \
(resultado_testes)->total++; \
if (condicao) { \
(resultado_testes)->passaram++; \
} else { \
(resultado_testes)->falharam++; \
printf("FALHOU: %s (linha %d)\n", descricao, __LINE__); \
} \
} while (0)
#endif
+103
View File
@@ -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;
}
+333
View File
@@ -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;
}
}
+93
View File
@@ -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";
}
}
+85
View File
@@ -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);
}
}
+428
View File
@@ -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;
}
+108
View File
@@ -0,0 +1,108 @@
#include "micropascal-tests/testes.h"
#include "micropascal-lexer/lexer.h"
#include <string.h>
static TokenKind tokenDe(const char* fonte)
{
Lexer lexer;
Token token;
lexerInicializar(&lexer, fonte);
token = lexerProximoToken(&lexer);
tokenLiberar(&token);
return token.kind;
}
static int lexemaDe(const char* fonte, const char* esperado)
{
Lexer lexer;
Token token;
int igual;
lexerInicializar(&lexer, fonte);
token = lexerProximoToken(&lexer);
igual = token.lexema != NULL && strcmp(token.lexema, esperado) == 0;
tokenLiberar(&token);
return igual;
}
static int contaTokens(const char* fonte)
{
Lexer lexer;
Token token;
int contador = 0;
lexerInicializar(&lexer, fonte);
while (1) {
token = lexerProximoToken(&lexer);
contador++;
if (token.kind == TOKEN_EOF || token.kind == TOKEN_ERRO) {
tokenLiberar(&token);
break;
}
tokenLiberar(&token);
}
return contador;
}
void runLexerTests(ResultadoTeste* resultado_testes)
{
TESTE_ASSERT(resultado_testes, tokenDe("program") == TOKEN_PROGRAM, "reconhece program");
TESTE_ASSERT(resultado_testes, tokenDe("if") == TOKEN_IF, "reconhece if");
TESTE_ASSERT(resultado_testes, tokenDe("then") == TOKEN_THEN, "reconhece then");
TESTE_ASSERT(resultado_testes, tokenDe("else") == TOKEN_ELSE, "reconhece else");
TESTE_ASSERT(resultado_testes, tokenDe("while") == TOKEN_WHILE, "reconhece while");
TESTE_ASSERT(resultado_testes, tokenDe("do") == TOKEN_DO, "reconhece do");
TESTE_ASSERT(resultado_testes, tokenDe("repeat") == TOKEN_REPEAT, "reconhece repeat");
TESTE_ASSERT(resultado_testes, tokenDe("until") == TOKEN_UNTIL, "reconhece until");
TESTE_ASSERT(resultado_testes, tokenDe("integer") == TOKEN_INTEGER, "reconhece integer");
TESTE_ASSERT(resultado_testes, tokenDe("real") == TOKEN_REAL, "reconhece real");
TESTE_ASSERT(resultado_testes, tokenDe("char") == TOKEN_CHAR, "reconhece char");
TESTE_ASSERT(resultado_testes, tokenDe("begin") == TOKEN_BEGIN, "reconhece begin");
TESTE_ASSERT(resultado_testes, tokenDe("end") == TOKEN_END, "reconhece end");
TESTE_ASSERT(resultado_testes, tokenDe("write") == TOKEN_WRITE, "reconhece write");
TESTE_ASSERT(resultado_testes, tokenDe("var") == TOKEN_VAR, "reconhece var");
TESTE_ASSERT(resultado_testes, tokenDe("div") == TOKEN_DIV, "reconhece div");
TESTE_ASSERT(resultado_testes, tokenDe("and") == TOKEN_AND, "reconhece and");
TESTE_ASSERT(resultado_testes, tokenDe("or") == TOKEN_OR, "reconhece or");
TESTE_ASSERT(resultado_testes, tokenDe("not") == TOKEN_NOT, "reconhece not");
TESTE_ASSERT(resultado_testes, tokenDe("Begin") == TOKEN_IDENTIFICADOR, "Begin nao e palavra reservada");
TESTE_ASSERT(resultado_testes, tokenDe("PROGRAM") == TOKEN_IDENTIFICADOR, "PROGRAM nao e palavra reservada");
TESTE_ASSERT(resultado_testes, tokenDe("_contador") == TOKEN_IDENTIFICADOR, "identificador com underscore");
TESTE_ASSERT(resultado_testes, tokenDe("abc123") == TOKEN_IDENTIFICADOR, "identificador alfanumerico");
TESTE_ASSERT(resultado_testes, lexemaDe("xyz", "xyz"), "lexema do identificador preservado");
TESTE_ASSERT(resultado_testes, tokenDe("123") == TOKEN_INTEIRO_LITERAL, "inteiro literal");
TESTE_ASSERT(resultado_testes, tokenDe("0") == TOKEN_INTEIRO_LITERAL, "inteiro literal zero");
TESTE_ASSERT(resultado_testes, tokenDe("3.14") == TOKEN_REAL_LITERAL, "real literal");
TESTE_ASSERT(resultado_testes, tokenDe("0.5") == TOKEN_REAL_LITERAL, "real literal com zero a esquerda");
TESTE_ASSERT(resultado_testes, tokenDe(".5") == TOKEN_REAL_LITERAL, "real literal sem parte inteira");
TESTE_ASSERT(resultado_testes, tokenDe("7.0") == TOKEN_REAL_LITERAL, "real literal inteiro");
TESTE_ASSERT(resultado_testes, tokenDe("'a'") == TOKEN_CHAR_LITERAL, "char literal letra");
TESTE_ASSERT(resultado_testes, tokenDe("'0'") == TOKEN_CHAR_LITERAL, "char literal digito");
TESTE_ASSERT(resultado_testes, tokenDe("'\\n'") == TOKEN_CHAR_LITERAL, "char literal quebra de linha");
TESTE_ASSERT(resultado_testes, tokenDe("'\\t'") == TOKEN_CHAR_LITERAL, "char literal tabulacao");
TESTE_ASSERT(resultado_testes, tokenDe("<") == TOKEN_MENOR, "menor");
TESTE_ASSERT(resultado_testes, tokenDe(">") == TOKEN_MAIOR, "maior");
TESTE_ASSERT(resultado_testes, tokenDe("<=") == TOKEN_MENOR_IGUAL, "menor ou igual");
TESTE_ASSERT(resultado_testes, tokenDe(">=") == TOKEN_MAIOR_IGUAL, "maior ou igual");
TESTE_ASSERT(resultado_testes, tokenDe("=") == TOKEN_IGUAL, "igual");
TESTE_ASSERT(resultado_testes, tokenDe("<>") == TOKEN_DIFERENTE, "diferente");
TESTE_ASSERT(resultado_testes, tokenDe("+") == TOKEN_MAIS, "mais");
TESTE_ASSERT(resultado_testes, tokenDe("-") == TOKEN_MENOS, "menos");
TESTE_ASSERT(resultado_testes, tokenDe("*") == TOKEN_MULTIPLICACAO, "multiplicacao");
TESTE_ASSERT(resultado_testes, tokenDe("/") == TOKEN_DIVISAO, "divisao de reais");
TESTE_ASSERT(resultado_testes, tokenDe(":=") == TOKEN_ATRIBUICAO, "atribuicao");
TESTE_ASSERT(resultado_testes, tokenDe("(") == TOKEN_ABRE_PARENTESES, "abre parenteses");
TESTE_ASSERT(resultado_testes, tokenDe(")") == TOKEN_FECHA_PARENTESES, "fecha parenteses");
TESTE_ASSERT(resultado_testes, tokenDe(",") == TOKEN_VIRGULA, "virgula");
TESTE_ASSERT(resultado_testes, tokenDe(";") == TOKEN_PONTO_VIRGULA, "ponto e virgula");
TESTE_ASSERT(resultado_testes, tokenDe(".") == TOKEN_PONTO, "ponto");
TESTE_ASSERT(resultado_testes, tokenDe(":") == TOKEN_DOIS_PONTOS, "dois pontos");
TESTE_ASSERT(resultado_testes, contaTokens(" \n\t\r ") == 1, "brancos ignorados resultam em EOF");
TESTE_ASSERT(resultado_testes, contaTokens("a b") == 3, "conta tokens simples");
TESTE_ASSERT(resultado_testes, tokenDe("$") == TOKEN_ERRO, "caractere invalido gera erro");
TESTE_ASSERT(resultado_testes, tokenDe("@") == TOKEN_ERRO, "arroba gera erro");
}
+27
View File
@@ -0,0 +1,27 @@
#include "micropascal-tests/testes.h"
#include <stdio.h>
int main(void)
{
ResultadoTeste resultado_testes;
resultado_testes.total = 0;
resultado_testes.passaram = 0;
resultado_testes.falharam = 0;
printf("Executando testes do lexer\n");
runLexerTests(&resultado_testes);
printf("Executando testes do parser\n");
runParserTests(&resultado_testes);
printf("\nTotal: %d | Passaram: %d | Falharam: %d\n",
resultado_testes.total,
resultado_testes.passaram,
resultado_testes.falharam);
if (resultado_testes.falharam > 0) {
return 1;
}
return 0;
}
+111
View File
@@ -0,0 +1,111 @@
#include "micropascal-tests/testes.h"
#include "micropascal-lexer/lexer.h"
#include "micropascal-parser/parser.h"
#include <string.h>
static int programaValido(const char* fonte)
{
Lexer lexer;
Parser parser;
AstNo* programa;
int valido;
lexerInicializar(&lexer, fonte);
parserInicializar(&parser, &lexer);
parserSilenciarErros(&parser, 1);
programa = parserAnalisarPrograma(&parser);
valido = !parser.houve_erro;
tokenLiberar(&parser.atual);
astLiberar(programa);
return valido;
}
static const char* PROGRAMA_SIMPLES =
"program P;\n"
"var\n"
" x : integer;\n"
"begin\n"
" x := 1;\n"
"end.\n";
static const char* PROGRAMA_PARIDADE =
"program TestaParidade;\n"
"var\n"
" n : integer;\n"
"begin\n"
" n := 2 * 13 + 5;\n"
" if n = (n div 2)*2 then\n"
" write('p')\n"
" ;\n"
" else\n"
" write('i')\n"
" ;\n"
"end.\n";
static const char* PROGRAMA_IMPARES =
"program SomaImpares;\n"
"var\n"
" n : integer;\n"
" i, proximoImpar, soma : integer;\n"
"begin\n"
" n := 4;\n"
" i := 0;\n"
" soma := 0;\n"
" while i < n do\n"
" begin\n"
" proximoImpar := 2*i + 1;\n"
" soma := soma + proximoImpar;\n"
" i := i + 1;\n"
" end;\n"
" write(soma);\n"
" write('\\n');\n"
"end.\n";
static const char* PROGRAMA_REPEAT =
"program Contador;\n"
"var\n"
" i : integer;\n"
"begin\n"
" i := 0;\n"
" repeat\n"
" i := i + 1;\n"
" until i >= 10;\n"
"end.\n";
static const char* PROGRAMA_TIPOS =
"program Tipos;\n"
"var\n"
" a, b : integer;\n"
" c : real;\n"
" d : char;\n"
"begin\n"
" a := 1;\n"
" b := 2;\n"
" c := 1.5 + 2.5;\n"
" d := 'x';\n"
"end.\n";
void runParserTests(ResultadoTeste* resultado_testes)
{
TESTE_ASSERT(resultado_testes, programaValido(PROGRAMA_SIMPLES), "programa simples valido");
TESTE_ASSERT(resultado_testes, programaValido(PROGRAMA_PARIDADE), "programa TestaParidade valido");
TESTE_ASSERT(resultado_testes, programaValido(PROGRAMA_IMPARES), "programa SomaImpares valido");
TESTE_ASSERT(resultado_testes, programaValido(PROGRAMA_REPEAT), "programa com repeat until valido");
TESTE_ASSERT(resultado_testes, programaValido(PROGRAMA_TIPOS), "programa com varios tipos valido");
TESTE_ASSERT(resultado_testes, programaValido("program P;\nbegin\n x := 1 + 2 * 3;\nend.\n"), "precedencia multiplicacao sobre soma");
TESTE_ASSERT(resultado_testes, programaValido("program P;\nbegin\n x := (1 + 2) * 3;\nend.\n"), "parenteses");
TESTE_ASSERT(resultado_testes, programaValido("program P;\nbegin\n x := not a and b or c;\nend.\n"), "operadores not and or");
TESTE_ASSERT(resultado_testes, programaValido("program P;\nbegin\n x := a = b;\nend.\n"), "igualdade");
TESTE_ASSERT(resultado_testes, programaValido("program P;\nbegin\n x := a <> b;\nend.\n"), "diferente");
TESTE_ASSERT(resultado_testes, programaValido("program P;\nbegin\n x := a <= b;\nend.\n"), "menor ou igual");
TESTE_ASSERT(resultado_testes, programaValido("program P;\nbegin\n if a then b := 1;\nend.\n"), "decisao sem else");
TESTE_ASSERT(resultado_testes, programaValido("program P;\nbegin\n while a do b := 1;\nend.\n"), "iteracao while");
TESTE_ASSERT(resultado_testes, !programaValido("program P\nbegin end.\n"), "falta ponto e virgula apos nome");
TESTE_ASSERT(resultado_testes, !programaValido("program P;\nbegin\n x := ;\nend.\n"), "expressao ausente");
TESTE_ASSERT(resultado_testes, !programaValido("program P;\nbegin\n x := 1 +\nend.\n"), "operando ausente");
TESTE_ASSERT(resultado_testes, !programaValido("program P;\nbegin\n if a then\nend.\n"), "comando ausente apos then");
TESTE_ASSERT(resultado_testes, !programaValido("program P;\nvar x integer;\nbegin end.\n"), "falta dois pontos na declaracao");
TESTE_ASSERT(resultado_testes, !programaValido("program P;\nbegin\n x := 1\nend.\n"), "falta ponto e virgula no comando");
}