Skip to content
Merged
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
36 changes: 9 additions & 27 deletions config.mk
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
# Configuration for C² project
CC := gcc
CFLAGS := -std=gnu99 -Wall -Wextra -pedantic -Iinclude -D_GNU_SOURCE
LDFLAGS :=
CC = gcc
CFLAGS = -std=gnu99 -Wall -Wextra -pedantic -Iinclude -D_GNU_SOURCE -g -O0 -DDEBUG
LDFLAGS =

TARGET := csq-x86
SRCDIR = src
BUILDDIR = build
BINDIR = bin

# Directories
SRCDIR := src
INCDIR := include
BUILDDIR := build
BINDIR := bin

# Build type: debug (default) or release
# Usage: make BUILD_TYPE=release
BUILD_TYPE ?= debug

ifeq ($(BUILD_TYPE),release)
CFLAGS += -O2 -DNDEBUG
else
CFLAGS += -g -O0 -DDEBUG
endif

# Source files (automatically find all .c files in src directory)
SRCS := $(shell find $(SRCDIR) -name "*.c")
OBJS := $(patsubst $(SRCDIR)/%.c, $(BUILDDIR)/%.o, $(SRCS))

# Target binary path
TARGET := $(BINDIR)/$(TARGET)
TARGET = csq-x86
SRCS = $(shell find $(SRCDIR) -name '*.c')
OBJS = $(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%.o,$(SRCS))
3 changes: 1 addition & 2 deletions include/csquare/opt-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ typedef struct {
bool show_help;
} csq_options;

typedef void (*opt_func_t)(csq_options* opts, const char* arg);
typedef void (*opt_func_t)(csq_options *opts, const char *arg);

