Logger, a little bit of parser
This commit is contained in:
parent
6322f2f93c
commit
957a15a3af
61
src/include/ast.h
Normal file
61
src/include/ast.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
|
||||
#ifndef _H_MCL_AST
|
||||
#define _H_MCL_AST
|
||||
|
||||
#include "loc.h"
|
||||
#include "dyn_arr.h"
|
||||
|
||||
|
||||
DEFINE_DA(ast_node, void*);
|
||||
|
||||
|
||||
typedef enum ast_type_e {
|
||||
AT_BIN_ADD,
|
||||
AT_BIN_SUB,
|
||||
AT_BIN_DIV,
|
||||
AT_BIN_MUL,
|
||||
AT_UN_DEREF,
|
||||
AT_UN_XOR,
|
||||
AT_FUNC,
|
||||
AT_ASSIGN,
|
||||
AT_EXPR,
|
||||
} ast_type_t;
|
||||
|
||||
typedef struct ast_ident_s {
|
||||
char* name;
|
||||
loc_t loc;
|
||||
} ast_ident_t;
|
||||
|
||||
typedef struct type_s {
|
||||
ast_ident_t name;
|
||||
struct type_s* inner;
|
||||
} type_t;
|
||||
|
||||
|
||||
typedef struct ast_node_s {
|
||||
ast_type_t* type;
|
||||
loc_t loc;
|
||||
} ast_node_t;
|
||||
|
||||
|
||||
typedef struct ast_program_s {
|
||||
mcl_da_ast_node_t body;
|
||||
loc_t loc;
|
||||
} ast_program_t;
|
||||
|
||||
typedef struct ast_func_param_s {
|
||||
ast_ident_t name;
|
||||
type_t type;
|
||||
} ast_func_param_t;
|
||||
|
||||
DEFINE_DA(func_param, ast_func_param_t);
|
||||
|
||||
typedef struct ast_func_decl_s {
|
||||
ast_type_t* type;
|
||||
loc_t loc;
|
||||
ast_ident_t id;
|
||||
mcl_da_func_param_t params;
|
||||
mcl_da_ast_node_t body;
|
||||
} ast_func_decl_t;
|
||||
|
||||
#endif
|
|
@ -2,15 +2,13 @@
|
|||
#define _H_MCL_CLIARGS
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "dyn_arr.h"
|
||||
|
||||
#ifndef MCL_VERSION
|
||||
#define MCL_VERSION "0.0.1"
|
||||
#endif
|
||||
|
||||
typedef char* string;
|
||||
DEFINE_DA(string, char*)
|
||||
|
||||
static struct option cli_options[] = {
|
||||
|
|
|
@ -10,8 +10,11 @@ typedef struct mcl_da_##name##_s { \
|
|||
size_t capacity; \
|
||||
} mcl_da_##name##_t; \
|
||||
type* mcl_da_##name##_pop(mcl_da_##name##_t* da); \
|
||||
type* mcl_da_##name##_peek(mcl_da_##name##_t* da); \
|
||||
type* mcl_da_##name##_pop_front(mcl_da_##name##_t* da); \
|
||||
type* mcl_da_##name##_peek_front(mcl_da_##name##_t* da); \
|
||||
void mcl_da_##name##_push(mcl_da_##name##_t* da, type item); \
|
||||
void mcl_da_##name##_free(mcl_da_##name##_t* da); \
|
||||
void mcl_da_##name##_free(mcl_da_##name##_t* da);
|
||||
|
||||
#define DEFINE_DA_IMPL(name, type) \
|
||||
type* mcl_da_##name##_pop(mcl_da_##name##_t* da) { \
|
||||
|
@ -38,50 +41,74 @@ void mcl_da_##name##_push(mcl_da_##name##_t* da, type item) { \
|
|||
} \
|
||||
da->items[da->count++] = item; \
|
||||
} \
|
||||
type* mcl_da_##name##_pop_front(mcl_da_##name##_t* da) { \
|
||||
if (da->capacity <= 0 || da->count <= 0) \
|
||||
return NULL; \
|
||||
if (da->count < da->capacity / 2) { \
|
||||
da->capacity /= 2; \
|
||||
da->items = realloc(da->items, \
|
||||
da->capacity * sizeof(type)); \
|
||||
assert(da->items && "Out of memory"); \
|
||||
} \
|
||||
type* item = malloc(sizeof(type)); \
|
||||
type* temp = malloc(sizeof(type) * da->count); \
|
||||
*item = da->items[0]; \
|
||||
memcpy(temp, &da->items[1], sizeof(type) * da->count); \
|
||||
memcpy(da->items, temp, sizeof(type) * --da->count); \
|
||||
free(temp); \
|
||||
return item; \
|
||||
} \
|
||||
type* mcl_da_##name##_peek(mcl_da_##name##_t* da) { \
|
||||
if (da->count < 1) return NULL; \
|
||||
return &da->items[da->count - 1]; \
|
||||
} \
|
||||
type* mcl_da_##name##_peek_front(mcl_da_##name##_t* da) { \
|
||||
return &da->items[0]; \
|
||||
} \
|
||||
void mc_da_##name##_free(mcl_da_##name##_t* da) { \
|
||||
free(da->items); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define DEFINE_PTR_DA(name, type) \
|
||||
typedef struct mcl_ptr_da_##name##_s { \
|
||||
type** items; \
|
||||
size_t count; \
|
||||
size_t capacity; \
|
||||
} mcl_ptr_da_##name##_t; \
|
||||
type* mcl_da_##name##_pop(mcl_da_##name##_t* da); \
|
||||
void mcl_da_##name##_push(mcl_da_##name##_t* da, type* item);
|
||||
|
||||
|
||||
#define DEFINE_PTR_DA_IMPL(type) \
|
||||
type* mcl_ptr_da_##name##_pop(mcl_da_##name##_t* da) { \
|
||||
if (da->capacity <= 0 || da->count <= 0) \
|
||||
return NULL; \
|
||||
if (da->count < da->capacity / 2) { \
|
||||
da->capacity /= 2; \
|
||||
da->items = realloc(da->items, \
|
||||
da->capacity * sizeof(type*)); \
|
||||
assert(da->items && "Out of memory"); \
|
||||
} \
|
||||
return da->items[(da->count--) - 1]; \
|
||||
} \
|
||||
void mcl_ptr_da_##name##_push(mcl_da_##name##_t* da, type* item) { \
|
||||
if (da->capacity <= da->count) { \
|
||||
if (da->capacity == 0) { \
|
||||
da->capacity = 8; \
|
||||
} else { \
|
||||
da->capacity *= 2; \
|
||||
} \
|
||||
da->items = realloc(da->items, \
|
||||
da->capacity * sizeof(type*)); \
|
||||
assert(da->items && "Out of memory"); \
|
||||
} \
|
||||
da->items[da->count++] = item; \
|
||||
} \
|
||||
void mc_ptr_da_##name##_free(mcl_da_##name##_* da) { \
|
||||
free(da->items); \
|
||||
}
|
||||
//#define DEFINE_PTR_DA(name, type) \
|
||||
//typedef struct mcl_ptr_da_##name##_s { \
|
||||
// type** items; \
|
||||
// size_t count; \
|
||||
// size_t capacity; \
|
||||
//} mcl_ptr_da_##name##_t; \
|
||||
//type* mcl_da_##name##_pop(mcl_da_##name##_t* da); \
|
||||
//void mcl_da_##name##_push(mcl_da_##name##_t* da, type* item);
|
||||
//
|
||||
//
|
||||
//#define DEFINE_PTR_DA_IMPL(type) \
|
||||
//type* mcl_ptr_da_##name##_pop(mcl_da_##name##_t* da) { \
|
||||
// if (da->capacity <= 0 || da->count <= 0) \
|
||||
// return NULL; \
|
||||
// if (da->count < da->capacity / 2) { \
|
||||
// da->capacity /= 2; \
|
||||
// da->items = realloc(da->items, \
|
||||
// da->capacity * sizeof(type*)); \
|
||||
// assert(da->items && "Out of memory"); \
|
||||
// } \
|
||||
// return da->items[(da->count--) - 1]; \
|
||||
//} \
|
||||
//void mcl_ptr_da_##name##_push(mcl_da_##name##_t* da, type* item) { \
|
||||
// if (da->capacity <= da->count) { \
|
||||
// if (da->capacity == 0) { \
|
||||
// da->capacity = 8; \
|
||||
// } else { \
|
||||
// da->capacity *= 2; \
|
||||
// } \
|
||||
// da->items = realloc(da->items, \
|
||||
// da->capacity * sizeof(type*)); \
|
||||
// assert(da->items && "Out of memory"); \
|
||||
// } \
|
||||
// da->items[da->count++] = item; \
|
||||
//} \
|
||||
//void mc_ptr_da_##name##_free(mcl_da_##name##_* da) { \
|
||||
// free(da->items); \
|
||||
//}
|
||||
|
||||
#define MCL_DA_FOR_IN(type, da, item, body) do { \
|
||||
type item; \
|
||||
|
|
6
src/include/errors.h
Normal file
6
src/include/errors.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef _H_MCL_ERRORS
|
||||
#define _H_MCL_ERRORS
|
||||
|
||||
const char* FUNC_DECL_EXMPL = "To define a function follow this example: \nmain :: fn(argc: i32, argv: string[]) {\n ...\n}";
|
||||
|
||||
#endif
|
46
src/include/logger.h
Normal file
46
src/include/logger.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef _H_MCL_LOG
|
||||
#define _H_MCL_LOG
|
||||
|
||||
#include "loc.h"
|
||||
|
||||
#ifdef _LOG_COLORS
|
||||
#define RESET "\x1b[0m"
|
||||
#define BRIGHT "\x1b[1m"
|
||||
#define DIM "\x1b[2m"
|
||||
#define UNDERSCORE "\x1b[4m"
|
||||
#define BLINK "\x1b[5m"
|
||||
#define REVERSE "\x1b[7m"
|
||||
#define HIDDEN "\x1b[8m"
|
||||
#define FG_BLACK "\x1b[30m"
|
||||
#define FG_RED "\x1b[31m"
|
||||
#define FG_GREEN "\x1b[32m"
|
||||
#define FG_YELLOW "\x1b[33m"
|
||||
#define FG_BLUE "\x1b[34m"
|
||||
#define FG_MAGENTA "\x1b[35m"
|
||||
#define FG_CYAN "\x1b[36m"
|
||||
#define FG_WHITE "\x1b[37m"
|
||||
#define BG_BLACK "\x1b[40m"
|
||||
#define BG_RED "\x1b[41m"
|
||||
#define BG_GREEN "\x1b[42m"
|
||||
#define BG_YELLOW "\x1b[43m"
|
||||
#define BG_BLUE "\x1b[44m"
|
||||
#define BG_MAGENTA "\x1b[45m"
|
||||
#define BG_CYAN "\x1b[46m"
|
||||
#define BG_WHITE "\x1b[47m"
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum log_level_e {
|
||||
ERROR = 0,
|
||||
WARN,
|
||||
HELP,
|
||||
INFO,
|
||||
DEBUG,
|
||||
} log_level_t;
|
||||
|
||||
static log_level_t FILTER_LEVEL = INFO;
|
||||
|
||||
void mcl_log(log_level_t level, const char* fmt, ...);
|
||||
void mcl_log_loc(log_level_t level, loc_t* loc, const char* fmt, ...);
|
||||
|
||||
#endif
|
10
src/include/parser.h
Normal file
10
src/include/parser.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef _H_MCL_PARSER
|
||||
#define _H_MCL_PARSER
|
||||
|
||||
|
||||
#include "tokeniser.h"
|
||||
#include "ast.h"
|
||||
|
||||
ast_program_t* parse(mcl_da_token_t* tokens);
|
||||
|
||||
#endif
|
|
@ -26,6 +26,16 @@ typedef enum token_type_e {
|
|||
TT_EQ, // =
|
||||
TT_LT, // <
|
||||
TT_GT, // >
|
||||
TT_KW_FN,
|
||||
TT_KW_RETURN,
|
||||
TT_KW_IF,
|
||||
TT_KW_ELSE,
|
||||
TT_KW_FOR,
|
||||
TT_KW_WHILE,
|
||||
TT_KW_STRUCT,
|
||||
TT_KW_ENUM,
|
||||
TT_KW_BREAK,
|
||||
TT_KW_CONTINUE,
|
||||
} token_type_t;
|
||||
|
||||
|
||||
|
|
16
src/loc.c
Normal file
16
src/loc.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "loc.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// NEEDS to be freed
|
||||
char* loc_str(loc_t* loc) {
|
||||
size_t len = ( (20*2) + // 2 max lens of u64 int as strings
|
||||
strlen(loc->file) + // file path length
|
||||
2 // 2 colons
|
||||
);
|
||||
char* buf = malloc(sizeof(char)*len);
|
||||
snprintf(buf, len, "%s:%zu:%zu", loc->file, loc->line, loc->col);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
44
src/logger.c
Normal file
44
src/logger.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define _LOG_COLORS
|
||||
#include "logger.h"
|
||||
#include "loc.h"
|
||||
|
||||
|
||||
void mcl_log(log_level_t level, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char* prefix;
|
||||
switch (level) {
|
||||
case ERROR: prefix = BRIGHT FG_RED "ERROR" RESET; break;
|
||||
case WARN: prefix = BRIGHT FG_YELLOW "WARN" RESET; break;
|
||||
case HELP: prefix = BRIGHT FG_CYAN "HELP" RESET; break;
|
||||
case INFO: prefix = BRIGHT FG_GREEN "INFO" RESET; break;
|
||||
case DEBUG: prefix = BRIGHT FG_BLUE "DEBUG" RESET; break;
|
||||
}
|
||||
printf("%s: ", prefix);
|
||||
vprintf(fmt, args);
|
||||
puts("");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void mcl_log_loc(log_level_t level, loc_t* loc, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char* prefix;
|
||||
switch (level) {
|
||||
case ERROR: prefix = BRIGHT FG_RED "ERROR" RESET; break;
|
||||
case WARN: prefix = BRIGHT FG_YELLOW "WARN" RESET; break;
|
||||
case HELP: prefix = BRIGHT FG_CYAN "HELP" RESET; break;
|
||||
case INFO: prefix = BRIGHT FG_GREEN "INFO" RESET; break;
|
||||
case DEBUG: prefix = BRIGHT FG_BLUE "DEBUG" RESET; break;
|
||||
}
|
||||
|
||||
printf(BRIGHT"%s"RESET":"BRIGHT"%zu"RESET":"BRIGHT"%zu"RESET": ", loc->file, loc->line, loc->col);
|
||||
|
||||
printf("%s: ", prefix);
|
||||
vprintf(fmt, args);
|
||||
puts("");
|
||||
va_end(args);
|
||||
}
|
15
src/main.c
15
src/main.c
|
@ -1,21 +1,23 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "cliargs.h"
|
||||
#include "dyn_arr.h"
|
||||
#include "token.h"
|
||||
#include "tokeniser.h"
|
||||
#include "parser.h"
|
||||
#include "logger.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
cliargs_t* cliargs = parse_cliargs(argc, argv);
|
||||
printf("Hewo world :33\n");
|
||||
printf("Output file: %s\n", cliargs->output);
|
||||
mcl_log(DEBUG, "Output file: %s", cliargs->output);
|
||||
|
||||
MCL_DA_FOR_IN(char*, &cliargs->input, file, {
|
||||
printf("Input file: %s\n", file);
|
||||
mcl_log(DEBUG, "Input file: %s", file);
|
||||
tokeniser_t* tokeniser = tokenise(file);
|
||||
if (!tokeniser) {
|
||||
printf("Failed to tokenise\n");
|
||||
mcl_log(ERROR, "Failed to tokenise");
|
||||
return 1;
|
||||
}
|
||||
MCL_DA_FOR_IN(token_t, &tokeniser->tokens, token, {
|
||||
|
@ -25,9 +27,8 @@ int main(int argc, char** argv) {
|
|||
token.loc.col,
|
||||
token_to_string(&token));
|
||||
});
|
||||
//ast_program_t* prog = parse(&tokeniser->tokens);
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
111
src/parser.c
Normal file
111
src/parser.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "ast.h"
|
||||
#include "token.h"
|
||||
#include "tokeniser.h"
|
||||
#include "errors.h"
|
||||
#include "dyn_arr.h"
|
||||
#include "logger.h"
|
||||
|
||||
DEFINE_DA_IMPL(ast_node, void*);
|
||||
DEFINE_DA_IMPL(func_param, ast_func_param_t);
|
||||
|
||||
token_t* expect_token(mcl_da_token_t* tks, token_t t);
|
||||
token_t* try_token(mcl_da_token_t* tks, token_t t);
|
||||
token_t* expect_token_err(mcl_da_token_t* tks, token_t t);
|
||||
ast_func_decl_t* parse_func(mcl_da_token_t* tokens, ast_ident_t name);
|
||||
|
||||
|
||||
ast_program_t* parse(mcl_da_token_t* tokens) {
|
||||
ast_program_t* prog = malloc(sizeof(ast_program_t));
|
||||
assert(prog && "Out of mem");
|
||||
|
||||
token_t* tok = NULL;
|
||||
while ((tok=mcl_da_token_pop_front(tokens)) != NULL) {
|
||||
switch(tok->type) {
|
||||
case TT_IDENT: {
|
||||
// printf("IDENT: %s\n", tok->text);
|
||||
if (!expect_token_err(tokens, (token_t){.type=TT_COLON })) return NULL;
|
||||
if (!expect_token_err(tokens, (token_t){.type=TT_COLON })) return NULL;
|
||||
token_t* type = mcl_da_token_pop_front(tokens);
|
||||
|
||||
if (type->type == TT_KW_FN) {
|
||||
ast_ident_t name = {
|
||||
.name = tok->text,
|
||||
.loc = tok->loc
|
||||
};
|
||||
mcl_da_ast_node_push(&prog->body, parse_func(tokens, name));
|
||||
} else if (type->type == TT_KW_STRUCT) {
|
||||
|
||||
} else if (type->type == TT_KW_ENUM) {
|
||||
|
||||
}
|
||||
return NULL;
|
||||
|
||||
} break;
|
||||
}
|
||||
// mcl_da_ast_node_push(prog->body, );
|
||||
}
|
||||
return prog;
|
||||
}
|
||||
|
||||
|
||||
ast_func_decl_t* parse_func(mcl_da_token_t* tokens, ast_ident_t name) {
|
||||
ast_func_decl_t* func = malloc(sizeof(ast_func_decl_t));
|
||||
// parse args
|
||||
if (!expect_token_err(tokens, (token_t){.type=TT_PAREN_L})) return NULL;
|
||||
while (!try_token(tokens, (token_t){.type=TT_PAREN_R})) {
|
||||
|
||||
// Name
|
||||
token_t* arg_name = expect_token_err(tokens,(token_t){.type=TT_IDENT});
|
||||
if (!arg_name) return NULL;
|
||||
|
||||
if (!expect_token_err(tokens, (token_t){.type=TT_COLON})) return NULL;
|
||||
|
||||
// Type
|
||||
token_t* type = expect_token_err(tokens, (token_t){.type=TT_IDENT});
|
||||
if (!type) return NULL;
|
||||
|
||||
ast_func_param_t param = {
|
||||
.name = { .name = arg_name->text, .loc = arg_name->loc },
|
||||
.type = { .name = { .name = type->text, .loc = type->loc}, .inner=NULL},
|
||||
};
|
||||
mcl_da_func_param_push(&func->params, param);
|
||||
|
||||
if (!try_token(tokens, (token_t){.type=TT_COMMA})) {
|
||||
if (!expect_token_err(tokens, (token_t){.type=TT_PAREN_R})) return NULL;
|
||||
}
|
||||
}
|
||||
// parse body
|
||||
return func;
|
||||
}
|
||||
|
||||
token_t* expect_token(mcl_da_token_t* tks, token_t t) {
|
||||
token_t* _tok_ = mcl_da_token_pop_front(tks);
|
||||
if (_tok_->type != t.type) {
|
||||
return NULL;
|
||||
}
|
||||
return _tok_;
|
||||
}
|
||||
token_t* try_token(mcl_da_token_t* tks, token_t t) {
|
||||
token_t* _tok_ = mcl_da_token_peek_front(tks);
|
||||
if (_tok_->type != t.type) {
|
||||
return NULL;
|
||||
}
|
||||
return _tok_;
|
||||
}
|
||||
token_t* expect_token_err(mcl_da_token_t* tks, token_t t) {
|
||||
token_t* _tok_ = mcl_da_token_pop_front(tks);
|
||||
if (_tok_->type != t.type) {
|
||||
mcl_log(ERROR, "Expected %s", token_to_string(&t));
|
||||
mcl_log_loc(INFO, &_tok_->loc, "Got %s", token_to_string(_tok_));
|
||||
return NULL;
|
||||
|
||||
}
|
||||
return _tok_;
|
||||
}
|
||||
|
76
src/token.c
76
src/token.c
|
@ -3,21 +3,29 @@
|
|||
#include <string.h>
|
||||
#include "token.h"
|
||||
|
||||
char* escape_str(char* str);
|
||||
|
||||
char* token_to_string(token_t* t) {
|
||||
char* buf = {0};
|
||||
int len = 0;
|
||||
switch(t->type) {
|
||||
case TT_IDENT:
|
||||
return t->text;
|
||||
case TT_STR:
|
||||
len = strlen(t->text)+3;
|
||||
// printf("IDENT\n");
|
||||
len = strlen(t->text)+10;
|
||||
buf = malloc(len);
|
||||
snprintf(buf, len, "\"%s\"", t->text);
|
||||
snprintf(buf, len, "IDENT(\"%s\")", escape_str(t->text));
|
||||
return buf;
|
||||
case TT_STR:
|
||||
// printf("STR\n");
|
||||
len = strlen(t->text)+10;
|
||||
buf = malloc(len);
|
||||
snprintf(buf, len, "STR(\"%s\")", t->text);
|
||||
buf = escape_str(t->text);
|
||||
return buf;
|
||||
case TT_CHR:
|
||||
buf = malloc(4);
|
||||
snprintf(buf, 4, "'%c\'", *t->text);
|
||||
// printf("CHR\n");
|
||||
buf = malloc(10);
|
||||
snprintf(buf, 10, "CHAR('%c')", *t->text);
|
||||
return buf;
|
||||
case TT_CURLY_R:
|
||||
return "}";
|
||||
|
@ -57,5 +65,61 @@ char* token_to_string(token_t* t) {
|
|||
return "<";
|
||||
case TT_GT:
|
||||
return ">";
|
||||
case TT_KW_FN:
|
||||
return "KEYWORD(fn)";
|
||||
case TT_KW_RETURN:
|
||||
return "KEYWORD(return)";
|
||||
case TT_KW_IF:
|
||||
return "KEYWORD(if)";
|
||||
case TT_KW_ELSE:
|
||||
return "KEYWORD(else)";
|
||||
case TT_KW_FOR:
|
||||
return "KEYWORD(for)";
|
||||
case TT_KW_WHILE:
|
||||
return "KEYWORD(while)";
|
||||
case TT_KW_STRUCT:
|
||||
return "KEYWORD(struct)";
|
||||
case TT_KW_ENUM:
|
||||
return "KEYWORD(enum)";
|
||||
case TT_KW_BREAK:
|
||||
return "KEYWORD(break)";
|
||||
case TT_KW_CONTINUE:
|
||||
return "KEYWORD(continue)";
|
||||
}
|
||||
}
|
||||
|
||||
char* escape_str(char* str) {
|
||||
// First, determine the length of the new string
|
||||
size_t new_length = 0;
|
||||
for (const char* p = str; *p != '\0'; ++p) {
|
||||
if (*p == '\n' || *p == '\r') {
|
||||
new_length += 2; // Each '\n' or '\r' becomes two characters: '\\' and 'n' or 'r'
|
||||
} else {
|
||||
new_length += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory for the new string
|
||||
char* new_str = (char*)malloc(new_length + 1); // +1 for the null terminator
|
||||
if (new_str == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Replace '\n' with "\\n" and '\r' with "\\r"
|
||||
char* q = new_str;
|
||||
for (const char* p = str; *p != '\0'; ++p) {
|
||||
if (*p == '\n') {
|
||||
*q++ = '\\';
|
||||
*q++ = 'n';
|
||||
} else if (*p == '\r') {
|
||||
*q++ = '\\';
|
||||
*q++ = 'r';
|
||||
} else {
|
||||
*q++ = *p;
|
||||
}
|
||||
}
|
||||
*q = '\0'; // Null-terminate the new string
|
||||
|
||||
return new_str;
|
||||
}
|
159
src/tokeniser.c
159
src/tokeniser.c
|
@ -4,15 +4,34 @@
|
|||
|
||||
#include "tokeniser.h"
|
||||
#include "dyn_arr.h"
|
||||
#include "logger.h"
|
||||
#include "token.h"
|
||||
|
||||
DEFINE_DA_IMPL(token, token_t)
|
||||
|
||||
#define TZ_TOK_PUSH(_loc, _type, _text) mcl_da_token_push(&tz->tokens, (token_t){.loc = (_loc), .type = (_type), .text=(_text)})
|
||||
|
||||
static struct {
|
||||
char* k;
|
||||
token_type_t v;
|
||||
} KEYWORDS[] = {
|
||||
{"fn", TT_KW_FN },
|
||||
{"return", TT_KW_RETURN},
|
||||
{"for", TT_KW_FOR},
|
||||
{"if", TT_KW_IF},
|
||||
{"else", TT_KW_ELSE},
|
||||
{"enum", TT_KW_ENUM},
|
||||
{"struct", TT_KW_STRUCT},
|
||||
{"while", TT_KW_WHILE},
|
||||
{"break", TT_KW_BREAK},
|
||||
{"continue", TT_KW_CONTINUE}
|
||||
};
|
||||
|
||||
tokeniser_t* tokenise(char* file) {
|
||||
tokeniser_t* tz = malloc(sizeof(tokeniser_t));
|
||||
tz->loc.file = file;
|
||||
tz->loc.line = 1;
|
||||
tz->loc.col = 1;
|
||||
FILE* f = fopen(file, "r");
|
||||
if (!f) {
|
||||
printf("Could not open file %s\n", file);
|
||||
|
@ -21,30 +40,33 @@ tokeniser_t* tokenise(char* file) {
|
|||
|
||||
char c;
|
||||
while ((c = fgetc(f)) != EOF) {
|
||||
tz->loc.col++;
|
||||
switch(c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r': break;
|
||||
case '\r':
|
||||
case ' ':{
|
||||
tz->loc.col += 1;
|
||||
} break;
|
||||
|
||||
case '\n': {
|
||||
tz->loc.col = 0;
|
||||
tz->loc.col = 1;
|
||||
tz->loc.line++;
|
||||
} break;
|
||||
|
||||
case '"': {
|
||||
loc_t loc = tz->loc;
|
||||
int size = 256;
|
||||
int i = 0;
|
||||
char* buf = malloc(size * sizeof(char));
|
||||
while ((c = fgetc(f)) != EOF) {
|
||||
tz->loc.col++;
|
||||
if (size <= strlen(buf) - 1) {
|
||||
buf = realloc(buf, size *= 2);
|
||||
}
|
||||
if (c == '\n') {
|
||||
printf("ERROR: Newline in string\n");
|
||||
mcl_log_loc(ERROR, &tz->loc, "No newlines in strings");
|
||||
return NULL;
|
||||
}
|
||||
tz->loc.col++;
|
||||
|
||||
if (c == '"') break;
|
||||
if (c == '\\') {
|
||||
switch (c = fgetc(f)) {
|
||||
|
@ -55,25 +77,36 @@ tokeniser_t* tokenise(char* file) {
|
|||
|
||||
buf[i++] = c;
|
||||
}
|
||||
TZ_TOK_PUSH(tz->loc, TT_STR, buf);
|
||||
TZ_TOK_PUSH(loc, TT_STR, buf);
|
||||
} break;
|
||||
|
||||
case '\'': {
|
||||
loc_t loc = tz->loc;
|
||||
bool escape = false;
|
||||
char c = fgetc(f);
|
||||
tz->loc.col += 1;
|
||||
char* buf = malloc(1 * sizeof(char));
|
||||
if (c == '\\') {
|
||||
c = fgetc(f);
|
||||
tz->loc.col += 1;
|
||||
switch (c) {
|
||||
case 'n': *buf = '\n'; break;
|
||||
default:
|
||||
printf("ERROR: Unknown escape: \\%c\n", c);
|
||||
mcl_log_loc(ERROR, &tz->loc, "Unknown escape: \\%c\n", c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
tz->loc.col += 1;
|
||||
*buf = c;
|
||||
}
|
||||
TZ_TOK_PUSH(tz->loc, TT_CHR, buf);
|
||||
|
||||
c = fgetc(f);
|
||||
if (c != '\'') {
|
||||
mcl_log_loc(ERROR, &tz->loc, "Expected \"'\" found \"%c\"", c);
|
||||
return NULL;
|
||||
}
|
||||
TZ_TOK_PUSH(loc, TT_CHR, buf);
|
||||
|
||||
}
|
||||
|
||||
|
@ -104,6 +137,7 @@ tokeniser_t* tokenise(char* file) {
|
|||
case 'y': case 'Y':
|
||||
case 'z': case 'Z':
|
||||
case '_': {
|
||||
loc_t loc = tz->loc;
|
||||
int size = 256;
|
||||
int i = 1;
|
||||
char* buf = malloc(size * sizeof(char));
|
||||
|
@ -114,6 +148,7 @@ tokeniser_t* tokenise(char* file) {
|
|||
(c >= '0' && c <= '9') ||
|
||||
(c == '_')
|
||||
)) {
|
||||
tz->loc.col++;
|
||||
ungetc(c, f);
|
||||
break;
|
||||
};
|
||||
|
@ -124,31 +159,97 @@ tokeniser_t* tokenise(char* file) {
|
|||
tz->loc.col++;
|
||||
buf[i++] = c;
|
||||
}
|
||||
TZ_TOK_PUSH(tz->loc, TT_IDENT, buf);
|
||||
bool found = false;
|
||||
for (int i = 0; i < sizeof(KEYWORDS)/sizeof(KEYWORDS[0]); i++) {
|
||||
if (strcmp(buf, KEYWORDS[i].k) == 0) {
|
||||
TZ_TOK_PUSH(loc, KEYWORDS[i].v, NULL);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) TZ_TOK_PUSH(loc, TT_IDENT, buf);
|
||||
|
||||
} break;
|
||||
|
||||
case '}': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '{': TZ_TOK_PUSH(tz->loc, TT_CURLY_L, NULL); break;
|
||||
case ']': TZ_TOK_PUSH(tz->loc, TT_BRACK_R, NULL); break;
|
||||
case '[': TZ_TOK_PUSH(tz->loc, TT_BRACK_L, NULL); break;
|
||||
case ')': TZ_TOK_PUSH(tz->loc, TT_PAREN_R, NULL); break;
|
||||
case '(': TZ_TOK_PUSH(tz->loc, TT_PAREN_L, NULL); break;
|
||||
case ':': TZ_TOK_PUSH(tz->loc, TT_COLON, NULL); break;
|
||||
case ';': TZ_TOK_PUSH(tz->loc, TT_SEMI, NULL); break;
|
||||
case ',': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '.': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '&': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '*': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '+': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '-': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '/': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '|': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '=': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '<': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '>': TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL); break;
|
||||
case '}': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '{': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_L, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case ']': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_BRACK_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '[': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_BRACK_L, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case ')': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_PAREN_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '(': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_PAREN_L, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case ':': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_COLON, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case ';': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_SEMI, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case ',': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '.': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '&': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '*': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '+': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '-': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '/': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '|': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '=': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '<': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
case '>': {
|
||||
TZ_TOK_PUSH(tz->loc, TT_CURLY_R, NULL);
|
||||
tz->loc.col++;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return tz;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user