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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install gcc flex bison libfl-dev -y
sudo apt-get install gcc flex bison libfl-dev libasan8 libubsan1 -y

- name: Build Brainrot
run: |
Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:
- name: Install Python and dependencies
run: |
sudo apt-get update
sudo apt-get install python3 python3-pip valgrind -y
sudo apt-get install python3 python3-pip valgrind libfl-dev libasan8 libubsan1 -y
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ FLEX := flex
PYTHON := python3

# Compiler and linker flags
CFLAGS := -Wall -Wextra -Wpedantic -Werror -O2 -Wuninitialized
CFLAGS := -Wall -Wextra -Wpedantic -Werror -O2 -Wuninitialized -fsanitize=address,undefined -fno-omit-frame-pointer -g
LDFLAGS := -lfl -lm -ldl -rdynamic
SO_CFLAGS := -fPIC -shared

Expand Down
2 changes: 2 additions & 0 deletions lib/string_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ typedef struct {
size_t len;
} String;

#define STRING_LITERAL(s) ((String){ .data = (s), .len = sizeof(s) - 1 })

#endif
66 changes: 31 additions & 35 deletions semantic_analyzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,22 +106,18 @@ bool semantic_analyze(ASTNode *root) {
}

/* Add a semantic error */
void add_semantic_error(SemanticAnalyzer *analyzer, SemanticErrorType type,
char *message, int line_number) {
if (!analyzer || !message) return;
void add_semantic_error(SemanticAnalyzer *analyzer, SemanticErrorType type,
String message, int line_number) {
if (!analyzer || !message.data) return;

SemanticError *error = SAFE_MALLOC(SemanticError);
if (!error) return;

error->type = type;
String s = {
.data = message,
.len = MAX_BUFFER_LEN
};
error->message = safe_strdup(&s);
error->message = safe_strdup(&message);
error->line_number = (line_number > 0) ? line_number : 1;
error->next = analyzer->errors;

analyzer->errors = error;
analyzer->has_errors = true;
analyzer->error_count++;
Expand Down Expand Up @@ -411,7 +407,7 @@ bool validate_binary_operation(ASTNode *left, ASTNode *right, OperatorType op, S
return true;
}
add_semantic_error(analyzer, SEMANTIC_ERROR_TYPE_MISMATCH,
"Invalid pointer arithmetic", 1);
STRING_LITERAL("Invalid pointer arithmetic"), 1);
return false;
}
/* fallthrough */
Expand All @@ -432,7 +428,7 @@ bool validate_binary_operation(ASTNode *left, ASTNode *right, OperatorType op, S
snprintf(error_msg, sizeof(error_msg),
"Arithmetic operation requires numeric types, got %s and %s",
vartype_to_string(left_type), vartype_to_string(right_type));
add_semantic_error(analyzer, SEMANTIC_ERROR_TYPE_MISMATCH, error_msg, 1);
add_semantic_error(analyzer, SEMANTIC_ERROR_TYPE_MISMATCH, STRING_LITERAL(error_msg), 1);
return false;
}
return true; /* Allow most numeric combinations */
Expand Down Expand Up @@ -467,7 +463,7 @@ bool validate_binary_operation(ASTNode *left, ASTNode *right, OperatorType op, S
snprintf(error_msg, sizeof(error_msg),
"Relational comparison requires numeric types, got %s and %s",
vartype_to_string(left_type), vartype_to_string(right_type));
add_semantic_error(analyzer, SEMANTIC_ERROR_TYPE_MISMATCH, error_msg, 1);
add_semantic_error(analyzer, SEMANTIC_ERROR_TYPE_MISMATCH, STRING_LITERAL(error_msg), 1);
return false;
}
return true;
Expand Down Expand Up @@ -513,15 +509,15 @@ void* semantic_visit_identifier(Visitor *self, ASTNode *node) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Variable '%s' is out of scope", name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_SCOPE_ERROR,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
} else {
Variable *var = get_variable(name);
if (!var) {
if (!is_builtin_function(name)) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Undefined variable '%s'", name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_UNDEFINED_VARIABLE,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
}
}
}
Expand All @@ -543,7 +539,7 @@ void* semantic_visit_function_call(Visitor *self, ASTNode *node) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Undefined function '%s'", func_name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_UNDEFINED_FUNCTION,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
}
}