typedef struct {
const char *long_name;
Expand All @@ -22,7 +22,6 @@ typedef struct {
opt_func_t func;
} opt_map_t;


csq_options *options_parse(int argc, char *argv[]);
void options_free(csq_options *opts);

Expand Down
7 changes: 7 additions & 0 deletions include/csquare/tests/lexer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef _LEXER_TESTS_H
#define _LEXER_TESTS_H

int test_percent_error(void);
int test_multiple_errors(void);

#endif
40 changes: 40 additions & 0 deletions include/csquare/tests/tests.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef _TESTS_H
#define _TESTS_H

#include <stdio.h>

#define CLR_RESET "\x1b[0m"
#define CLR_RED "\x1b[31m"
#define CLR_GREEN "\x1b[32m"
#define CLR_BLUE "\x1b[34m"
#define CLR_DIM "\x1b[90m"

extern int tests_failed;

#define TEST(name) int name(void)

#define RUN_TEST(name) \
do { \
printf("Running" CLR_BLUE " %-32s" CLR_RESET, #name); \
int r = name(); \
if (r == 0) { \
printf(CLR_GREEN "[PASS]" CLR_RESET "\n"); \
} else { \
printf(CLR_RED "[FAIL]" CLR_RESET "\n\n"); \
tests_failed++; \
} \
} while (0)

#define ASSERT(cond, fmt, ...) \
do { \
if (!(cond)) { \
printf("\n " CLR_RED "Assertion failed:" CLR_RESET " "); \
printf(fmt, ##__VA_ARGS__); \
printf("\n"); \
return 1; \
} \
} while (0)

int tests_main(void);

#endif
51 changes: 41 additions & 10 deletions makefile
Original file line number Diff line number Diff line change
@@ -1,32 +1,61 @@
# =============================
# Makefile for C² Compiler
# Supports normal and test builds
# =============================

include config.mk

.PHONY: all clean directories rebuild
.PHONY: all clean rebuild info directories

# Default target
# -----------------------------
# Build targets
# -----------------------------
all: directories $(TARGET)

rebuild: clean all

directories:
@mkdir -p $(BUILDDIR) $(BINDIR) $(shell find $(SRCDIR) -type d | sed 's/$(SRCDIR)/$(BUILDDIR)/')

# Target executable
# Normal build
$(TARGET): $(OBJS)
@echo "Linking $(TARGET)"
$(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS)
$(CC) $(CFLAGS) $(OBJS) -o $(BINDIR)/$(TARGET) $(LDFLAGS)

# test build with tests
TEST_TARGET := csq-x86-test
TEST_OBJS := $(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%_test.o,$(SRCS))

$(TEST_TARGET): directories $(TEST_OBJS)
@echo "Linking test binary $(BINDIR)/$(TEST_TARGET)"
$(CC) $(CFLAGS) $(TEST_OBJS) -o $(BINDIR)/$(TEST_TARGET) $(LDFLAGS)

# Object files from C source files
# -----------------------------
# Compile source files
# -----------------------------
$(BUILDDIR)/%.o: $(SRCDIR)/%.c
@echo "Compiling $<"
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@

# Clean build artifacts
$(BUILDDIR)/%_test.o: $(SRCDIR)/%.c
@echo "Compiling test $<"
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -DCSQ_RUN_TESTS -c $< -o $@

# -----------------------------
# Token/Directory management
# -----------------------------
directories:
@mkdir -p $(BUILDDIR) $(BINDIR) $(shell find $(SRCDIR) -type d | sed 's|$(SRCDIR)|$(BUILDDIR)|')

# -----------------------------
# Cleaning
# -----------------------------
clean:
@echo "Cleaning build artifacts"
@rm -rf $(BUILDDIR) $(BINDIR)

# Print Makefile information
# -----------------------------
# test info
# -----------------------------
info:
@echo "C² Build Configuration:"
@echo " Compiler: $(CC)"
Expand All @@ -36,5 +65,7 @@ info:
@echo " Build dir: $(BUILDDIR)"
@echo " Binary dir: $(BINDIR)"
@echo " Target: $(TARGET)"
@echo " test Target: $(TEST_TARGET)"
@echo " Sources: $(SRCS)"
@echo " Objects: $(OBJS)"
@echo " test Objects: $(TEST_OBJS)"
3 changes: 1 addition & 2 deletions src/lexer/lex_symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,10 @@ token *lex_symbol(const char *p, int *len, int *line, int *col) {
best_len = 1;
best_type = T_ERROR;
*len = best_len;
*col = (*col) + (*line);
return NULL;
}

*len = best_len;
*col = (*col) + (*line);
*col = (*col) + (*len);
return new_token(p, best_len, best_type, *line, *col - *len);
}
2 changes: 1 addition & 1 deletion src/lexer/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ token_list *lex(const char *src) {
sprintf(buf, msg, c);
token *tk;
token *errtk =
error_token(strdup(buf), p, 1, line, col, SYNERR_UNKNOWN_CHARACTER);
error_token(strdup(buf), p, 1, line, col - 1, SYNERR_UNKNOWN_CHARACTER);

if (isdigit(c)) {
tk = lex_digit(p, &consumed, &line, &col);
Expand Down
11 changes: 9 additions & 2 deletions src/main.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "csquare/error.h"
#include "csquare/lexer/lexer.h"
#include "csquare/opt-common.h"
#include "csquare/tests/tests.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

Expand Down Expand Up @@ -65,6 +67,9 @@ int main(int argc, char *argv[]) {
if (!opts)
return EXIT_FAILURE;

#ifdef CSQ_RUN_TESTS
return tests_main();
#else
if (argc < 2) {
fprintf(stderr, "Usage: %s <source-file>\n", argv[0]);
return EXIT_FAILURE;
Expand Down Expand Up @@ -96,9 +101,11 @@ int main(int argc, char *argv[]) {
highlight_start, highlight_len);
print_error(&e);
}

free_token_list(lexed);
free(src);
}
#endif

free_token_list(lexed);
free(src);
return 0;
}
63 changes: 63 additions & 0 deletions src/tests/lexer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "csquare/lexer/lexer.h"
#include "csquare/tests/tests.h"
#include <stdlib.h>
#include <string.h>

TEST(test_percent_error) {
const char *src = "void main() {\n %\n}";
token_list *tokens = lex(src);

token *percent = NULL;

for (size_t i = 0; i < tokens->count; i++) {
if (tokens->tokens[i]->start[0] == '%') {
percent = tokens->tokens[i];
break;
}
}

ASSERT(percent != NULL, "Percent token not found");
ASSERT(percent->type == T_ERROR, "Percent token type not ERROR");
ASSERT(percent->line == 2, "Line mismatch (got %d, expected 2)",
percent->line);
ASSERT(percent->col == 5, "Column mismatch (got %d, expected 5)",
percent->col);

ASSERT(strcmp(percent->errmsg, "unknown character \x1b[32m'%'\x1b[0m") == 0,
"Error message mismatch (got \"%s\")", percent->errmsg);

free_token_list(tokens);
return 0;
}

TEST(test_multiple_errors) {
const char *src = "abc $ % @";
token_list *tokens = lex(src);

const char *expected_msgs[] = {"unknown character \x1b[32m'$'\x1b[0m",
"unknown character \x1b[32m'%'\x1b[0m",
"unknown character \x1b[32m'@'\x1b[0m"};

int found = 0;

for (size_t i = 0; i < tokens->count; i++) {
token *tk = tokens->tokens[i];

if (tk->type == T_ERROR) {
ASSERT(found < 3, "Too many error tokens found");

ASSERT(strcmp(tk->errmsg, expected_msgs[found]) == 0,
"Message mismatch\n"
" got: \"%s\"\n"
" expected: \"%s\"",
tk->errmsg, expected_msgs[found]);

found++;
}
}

ASSERT(found == 3, "Expected 3 error tokens, got %d", found);

free_token_list(tokens);
return 0;
}
21 changes: 21 additions & 0 deletions src/tests/tests.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "csquare/tests/tests.h"
#include "csquare/tests/lexer.h"

int tests_failed = 0;

int tests_main(void) {
printf("\n=== C² Test Suite ===\n\n");

RUN_TEST(test_multiple_errors);
RUN_TEST(test_percent_error);

printf("\n");

if (tests_failed == 0) {
printf(CLR_GREEN "All tests passed" CLR_RESET "\n\n");
return 0;
} else {
printf(CLR_RED "%d test(s) failed" CLR_RESET "\n\n", tests_failed);
return 1;
}
}
Loading