#include "compiler.h" #include "common.h" #include "emit.h" #include "lexer.h" #include "libc.h" #include "list.h" Parser *parser; Emitter *emitter; Arena *arena; List *code; List *memory; /**************************************************** * Scope ***************************************************/ void scopes_init(void) { Scope *current; Scope child = {0}; child.symbols = List_init(arena); child.locals_offset = 0; current = (Scope *)List_push(arena, parser->scopes, &child, sizeof(Scope)); parser->current_scope = current; } Scope * scope_new(void) { Scope *current; Scope child = {0}; child.symbols = List_init(arena); child.parent = parser->current_scope; child.locals_offset = 0; current = (Scope *)List_push(arena, parser->scopes, &child, sizeof(Scope)); parser->current_scope = current; parser->scope_idx++; parser->depth++; return current; } void scope_pop(void) { if(parser->current_scope) { parser->current_scope = parser->current_scope->parent; parser->depth--; } } void scope_push(void) { parser->scope_idx++; parser->depth++; parser->current_scope = (Scope *)List_get(parser->scopes, parser->scope_idx); } Symbol * scope_get_symbol(Scope *scope, const char *name, u32 name_length) { u32 count, i; if(!scope) return nil; count = scope->symbols->count; for(i = 0; i < count; i++) { Symbol *sym = List_get(scope->symbols, i); if(sym->name_length == name_length && sleq(sym->name, name, name_length)) return sym; } return scope_get_symbol(scope->parent, name, name_length); } Symbol * scope_add_symbol(const char *name, u32 name_length, SymbolType type, u32 size) { Symbol new_sym = {0}; Symbol *sym = scope_get_symbol(parser->current_scope, name, name_length); if(sym != nil) { if(parser->pass) return sym; else emitter->error("duplicate found", 14, parser->previous.line); } scpy(new_sym.name, name, name_length); new_sym.name_length = name_length; new_sym.type = type; new_sym.secondary_type = SYMBOL_VOID; new_sym.size = size; new_sym.ref = parser->current_scope->locals_offset; new_sym.scope = parser->scope_idx; parser->current_scope->locals_offset += size; if(type == SYMBOL_PLEX || type == SYMBOL_METHOD || type == SYMBOL_TRAIT || type == SYMBOL_FUNCTION) { new_sym.args = List_init(arena); } if(type == SYMBOL_PLEX || type == SYMBOL_METHOD || type == SYMBOL_TRAIT) new_sym.fields = List_init(arena); return List_push(arena, parser->current_scope->symbols, &new_sym, sizeof(Symbol)); } bool is_global(void) { return parser->current_scope != nil && parser->current_scope->parent == nil; } bool is_type(void) { return parser->previous.type >= TOKEN_TYPE_I8 && parser->previous.type <= TOKEN_TYPE_PTR; } bool is_current_type(void) { return parser->current.type >= TOKEN_TYPE_I8 && parser->current.type <= TOKEN_TYPE_PTR; } SymbolType token_type_to_sym_type(TokenType t) { switch(t) { case TOKEN_TYPE_BOOL: return SYMBOL_BOOL; case TOKEN_TYPE_BYTE: return SYMBOL_BYTE; case TOKEN_TYPE_INT: return SYMBOL_INT; case TOKEN_TYPE_NAT: return SYMBOL_NAT; case TOKEN_TYPE_REAL: return SYMBOL_REAL; case TOKEN_TYPE_STR: return SYMBOL_STR; case TOKEN_TYPE_U8: return SYMBOL_U8; case TOKEN_TYPE_I8: return SYMBOL_I8; case TOKEN_TYPE_I16: return SYMBOL_I16; case TOKEN_TYPE_U16: return SYMBOL_U16; default: break; } return SYMBOL_UNDEFINED; } /**************************************************** * Parser ***************************************************/ bool advance(void) { parser->before = parser->previous; parser->previous = parser->current; for(;;) { parser->current = next_token(); if(parser->current.type != TOKEN_ERROR) return true; return false; } } bool check(TokenType type) { return parser->current.type == type; } bool consume_is_type(void) { if(is_type()) { advance(); return true; } return false; } bool consume(TokenType type) { if(check(type)) { advance(); return true; } return false; } bool match(TokenType type) { if(!check(type)) return false; advance(); return true; } void expect(TokenType type) { if(!consume(type)) { emitter->error(parser->previous.start, parser->previous.length, parser->previous.line); } } u32 variable_declaration(Symbol *def); void define_plex(void) { } void define_trait(void) { } void define_function(void) { Symbol *fn; u32 size = 0; advance(); fn = scope_add_symbol(parser->previous.start, parser->previous.length, SYMBOL_FUNCTION, 0); /* need to push scope early because the variables need to be a part of the fn * scope */ scope_new(); expect(TOKEN_LPAREN); /* parse the args */ while(!check(TOKEN_RPAREN)) { advance(); size += variable_declaration(fn); if(check(TOKEN_RPAREN)) break; expect(TOKEN_COMMA); } advance(); if(is_current_type()) { /* get return slot */ fn->secondary_type = token_type_to_sym_type(parser->current.type); advance(); } expect(TOKEN_LBRACE); /* get the size of all the locals for the function in the body */ while(parser->depth > 0) { if(match(TOKEN_LBRACE)) { scope_new(); continue; } else if(match(TOKEN_RBRACE)) { scope_pop(); continue; } else if(is_type() && parser->current.type == TOKEN_IDENTIFIER) size += variable_declaration(nil); advance(); } fn->size = size; } void calculate_strides(List *dims, List *strides) { u32 *num; u32 i; u32 num_dims = dims->count; u32 current_stride = 1; if(num_dims == 1) { List_push(arena, strides, ¤t_stride, sizeof(u32)); return; } for(i = num_dims - 1; i > 0; i--) { List_push(arena, strides, ¤t_stride, sizeof(u32)); /* this is very slow but for small numbers of dimensions its fine */ num = (u32 *)List_get(dims, i); if(num) { current_stride *= (*num); } else { emitter->error("Tried to get a dimension that did not exist", 43, parser->previous.line); } } } Symbol* define_array(void) { i32 size = 0, n = 0, flat_array_length = 1; TokenType tt = parser->previous.type; SymbolType st = token_type_to_sym_type(tt); Symbol *array; List *dims = List_init(arena); List *strides = List_init(arena); advance(); while(!match(TOKEN_RBRACKET)) { if(parser->current.type == TOKEN_LITERAL_INT) { n = ston(parser->current.start, parser->current.length); flat_array_length *= n; List_push(arena, dims, &n, sizeof(u32)); } advance(); if(check(TOKEN_LBRACKET)) break; if(check(TOKEN_COMMA)) { /* it is a multidimensional array */ } } size = emitter->get_size(st) * flat_array_length; array = scope_add_symbol(parser->current.start, parser->current.length, SYMBOL_ARRAY, size); array->secondary_type = st; calculate_strides(dims, strides); array->args = dims; array->fields = strides; return array; } void build_symbol_table(char *source) { init_lexer(source); advance(); scopes_init(); while(!match(TOKEN_EOF)) { if(match(TOKEN_LBRACE)) { scope_new(); } else if(match(TOKEN_RBRACE)) { scope_pop(); } else if(match(TOKEN_KEYWORD_FN)) { define_function(); } else if(match(TOKEN_KEYWORD_PLEX)) { define_plex(); } else if(match(TOKEN_KEYWORD_TRAIT)) { define_trait(); } else { /* in binary bytecode output mode we need to count the bytes here */ /* otherwise ignore everything */ advance(); } } } void expression(void); void statement(void); void declaration(void); ParseRule *get_rule(TokenType type); void parse_precedence(Precedence precedence); u32 variable_declaration(Symbol *def) { i32 size = 0; TokenType tt = parser->previous.type; SymbolType st = token_type_to_sym_type(tt); Symbol *variable; List *array_literal; if(!def && tt == TOKEN_TYPE_STR) { variable = scope_add_symbol(parser->current.start, parser->current.length, SYMBOL_STR, 0); if(!variable) { emitter->error("cannot find str symbol", 23, parser->current.line); return 0; } advance(); if(match(TOKEN_EQ)) { expect(TOKEN_LITERAL_STR); variable->size = parser->previous.length - 2; emitter->emit_str(arena, memory, variable, parser->previous.start, parser->previous.length); expect(TOKEN_SEMICOLON); } parser->current_type = st; return emitter->get_size(st); } if(!def && parser->current.type == TOKEN_LBRACKET) { variable = define_array(); if(!variable) { emitter->error("cannot find array symbol", 25, parser->current.line); return 0; } advance(); if(match(TOKEN_EQ)) { expect(TOKEN_LBRACKET); array_literal = List_init(arena); while(!match(TOKEN_RBRACKET)) { StrBuf_append_exactly(arena, array_literal, (char *)parser->current.start, parser->current.length); advance(); if(match(TOKEN_RBRACKET)) break; expect(TOKEN_COMMA); } expect(TOKEN_SEMICOLON); emitter->emit_array(arena, memory, variable, array_literal); } else { expect(TOKEN_SEMICOLON); emitter->emit_array(arena, memory, variable, nil); emitter->emit_zero_block(arena, memory, variable->size * emitter->get_size(variable->secondary_type)); } parser->current_type = st; return emitter->get_size(st); } if(st != SYMBOL_UNDEFINED) { size = emitter->get_size(st); variable = scope_add_symbol(parser->current.start, parser->current.length, st, size); if(!def && (parser->pass == 0)) return size; if(def) { List_push(arena, def->args, variable, sizeof(Symbol)); } else { emitter->emit_type(arena, code, variable); parser->current_type = st; } } else { /* we need to look up the type */ emitter->error("Not implemented", 16, parser->previous.line); } advance(); if(def && (check(TOKEN_COMMA) || check(TOKEN_RPAREN))) return size; if(def) emitter->error(parser->previous.start, parser->previous.length, parser->previous.line); if(parser->pass == 0) return size; if(match(TOKEN_EQ)) { emitter->emit_set_value(arena, code); expression(); emitter->emit_constant(arena, code, variable); } consume(TOKEN_SEMICOLON); emitter->emit_end_statement(arena, code); parser->current_type = SYMBOL_UNDEFINED; return size; } void binary(void) { TokenType operatorType = parser->previous.type; ParseRule *rule = get_rule(operatorType); parse_precedence((Precedence)(rule->precedence + 1)); switch(operatorType) { case TOKEN_BANG_EQ: emitter->emit_ne(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_EQ_EQ: emitter->emit_eq(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_GT: emitter->emit_gt(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_GTE: emitter->emit_ge(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_LT: emitter->emit_lt(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_LTE: emitter->emit_le(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_PLUS: emitter->emit_add(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_MINUS: emitter->emit_sub(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_STAR: emitter->emit_mul(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_SLASH: emitter->emit_div(arena, code, emitter->get_size(parser->current_type)); break; case TOKEN_OPERATOR_AND: emitter->emit_and(arena, code); break; case TOKEN_OPERATOR_OR: emitter->emit_or(arena, code); break; case TOKEN_OPERATOR_XOR: emitter->emit_xor(arena, code); break; case TOKEN_OPERATOR_MOD: emitter->emit_mod(arena, code); break; case TOKEN_SLL: emitter->emit_sll(arena, code); break; case TOKEN_SRL: emitter->emit_srl(arena, code); break; default: return; } } void literal(void) { switch(parser->previous.type) { case TOKEN_KEYWORD_FALSE: emitter->emit_false(arena, code); break; case TOKEN_KEYWORD_TRUE: emitter->emit_true(arena, code); break; case TOKEN_KEYWORD_NIL: emitter->emit_nil(arena, code); break; default: return; } } void expression(void) { parse_precedence(PREC_ASSIGNMENT); } void dot(void) { Symbol *sym = scope_get_symbol(parser->current_scope, parser->before.start, parser->before.length); if(sym == nil) { emitter->error(parser->current.start, parser->current.length, parser->current.line); } } void variable(void) { Symbol *sym = scope_get_symbol(parser->current_scope, parser->previous.start, parser->previous.length); if(sym == nil) { emitter->error(parser->previous.start, parser->previous.length, parser->previous.line); return; } if(sym->type == SYMBOL_FUNCTION) { parser->call_fn = sym; return; } if(sym->type == SYMBOL_STR) { emitter->emit_deref_prolog(arena, code, sym); if(match(TOKEN_LBRACKET)) { if (sym->scope) emitter->emit_deref(arena, code, 2); /* add offset of "length"*/ emitter->emit_nat(arena, code, "2", 1); emitter->emit_add(arena, code, 2); expression(); emitter->emit_add(arena, code, 2); while(!match(TOKEN_RBRACKET)) { } if(match(TOKEN_EQ)) { expression(); emitter->emit_stack_rot(arena, code, 1); emitter->emit_stack_rot(arena, code, 1); emitter->emit_ref_store(arena, code, 1); } else { emitter->emit_deref(arena, code, 1); } parser->current_type = SYMBOL_BYTE; } else if(match(TOKEN_DOT)) { if(sleq("length", parser->current.start, parser->current.length)) { if (sym->scope) emitter->emit_deref(arena, code, 2); emitter->emit_deref(arena, code, 2); } else { emitter->error("arrays currently can only get their length, don't do " "anything fancy yet...", 75, parser->current.line); } parser->current_type = SYMBOL_NAT; advance(); } else { if (sym->scope) emitter->emit_deref(arena, code, 2); } return; } if(sym->type == SYMBOL_ARRAY) { u32 size = emitter->get_size(sym->secondary_type); if(match(TOKEN_LBRACKET)) { emitter->emit_deref_prolog(arena, code, sym); expression(); emitter->emit_address(arena, code, 2); emitter->emit_mul(arena, code, 2); emitter->emit_add(arena, code, 2); /* add offset of "length"*/ emitter->emit_nat(arena, code, "2", 1); emitter->emit_add(arena, code, 2); while(!match(TOKEN_RBRACKET)) { /* eventually do something with multidimensional arrays */ } if(match(TOKEN_EQ)) { expression(); if(size == 1) { emitter->emit_stack_rot(arena, code, 1); emitter->emit_stack_rot(arena, code, 1); } else { emitter->emit_stack_swap(arena, code, 2); } emitter->emit_ref_store(arena, code, size); } else { emitter->emit_deref(arena, code, size); } parser->current_type = sym->secondary_type; } else if(match(TOKEN_DOT)) { emitter->emit_deref_prolog(arena, code, sym); if(sleq("length", parser->current.start, parser->current.length)) { emitter->emit_deref(arena, code, size); } else { emitter->error("arrays currently can only get their length, don't do " "anything fancy yet...", 75, parser->current.line); } parser->current_type = SYMBOL_NAT; advance(); } return; } parser->current_type = sym->type; if(match(TOKEN_EQ)) { expression(); emitter->emit_set_variable(arena, code, sym); } else { emitter->emit_variable(arena, code, sym); } } void cast_type(void) { SymbolType st = parser->current_type; TokenType cast_type; if(!(parser->current.type >= TOKEN_TYPE_I8 && parser->current.type <= TOKEN_TYPE_PTR)) { emitter->error("Expect type name after 'as'.", 26, parser->current.line); return; } cast_type = parser->current.type; advance(); switch(st) { case SYMBOL_INT: { switch(cast_type) { case TOKEN_TYPE_NAT: { emitter->emit_cast_int_to_nat(arena, code); break; } case TOKEN_TYPE_REAL: { emitter->emit_cast_int_to_real(arena, code); break; } case TOKEN_TYPE_STR: { emitter->emit_cast_int_to_str(arena, code); break; } default: emitter->error("Not castable to int", 19, parser->previous.line); } break; } case SYMBOL_NAT: { switch(cast_type) { case TOKEN_TYPE_INT: { emitter->emit_cast_nat_to_int(arena, code); break; } case TOKEN_TYPE_REAL: { emitter->emit_cast_nat_to_real(arena, code); break; } case TOKEN_TYPE_STR: { emitter->emit_cast_nat_to_str(arena, code); break; } default: emitter->error("Not castable to nat", 19, parser->previous.line); } break; } case SYMBOL_REAL: { switch(cast_type) { case TOKEN_TYPE_NAT: { emitter->emit_cast_real_to_nat(arena, code); break; } case TOKEN_TYPE_INT: { emitter->emit_cast_real_to_int(arena, code); break; } case TOKEN_TYPE_STR: { emitter->emit_cast_real_to_str(arena, code); break; } default: emitter->error("Not castable to real", 20, parser->previous.line); } break; } case SYMBOL_STR: { switch(cast_type) { case TOKEN_TYPE_NAT: { emitter->emit_cast_str_to_nat(arena, code); break; } case TOKEN_TYPE_REAL: { emitter->emit_cast_str_to_real(arena, code); break; } case TOKEN_TYPE_INT: { emitter->emit_cast_str_to_int(arena, code); break; } default: emitter->error("Not castable to str", 19, parser->previous.line); } break; } default: emitter->error("Type cast not implemented for this type (oops)", 46, parser->previous.line); } } void declaration(void) { if(is_type() && (parser->current.type == TOKEN_IDENTIFIER || parser->current.type == TOKEN_LBRACKET)) variable_declaration(nil); else statement(); } void print_statement(void) { expression(); if (parser->current_type == SYMBOL_STR) { emitter->emit_nat(arena, code, "2", 1); emitter->emit_add(arena, code, 2); } consume(TOKEN_SEMICOLON); emitter->emit_print(arena, code); emitter->emit_end_statement(arena, code); } void if_statement(void) { consume(TOKEN_LPAREN); expression(); consume(TOKEN_RPAREN); emitter->emit_if(arena, code); statement(); emitter->emit_patch_if(arena, code, emitter->ifs); if(match(TOKEN_KEYWORD_ELSE)) { emitter->else_if_depth++; statement(); emitter->else_if_depth--; } if(emitter->else_if_depth == 0) emitter->emit_patch_if_done(arena, code, emitter->ifs++); } void while_statement(void) { u32 this_while = emitter->loops++; emitter->emit_while(arena, code, this_while); consume(TOKEN_LPAREN); expression(); consume(TOKEN_RPAREN); emitter->emit_while_postfix(arena, code); statement(); emitter->emit_patch_while(arena, code, this_while); } void block(void) { while(!check(TOKEN_RBRACE) && !check(TOKEN_EOF)) { declaration(); } consume(TOKEN_RBRACE); } void function(void) { Symbol *sym = scope_get_symbol(parser->current_scope, parser->previous.start, parser->previous.length); emitter->emit_function(arena, code, sym); scope_push(); while(!check(TOKEN_RPAREN)) advance(); consume(TOKEN_RPAREN); if (is_current_type()) advance(); expect(TOKEN_LBRACE); block(); emitter->emit_arena_fn_return(arena, code); } void call(void) { if(!check(TOKEN_RPAREN)) { do { expression(); } while(match(TOKEN_COMMA)); } consume(TOKEN_RPAREN); emitter->emit_arena_fn_call(arena, code, parser->call_fn); parser->current_type = parser->call_fn->secondary_type; return; } void return_statement(void) { if(match(TOKEN_SEMICOLON)) { emitter->emit_early_return(arena, code); } else { expression(); consume(TOKEN_SEMICOLON); emitter->emit_early_return(arena, code); } } void statement(void) { if(match(TOKEN_LBRACE)) { scope_push(); block(); scope_pop(); } else if(match(TOKEN_KEYWORD_FN)) { advance(); function(); } else if(match(TOKEN_KEYWORD_RETURN)) { return_statement(); } else if(match(TOKEN_KEYWORD_IF)) { if_statement(); } else if(match(TOKEN_KEYWORD_WHILE)) { while_statement(); } else if(match(TOKEN_KEYWORD_PRINT)) { print_statement(); } else if(match(TOKEN_KEYWORD_HALT)) { emitter->emit_halt(arena, code); } else { expression(); } } void grouping(void) { emitter->emit_open_paren(arena, code); expression(); emitter->emit_close_paren(arena, code); consume(TOKEN_RPAREN); } void number(void) { switch(parser->current_type) { case SYMBOL_BOOL: case SYMBOL_BYTE: case SYMBOL_U8: case SYMBOL_I8: emitter->emit_byte(arena, code, parser->previous.start, parser->previous.length); break; default: emitter->emit_nat(arena, code, parser->previous.start, parser->previous.length); break; } } void string(void) { emitter->emit_inline_str(arena, code, parser->previous.start, parser->previous.length); } void character(void) { emitter->emit_char(arena, code, parser->previous.start, parser->previous.length); } void unary(void) { TokenType operatorType = parser->previous.type; parse_precedence(PREC_UNARY); switch(operatorType) { case TOKEN_MINUS: emitter->emit_neg(arena, code); break; case TOKEN_BANG: emitter->emit_not(arena, code); break; default: return; } } void read(void) { emitter->emit_read(arena, code); } void write(void) { consume(TOKEN_EQ); expression(); emitter->emit_write(arena, code); } void semicolon(void) { emitter->emit_end_statement(arena, code); } ParseRule rules[] = { /* TOKEN_ERROR */ {nil, nil, PREC_NONE}, /* TOKEN_EOF */ {nil, nil, PREC_NONE}, /* TOKEN_LPAREN */ {grouping, call, PREC_CALL}, /* TOKEN_RPAREN */ {nil, nil, PREC_NONE}, /* TOKEN_LBRACE */ {nil, nil, PREC_NONE}, /* TOKEN_RBRACE */ {nil, nil, PREC_NONE}, /* TOKEN_LBRACKET */ {nil, nil, PREC_NONE}, /* TOKEN_RBRACKET */ {nil, nil, PREC_NONE}, /* TOKEN_DOT */ {nil, dot, PREC_CALL}, /* TOKEN_IDENTIFIER */ {variable, nil, PREC_NONE}, /* TOKEN_LITERAL_INT */ {number, nil, PREC_NONE}, /* TOKEN_LITERAL_NAT */ {number, nil, PREC_NONE}, /* TOKEN_LITERAL_REAL */ {number, nil, PREC_NONE}, /* TOKEN_LITERAL_STR */ {string, nil, PREC_NONE}, /* TOKEN_TYPE_I8 */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_I16 */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_INT */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_U8 */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_U16 */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_NAT */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_REAL */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_STR */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_BOOL */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_BYTE */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_VOID */ {nil, nil, PREC_NONE}, /* TOKEN_TYPE_PTR */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_PLEX */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_FN */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_CONST */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_IF */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_IS */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_AS */ {nil, cast_type, PREC_CAST}, /* TOKEN_KEYWORD_ELSE */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_WHILE */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_FOR */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_RETURN */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_USE */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_INIT */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_THIS */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_OPEN */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_READ */ {read, nil, PREC_NONE}, /* TOKEN_KEYWORD_WRITE */ {write, nil, PREC_NONE}, /* TOKEN_KEYWORD_STAT */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_CLOSE */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_LOOP */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_DO */ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_NIL */ {literal, nil, PREC_NONE}, /* TOKEN_KEYWORD_TRUE */ {literal, nil, PREC_NONE}, /* TOKEN_KEYWORD_FALSE */ {literal, nil, PREC_NONE}, /* TOKEN_OPERATOR_AND */ {nil, binary, PREC_NONE}, /* TOKEN_OPERATOR_OR */ {nil, binary, PREC_NONE}, /* TOKEN_OPERATOR_XOR */ {nil, binary, PREC_NONE}, /* TOKEN_OPERATOR_MOD */ {nil, binary, PREC_NONE}, /* TOKEN_BANG */ {unary, nil, PREC_NONE}, /* TOKEN_BANG_EQ */ {nil, binary, PREC_EQUALITY}, /* TOKEN_EQ */ {nil, nil, PREC_NONE}, /* TOKEN_EQ_EQ */ {nil, binary, PREC_EQUALITY}, /* TOKEN_AND */ {nil, nil, PREC_NONE}, /* TOKEN_AND_AND */ {nil, nil, PREC_NONE}, /* TOKEN_PIPE */ {nil, nil, PREC_NONE}, /* TOKEN_PIPE_PIPE */ {nil, nil, PREC_NONE}, /* TOKEN_QUESTION */ {nil, nil, PREC_NONE}, /* TOKEN_QUESTION_DOT */ {nil, nil, PREC_NONE}, /* TOKEN_PLUS */ {nil, binary, PREC_TERM}, /* TOKEN_MINUS */ {unary, binary, PREC_TERM}, /* TOKEN_STAR */ {nil, binary, PREC_FACTOR}, /* TOKEN_SLASH */ {nil, binary, PREC_FACTOR}, /* TOKEN_MESH */ {nil, nil, PREC_NONE}, /* TOKEN_BIG_MONEY */ {nil, nil, PREC_NONE}, /* TOKEN_GT */ {nil, binary, PREC_COMPARISON}, /* TOKEN_LT */ {nil, binary, PREC_COMPARISON}, /* TOKEN_GTE */ {nil, binary, PREC_COMPARISON}, /* TOKEN_LTE */ {nil, binary, PREC_COMPARISON}, /* TOKEN_COMMA */ {nil, nil, PREC_NONE}, /* TOKEN_COLON */ {nil, nil, PREC_NONE}, /* TOKEN_CARET */ {nil, nil, PREC_NONE}, /* TOKEN_SEMICOLON */ {semicolon, nil, PREC_NONE}, /* TOKEN_ARROW_RIGHT */ {nil, nil, PREC_NONE}, /* TOKEN_SLL */ {nil, binary, PREC_NONE}, /* TOKEN_SRL */ {nil, binary, PREC_NONE}, /* TOKEN_KEYWORD_PRINT*/ {nil, binary, PREC_NONE}, /* TOKEN_KEYWORD_TRAIT*/ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_HALT*/ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_DEVMAP*/ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_BYTE*/ {nil, nil, PREC_NONE}, /* TOKEN_KEYWORD_CHAR*/ {character, nil, PREC_NONE}, }; void parse_precedence(Precedence precedence) { ParseFn prefixRule; ParseFn infixRule; advance(); prefixRule = get_rule(parser->previous.type)->prefix; if(prefixRule == nil) return; prefixRule(); while(precedence <= get_rule(parser->current.type)->precedence) { advance(); infixRule = get_rule(parser->previous.type)->infix; infixRule(); } } ParseRule * get_rule(TokenType type) { return &rules[type]; } void emit_program(char *source) { init_lexer(source); advance(); emitter->prolog(arena, code); while(!match(TOKEN_EOF)) declaration(); emitter->epilogue(arena, code); } bool compile(Arena *a, List *c, List *m, Emitter *e, char *source) { Parser p = {0}; arena = a; emitter = e; code = c; memory = m; parser = &p; parser->scopes = List_init(arena); build_symbol_table(source); parser->pass++; parser->depth = 0; parser->scope_idx = 0; parser->current_scope = List_get(parser->scopes, 0); emit_program(source); return true; }