This commit is contained in:
Guillem George 2025-10-28 19:38:32 +01:00
parent 5f4d6af9c0
commit afe78e4401
7 changed files with 131 additions and 93 deletions

View file

@ -27,7 +27,7 @@ size_t hash(const char *key)
return hash; return hash;
} }
struct hash_map *hashMapInit(size_t size) struct hash_map *hashmap_init(size_t size)
{ {
struct pair_list **data = calloc(size, sizeof(struct pair_list)); struct pair_list **data = calloc(size, sizeof(struct pair_list));
struct hash_map *map = malloc(sizeof(struct hash_map)); struct hash_map *map = malloc(sizeof(struct hash_map));
@ -36,8 +36,8 @@ struct hash_map *hashMapInit(size_t size)
return map; return map;
} }
bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, bool hashmap_insert(struct hash_map *hash_map, char *key, void *value,
bool *updated) bool *updated)
{ {
if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0)
{ {
@ -79,7 +79,7 @@ bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value,
return true; return true;
} }
void hashMapFree(struct hash_map *hash_map) void hashmap_free(struct hash_map *hash_map)
{ {
if (hash_map == NULL) if (hash_map == NULL)
return; return;
@ -100,7 +100,10 @@ void hashMapFree(struct hash_map *hash_map)
free(hash_map); free(hash_map);
} }
void hashMapDump(struct hash_map *hash_map) // WARNING
// Will only work with string values
// DO NOT attempt to call it with anything else
void hashmap_dump(struct hash_map *hash_map)
{ {
for (size_t i = 0; i < hash_map->size; i++) for (size_t i = 0; i < hash_map->size; i++)
{ {
@ -109,12 +112,14 @@ void hashMapDump(struct hash_map *hash_map)
if (entry != NULL) if (entry != NULL)
{ {
is_null = false; is_null = false;
printf("%s: %s", entry->key, entry->value); char *val = entry->value;
printf("%s: %s", entry->key, val);
entry = entry->next; entry = entry->next;
} }
while (entry != NULL) while (entry != NULL)
{ {
printf(", %s: %s", entry->key, entry->value); char *val = entry->value;
printf(", %s: %s", entry->key, val);
entry = entry->next; entry = entry->next;
} }
if (!is_null) if (!is_null)
@ -122,7 +127,7 @@ void hashMapDump(struct hash_map *hash_map)
} }
} }
const char *hashMapGet(const struct hash_map *hash_map, const char *key) void *hashmap_get(const struct hash_map *hash_map, char *key)
{ {
if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0)
return NULL; return NULL;
@ -139,7 +144,7 @@ const char *hashMapGet(const struct hash_map *hash_map, const char *key)
return entry->value; return entry->value;
} }
bool hashMapRemove(struct hash_map *hash_map, const char *key) bool hashmap_remove(struct hash_map *hash_map, char *key)
{ {
if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL) if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL)
return false; return false;

View file

@ -1,13 +1,17 @@
#ifndef HASH_MAP_H #ifndef HASH_MAPS_H
#define HASH_MAP_H #define HASH_MAPS_H
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
// WARNING I made the choice to discard the const qualifier of the key argument
// To add the possibility to free it.
// Note that key should *NEVER* be changed once it has been added to the hashmap
struct pair_list struct pair_list
{ {
const char *key; char *key;
char *value; void *value;
struct pair_list *next; struct pair_list *next;
}; };
@ -18,12 +22,12 @@ struct hash_map
}; };
size_t hash(const char *str); size_t hash(const char *str);
struct hash_map *hashMapInit(size_t size); struct hash_map *hashmap_init(size_t size);
bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, bool hashmap_insert(struct hash_map *hash_map, char *key, void *value,
bool *updated); bool *updated);
void hashMapFree(struct hash_map *hash_map); void hashmap_free(struct hash_map *hash_map);
void hashMapDump(struct hash_map *hash_map); void hashmap_dump(struct hash_map *hash_map);
const char *hashMapGet(const struct hash_map *hash_map, const char *key); void *hashmap_get(const struct hash_map *hash_map, char *key);
bool hashMapRemove(struct hash_map *hash_map, const char *key); bool hashmap_remove(struct hash_map *hash_map, char *key);
#endif /* ! HASH_MAP_H */ #endif /* ! HASH_MAPS_H */

