global Intern_String intern_empty; global Intern_String intern_s64; global Intern_String intern_s32; global Intern_String intern_s16; global Intern_String intern_s8; global Intern_String intern_u64; global Intern_String intern_u32; global Intern_String intern_u16; global Intern_String intern_u8; global Intern_String intern_void; global Intern_String intern_sizeu; global Intern_String keyword_sizeof; global Intern_String keyword_enum; global Intern_String keyword_typedef; global Intern_String keyword_struct; global Intern_String keyword_union; global Intern_String keyword_function; global Intern_String keyword_global; global AST_Node *type_s64; global AST_Node *type_s32; global AST_Node *type_s16; global AST_Node *type_s8; global AST_Node *type_u64; global AST_Node *type_u32; global AST_Node *type_u16; global AST_Node *type_u8; global AST_Node *type_void; global AST_Node *type_sizeu; function void parser_init(Parser *p){ p->interns_count = 4096; p->interns = arena_push_array(&p->intern_table_arena, Intern_String, p->interns_count); p->symbols_count = 4096; p->symbols = arena_push_array(&p->symbol_table_arena, AST_Node, p->symbols_count); keyword_sizeof = intern_string(p, lit("sizeof")); keyword_struct = intern_string(p, lit("struct")); keyword_enum = intern_string(p, lit("enum")); keyword_typedef = intern_string(p, lit("typedef")); keyword_union = intern_string(p, lit("union")); keyword_function = intern_string(p, lit("function")); keyword_global = intern_string(p, lit("global")); p->first_keyword = keyword_sizeof.s.str; p->last_keyword = keyword_global.s.str; intern_s64 = intern_string(p, lit("S64")); intern_s32 = intern_string(p, lit("S32")); intern_s16 = intern_string(p, lit("S16")); intern_s8 = intern_string(p, lit("S8")); intern_u64 = intern_string(p, lit("U64")); intern_u32 = intern_string(p, lit("U32")); intern_u16 = intern_string(p, lit("U16")); intern_u8 = intern_string(p, lit("U8")); intern_void = intern_string(p, lit("void")); intern_sizeu = intern_string(p, lit("SizeU")); parser_push_scope(p); // Global scope type_s64 = symbol_register_basic_type(p, intern_s64, sizeof(S64)); type_s32 = symbol_register_basic_type(p, intern_s32, sizeof(S32)); type_s16 = symbol_register_basic_type(p, intern_s16, sizeof(S16)); type_s8 = symbol_register_basic_type(p, intern_s8, sizeof(S8)); type_u64 = symbol_register_basic_type(p, intern_u64, sizeof(U64)); type_u32 = symbol_register_basic_type(p, intern_u32, sizeof(U32)); type_u16 = symbol_register_basic_type(p, intern_u16, sizeof(U16)); type_u8 = symbol_register_basic_type(p, intern_u8, sizeof(U8)); type_void = symbol_register_basic_type(p, intern_void, sizeof(void)); type_sizeu = symbol_register_basic_type(p, intern_sizeu, sizeof(SizeU)); } function B32 intern_is_keyword(Parser *p, Intern_String intern){ if(intern.s.str >= p->first_keyword && intern.s.str <= p->last_keyword) return true; return false; } function void parser_push_error(Parser *p, Token *token, char *str, ...){ String string; { va_list args1, args2; va_start(args1, str); va_copy(args2, args1); string.len = vsnprintf(0, 0, str, args2); va_end(args2); string.str = arena_push_size(&p->main_arena, string.len + 1); vsnprintf((char*)string.str, string.len + 1, str, args1); va_end(args1); } lex_print("Error: %s\n", string.str);// @Todo(Krzosa): Parser_Error *error = arena_push_struct(&p->main_arena, Parser_Error); error->message = string; error->next = 0; error->token = token; SLLQueuePush(p->first_error, p->last_error, error); } function void intern_tokens(Parser *p){ for(S64 i = 0; i < p->tokens.len; i++){ Token *t = p->tokens.tokens + i; if(t->kind == TK_Identifier){ t->intern_val = intern_string(p, t->string); if(intern_is_keyword(p, t->intern_val)){ t->kind = TK_Keyword; } } else if(t->kind == TK_Error){ parser_push_error(p, t, (char *)t->error_val.str); } } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- typedef struct Table_Index{ U64 hash; U64 index; U64 iter; U64 max_size; }Table_Index; function Table_Index table_index_from_hash(U64 hash, U64 max_size){ Table_Index result = {0}; result.hash = hash; result.index = result.hash % max_size; result.iter = result.index; result.max_size = max_size; return result; } function Table_Index table_index_from_string(String string, U64 max_size){ U64 hash = hash_fnv(string); Table_Index result = table_index_from_hash(hash, max_size); return result; } function B32 table_index_advance(Table_Index *index){ index->iter = wrap_around_pow2(index->iter + 1, index->max_size); B32 result = index->iter == index->index; return result; } function Intern_String intern_string(Parser *p, String string){ Intern_String result = {}; Table_Index index = table_index_from_string(string, p->interns_count); for(;;){ Intern_String *intern = p->interns + index.iter; if(intern->s.str == 0){ result.s = arena_push_string_copy(&p->main_arena, string); p->interns_in_bytes += string.len; p->interns_inserted += 1; *intern = result; break; } else if(string_compare(intern->s, string)){ result = *intern; break; } if (table_index_advance(&index)) break; } return result; } //----------------------------------------------------------------------------- // Symbols //----------------------------------------------------------------------------- function AST_Node * symbol_alloc_slot(Parser *p, Intern_String string, B32 is_global){ Table_Index index = table_index_from_string(string.s, p->symbols_count); for(;;){ AST_Node *symbol = p->symbols + index.iter; if(symbol->name.s.str == 0){ /* @Note(Krzosa): Push on scope */ { if(is_global){ SLLQueuePushMod(p->scope_stack->first, p->scope_stack->last, symbol, next_scope); } else{ SLLQueuePushMod(p->global_scope->first, p->global_scope->last, symbol, next_scope); } } symbol->name = string; p->symbols_inserted++; return symbol; } else if(intern_compare(symbol->name, string)){ return symbol; } if (table_index_advance(&index)) break; } assert_msg(0, "Ran out of slots in symbol table"); return 0; } function AST_Node * symbol_lookup(Parser *p, Intern_String string){ Table_Index index = table_index_from_string(string.s, p->symbols_count); for(;;){ AST_Node *symbol = p->symbols + index.iter; if(symbol->name.s.str == 0){ return 0; } else if(intern_compare(symbol->name, string)){ return symbol; } if (table_index_advance(&index)) return 0; } } function AST_Node * symbol_register_basic_type(Parser *p, Intern_String string, SizeU size){ AST_Node *node = symbol_alloc_slot(p, string, true); assert(node->kind == AK_None); node->kind = AK_BaseType; node->base_type_size = size; return node; } function void symbol_register(Parser *p, AST_Node *node){ AST_Node *look = symbol_alloc_slot(p, node->name, false); if(look->kind == AK_None){ ast_copy_symbol(look, node); } else if(look->kind == node->kind){ if(look->kind == AK_Enum || look->kind == AK_Function || look->kind == AK_Union || look->kind == AK_Struct){ if(look->first_child == 0){ ast_copy_symbol(look, node); } else { parser_push_error(p, token_get(p), "Symbol already has a body"); } } else { parser_push_error(p, token_get(p), "Trying to register a symbol again"); } } else{ parser_push_error(p, token_get(p), "Trying to register a symbol of different kind with the same name"); } } function AST_Node * symbol_lookup_type(Parser *p, Intern_String string){ AST_Node *node = symbol_lookup(p, string); if(node){ if(ast_is_type(node)){ return node; } } return 0; } function AST_Node * symbol_require_type(Parser *p, Token *token){ AST_Node *result = symbol_lookup_type(p, token->intern_val); if(!result){ parser_push_error(p, token, "Undefined type"); } return result; } function void parser_push_scope(Parser *p){ Scope *scope = 0; SLLStackPop(p->scope_free_list, scope); if(!scope){ scope = arena_push_struct(&p->main_arena, Scope); } SLLStackPush(p->scope_stack, scope); if(p->global_scope == 0){ p->global_scope = scope; } } function void parser_pop_scope(Parser *p){ Scope *scope = 0; SLLStackPop(p->scope_stack, scope); assert(scope); for(AST_Node *s = scope->first; s; s=s->next_scope){ memory_zero(s, sizeof(AST_Node)); p->symbols_inserted--; } memory_zero(scope, sizeof(Scope)); SLLStackPush(p->scope_free_list, scope); }