i have created a simple intrepeter using c flex(for lexer) and bison(for parser) i have support for variables, arrays and 2 dimentional arrays, i have created a way to include files inside the main file that will be runned by the intrepeter(my goal is to create a way for users to create librarys) and for me as the creator of the language to create a standard library for the language. my issue is that i get a Parse error: syntax error for each file i include, if i add more files then multiple Parse error: syntax error will be written after the intrepter is done with executing my code. if i dont include files then i dont get the Parse error: syntax error error, my issue is that i dont know where this problem start in my code.
i have main.c file lexer.l file, parser.y file a hashtable.c and a garbagecollection.c file with their .h files aswell, for testing the intrepeter i have a test.hussein file (will be runned by the intrepeter) and fileen.hslib and filto.hslib for the library files that will be included inside the test.hussein file
main.c:
#include "parser.tab.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern FILE *yyin;
#ifdef _WIN32
#include <windows.h>
HINSTANCE hInstance;
#endif
int main(int argc, char *argv[]) {
#ifdef _WIN32
hInstance = GetModuleHandle(NULL);
#endif
initialize_hashtable();
initialize_garbage_collection();
if (argc != 2) {
fprintf(stderr, "Usage: %s <filename.hussein>n", argv[0]);
return 1;
}
// Ensure that the file has a .hussein extension
const char *filename = argv[1];
const char *extension = strrchr(filename, '.');
if (!extension || strcmp(extension, ".hussein") != 0) {
fprintf(stderr, "Error: Only .hussein files are accepted as inputn");
return 1;
}
FILE *file = fopen(filename, "r");
if (!file) {
perror("Error opening file");
return 1;
}
yyin = file;
yyparse();
fclose(file);
//garbage_collect();
return 0;
}
parser.y:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashtable.h"
#include "garbagecollection.h"
int array_size;
int twod_array_size_row;
int twod_array_size_col;
#define YYDEBUG 1
extern int yydebug;
%}
%union {
int num;
char *str;
}
%token <str> EQUALS
%token <str> SEMICOLON
%token <str> PLUS
%token <str> MINUS
%token <str> MULTIPLY
%token <str> DIVIDE
%token LPAR
%token RPAR
%token <str> LCB
%token <str> RCB
%token <str> MAIN
%token <str> LIBDEF
%token FREEMEM
%token <str> CALL
%token VAR
%token FILENAME
%token <num> NUMBER
%token <str> IDENT
%token <str> LSB
%token <str> RSB
%token <str> COMMA
%token IMPORT
%type <num> expr
%type <str> var_declaration assignment display
%type <str> statement_list
%type <str> libprogstart
%left PLUS MINUS
%left MULTIPLY DIVIDE
%start program
%%
program: start_stmt
;
start_stmt: libprogstart mainprog
| mainprog
;
libprogstart: LIBDEF LCB statement_list RCB SEMICOLON;
mainprog: import_list_opt MAIN LCB statement_list RCB SEMICOLON
;
import_list_opt: import_list
| /* empty */
;
import_list: IMPORT_stmt_list
;
IMPORT_stmt_list: IMPORT_stmt
| IMPORT_stmt_list IMPORT_stmt
;
IMPORT_stmt: IMPORT FILENAME ;
statement_list: /* empty */
| statement_list statement SEMICOLON
;
statement: var_declaration
| assignment
| display
| freememory
;
var_declaration: IDENT LSB expr RSB { insert_array($1,$3); array_size = $3; }
| VAR IDENT { insert_variable($2); }
| IDENT LSB expr RSB LSB expr RSB { insert_2d_array($1, $3, $6); twod_array_size_col = $6; twod_array_size_row = $3; }
;
assignment: IDENT EQUALS expr %prec EQUALS { update_variable($1, $3); }
| IDENT LSB expr RSB EQUALS expr %prec EQUALS { update_array_element($1, $3, $6, array_size); }
| IDENT LSB expr RSB LSB expr RSB EQUALS expr %prec EQUALS { update_2d_array_element($1, $3, $6, $9, twod_array_size_row, twod_array_size_col); }
;
display: CALL IDENT %prec CALL { display_variable($2); }
| CALL IDENT LSB expr RSB %prec CALL { display_array_element($2, $4, array_size); }
| CALL IDENT LSB expr RSB LSB expr RSB %prec CALL { display_2d_array_element($2, $4, $7, twod_array_size_row, twod_array_size_col); }
;
freememory: FREEMEM LPAR IDENT RPAR {
void *ptr = get_memory_block_pointer($3);
if(ptr){
remove_from_garbage_collection(ptr);
}
else {
fprintf(stderr, "Error: Variable '%s' not foundn", $3);
}
}
expr: NUMBER { $$ = $1; }
| IDENT { $$ = get_variable_value($1); }
| IDENT LSB expr RSB { $$ = get_array_element_value($1, $3, array_size); }
| IDENT LSB expr RSB LSB expr RSB { $$ = get_2d_array_element_value($1, $3, $6, twod_array_size_row, twod_array_size_col); }
| expr PLUS expr { $$ = $1 + $3; }
| expr MINUS expr { $$ = $1 - $3; }
| expr MULTIPLY expr { $$ = $1 * $3; }
| expr DIVIDE expr {
if ($3 != 0) {
$$ = $1 / $3;
} else {
fprintf(stderr, "Error: Division by zeron");
$$ = 0;
}
}
| LPAR expr RPAR { $$ = $2; }
;
%%
void yyerror(const char *s) {
fprintf(stderr, "Parse error: %sn", s);
}
lexer.l:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parser.tab.h"
char* yytext;
#define MAX_INCLUDE_DEPTH 100
static FILE* file_stack[MAX_INCLUDE_DEPTH];
static int file_stack_top = -1;
void handle_include(const char* filename) {
const char *ext = strrchr(filename, '.');
if (!ext || strcmp(ext, ".hslib") != 0) {
fprintf(stderr, "Error: Invalid file extension for %s. Only .hslib files are allowed.n", filename);
exit(EXIT_FAILURE);
}
FILE* file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Error opening library file %sn", filename);
exit(EXIT_FAILURE);
}
if (file_stack_top >= MAX_INCLUDE_DEPTH - 1) {
fprintf(stderr, "Error: Maximum include depth exceededn");
exit(EXIT_FAILURE);
}
file_stack[++file_stack_top] = file;
yypush_buffer_state(yy_create_buffer(file, YY_BUF_SIZE));
printf("opening file %sn", filename);
}
void finish_include() {
if (file_stack_top >= 0) {
fclose(file_stack[file_stack_top]);
file_stack[file_stack_top] = NULL;
file_stack_top--;
yypop_buffer_state();
if (file_stack_top < 0) {
printf("closing library filen");
}
}
}
void print_debug(const char *msg) {
printf("DEBUG: %sn", msg);
}
%}
DIGIT [0-9]
WS [ tn]
IDENT [a-zA-Z_][a-zA-Z0-9_]*
%option stack
%x INCL
%%
"Import" {
BEGIN(INCL); return IMPORT;
}
<INCL>[ t]*"[a-zA-Z0-9]+.hslib" {
char filename[256];
sscanf(yytext, " "%[^"]"", filename);
handle_include(filename);
BEGIN(0);
yyparse();
return FILENAME;
}
<INCL><<EOF>> {
if (file_stack_top >= 0) {
finish_include();
}
BEGIN(0);
return 0;
}
{WS} /* Ignore whitespace */
{DIGIT}+ { yylval.num = atoi(yytext); return NUMBER; }
"Var" { return VAR; }
"Void Main()" { return MAIN; }
"Call" { return CALL; }
"Library" { return LIBDEF; }
"Free" { return FREEMEM; }
{IDENT} { yylval.str = strdup(yytext); return IDENT; }
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return MULTIPLY; }
"/" { return DIVIDE; }
"=" { return EQUALS; }
";" { return SEMICOLON; }
"(" { return LPAR; }
")" { return RPAR; }
"{" { return LCB; }
"}" { return RCB; }
"[" { return LSB; }
"]" { return RSB; }
"##".* { /* ignore comments */ }
"/#"[^#]*"#/" { print_debug("Block comment detected"); /* ignore block comments */ }
. { fprintf(stderr, "Error: Unexpected character '%s'n", yytext); }
%%
int yywrap() {
if (file_stack_top >= 0) {
finish_include();
return 0;
}
return 1;
}
hashtable.c:
#include "hashtable.h"
#include "garbagecollection.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASH_SIZE 101
struct Node *hash_table[HASH_SIZE]; // Define hash_table
unsigned int hash(const char *str) {
unsigned int hash_val = 0;
while (*str) {
hash_val = (hash_val << 5) + *str++;
}
return hash_val % HASH_SIZE;
}
void initialize_hashtable() {
for (int i = 0; i < HASH_SIZE; ++i) {
hash_table[i] = NULL;
}
}
void insert_variable(const char *name) {
unsigned int index = hash(name);
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
if (!new_node) {
fprintf(stderr, "Error: Failed to allocate memory for variable noden");
return;
}
new_node->name = strdup(name);
if (!new_node->name) {
fprintf(stderr, "Error: Failed to allocate memory for variable namen");
free(new_node);
return;
}
new_node->is_array = 0;
new_node->value = malloc(sizeof(int)); // Allocate space for single int
if (!new_node->value) {
fprintf(stderr, "Error: Failed to allocate memory for variable valuen");
free(new_node->name);
free(new_node);
return;
}
*((int *)new_node->value) = 0; // Default value
new_node->next = hash_table[index];
hash_table[index] = new_node;
}
void insert_array(const char *name, int array_size) {
unsigned int index = hash(name);
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
if (!new_node) {
fprintf(stderr, "Error: Failed to allocate memory for array noden");
return;
}
new_node->name = strdup(name);
if (!new_node->name) {
fprintf(stderr, "Error: Failed to allocate memory for array namen");
free(new_node);
return;
}
new_node->is_array = 1;
new_node->size = array_size;
new_node->value = malloc(array_size * sizeof(int)); // Allocate space for the array
if (!new_node->value) {
fprintf(stderr, "Error: Failed to allocate memory for array valuen");
free(new_node->name);
free(new_node);
return;
}
for (int i = 0; i < array_size; ++i) {
((int *)new_node->value)[i] = 0; // Default values for the array
}
new_node->next = hash_table[index];
hash_table[index] = new_node;
}
void insert_2d_array(const char *name, int rows, int cols) {
unsigned int index = hash(name);
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
if (!new_node) {
fprintf(stderr, "Error: Failed to allocate memory for 2D array noden");
return;
}
new_node->name = strdup(name);
if (!new_node->name) {
fprintf(stderr, "Error: Failed to allocate memory for 2D array namen");
free(new_node);
return;
}
new_node->is_array = 1;
new_node->rows = rows;
new_node->cols = cols;
new_node->size = rows * cols;
new_node->value = malloc(rows * sizeof(int *)); // Allocate space for rows
if (!new_node->value) {
fprintf(stderr, "Error: Failed to allocate memory for 2D array valuen");
free(new_node->name);
free(new_node);
return;
}
for (int i = 0; i < rows; ++i) {
((int **)new_node->value)[i] = malloc(cols * sizeof(int)); // Allocate space for columns
if (!((int **)new_node->value)[i]) {
fprintf(stderr, "Error: Failed to allocate memory for 2D array columnn");
// Free previously allocated memory
for (int j = 0; j < i; ++j) {
free(((int **)new_node->value)[j]);
}
free(new_node->name);
free(new_node->value);
free(new_node);
return;
}
for (int j = 0; j < cols; ++j) {
((int **)new_node->value)[i][j] = 0; // Default values for the 2D array
}
}
new_node->next = hash_table[index];
hash_table[index] = new_node;
}
void update_variable(const char *name, int value) {
unsigned int index = hash(name);
struct Node *current = hash_table[index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && !current->is_array) {
*((int *)current->value) = value;
// Track allocated memory in garbage collection
add_to_garbage_collection(current->value);
// printf("Updated variable %s to %d, added to garbage collectionn", name, value); // Debug print
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declaredn", name);
}
void update_array_element(const char *name, int index, int value, int array_size) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (index >= 0 && index < current->size) {
((int *)current->value)[index] = value;
// Track allocated memory in garbage collection
add_to_garbage_collection(&((int *)current->value)[index]);
// printf("Updated array %s[%d] to %d, added to garbage collectionn", name, index, value); // Debug print
} else {
fprintf(stderr, "Error: Array index out of boundsn");
}
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not an arrayn", name);
}
void update_2d_array_element(const char *name, int row, int col, int value, int rows, int cols) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (row >= 0 && row < current->rows && col >= 0 && col < current->cols) {
((int **)current->value)[row][col] = value;
// Track allocated memory in garbage collection
add_to_garbage_collection(&((int **)current->value)[row][col]);
// printf("Updated 2D array %s[%d][%d] to %d, added to garbage collectionn", name, row, col, value); // Debug print
} else {
fprintf(stderr, "Error: 2D Array index out of boundsn");
}
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not a 2D arrayn", name);
}
int get_variable_value(const char *name) {
unsigned int index = hash(name);
struct Node *current = hash_table[index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && !current->is_array) {
return *((int *)current->value);
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declaredn", name);
return 0; // Return a default value
}
int get_array_element_value(const char *name, int index, int array_size) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (index >= 0 && index < current->size) {
return ((int *)current->value)[index];
} else {
fprintf(stderr, "Error: Array index out of boundsn");
return 0; // Return a default value
}
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not an arrayn", name);
return 0; // Return a default value
}
int get_2d_array_element_value(const char *name, int row, int col, int rows, int cols) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (row >= 0 && row < current->rows && col >= 0 && col < current->cols) {
return ((int **)current->value)[row][col];
} else {
fprintf(stderr, "Error: 2D Array index out of boundsn");
return 0; // Return a default value
}
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not a 2D arrayn", name);
return 0; // Return a default value
}
void display_variable(const char *name) {
unsigned int index = hash(name);
struct Node *current = hash_table[index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && !current->is_array) {
printf("%s = %dn", name, *((int *)current->value));
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declaredn", name);
}
void display_array_element(const char *name, int index, int array_size) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (index >= 0 && index < current->size) {
printf("%s[%d] = %dn", name, index, ((int *)current->value)[index]);
} else {
fprintf(stderr, "Error: Array index out of boundsn");
}
return;
}
current = current->next;
}
fprintf(stderr, "Error: Variable '%s' not declared or is not an arrayn", name);
}
void display_2d_array_element(const char *name, int row, int col, int rows, int cols) {
unsigned int array_index = hash(name);
struct Node *current = hash_table[array_index];
while (current != NULL) {
if (strcmp(current->name, name) == 0 && current->is_array) {
if (row >= 0 && row < current->rows && col >= 0 && col < current->cols) {
printf("%s[%d][%d] = %dn", name, row, col, ((int **)current->value)[row][col]);
} else {
fprintf(stderr, "Error: 2D Array index out of boundsn");
}
return;
}
current = current->next;
}
}
hashtable.h:
// hashtable.h
// Copyright (c) 2023 HusseinSharp(H#)
#ifndef HASHTABLE_H
#define HASHTABLE_H
#define HASH_SIZE 101
struct Node {
char *name;
int is_array; // Indicates whether the variable is an array
void *value; // Value can be int or int array
int size; // Size of the array
int rows;
int cols;
struct Node *next;
};
extern struct Node *hash_table[HASH_SIZE]; // Declare hash_table as external
unsigned int hash(const char *str); // Ensure the hash function is declared
void initialize_hashtable();
void insert_variable(const char *name);
void insert_array(const char *name, int array_size);
void insert_2d_array(const char *name, int rows, int cols);
void update_variable(const char *name, int value);
void update_array_element(const char *name, int index, int value, int array_size);
void update_2d_array_element(const char *name, int row, int col, int value,int rows ,int cols);
int get_variable_value(const char *name);
int get_array_element_value(const char *name, int index, int array_size);
int get_2d_array_element_value(const char *name, int row, int col,int rows,int cols);
void display_variable(const char *name);
void display_array_element(const char *name, int index, int array_size);
void display_2d_array_element(const char *name, int row, int col,int rows,int cols);
#endif // HASHTABLE_H
garbagecollection.c:
#include "garbagecollection.h"
#include "hashtable.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Definition for the garbage collection linked list
static struct MemoryBlock *garbage_collection = NULL;
// Function to initialize garbage collection
void initialize_garbage_collection() {
garbage_collection = NULL;
}
// Function to add a memory block to the garbage collection list
void add_to_garbage_collection(void *ptr) {
// Check if the block is already in the garbage collection list
struct MemoryBlock *current = garbage_collection;
while (current != NULL) {
if (current->ptr == ptr) {
// printf("Memory block %p is already in the garbage collectionn", ptr); // Debug print
return; // Already in the list, do not add again
}
current = current->next;
}
// If not found, add to the list
struct MemoryBlock *block = (struct MemoryBlock *)malloc(sizeof(struct MemoryBlock));
if (!block) {
// fprintf(stderr, "Error: Failed to allocate memory for garbage collectionn");
return;
}
block->ptr = ptr;
block->next = garbage_collection;
garbage_collection = block;
// printf("Added to garbage collection: %pn", ptr); // Debug print
}
// Function to free all memory blocks tracked by garbage collection
void garbage_collect() {
struct MemoryBlock *current = garbage_collection;
while (current != NULL) {
struct MemoryBlock *temp = current;
current = current->next;
// printf("Freeing: %pn", temp->ptr); // Debug print
free(temp->ptr);
free(temp);
}
garbage_collection = NULL;
}
// Function to remove a memory block from the garbage collection list
void remove_from_garbage_collection(void *ptr) {
struct MemoryBlock *current = garbage_collection;
struct MemoryBlock *prev = NULL;
// Traverse the garbage collection list
while (current != NULL) {
if (current->ptr == ptr) {
// Found the memory block to remove
if (prev != NULL) {
// Update the previous block's next pointer
prev->next = current->next;
} else {
// If the found block is the head of the list
garbage_collection = current->next;
}
// printf("Removing from garbage collection: %pn", ptr); // Debug print
free(current);
return;
}
// Move to the next block
prev = current;
current = current->next;
}
// If the specified memory block is not found
// fprintf(stderr, "Error: Memory block not found in garbage collection: %pn", ptr); // Debug print
}
// Function to get a memory block pointer from the hashtable
void* get_memory_block_pointer(const char *name) {
unsigned int index = hash(name); // Ensure hash function is accessible
struct Node *current = hash_table[index]; // Access the hashtable
while (current != NULL) {
if (strcmp(current->name, name) == 0) {
return current->value;
}
current = current->next;
}
//fprintf(stderr, "Error: Memory block for '%s' not foundn", name);
return NULL; // Return NULL if not found
}
garbagecollection.h:
// garbage_collection.h
#ifndef GARBAGE_COLLECTION_H
#define GARBAGE_COLLECTION_H
// Define a structure for tracking allocated memory blocks
struct MemoryBlock {
void *ptr;
struct MemoryBlock *next;
};
// Function to initialize garbage collection
void initialize_garbage_collection();
// Function to add a memory block to the garbage collection list
void add_to_garbage_collection(void *ptr);
void remove_from_garbage_collection(void *ptr);
void* get_memory_block_pointer(const char *name);
// Function to free all memory blocks tracked by garbage collection
void garbage_collect();
#endif // GARBAGE_COLLECTION_H
test.hussein:
Import "filen.hslib"
Import "filto.hslib"
Void Main(){
testvalue = 40;
Call testvalue;
Var data;
data = ((testvalue/2)/5);
Call data;
};
filen.hslib:
Library{
Var testvalue;
testvalue = 50;
Call testvalue;
};
filto.hslib:
Library{
testvalue = testvalue*2;
Call testvalue;
};
this is quite the project and a probably a lot of bad design decision made by me, but i belive i can fix this issue with a bit of help