typedef struct Parser_Error Parser_Error; struct Parser_Error{ Parser_Error *next; String message; Token *token; }; typedef struct Parser{ Token_Array tokens; Arena *arena; Parser_Error *first_error; Parser_Error *last_error; }Parser; 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->arena, string.len + 1); vsnprintf((char*)string.str, string.len + 1, str, args1); va_end(args1); } printf("Error: %s %s:%d\n", string.str, token->file.str, (S32)token->line); Parser_Error *error = arena_push_struct(p->arena, Parser_Error); error->message = string; error->next = 0; error->token = token; SLLQueuePush(p->first_error, p->last_error, error); __debugbreak(); } function Token * token_get(Parser *p){ Token *result = token_array_iter_peek(&p->tokens, 0); return result; } function Token * token_is(Parser *p, Token_Kind kind){ Token *result = token_get(p); if(result->kind == kind) return result; return 0; } function Token * token_next(Parser *p){ Token *result = token_array_iter_next(&p->tokens); return result; } function Token * token_match(Parser *p, Token_Kind kind){ Token *token = token_get(p); if(token->kind == kind){ token = token_next(p); return token; } return 0; } function Token * token_match_keyword(Parser *p, Intern_String string){ Token *token = token_get(p); if(token->kind == TK_Keyword){ if(intern_compare(token->intern_val, string)){ token = token_next(p); return token; } } return 0; } function Token * token_expect(Parser *p, Token_Kind kind){ Token *token = token_get(p); if(token->kind == kind){ token = token_next(p); return token; } parser_push_error(p, token, "Expected token of kind: %s, got instead token of kind: %s.", token_kind_string[kind], token_kind_string[token->kind]); return 0; } /* add = [+-] mul = [/%*] compare = == | != | >= | > | <= | < logical = [&|^] | && | || expr_atom = Int | Float | String | Identifier | 'cast' '(' typespec ',' expr ')' mul_expr = expr_atom (mul expr_atom)* add_expr = mul_expr (add mul_expr)* compare_expr = add_expr (compare add_expr)* logical_expr = compare_expr (logical compare_expr)* ternary_expr = logical_expr ('?' ternary_expr ':' ternary_expr)? expr = logical_expr */ function Expr * parse_expr_atom(Parser *p){ Token *token = 0; if((token = token_match(p, TK_StringLit))){ Expr *result = expr_str(p->arena, token); return result; } else if((token = token_match(p, TK_Int))){ Expr *result = expr_int(p->arena, token); return result; } else if((token = token_match_keyword(p, keyword_cast))){ token_expect(p, TK_OpenParen); token_expect(p, TK_Identifier); token_expect(p, TK_Comma); token_expect(p, TK_Identifier); token_expect(p, TK_CloseParen); return 0; } else{ parser_push_error(p, token_get(p), "Failed to parse expression"); return 0; } } function B32 token_is_mul(Parser *p){ Token *token = token_get(p); B32 result = token->kind >= TK_FirstMul && token->kind <= TK_LastMul; return result; } function Expr * parse_expr_mul(Parser *p){ Expr *left = parse_expr_atom(p); while(token_is_mul(p)){ Token *op = token_next(p); Expr *right = parse_expr_atom(p); left = expr_binary(p->arena, op, left, right); } return left; } function B32 token_is_add(Parser *p){ Token *token = token_get(p); B32 result = token->kind >= TK_FirstAdd && token->kind <= TK_LastAdd; return result; } function Expr * parse_expr_add(Parser *p){ Expr *left = parse_expr_mul(p); while(token_is_add(p)){ Token *op = token_next(p); Expr *right = parse_expr_mul(p); left = expr_binary(p->arena, op, left, right); } return left; } function B32 token_is_compare(Parser *p){ Token *token = token_get(p); B32 result = token->kind >= TK_FirstCompare && token->kind <= TK_LastCompare; return result; } function Expr * parse_expr_compare(Parser *p){ Expr *left = parse_expr_add(p); while(token_is_compare(p)){ Token *op = token_next(p); Expr *right = parse_expr_add(p); left = expr_binary(p->arena, op, left, right); } return left; } function B32 token_is_logical(Parser *p){ Token *token = token_get(p); B32 result = token->kind >= TK_FirstLogical && token->kind <= TK_LastLogical; return result; } function Expr * parse_expr_logical(Parser *p){ Expr *left = parse_expr_compare(p); while(token_is_logical(p)){ Token *op = token_next(p); Expr *right = parse_expr_compare(p); left = expr_binary(p->arena, op, left, right); } return left; } function Expr * parse_expr_ternary(Parser *p){ Expr *cond = parse_expr_logical(p); Token *token = 0; if((token = token_match(p, TK_Question))){ Expr *on_true = parse_expr_ternary(p); token_expect(p, TK_Colon); Expr *on_false = parse_expr_ternary(p); Expr *result = expr_ternary(p->arena, token, cond, on_true, on_false); return result; } return cond; } function Expr * parse_expr(Parser *p){ return parse_expr_ternary(p); } function S64 eval_expr(Expr *expr){ switch(expr->kind){ case EK_Int: return expr->int_val; break; case EK_Ternary:{ S64 cond = eval_expr(expr->ternary.cond); if(cond) return eval_expr(expr->ternary.on_true); else return eval_expr(expr->ternary.on_false); } break; case EK_Binary: { S64 left = eval_expr(expr->binary.left); S64 right = eval_expr(expr->binary.right); switch(expr->binary.op){ case TK_Add: return left + right; break; case TK_Sub: return left - right; break; case TK_Mul: return left * right; break; case TK_Div: return left / right; break; case TK_Mod: return left % right; break; case TK_Equals: return left == right; break; case TK_NotEquals: return left != right; break; case TK_GreaterThenOrEqual: return left >= right; break; case TK_LesserThenOrEqual: return left <= right; break; case TK_GreaterThen: return left > right; break; case TK_LesserThen: return left < right; break; case TK_BitAnd: return left & right; break; case TK_BitOr: return left | right; break; case TK_BitXor: return left ^ right; break; case TK_And: return left && right; break; case TK_Or: return left || right; break; case TK_LeftShift: return left << right; break; case TK_RightShift: return left >> right; break; default: invalid_codepath; } } break; default: invalid_codepath; } return 0; } function void parse_test(){ Arena *scratch = arena_begin_scratch(); String test_case = lit("32+52-242*2/424%5-23" " 1<<5>>6<<2 " " 1&&5*3 " " 1&&5||0 " " 1>5>=5==0 " " 1>5 ? 1 : 2 " ); Parser parser = { .tokens = lex_stream(scratch, test_case, lit("expr_test")), .arena = scratch, }; Parser *p = &parser; S64 t = 5; S64 test_val[] = { (32+52-242*2/424%5-23), (((1<<5)>>6)<<2), 1&&(t*3), (1&&t)||0, 1>t>=t==0, 1>t ? 1 : 2, }; for(int i = 0; i < buff_cap(test_val); i++){ Expr *expr = parse_expr(p); S64 val = eval_expr(expr); assert(val == test_val[i]); } arena_end_scratch(); }