Expand Down Expand Up @@ -584,7 +580,7 @@ void semantic_visit_declaration(Visitor *self, ASTNode *node) {
"Type mismatch in initialization of '%s': expected %s, got %s",
var_name.data, vartype_to_string(declared_type), vartype_to_string(init_type));
add_semantic_error(analyzer, SEMANTIC_ERROR_TYPE_MISMATCH,
error_msg, 1);
STRING_LITERAL(error_msg), 1);
}
}
}
Expand All @@ -602,7 +598,7 @@ void semantic_visit_assignment(Visitor *self, ASTNode *node) {
ASTNode *operand = node->data.op.left->data.unary.operand;
if (infer_expression_pointer_level(operand, analyzer) <= 0) {
add_semantic_error(analyzer, SEMANTIC_ERROR_INVALID_OPERATION,
"Cannot dereference a non-pointer expression",
STRING_LITERAL("Cannot dereference a non-pointer expression"),
node->line_number > 0 ? node->line_number : 1);
return;
}
Expand All @@ -622,7 +618,7 @@ void semantic_visit_assignment(Visitor *self, ASTNode *node) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Assignment to undefined variable '%s'", var_name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_UNDEFINED_VARIABLE,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
}
return;
}
Expand All @@ -631,14 +627,14 @@ void semantic_visit_assignment(Visitor *self, ASTNode *node) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Cannot assign to const variable '%s'", var_name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_CONST_ASSIGNMENT,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
}
} else {
if (symbol->is_const) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Cannot assign to const variable '%s'", var_name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_CONST_ASSIGNMENT,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
}
}
}
Expand All @@ -649,7 +645,7 @@ void semantic_visit_assignment(Visitor *self, ASTNode *node) {
!(node->data.op.left->type == NODE_UNARY_OPERATION &&
node->data.op.left->data.unary.op == OP_DEREFERENCE)) {
add_semantic_error(analyzer, SEMANTIC_ERROR_INVALID_OPERATION,
"Left-hand side of assignment is not assignable",
STRING_LITERAL("Left-hand side of assignment is not assignable"),
node->line_number > 0 ? node->line_number : 1);
return;
}
Expand All @@ -662,7 +658,7 @@ void semantic_visit_assignment(Visitor *self, ASTNode *node) {
if ((target_pointer_level > 0 || value_pointer_level > 0) &&
!check_type_compatibility_ex(target_type, target_pointer_level, value_type, value_pointer_level)) {
add_semantic_error(analyzer, SEMANTIC_ERROR_TYPE_MISMATCH,
"Assignment type mismatch",
STRING_LITERAL("Assignment type mismatch"),
node->line_number > 0 ? node->line_number : 1);
}
}
Expand Down Expand Up @@ -756,7 +752,7 @@ void collect_declarations(SemanticAnalyzer *analyzer, ASTNode *node) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Function '%s' is already defined", node->data.function_def.name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_REDEFINITION,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
} else {
add_symbol(analyzer, node->data.function_def.name, NONE, 0, false, true,
node->data.function_def.return_type, node->pointer_level,
Expand Down Expand Up @@ -997,13 +993,13 @@ void semantic_analyze_with_scope_tracking(SemanticAnalyzer *analyzer, ASTNode *n
(operand->type == NODE_UNARY_OPERATION && operand->data.unary.op == OP_DEREFERENCE));
if (!valid_lvalue) {
add_semantic_error(analyzer, SEMANTIC_ERROR_INVALID_OPERATION,
"Address-of requires an assignable expression",
STRING_LITERAL("Address-of requires an assignable expression"),
node->line_number > 0 ? node->line_number : 1);
}
} else if (node->data.unary.op == OP_DEREFERENCE) {
if (infer_expression_pointer_level(node->data.unary.operand, analyzer) <= 0) {
add_semantic_error(analyzer, SEMANTIC_ERROR_INVALID_OPERATION,
"Cannot dereference a non-pointer expression",
STRING_LITERAL("Cannot dereference a non-pointer expression"),
node->line_number > 0 ? node->line_number : 1);
}
}
Expand All @@ -1025,7 +1021,7 @@ void semantic_analyze_with_scope_tracking(SemanticAnalyzer *analyzer, ASTNode *n
if (!var) break;
if (var->var_type != VAR_STRUCT) {
add_semantic_error(analyzer, SEMANTIC_ERROR_TYPE_MISMATCH,
"Member access on non-struct variable",
STRING_LITERAL("Member access on non-struct variable"),
node->line_number > 0 ? node->line_number : 1);
break;
}
Expand All @@ -1038,7 +1034,7 @@ void semantic_analyze_with_scope_tracking(SemanticAnalyzer *analyzer, ASTNode *n
var->struct_name.data,
node->data.struct_access.member_name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_UNDEFINED_VARIABLE,
msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(msg), node->line_number > 0 ? node->line_number : 1);
}
}
break;
Expand Down Expand Up @@ -1107,7 +1103,7 @@ void semantic_analyze_node(SemanticAnalyzer *analyzer, ASTNode *node) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Undefined variable '%s'", name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_UNDEFINED_VARIABLE,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
}
}
break;
Expand All @@ -1124,12 +1120,12 @@ void semantic_analyze_node(SemanticAnalyzer *analyzer, ASTNode *node) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Assignment to undefined variable '%s'", var_name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_UNDEFINED_VARIABLE,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
} else if (symbol && symbol->is_const) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Cannot assign to const variable '%s'", var_name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_CONST_ASSIGNMENT,
error_msg, node->line_number > 0 ? node->line_number : 1);
STRING_LITERAL(error_msg), node->line_number > 0 ? node->line_number : 1);
}
} else if (node->data.op.left->type != NODE_ARRAY_ACCESS &&
node->data.op.left->type != NODE_STRUCT_ACCESS &&
Expand Down Expand Up @@ -1240,13 +1236,13 @@ void semantic_analyze_node(SemanticAnalyzer *analyzer, ASTNode *node) {
(operand->type == NODE_UNARY_OPERATION && operand->data.unary.op == OP_DEREFERENCE));
if (!valid_lvalue) {
add_semantic_error(analyzer, SEMANTIC_ERROR_INVALID_OPERATION,
"Address-of requires an assignable expression",
STRING_LITERAL("Address-of requires an assignable expression"),
node->line_number > 0 ? node->line_number : 1);
}
} else if (node->data.unary.op == OP_DEREFERENCE) {
if (infer_expression_pointer_level(node->data.unary.operand, analyzer) <= 0) {
add_semantic_error(analyzer, SEMANTIC_ERROR_INVALID_OPERATION,
"Cannot dereference a non-pointer expression",
STRING_LITERAL("Cannot dereference a non-pointer expression"),
node->line_number > 0 ? node->line_number : 1);
}
}
Expand Down Expand Up @@ -1314,7 +1310,7 @@ bool add_semantic_variable(SemanticAnalyzer *analyzer, const String name, VarTyp
if (hm_get(analyzer->current_scope->variables, name.data, name.len + 1)) {
char error_msg[MAX_BUFFER_LEN];
snprintf(error_msg, sizeof(error_msg), "Variable '%s' already declared in current scope", name.data);
add_semantic_error(analyzer, SEMANTIC_ERROR_REDEFINITION, error_msg, 1);
add_semantic_error(analyzer, SEMANTIC_ERROR_REDEFINITION, STRING_LITERAL(error_msg), 1);
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions semantic_analyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ bool analyze_with_scopes(SemanticAnalyzer *analyzer, ASTNode *root);
void semantic_analyze_node(SemanticAnalyzer *analyzer, ASTNode *node);

/* Error reporting functions */
void add_semantic_error(SemanticAnalyzer *analyzer, SemanticErrorType type,
char *message, int line_number);
void add_semantic_error(SemanticAnalyzer *analyzer, SemanticErrorType type,
String message, int line_number);
void print_semantic_errors(SemanticAnalyzer *analyzer);
void free_semantic_errors(SemanticError *errors);

Expand Down
Loading