View file

@ -7,13 +7,13 @@
#include <unistd.h> #include <unistd.h>
// Helps to match a string (excludes blanks and special characters) // Helps to match a string (excludes blanks and special characters)
int isChar(char c) int ischar(char c)
{ {
return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#' return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'
&& c != '\n'; && c != '\n';
} }
int skipBlanks(char *buf, size_t buf_len) int skipblanks(char *buf, size_t buf_len)
{ {
size_t i = 0; size_t i = 0;
while (i < buf_len && (isblank(buf[i]) || buf[i] == '\n')) while (i < buf_len && (isblank(buf[i]) || buf[i] == '\n'))
@ -22,7 +22,7 @@ int skipBlanks(char *buf, size_t buf_len)
} }
// Returns 1 if line is blank // Returns 1 if line is blank
int isBlankLine(struct line *l) int isblankline(struct line *l)
{ {
size_t line_size = l->length; size_t line_size = l->length;
char *buf = l->buffer; char *buf = l->buffer;
@ -42,12 +42,12 @@ int isBlankLine(struct line *l)
// Returns the next word from buf until buf_len, // Returns the next word from buf until buf_len,
// and the numbers of read characters in *read_chars // and the numbers of read characters in *read_chars
// WARNING allocates the result on the heap // WARNING allocates the result on the heap
size_t readWord(char *buf, size_t buf_len, char **word) size_t readword(char *buf, size_t buf_len, char **word)
{ {
size_t i = 0; size_t i = 0;
size_t res_size = STRING_BUFFER_SIZE; size_t res_size = STRING_BUFFER_SIZE;
char *res = malloc(sizeof(char) * res_size); char *res = malloc(sizeof(char) * res_size);
while (i < buf_len && isChar(buf[i])) while (i < buf_len && ischar(buf[i]))
{ {
// Reallocate more space if necessary // Reallocate more space if necessary
if (i >= res_size - 1) if (i >= res_size - 1)

View file

@ -18,9 +18,9 @@ struct line
FILE* file_stream; // Full file stream FILE* file_stream; // Full file stream
}; };
int isChar(char c); int ischar(char c);
int isBlankLine(struct line *l); int isblankline(struct line *l);
int skipBlanks(char *buf, size_t buf_len); int skipblanks(char *buf, size_t buf_len);
size_t readWord(char *buf, size_t buf_len, char **word); size_t readword(char *buf, size_t buf_len, char **word);
#endif // LINES_H #endif // LINES_H

View file

@ -123,5 +123,5 @@ int main(int argc, char **argv)
if (filename == NULL) if (filename == NULL)
errx(GENERIC_ERR, "No Makefile found"); errx(GENERIC_ERR, "No Makefile found");
make(filename, flags); make(filename, flags, argv[0]);
} }

View file

@ -15,50 +15,81 @@
// Static variables // Static variables
struct hash_map *variables = NULL; struct hash_map *variables = NULL;
struct hash_map *rules = NULL; struct hash_map *rules = NULL;
char *program_name;
// ==== Misc ====
static void hashmap_deep_free(struct hash_map *hash_map)
{
if (hash_map == NULL)
return;
if (hash_map->data == NULL)
return;
for (size_t i = 0; i < hash_map->size; i++)
{
struct pair_list *entry = hash_map->data[i];
while (entry != NULL)
{
struct pair_list *next = entry->next;
free(entry->key);
free(entry->value);
free(entry);
entry = next;
}
}
free(hash_map->data);
free(hash_map);
}
static void free_all()
{
hashmap_deep_free(rules);
hashmap_deep_free(variables);
}
// static void dump_database()
// {
// hashmap_dump(variables);
// hashmap_dump(rules);
// }
// ==== Parsing ==== // ==== Parsing ====
// Registers a new variable and returns its pointer // Registers a new rule in the hashmap
// WARNING Allocates memory on the heap, // WARNING Allocates memory on the heap,
// the variables hashmap should be freed before exit // the rules hashmap should be freed before exit
static struct variable *createVariable(char *name) static void register_rule(char *name, struct list *dependencies,
struct list *recipe)
{ {
struct variable *res = malloc(sizeof(struct variable)); struct rule *rule = malloc(sizeof(struct rule));
res->name = name; rule->name = name;
res->value = NULL; rule->dependencies = dependencies;
rule->recipe = recipe;
int err = hashMapInsert(variables, name, NULL, NULL); int err = hashmap_insert(variables, name, rule, NULL);
if (!err)
{
errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap",
name);
}
}
// Registers a new variable in the hashmap
// WARNING Allocates memory on the heap,
// the variables hashmap should be freed before exit
static void register_variable(char *name, char *value)
{
int err = hashmap_insert(variables, name, value, NULL);
if (!err) if (!err)
{ {
// free(name);
free(res);
errx(2, "Internal Error: Couln't add entry for '%s' in the hashmap", errx(2, "Internal Error: Couln't add entry for '%s' in the hashmap",
name); name);
} }
return res;
}
// Registers a new rule and returns its pointer
// WARNING Allocates memory on the heap,
// the rules hashmap should be freed before exit
static struct rule *createRule(char *name)
{
struct rule *res = malloc(sizeof(struct rule));
res->name = name;
res->dependencies = NULL;
res->recipe = NULL;
int err = hashMapInsert(variables, name, NULL, NULL);
if (!err)
errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap",
name);
return res;
} }
// Parse dependencies from buf and returns them inside a chained list // Parse dependencies from buf and returns them inside a chained list
static struct list *readDependencies(struct line *l, size_t offset) static struct list *read_deps(struct line *l, size_t offset)
{ {
size_t i = offset; size_t i = offset;
size_t buf_size = l->length; size_t buf_size = l->length;
@ -67,11 +98,11 @@ static struct list *readDependencies(struct line *l, size_t offset)
while (i < buf_size) while (i < buf_size)
{ {
i += skipBlanks(buf + i, buf_size - i); i += skipblanks(buf + i, buf_size - i);
// Read word // Read word
char *dep_name; char *dep_name;
i += readWord(buf + i, buf_size - i, &dep_name); i += readword(buf + i, buf_size - i, &dep_name);
if (dep_name != NULL) if (dep_name != NULL)
// Add to list // Add to list
res = list_append(res, dep_name); res = list_append(res, dep_name);
@ -81,7 +112,7 @@ static struct list *readDependencies(struct line *l, size_t offset)
return res; return res;
// Unknown chars // Unknown chars
if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' if (!ischar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0'
&& buf[i] != '\n') && buf[i] != '\n')
{ {
printf("DEBUG: line: %s", l->buffer); printf("DEBUG: line: %s", l->buffer);
@ -97,7 +128,7 @@ static struct list *readDependencies(struct line *l, size_t offset)
// Searches the following lines for recipes and returns them in the form of a // Searches the following lines for recipes and returns them in the form of a
// list // list
// WARNING begins to read the following line // WARNING begins to read the following line
static struct list *readRecipe(struct line *l) static struct list *read_recipe(struct line *l)
{ {
FILE *stream = l->file_stream; FILE *stream = l->file_stream;
char *buf = l->buffer; char *buf = l->buffer;
@ -111,7 +142,7 @@ static struct list *readRecipe(struct line *l)
l->number++; l->number++;
// Skip blank lines and comments // Skip blank lines and comments
if (isBlankLine(l)) if (isblankline(l))
continue; continue;
else if (buf[0] != '\t') // Not a recipe else if (buf[0] != '\t') // Not a recipe
{ {
@ -134,7 +165,7 @@ static struct list *readRecipe(struct line *l)
} }
// Reads the value after a variable declaration // Reads the value after a variable declaration
static char *readValue(char *buf, size_t buf_size) static char *read_value(char *buf, size_t buf_size)
{ {
size_t i = 0; size_t i = 0;
size_t str_buf_size = STRING_BUFFER_SIZE; size_t str_buf_size = STRING_BUFFER_SIZE;
@ -164,48 +195,49 @@ static char *readValue(char *buf, size_t buf_size)
// Takes a buffer containing the line to parse and it length // Takes a buffer containing the line to parse and it length
// As well as the line number in the file for error handling // As well as the line number in the file for error handling
static void parseLine(struct line *current_line) static void parse_line(struct line *current_line)
{ {
char *buf = current_line->buffer; char *buf = current_line->buffer;
size_t line_size = current_line->length; size_t line_size = current_line->length;
size_t i = 0; size_t i = 0;
i += skipBlanks(buf + i, line_size - i); i += skipblanks(buf + i, line_size - i);
// Read name // Read name
char *name; char *name;
i += readWord(buf + i, line_size - i, &name); i += readword(buf + i, line_size - i, &name);
// if (name == NULL) // if (name == NULL)
// errx(1, "Il s'est passé quoi là ? \nUnexpected character at %lu:%lu", // errx(1, "Il s'est passé quoi là ? \nUnexpected character at %lu:%lu",
// current_line->number, i); // current_line->number, i);
i += skipBlanks(buf + i, line_size - i); i += skipblanks(buf + i, line_size - i);
// Potential elements // Potential elements
struct rule *new_rule; struct list *dependencies;
struct variable *new_variable; struct list *recipe;
char *value;
// Definition type // Definition type
switch (buf[i]) switch (buf[i])
{ {
// Variable // Variable
case '=': case '=':
new_variable = createVariable(name); value = read_value(buf + i, line_size);
new_variable->value = readValue(buf + i, line_size); register_variable(name, value);
break; break;
// Rule // Rule
case ':': case ':':
new_rule = createRule(name); dependencies = read_deps(current_line, i + 1);
new_rule->dependencies = readDependencies(current_line, i + 1); recipe = read_recipe(current_line);
new_rule->recipe = readRecipe(current_line); register_rule(name, dependencies, recipe);
// Check for EOF // Check for EOF
if (current_line->length == -1) if (current_line->length == -1)
return; return;
parseLine(current_line); parse_line(current_line);
// TODO: check for loooooops // TODO: check for loooooops
break; break;
@ -228,7 +260,7 @@ static void parseLine(struct line *current_line)
// free(name); // free(name);
} }
void makeParse(char *path) void make_parse(char *path)
{ {
// Open file // Open file
FILE *stream = fopen(path, "r"); FILE *stream = fopen(path, "r");
@ -236,8 +268,8 @@ void makeParse(char *path)
errx(2, "Could not open file: %s", path); errx(2, "Could not open file: %s", path);
// Init hash maps // Init hash maps
variables = hashMapInit(HASHMAP_SIZE); variables = hashmap_init(HASHMAP_SIZE);
rules = hashMapInit(HASHMAP_SIZE); rules = hashmap_init(HASHMAP_SIZE);
if (variables == NULL || rules == NULL) if (variables == NULL || rules == NULL)
errx(1, "Internal error: Failed to initiate hash maps"); errx(1, "Internal error: Failed to initiate hash maps");
@ -260,7 +292,7 @@ void makeParse(char *path)
current_line.buffer = buf; current_line.buffer = buf;
current_line.length = nread; current_line.length = nread;
parseLine(&current_line); parse_line(&current_line);
current_line.number += 1; current_line.number += 1;
} }
@ -274,18 +306,14 @@ void makeParse(char *path)
// ==== MAKE ==== // ==== MAKE ====
void make(char *path, int flags) void make(char *path, int flags, char *argv0)
{ {
program_name = argv0;
if (flags & FLAGS_PRINT) if (flags & FLAGS_PRINT)
errx(GENERIC_ERR, "Not Implemented"); errx(GENERIC_ERR, "Not Implemented");
makeParse(path); make_parse(path);
// dump_database();
free_all();
} }
// ==== Misc ====
// static void free_all()
// {
// hashMapFree(rules);
// hashMapFree(variables);
// }

View file

@ -37,6 +37,7 @@ struct rule
struct list *recipe; struct list *recipe;
}; };
void make(char *path, int flags); void make(char *path, int flags, char* program_name);
void make_parse(char *path);
#endif // ! MINIMAKE_H #endif // ! MINIMAKE_H