Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ CC = gcc
CFLAGS = -Isrc -Wall -Wextra -std=c11 -g
LDFLAGS =

SRC = src/main.c src/lexer/lexer.c
SRC = src/main.c src/lexer/lexer.c src/parser/ast.c src/parser/parser.c
OBJ = $(SRC:.c=.o)

TARGET = eac
Expand All @@ -18,7 +18,7 @@ else
SELECTED_TEST := tests/$(TEST_GOAL)
endif

.PHONY: all clean test test-all $(TEST_GOAL)
.PHONY: all clean test test-all test-parser $(TEST_GOAL)

all: $(TARGET)

Expand All @@ -32,6 +32,30 @@ test: $(TARGET)
@echo "Running test file: $(SELECTED_TEST)"
@./$(TARGET) $(SELECTED_TEST)

test-parser: $(TARGET)
@echo "========================================================================"
@echo " EaC PARSER TESTS"
@echo "========================================================================"
@echo ""
@echo "[TEST 1] Simple Variable Declaration:"
@./$(TARGET) tests/parser/test_var_decl.eac
@echo ""
@echo "[TEST 2] Expressions and Operators:"
@./$(TARGET) tests/parser/test_expressions.eac
@echo ""
@echo "[TEST 3] Control Flow (if/while/for):"
@./$(TARGET) tests/parser/test_control_flow.eac
@echo ""
@echo "[TEST 4] Functions:"
@./$(TARGET) tests/parser/test_functions.eac
@echo ""
@echo "[TEST 5] Complete Program:"
@./$(TARGET) tests/parser/test_complete.eac
@echo ""
@echo "========================================================================"
@echo " PARSER TESTS COMPLETED"
@echo "========================================================================"

ifneq ($(TEST_GOAL),)
$(TEST_GOAL):
endif
Expand Down Expand Up @@ -101,4 +125,4 @@ clean:
@if exist $(TARGET_BIN) del /f /q $(TARGET_BIN) >nul 2>&1
@if exist $(TARGET) del /f /q $(TARGET) >nul 2>&1
@if not "$(OBJ_CLEAN)"=="" del /f /q $(OBJ_CLEAN) >nul 2>&1
@if exist output rmdir /s /q output >nul 2>&1
@if exist output rmdir /s /q output >nul 2>&1
154 changes: 115 additions & 39 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "common/token.h"
#include "lexer/lexer.h"
#include "parser/parser.h"
#include "parser/ast.h"

