function Token * token_get(S64 i = 0){ Get_Ctx(Parse_Ctx); i += ctx->token_iter; if(i >= ctx->tokens.len){ return &ctx->empty_token; } Token *result = &ctx->tokens[i]; return result; } function Token * token_next(){ Get_Ctx(Parse_Ctx); Token *token = token_get(); ctx->token_iter++; return token; } function Token * token_is(Token_Kind kind){ Token *token = token_get(); if(token->kind == kind){ return token; } return 0; } function Token * token_match(Token_Kind kind){ Token *token = token_get(); if(token->kind == kind){ return token_next(); } return 0; } function Token * token_match_keyword(Intern_String string){ Token *token = token_get(); if(token->kind == TK_Keyword){ if(string.str == token->intern_val.str){ token = token_next(); return token; } } return 0; } function void parsing_error(Token *token, const char *str, ...){ Set_Scratch(); STRING_FMT(imp_get(), str, string); // @Note(Krzosa): Print nice error message printf("\nError: %s", string.str); if(token){ printf(" %s:%d\n", token->file.str, (S32)token->line); // @Note(Krzosa): Print error line { int i = 0; while(token->line_begin[i]!='\n' && token->line_begin[i]!=0) i++; printf("%.*s\n", i, token->line_begin); // @Note(Krzosa): Print error marker int token_i = token->str - token->line_begin; for(int i = 0; i < token_i-2; i++) printf(" "); printf("^^^^^^\n"); } } __debugbreak(); } function Token * token_expect(Token_Kind kind){ Token *token = token_get(); if(token->kind == kind){ token = token_next(); return token; } parsing_error(token, "Expected token of kind: [%s], got instead token of kind: [%s]", token_kind_string(kind).str, token_kind_string(token->kind).str); return 0; } //----------------------------------------------------------------------------- // Expression parsing //----------------------------------------------------------------------------- /* add = [+-] mul = [/%*] compare = == | != | >= | > | <= | < logical = [&|^] | && | || unary = [&*-!~+] | ++ | -- atom_expr = Int | Float | String | Identifier | 'cast' '(' typespec ',' expr ')' | 'size_type' '(' typespec ')' | 'size_expr' '(' expr ')' | '{' compound_expr '}' | '(' expr ')' | '(' ':' typespec ')' '{' compound_expr '}' postfix_expr = atom_expr ('[' expr ']' | '.' Identifier | ++ | -- | '(' expr_list ')')* unary_expr = unary ? unary_expr : atom_expr mul_expr = atom_expr (mul atom_expr)* add_expr = mul_expr (add mul_expr)* logical_expr = add_expr (logical add_expr)* compare_expr = logical_expr (compare logical_expr)* ternary_expr = compare_expr ('?' ternary_expr ':' ternary_expr)? expr = logical_expr Compound literals - (:[23]*Type){} - Type{} - { } */ function Ast_Expr *parse_expr(S64 rbp = 0); function Ast_Expr * parse_expr_nud(Token *token){ switch(token->kind){ case TK_StringLit: return ast_expr_string(token, token->intern_val); case TK_Identifier: return ast_expr_identifier(token, token->intern_val); case TK_Integer: return ast_expr_integer(token, token->int_val); case TK_OpenParen: {Ast_Expr *result = parse_expr(); token_expect(TK_CloseParen); return result;} default: parsing_error(token, "Unexpected token of kind: [%s] in expression", token_kind_string(token->kind).str); return 0; } } function S64 op_precedence(Token_Kind kind){ Get_Ctx(Parse_Ctx); S64 result = ctx->pt[kind]; return result; } function Ast_Expr * parse_expr_led(Token *op, Ast_Expr *left){ enum{ Left_Associative, Right_Associative }; S64 assoc = Left_Associative; Ast_Expr *right = parse_expr(op_precedence(op->kind) - assoc); switch(op->kind){ case TK_Add: case TK_Mul: case TK_Sub: case TK_Div: return ast_expr_binary(left, right, op); default: parsing_error(op, "Unexpected token of kind: [%s] in expression", token_kind_string(op->kind).str); return 0; } } function Ast_Expr * parse_expr(S64 rbp){ Token *token = token_next(); Ast_Expr *left = parse_expr_nud(token); while(rbp < op_precedence(token_get()->kind)){ token = token_next(); left = parse_expr_led(token, left); } return left; } function S64 expr_eval(Ast_Expr *expr){ switch(expr->kind){ case AK_Expr_Int: return expr->int_val; case AK_Expr_Binary : { S64 left = expr_eval(expr->binary.left); S64 right = expr_eval(expr->binary.right); switch(expr->binary.op){ case TK_Add: return left + right; case TK_Sub: return left - right; case TK_Mul: return left * right; case TK_Div: return left / right; default: invalid_codepath; } }break; default: invalid_codepath; } return 0; } #define TEST_PARSER() \ Set_Scratch(); \ Parse_Ctx ctx = {}; \ ctx.init(); \ Set_Ctx(&ctx, Parse_Ctx_ID) function void test_parse_expr(){ TEST_PARSER(); struct Test{String str;S64 val;}; Array exprs = {}; exprs.add({"(4+5)*2"_s, (4+5)*2}); exprs.add({"4+5*2"_s, 4+5*2}); exprs.add({"4*5+5"_s, 4*5+5}); exprs.add({"4+5+5+3"_s, 4+5+5+3}); For(exprs,it,i){ lex_restream(&ctx, it->str, "test_expr"_s); Ast_Expr *result = parse_expr(); S64 val = expr_eval(result); assert(val == it->val); } } //----------------------------------------------------------------------------- // Parsing declarations //----------------------------------------------------------------------------- function Ast_Decl * parse_decl(){ Ast_Decl *result = 0; Token *token = token_match(TK_Identifier); if(token){ if(token_match(TK_DoubleColon)){ if(token_match_keyword(keyword_const)){ Ast_Expr *expr = parse_expr(); result = ast_decl_const(token, token->intern_val, expr); } } else parsing_error(token, "Encountered unexpected token while parsing a top level declarations"); } return result; } function void test_parse_decl(){ TEST_PARSER(); lex_restream(&ctx, "thing :: const 24252\n"_s, "test_parse_decl"_s); Ast_Decl *result = parse_decl(); }