247 lines
6.4 KiB
C++
247 lines
6.4 KiB
C++
|
|
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];
|
|
if(result->kind == TK_NewLine){
|
|
ctx->indent = result->indent;
|
|
}
|
|
|
|
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<Test> 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(){Get_Ctx(Parse_Ctx);
|
|
Ast_Decl *result = 0;
|
|
Token *token = token_match(TK_Identifier);
|
|
if(token){
|
|
if(token_match(TK_ColonAssign)){
|
|
if(ctx->indent != 0)
|
|
parsing_error(token, "Top level declarations shouldn't be indented");
|
|
|
|
Ast_Expr *expr = parse_expr();
|
|
result = ast_decl_var(token, 0, token->intern_val, expr);
|
|
}
|
|
else parsing_error(token, "Encountered unexpected token while parsing a top level declarations");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function Ast_Package *
|
|
parse_file(){
|
|
Ast_Package *result = ast_package(token_get(), token_get()->file);
|
|
while(!token_is(TK_End)){
|
|
while(token_match(TK_NewLine));
|
|
Ast_Decl *decl = parse_decl();
|
|
if(!decl) break;
|
|
result->decls.add(decl);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function void
|
|
test_parse_decl(){
|
|
TEST_PARSER();
|
|
lex_restream(&ctx, "thing := 24252\nanother_thing := \"string\"\n\nref := thing"_s, "test_parse_decl"_s);
|
|
Ast_Package *result = parse_file();
|
|
}
|