const char* getTokenSpecial(TokenType type) {
switch (type) {
Expand Down Expand Up @@ -158,7 +160,6 @@ bool createDirectory(const char* path) {
return true;
}


const char* extractFilename(const char* path) {
const char* filename = strrchr(path, '/');
if (filename == NULL) {
Expand All @@ -167,23 +168,21 @@ const char* extractFilename(const char* path) {
return filename ? filename + 1 : path;
}

char* generateOutputFilename(const char* inputPath) {
char* generateOutputFilename(const char* inputPath, const char* suffix) {
const char* filename = extractFilename(inputPath);
size_t len = strlen(filename);

// Create output directory
if (!createDirectory("output")) {
return NULL;
}

const char* prefix = "output/symbol_table_";
const char* prefix = "output/";
size_t prefixLen = strlen(prefix);
const char* suffix = ".txt";
size_t suffixLen = strlen(suffix);

char* output;
if (len > 4 && strcmp(filename + len - 4, ".eac") == 0) {
size_t stemLen = len - 4; // exclude .eac
size_t stemLen = len - 4;
output = (char*)malloc(prefixLen + stemLen + suffixLen + 1);
if (output == NULL) {
fprintf(stderr, "Error: Memory allocation failed.\n");
Expand Down Expand Up @@ -243,51 +242,25 @@ void printToken(FILE* outFile, Token token) {
fprintf(outFile, "%s\n", lexeme);
}

// ===== Main Program =====

int main(int argc, char* argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <source-file.eac>\n", argv[0]);
return 1;
}

const char* sourcePath = argv[1];

if (!hasEacExtension(sourcePath)) {
fprintf(stderr, "Error: Source file '%s' must have a .eac extension.\n", sourcePath);
return 1;
}

if (!createDirectory("output")) {
return 1;
}

char* outputPath = generateOutputFilename(sourcePath);
void runLexerOnly(const char* sourcePath, const char* source) {
char* outputPath = generateOutputFilename(sourcePath, "_tokens.txt");
if (outputPath == NULL) {
return 1;
}

char* source = readFile(sourcePath);
if (source == NULL) {
free(outputPath);
return 1;
return;
}

Lexer* lexer = initLexer(source);
if (lexer == NULL) {
fprintf(stderr, "Error: Failed to initialize lexer.\n");
free(source);
free(outputPath);
return 1;
return;
}

FILE* outFile = fopen(outputPath, "w");
if (outFile == NULL) {
fprintf(stderr, "Error: Could not create output file '%s'.\n", outputPath);
freeLexer(lexer);
free(source);
free(outputPath);
return 1;
return;
}

fprintf(outFile, "EaC Lexer Output\n");
Expand Down Expand Up @@ -348,8 +321,111 @@ int main(int argc, char* argv[]) {

fclose(outFile);
freeLexer(lexer);
free(source);
free(outputPath);
}

void runParser(const char* sourcePath, const char* source) {
Lexer* lexer = initLexer(source);
if (lexer == NULL) {
fprintf(stderr, "Error: Failed to initialize lexer.\n");
return;
}

Parser* parser = initParser(lexer);
if (parser == NULL) {
fprintf(stderr, "Error: Failed to initialize parser.\n");
freeLexer(lexer);
return;
}

return hasErrors ? 1 : 0;
printf("\n");
printf("==========================================================================\n");
printf("EaC Parser\n");
printf("==========================================================================\n");
printf("Source file: %s\n", sourcePath);
printf("Parsing...\n\n");

ASTNode* ast = parse(parser);

if (ast == NULL || hasError(parser)) {
printf("Status: FAILED - Parsing errors occurred\n");
printf("==========================================================================\n");
} else {
printf("Status: SUCCESS - AST generated\n");
printf("==========================================================================\n");
printf("\nAbstract Syntax Tree:\n");
printf("--------------------------------------------------------------------------\n");
printAST(ast, 0);
printf("==========================================================================\n");

// Save AST to file
char* astOutputPath = generateOutputFilename(sourcePath, "_ast.txt");
if (astOutputPath) {
FILE* astFile = fopen(astOutputPath, "w");
if (astFile) {
fprintf(astFile, "EaC Abstract Syntax Tree\n");
fprintf(astFile, "Source: %s\n", sourcePath);
fprintf(astFile, "==========================================================================\n\n");

// Redirect printAST to file (would need to modify printAST for this)
// For now, just indicate success
fprintf(astFile, "AST generated successfully.\n");
fprintf(astFile, "See console output for tree visualization.\n");

fclose(astFile);
printf("\nAST saved to: %s\n", astOutputPath);
}
free(astOutputPath);
}
}

if (ast) {
freeAST(ast);
}
freeParser(parser);
freeLexer(lexer);
}

int main(int argc, char* argv[]) {
bool parserMode = false;
const char* sourcePath = NULL;

// Parse command line arguments
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--parse") == 0 || strcmp(argv[i], "-p") == 0) {
parserMode = true;
} else {
sourcePath = argv[i];
}
}

if (sourcePath == NULL) {
fprintf(stderr, "Usage: %s [--parse|-p] <source-file.eac>\n", argv[0]);
fprintf(stderr, " --parse, -p Run parser and generate AST\n");
fprintf(stderr, " (default) Run lexer only and generate tokens\n");
return 1;
}

if (!hasEacExtension(sourcePath)) {
fprintf(stderr, "Error: Source file '%s' must have a .eac extension.\n", sourcePath);
return 1;
}

if (!createDirectory("output")) {
return 1;
}

char* source = readFile(sourcePath);
if (source == NULL) {
return 1;
}

if (parserMode) {
runParser(sourcePath, source);
} else {
runLexerOnly(sourcePath, source);
}

free(source);
return 0;
}
Loading