Initial Commit - Not functional

This commit is contained in:
0x221E
2026-01-09 21:29:18 +01:00
commit 0845c56c2b
4 changed files with 394 additions and 0 deletions

389
ibuild.c Normal file
View File

@@ -0,0 +1,389 @@
#include "deps/utils/src/arena_alloc.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
void die(char* s)
{
printf("BuildSystem Error: %s\n", s);
// printf("Last syscall error: %s", ERRNO);
exit(1);
}
typedef struct
{
char* compiler_path;
char* build_dir;
char* target_exec;
char* src_dir;
char* version;
} CompileOptions;
void launch_compile(CompileOptions* co)
{
if(co == NULL) die("launch_compile() co has to be valid");
if(co->compiler_path == NULL) die("launch_compile() requires a valid compiler path");
pid_t p = fork();
if(p<0)
die("launch_compile() fork error");
else if (p==0)
{
char* args[] = {"compile", "test.c", "-o", "test", NULL};
if((execvp(co->compiler_path, args)) == -1)
die("launch_compile() execvp error");
}
}
bool detect_config_file()
{
if(access("IBUILD", F_OK | R_OK) == 0)
return true;
return false;
}
/*** configuration lexer ***/
typedef struct
{
char *src;
Arena alloc;
} Tokenizer;
typedef enum
{
T_INVALID = -1,
T_IDENTIFIER = 0,
T_STRING = 1,
T_IS = 2,
T_EOF = 3,
} TokenType;
typedef struct
{
TokenType type;
char* value;
int line;
} Token;
#define TOKEN_CONST {T_INVALID, NULL, 0}
bool is_alpha_uppercase(char s)
{
return (s >= 'A' && s <= 'Z');
}
bool is_alpha_lowercase(char s)
{
return (s >= 'a' && s <= 'z');
}
bool is_whitespace(char s)
{
return s == ' ' || s == '\t' || s == '\r' || s == '\n';
}
bool is_part_of_key(char s)
{
return is_alpha_uppercase(s) || s == '_';
}
size_t skip_group(Tokenizer* t, bool (*func)(char))
{
if(func == NULL) die("skip_group() func invalid!");
size_t len = 0;
while(func(*t->src))
{
len++;
t->src += 1;
}
return len;
}
Token tokenize_identifier(Tokenizer *t)
{
char* temp = t->src;
size_t len = skip_group(t, &is_part_of_key);
char* buf = (char*)arena_alloc(&t->alloc, sizeof(char) * len + 1);
memcpy(buf, temp, len);
buf[len] = '\0';
return (Token){T_IDENTIFIER, buf};
}
Token tokenize_string(Tokenizer *t)
{
t->src += 1;
char* temp = t->src;
size_t len = 0;
while(*t->src != '"' && *t->src != '\0')
{
len++;
t->src += 1;
}
if(*t->src == '"') t->src++;
char* buf = (char*)arena_alloc(&t->alloc, (sizeof(char) * len) + 1);
memcpy(buf, temp, len);
buf[len] = '\0';
return (Token){T_STRING, buf};
}
Token tokenizer_next(Tokenizer* t)
{
if(is_whitespace(*t->src)) skip_group(t, &is_whitespace);
if(is_alpha_uppercase(*t->src))
{
return tokenize_identifier(t);
}
switch(*t->src)
{
case '"':
return tokenize_string(t);
case '=':
t->src++;
return (Token){T_IS, NULL};
}
if(*t->src == '\0') return (Token){T_EOF, NULL};
t->src++;
return (Token){T_INVALID, NULL};
}
/*** configuration parser ***/
typedef enum
{
K_UNKNOWN = 0,
K_COMPILER_PATH = 1,
K_SRC_DIR = 2,
K_BUILD_DIR = 3,
} Key;
typedef enum
{
N_STRING = 0,
N_PAIR = 1
} NodeType;
typedef struct
{
NodeType type;
Key key;
void* value;
} Node;
typedef struct
{
Tokenizer* tokenizer;
size_t loc;
size_t cap;
Arena alloc;
} Parser;
typedef struct
{
Key key;
const char* value;
} KeyMap;
static KeyMap keyword_mappings[] = {
{K_COMPILER_PATH, "COMPILER_PATH"},
{K_SRC_DIR, "SRC_DIR"},
{K_BUILD_DIR, "BUILD_DIR"},
{K_UNKNOWN, NULL},
};
Key key_lookup(char* s)
{
if(s == NULL) return K_UNKNOWN;
for(const KeyMap* ptr = keyword_mappings; ptr->value != NULL; ptr++)
{
if(strcmp(ptr->value, s) == 0)
{
return ptr->key;
}
}
return K_UNKNOWN;
}
Token parser_peek(Parser* p, size_t o)
{
if (p->loc + o >= p->cap)
{
return ((Token*)p->tokenizer->alloc.start)[p->loc - 1];
}
return ((Token*)p->tokenizer->alloc.start)[p->loc + o];
}
Token parser_previous(Parser* p)
{
if(p->loc - 1 < 0)
{
die("parser logic error.");
}
return ((Token*)p->tokenizer->alloc.start)[p->loc - 1];
}
Token parser_advance(Parser* p)
{
if(p->loc + 1 >= p->cap)
{
return ((Token*)p->tokenizer->alloc.start)[p->loc];
}
p->loc++;
return ((Token*)p->tokenizer->alloc.start)[p->loc];
}
Node* parser_expression(Parser* p)
{
Token t = parser_peek(p,0);
if(t.type == T_STRING)
{
Key k = key_lookup(t.value);
if(k == K_UNKNOWN) die("Syntax error: Unexpected expression encountered");
Node* node = (Node*)arena_alloc(&p->alloc, sizeof(Node));
node->key = k;
node->value = (void*)t.value;
node->type = N_STRING;
return node;
}
die("Syntax error: Invalid expression.");
}
Node* parser_statement(Parser* p)
{
Token t = parser_advance(p);
if(t.type == T_IDENTIFIER)
{
Key k = key_lookup(t.value);
if(k == K_UNKNOWN) die("Syntax error: Unexpected identifer encountered");
Node* expression = parser_expression(p);
Node* node = (Node*)arena_alloc(&p->alloc, sizeof(Node));
node->key = k;
node->value = (void*)expression;
node->type = N_PAIR;
}
else
{
printf("%d", t.type);
die("Syntax error: expected an identifier");
}
}
Node* parser_parse(Parser* p)
{
return parser_statement(p);
}
/*** configuration file management ***/
long get_file_size(FILE* fd)
{
if(fd == NULL) die("get_file_size() fd cannot be NULL.");
if(fseek(fd, 0, SEEK_END) != 0) die("process_config() file exists, fseek SEEK_END fail.");
long size = ftell(fd);
if(fseek(fd, 0, SEEK_SET) != 0) die("process_config() file exists, fseek SEEK_SET fail.");
return size;
}
int process_config(Arena* tokens)
{
if(!detect_config_file())
return 1;
printf("IBUILD Configuration file detected.\n");
FILE* fd = fopen("IBUILD", "r");
if(fd == NULL) die("process_config() file exists however fd is NULL");
long fs = get_file_size(fd);
printf("IBUILD file of size: %d\n", fs);
char* config_mem = malloc(fs + 1);
fread(config_mem, sizeof(char), fs, fd);
config_mem[fs] = '\0';
printf("Config file:\n%s\n", config_mem);
size_t t_count = 0;
Tokenizer t = { .src = config_mem, .alloc = ARENA_CONST};
while(1)
{
Token token = tokenizer_next(&t);
if(token.type == T_INVALID) die("illegal token!");
Token* tm = arena_alloc(tokens, sizeof(Token));
*tm = token;
t_count++;
if(token.type == T_EOF) break;
}
Parser parser = {.tokenizer = &t, .loc = 0, .cap = t_count, .alloc = ARENA_CONST};
parser_parse(&parser);
free(config_mem);
return 0;
}
/*** build configuration process ***/
/*
void populate_compile_options(CompileOptions* co, Token* t)
{
switch(t->type)
{
case T_KEY_COMPILER_PATH: co->compiler_path = t->value; break;
case T_KEY_BUILD_DIR: co->build_dir = t->value; break;
case T_KEY_TARGET_EXEC: co->target_exec = t->value; break;
case T_KEY_SRC_DIR: co->compiler_path = t->value; break;
case T_KEY_VERSION: co->version = t->value; break;
}
}*/
void build(Token* options)
{
CompileOptions co;
co.compiler_path = "/usr/bin/gcc";
Token* temp = options;
for(; temp->type != T_EOF; temp++)
{
// populate_compile_options(&co, temp);
}
launch_compile(&co);
printf("Compilation finished.\n");
}
int main(int argc, char** argv)
{
Arena a = ARENA_CONST;
process_config(&a);
Token* ptr = (Token*)a.start;
for(; ptr->type != T_EOF; ptr++)
{
printf("TokenType: %d, Value: %s\n", ptr->type, ptr->value);
}
return 0;
}