From: Brendan Hansen Date: Thu, 21 May 2020 02:36:27 +0000 (-0500) Subject: Working on parser and custom printf alternative X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=012bfbbf3903297c540029abffe7f6ddbf6f2eef;p=onyx.git Working on parser and custom printf alternative --- diff --git a/bh.h b/bh.h index 6ee6f882..556f3f86 100644 --- a/bh.h +++ b/bh.h @@ -8,6 +8,7 @@ #include // TODO: Replace with custom implementation of printf #include +#include #include // TODO: Replace with needed functions #include @@ -42,6 +43,7 @@ typedef void* ptr; #ifdef BH_DEBUG void* bh__debug_malloc(size_t size, const char* file, u64 line); +void* bh__debug_aligned_alloc(size_t size, size_t alignment, const char* file, u64 line); void bh__debug_free(void* ptr, const char* file, u64 line); void* bh__debug_realloc(void* ptr, size_t size, const char* file, u64 line); @@ -121,8 +123,13 @@ i64 chars_match(char* ptr1, char* ptr2); //------------------------------------------------------------------------------------- // Helpful macros //------------------------------------------------------------------------------------- +#define bh_offset_of(Type, elem) ((isize)&(((Type)*) 0)->elem) +#define bh_aligh_of(Type) bh_offset_of(struct { char c; Type member; }, member) +#define bh_swap(Type, a, b) do { Type tmp = (a); (a) = (b); (b) = tmp; } while(0) + #define bh_pointer_add(ptr, amm) ((void *)((u8 *) ptr + amm)) #define BH_BIT(x) (1 << (x)) +#define BH_MASK_SET(var, set, mask) ((set) ? (var) |= (mask) : (var) &= ~(mask)) @@ -217,6 +224,7 @@ BH_ALLOCATOR_PROC(bh_scratch_allocator_proc); + //------------------------------------------------------------------------------------- // Better strings //------------------------------------------------------------------------------------- @@ -288,7 +296,8 @@ void bh_string_print(bh_string* str); typedef enum bh_file_error { BH_FILE_ERROR_NONE, - BH_FILE_ERROR_INVALID + BH_FILE_ERROR_INVALID, + BH_FILE_ERROR_BAD_FD, } bh_file_error; typedef enum bh_file_mode { @@ -363,6 +372,55 @@ i32 bh_file_contents_delete(bh_file_contents* contents); +//------------------------------------------------------------------------------------- +// Alternate printing +//------------------------------------------------------------------------------------- +// Barebones implementation of printf. Does not support all format options +// Currently supports: +// %c - chars +// %_(u)d - ints where _ is: +// nothing - decimal +// o - octal +// x - hexadecimal +// %_(u)l - longs where _ is: +// nothing - decimal +// o - octal +// x - hexadecimal +// %f - floating points +// %s - null terminated strings +// %p - pointers +// %% - literal % + +enum bh__print_format { + BH__PRINT_FORMAT_DECIMAL = BH_BIT(0), + BH__PRINT_FORMAT_OCTAL = BH_BIT(1), + BH__PRINT_FORMAT_HEXADECIMAL = BH_BIT(2), + BH__PRINT_FORMAT_UNSIGNED = BH_BIT(3), +}; + +isize bh_printf(char const *fmt, ...); +isize bh_printf_va(char const *fmt, va_list va); +isize bh_printf_err(char const *fmt, ...); +isize bh_printf_err_va(char const *fmt, va_list va); +isize bh_fprintf(bh_file* f, char const *fmt, ...); +isize bh_fprintf_va(bh_file* f, char const *fmt, va_list va); +char* bh_bprintf(char const *fmt, ...); +char* bh_bprintf_va(char const *fmt, va_list va); +isize bh_snprintf(char *str, isize n, char const *fmt, ...); +isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va); + + + + + + + + + + + + + //------------------------------------------------------------------------------------- // Better dynamically-sized arrays //------------------------------------------------------------------------------------- @@ -969,6 +1027,8 @@ bh_file_error bh_file_get_standard(bh_file* file, bh_file_standard stand) { sd_fd = STDERR_FILENO; filename = "stderr"; break; + default: + return BH_FILE_ERROR_BAD_FD; } file->fd = sd_fd; @@ -1144,6 +1204,164 @@ b32 bh_file_contents_delete(bh_file_contents* contents) { + + + + + + + + +//------------------------------------------------------------------------------------- +// ALTERNATE PRINTF IMPLEMENTATION +//------------------------------------------------------------------------------------- +isize bh_printf(char const *fmt, ...) { + isize res; + va_list va; + va_start(va, fmt); + res = bh_printf_va(fmt, va); + va_end(va); + return res; +} + +isize bh_printf_va(char const *fmt, va_list va) { + bh_file file; + bh_file_get_standard(&file, BH_FILE_STANDARD_OUTPUT); + return bh_fprintf_va(&file, fmt, va); +} + +isize bh_printf_err(char const *fmt, ...) { + isize res; + va_list va; + va_start(va, fmt); + res = bh_printf_err_va(fmt, va); + va_end(va); + return res; +} + +isize bh_printf_err_va(char const *fmt, va_list va) { + bh_file file; + bh_file_get_standard(&file, BH_FILE_STANDARD_ERROR); + return bh_fprintf_va(&file, fmt, va); +} + +isize bh_fprintf(bh_file* f, char const *fmt, ...) { + isize res; + va_list va; + va_start(va, fmt); + res = bh_fprintf_va(f, fmt, va); + va_end(va); + return res; +} + +isize bh_fprintf_va(bh_file* f, char const *fmt, va_list va) { + static char buf[4096]; + isize len = bh_snprintf_va(buf, sizeof(buf), fmt, va); + bh_file_write(f, buf, len - 1); + return len; +} + +char* bh_bprintf(char const *fmt, ...) { + char* res; + va_list va; + va_start(va, fmt); + res = bh_bprintf_va(fmt, va); + va_end(va); + return res; +} + +char* bh_bprintf_va(char const *fmt, va_list va) { + static char buffer[4096]; + bh_snprintf_va(buffer, sizeof(buffer), fmt, va); + return buffer; +} + +isize bh_snprintf(char *str, isize n, char const *fmt, ...) { + isize res; + va_list va; + va_start(va, fmt); + res = bh_snprintf_va(str, n, fmt, va); + va_end(va); + return res; +} + +isize bh__print_string(char* dest, isize n, char* src) { + isize len = 0; + while (n-- && (*dest++ = *src++)) len++; + return len; +} + +isize bh__printi64(char* str, isize n, enum bh__print_format format, i32 value) { + char buf[130]; + buf[129] = 0; + char* walker = buf + 129; + + while (value > 0) { + *--walker = '0' + (value % 10); + value /= 10; + } + + return bh__print_string(str, n, walker); +} + + +isize bh_snprintf_va(char *str, isize n, char const *fmt, va_list va) { + char const *text_start = str; + isize res; + + while (*fmt) { + i32 base = 10, size; + isize len = 0; + + while (*fmt && *fmt != '%') { + *(str++) = *(fmt++); + len++; + } + + fmt++; + + switch (*fmt++) { + case 'o': base = 8; break; + case 'x': base = 16; break; + default: fmt--; + } + + switch (*fmt) { + case 'c': { + char c = (char) va_arg(va, int); + *(str++) = c; + } break; + + case 'd': { + i64 value = (i64) va_arg(va, int); + len = bh__printi64(str, n, 0, value); + } break; + + default: fmt--; + } + + fmt++; + + str += len; + } + + return str - text_start + 1; +} + + + + + + + + + + + + + + + //------------------------------------------------------------------------------------- // ARRAY IMPLEMENTATION //------------------------------------------------------------------------------------- diff --git a/onyx b/onyx index bd859e22..43688daa 100755 Binary files a/onyx and b/onyx differ diff --git a/onyx.c b/onyx.c index 3840fa00..07d27214 100644 --- a/onyx.c +++ b/onyx.c @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) { // for (OnyxToken* it = token_arr; !bh_arr_end(token_arr, it); it++) { // onyx_token_null_toggle(*it); - // printf("%s '%s' (%s:%ld:%ld)\n", onyx_get_token_type_name(*it), it->token, it->pos.filename, it->pos.line, it->pos.column); + // printf("%s (%s:%ld:%ld)\n", onyx_get_token_type_name(it->type), it->pos.filename, it->pos.line, it->pos.column); // onyx_token_null_toggle(*it); // } diff --git a/onyxparser.c b/onyxparser.c index f194266b..d8c9fd86 100644 --- a/onyxparser.c +++ b/onyxparser.c @@ -5,23 +5,23 @@ struct OnyxTypeInfo builtin_types[] = { { ONYX_TYPE_INFO_KIND_UNKNOWN, 0, "unknown" }, { ONYX_TYPE_INFO_KIND_VOID, 0, "void" }, - + { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1 }, - + { ONYX_TYPE_INFO_KIND_UINT8, 1, "u8", 1, 1, 0, 0 }, { ONYX_TYPE_INFO_KIND_UINT16, 2, "u16", 1, 1, 0, 0 }, { ONYX_TYPE_INFO_KIND_UINT32, 4, "u32", 1, 1, 0, 0 }, { ONYX_TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0 }, - + { ONYX_TYPE_INFO_KIND_INT8, 1, "i8", 1, 0, 0, 0 }, { ONYX_TYPE_INFO_KIND_INT16, 2, "i16", 1, 0, 0, 0 }, { ONYX_TYPE_INFO_KIND_INT32, 4, "i32", 1, 0, 0, 0 }, { ONYX_TYPE_INFO_KIND_INT64, 8, "i64", 1, 0, 0, 0 }, - + { ONYX_TYPE_INFO_KIND_FLOAT32, 4, "f32", 0, 0, 1, 0 }, { ONYX_TYPE_INFO_KIND_FLOAT64, 8, "f64", 0, 0, 1, 0 }, { ONYX_TYPE_INFO_KIND_SOFT_FLOAT, 8, "sf64", 0, 0, 1, 0 }, - + { 0xffffffff } // Sentinel }; @@ -35,12 +35,12 @@ static void parser_next_token(OnyxParser* parser) { static b32 is_terminating_token(OnyxTokenType token_type) { switch (token_type) { - case TOKEN_TYPE_SYM_SEMICOLON: - case TOKEN_TYPE_CLOSE_BRACE: - case TOKEN_TYPE_OPEN_BRACE: - case TOKEN_TYPE_END_STREAM: + case TOKEN_TYPE_SYM_SEMICOLON: + case TOKEN_TYPE_CLOSE_BRACE: + case TOKEN_TYPE_OPEN_BRACE: + case TOKEN_TYPE_END_STREAM: return 1; - default: + default: return 0; } } @@ -49,7 +49,7 @@ static b32 is_terminating_token(OnyxTokenType token_type) { static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type) { OnyxToken* token = parser->curr_token; parser_next_token(parser); - + if (token->type != token_type) { onyx_message_add(parser->msgs, ONYX_MESSAGE_TYPE_EXPECTED_TOKEN, @@ -57,10 +57,14 @@ static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type) { onyx_get_token_type_name(token_type), onyx_get_token_type_name(token->type)); return NULL; } - + return token; } +static OnyxAstNode* parse_factor(OnyxParser* parser) { + return &error_node; +} + static OnyxAstNode* parse_expression(OnyxParser* parser) { return &error_node; } @@ -70,50 +74,54 @@ static OnyxAstNode* parse_if_stmt(OnyxParser* parser) { } static OnyxAstNode* parse_expression_statement(OnyxParser* parser) { - + } static OnyxAstNode* parse_return_statement(OnyxParser* parser) { expect(parser, TOKEN_TYPE_KEYWORD_RETURN); - + + OnyxAstNode* return_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_RETURN); + return_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_VOID]; OnyxAstNode* expr = NULL; - + parser_next_token(parser); if (parser->curr_token->type != TOKEN_TYPE_SYM_SEMICOLON) { expr = parse_expression(parser); - - if (expr == &error_node) { + + if (expr == NULL || expr == &error_node) { return &error_node; } } + + return return_node; } static OnyxAstNodeBlock* parse_block(OnyxParser* parser); static OnyxAstNode* parse_statement(OnyxParser* parser) { switch (parser->curr_token->type) { - case TOKEN_TYPE_KEYWORD_RETURN: + case TOKEN_TYPE_KEYWORD_RETURN: return parse_return_statement(parser); - - case TOKEN_TYPE_OPEN_BRACE: + + case TOKEN_TYPE_OPEN_BRACE: return (OnyxAstNode *) parse_block(parser); - - case TOKEN_TYPE_SYMBOL: - case TOKEN_TYPE_OPEN_PAREN: - case TOKEN_TYPE_SYM_PLUS: - case TOKEN_TYPE_SYM_MINUS: - case TOKEN_TYPE_SYM_BANG: - case TOKEN_TYPE_LITERAL_NUMERIC: - case TOKEN_TYPE_LITERAL_STRING: + + case TOKEN_TYPE_SYMBOL: + case TOKEN_TYPE_OPEN_PAREN: + case TOKEN_TYPE_SYM_PLUS: + case TOKEN_TYPE_SYM_MINUS: + case TOKEN_TYPE_SYM_BANG: + case TOKEN_TYPE_LITERAL_NUMERIC: + case TOKEN_TYPE_LITERAL_STRING: return parse_expression_statement(parser); - - case TOKEN_TYPE_KEYWORD_IF: + + case TOKEN_TYPE_KEYWORD_IF: return parse_if_stmt(parser); - - case TOKEN_TYPE_SYM_SEMICOLON: + + case TOKEN_TYPE_SYM_SEMICOLON: return NULL; - - default: + + default: printf("ERROR\n"); parser_next_token(parser); return NULL; @@ -128,140 +136,139 @@ static OnyxAstNodeBlock* parse_block(OnyxParser* parser) { expect(parser, TOKEN_TYPE_SYM_MINUS); return NULL; } - + expect(parser, TOKEN_TYPE_OPEN_BRACE); - + OnyxAstNodeBlock* block = (OnyxAstNodeBlock *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_BLOCK); - + OnyxAstNode** next = &block->body; OnyxAstNode* stmt = NULL; while (parser->curr_token->type != TOKEN_TYPE_CLOSE_BRACE) { stmt = parse_statement(parser); - + if (stmt != NULL && stmt->kind != ONYX_AST_NODE_KIND_ERROR) { *next = stmt; next = &stmt->next; } - + expect(parser, TOKEN_TYPE_SYM_SEMICOLON); } - + return block; } static OnyxTypeInfo* parse_type(OnyxParser* parser) { OnyxTypeInfo* type_info = &builtin_types[ONYX_TYPE_INFO_KIND_UNKNOWN]; - + OnyxToken* symbol = expect(parser, TOKEN_TYPE_SYMBOL); if (symbol == NULL) return type_info; - + onyx_token_null_toggle(*symbol); - + if (!bh_hash_has(OnyxAstNode*, parser->identifiers, symbol->token)) { onyx_message_add(parser->msgs, ONYX_MESSAGE_TYPE_UNKNOWN_TYPE, symbol->pos, symbol->token); } else { OnyxAstNode* type_info_node = bh_hash_get(OnyxAstNode*, parser->identifiers, symbol->token); - + if (type_info_node->kind == ONYX_AST_NODE_KIND_TYPE) { type_info = type_info_node->type; } } - + onyx_token_null_toggle(*symbol); return type_info; } static OnyxAstNodeParam* parse_function_params(OnyxParser* parser) { expect(parser, TOKEN_TYPE_OPEN_PAREN); - + if (parser->curr_token->type == TOKEN_TYPE_CLOSE_PAREN) { parser_next_token(parser); return NULL; } - + OnyxAstNodeParam* first_param = NULL; - + OnyxAstNodeParam* curr_param = NULL; OnyxAstNodeParam* trailer = NULL; - + OnyxToken* symbol; while (parser->curr_token->type != TOKEN_TYPE_CLOSE_PAREN) { if (parser->curr_token->type == TOKEN_TYPE_SYM_COMMA) parser_next_token(parser); - + symbol = expect(parser, TOKEN_TYPE_SYMBOL); - + curr_param = (OnyxAstNodeParam *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PARAM); curr_param->token = symbol; curr_param->type = parse_type(parser); - + if (first_param == NULL) first_param = curr_param; - + curr_param->next = NULL; if (trailer) trailer->next = curr_param; - + trailer = curr_param; } - + parser_next_token(parser); // Skip the ) return first_param; } static OnyxAstNodeFuncDef* parse_function_definition(OnyxParser* parser) { expect(parser, TOKEN_TYPE_KEYWORD_PROC); - + OnyxAstNodeFuncDef* func_def = (OnyxAstNodeFuncDef *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_FUNCDEF); func_def->param_count = 0; - + OnyxAstNodeParam* params = parse_function_params(parser); func_def->params = params; - + for (OnyxAstNode* walker = (OnyxAstNode *) params; walker != NULL; walker = walker->next) func_def->param_count++; - + expect(parser, TOKEN_TYPE_RIGHT_ARROW); - + OnyxTypeInfo* return_type = parse_type(parser); func_def->return_type = return_type; - + func_def->body = parse_block(parser); return func_def; } - static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) { switch (parser->curr_token->type) { - case TOKEN_TYPE_KEYWORD_USE: + case TOKEN_TYPE_KEYWORD_USE: assert(0); break; - - case TOKEN_TYPE_KEYWORD_EXPORT: + + case TOKEN_TYPE_KEYWORD_EXPORT: assert(0); - break; - - case TOKEN_TYPE_SYMBOL: { - OnyxToken* symbol = parser->curr_token; - parser_next_token(parser); - - expect(parser, TOKEN_TYPE_SYM_COLON); - expect(parser, TOKEN_TYPE_SYM_COLON); - - if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) { - OnyxAstNodeFuncDef* func_def = parse_function_definition(parser); - func_def->token = symbol; - return (OnyxAstNode *) func_def; - - } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) { - // Handle struct case - assert(0); - } else { - onyx_message_add(parser->msgs, - ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN, - parser->curr_token->pos, - onyx_get_token_type_name(parser->curr_token->type)); - } - } break; + break; + + case TOKEN_TYPE_SYMBOL: { + OnyxToken* symbol = parser->curr_token; + parser_next_token(parser); + + expect(parser, TOKEN_TYPE_SYM_COLON); + expect(parser, TOKEN_TYPE_SYM_COLON); + + if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) { + OnyxAstNodeFuncDef* func_def = parse_function_definition(parser); + func_def->token = symbol; + return (OnyxAstNode *) func_def; + + } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) { + // Handle struct case + assert(0); + } else { + onyx_message_add(parser->msgs, + ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN, + parser->curr_token->pos, + onyx_get_token_type_name(parser->curr_token->type)); + } + } break; } - + parser_next_token(parser); return NULL; } @@ -275,15 +282,15 @@ static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) { OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind) {\ OnyxAstNode* node = (OnyxAstNode *) bh_alloc(alloc, sizeof(OnyxAstNode)); node->kind = kind; - + return node; } OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs) { OnyxParser parser; - + bh_hash_init(bh_heap_allocator(), parser.identifiers); - + OnyxTypeInfo* it = &builtin_types[0]; while (it->kind != 0xffffffff) { OnyxAstNode* tmp = onyx_ast_node_new(alloc, ONYX_AST_NODE_KIND_TYPE); @@ -291,13 +298,13 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, Onyx bh_hash_put(OnyxAstNode*, parser.identifiers, (char *)it->name, tmp); it++; } - + parser.allocator = alloc; parser.tokenizer = tokenizer; parser.curr_token = tokenizer->tokens; parser.prev_token = NULL; parser.msgs = msgs; - + return parser; } @@ -307,18 +314,18 @@ void onyx_parser_free(OnyxParser* parser) { OnyxAstNode* onyx_parse(OnyxParser *parser) { OnyxAstNode* program = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PROGRAM); - + OnyxAstNode** prev_stmt = &program->next; OnyxAstNode* curr_stmt = NULL; while (parser->curr_token->type != TOKEN_TYPE_END_STREAM) { curr_stmt = parse_top_level_statement(parser); - + // Building a linked list of statements down the "next" chain if (curr_stmt != NULL && curr_stmt != &error_node) { *prev_stmt = curr_stmt; prev_stmt = &curr_stmt->next; } } - + return program; } diff --git a/progs/minimal.onyx b/progs/minimal.onyx index 9985f5a7..bbb2d1c8 100644 --- a/progs/minimal.onyx +++ b/progs/minimal.onyx @@ -1,6 +1,6 @@ /* This is a comment */ -log :: proc (a i32, b i64) -> i32 ---; +log :: proc (a i32, b i32) -> i32 ---; add :: proc (a i32, b i32) -> i32 { /* More comments */