From c351139f4d1d9d523ecc5b585de0855ef7fea1d4 Mon Sep 17 00:00:00 2001 From: sfja Date: Wed, 2 Apr 2025 18:39:19 +0200 Subject: [PATCH] add consts --- asm/eval.c | 3 ++ asm/main.c | 57 +++++++++++++++++++----- asm/parse.c | 118 ++++++++++++++++++++++++++++++++++++++++++-------- asm/parse.h | 14 ++++-- asm/resolve.c | 13 ++++++ asm/resolve.h | 4 ++ kern/main.asm | 50 +++++++++++++++------ 7 files changed, 214 insertions(+), 45 deletions(-) diff --git a/asm/eval.c b/asm/eval.c index b82d336..696f55b 100644 --- a/asm/eval.c +++ b/asm/eval.c @@ -85,6 +85,9 @@ EvaledOperand eval_operand_to_imm( case IdentResolTy_Label: case IdentResolTy_SubLabel: return (EvaledOperand) { .ty = EoTy_Imm, .imm = re->ip }; + case IdentResolTy_Const: + return (EvaledOperand) { .ty = EoTy_Imm, .imm = re->value }; + break; } fprintf(stderr, "unreachable\n"); exit(1); diff --git a/asm/main.c b/asm/main.c index 0c244c1..563e331 100644 --- a/asm/main.c +++ b/asm/main.c @@ -1,3 +1,4 @@ +#include "asm/report.h" #include "assemble.h" #include "eval.h" #include "parse.h" @@ -91,6 +92,15 @@ int main(int argc, char** argv) .text_len = parser.lexer.text_len, }; + IdentResolver resolver; + ident_resolver_construct(&resolver); + + OperandEvaluator evaluator = { + .re = &resolver, + .rep = &rep, + .second_pass = false, + }; + size_t lines_capacity = 1024; PLine** lines = malloc(sizeof(PLine*) * lines_capacity); size_t lines_size = 0; @@ -100,24 +110,47 @@ int main(int argc, char** argv) lines_capacity += 2; lines = realloc(lines, sizeof(PLine*) * lines_capacity); } - PLine* line = parser_next(&parser); - if (!line) { + PStmt* stmt = parser_next_stmt(&parser); + if (!stmt) { continue; } - lines[lines_size++] = line; + switch (stmt->ty) { + case PStmtTy_Line: + lines[lines_size++] = stmt->line; + // NOTE: Shallow free. + free(stmt); + break; + case PStmtTy_Global: + pstmt_free(stmt); + break; + case PStmtTy_Extern: + pstmt_free(stmt); + break; + case PStmtTy_Const: { + const IdentResol* existing + = ident_resolver_resolve(&resolver, stmt->ident); + if (existing != NULL) { + REPORTF_ERROR("redefinition of constant '%s'", stmt->ident); + reporter_print_loc(&rep, stmt->loc); + pstmt_free(stmt); + continue; + } + EvaledOperand evaled + = eval_operand_to_imm(&evaluator, stmt->value); + if (evaled.ty == EoTy_Err) { + pstmt_free(stmt); + continue; + } + ident_resolver_define_const( + &resolver, asm_strdup(stmt->ident), stmt->loc, evaled.imm); + pstmt_free(stmt); + break; + } + } } errors_occured &= parser_error_occured(&parser); - IdentResolver resolver; - ident_resolver_construct(&resolver); - - OperandEvaluator evaluator = { - .re = &resolver, - .rep = &rep, - .second_pass = false, - }; - size_t chunk_capacity = 64; uint16_t* chunk = malloc(sizeof(uint16_t) * chunk_capacity); diff --git a/asm/parse.c b/asm/parse.c index 51f111c..25df574 100644 --- a/asm/parse.c +++ b/asm/parse.c @@ -126,6 +126,26 @@ void pline_free(PLine* pline) free(pline); } +PStmt* pstmt_new_line(Loc loc, PLine* line) +{ + PStmt* stmt = malloc(sizeof(PStmt)); + *stmt = (PStmt) { .ty = PStmtTy_Line, .loc = loc, .line = line }; + return stmt; +} + +PStmt* pstmt_new_ident(PStmtTy ty, Loc loc, char* ident) +{ + PStmt* stmt = malloc(sizeof(PStmt)); + *stmt = (PStmt) { .ty = ty, .loc = loc, .ident = ident, .value = NULL }; + return stmt; +} +PStmt* pstmt_new_const(PStmtTy ty, Loc loc, char* ident, POperand* value) +{ + PStmt* stmt = malloc(sizeof(PStmt)); + *stmt = (PStmt) { .ty = ty, .loc = loc, .ident = ident, .value = value }; + return stmt; +} + void pstmt_free(PStmt* stmt) { switch (stmt->ty) { @@ -134,9 +154,12 @@ void pstmt_free(PStmt* stmt) break; case PStmtTy_Global: case PStmtTy_Extern: - case PStmtTy_Define: free(stmt->ident); break; + case PStmtTy_Const: + free(stmt->ident); + poperand_free(stmt->value); + break; } free(stmt); } @@ -184,7 +207,7 @@ static inline bool parser_eat(Parser* parser, TokTy ty) return false; } -static inline char* parser_ident_val(const Parser* parser, Tok tok) +static inline char* parser_text_val(const Parser* parser, Tok tok) { return asm_strndup(&parser->lexer.text[tok.loc.idx], tok.len); } @@ -218,7 +241,7 @@ static inline PLabel* parser_parse_labels( plabel_free(labels); return NULL; } - char* label_ident = parser_ident_val(parser, parser->eaten); + char* label_ident = parser_text_val(parser, parser->eaten); if (!parser_eat(parser, ':')) { parser_report(parser, "expected ':'", parser->tok.loc); plabel_free(labels); @@ -227,7 +250,7 @@ static inline PLabel* parser_parse_labels( } labels = plabel_new(labels, label_ident, true, loc); } else if (parser_eat(parser, TT_Ident)) { - *ident = parser_ident_val(parser, parser->eaten); + *ident = parser_text_val(parser, parser->eaten); *ident_loc = loc; if (!parser_eat(parser, ':')) { break; @@ -269,7 +292,7 @@ static inline POperand* parser_parse_operand_0(Parser* parser) { Loc loc = parser->tok.loc; if (parser_eat(parser, TT_Ident)) { - char* ident = parser_ident_val(parser, parser->eaten); + char* ident = parser_text_val(parser, parser->eaten); const char* reg_key[10] = { "r0", "r1", "r2", "r3", "r4", "rbp", "rsp", "rfl", "rcs", "rip" }; @@ -282,7 +305,7 @@ static inline POperand* parser_parse_operand_0(Parser* parser) } return poperand_new_str(PoTy_Ident, ident, parser->eaten.len, loc); } else if (parser_eat(parser, TT_Int)) { - char* str = parser_ident_val(parser, parser->eaten); + char* str = parser_text_val(parser, parser->eaten); uint64_t val = strtoull(str, NULL, 10); free(str); if (val > 0xffff) { @@ -294,7 +317,7 @@ static inline POperand* parser_parse_operand_0(Parser* parser) uint16_t imm = (uint16_t)val; return poperand_new_imm(imm, loc); } else if (parser_eat(parser, TT_Binary)) { - char* str = parser_ident_val(parser, parser->eaten); + char* str = parser_text_val(parser, parser->eaten); uint64_t val = strtoull(&str[2], NULL, 2); free(str); if (val > 0xffff) { @@ -306,7 +329,7 @@ static inline POperand* parser_parse_operand_0(Parser* parser) uint16_t imm = (uint16_t)val; return poperand_new_imm(imm, loc); } else if (parser_eat(parser, TT_Hex)) { - char* str = parser_ident_val(parser, parser->eaten); + char* str = parser_text_val(parser, parser->eaten); uint64_t val = strtoull(&str[2], NULL, 16); free(str); if (val > 0xffff) { @@ -318,12 +341,12 @@ static inline POperand* parser_parse_operand_0(Parser* parser) uint16_t imm = (uint16_t)val; return poperand_new_imm(imm, loc); } else if (parser_eat(parser, TT_Char)) { - char* str = parser_ident_val(parser, parser->eaten); + char* str = parser_text_val(parser, parser->eaten); uint16_t imm = (uint16_t)literal_char_val(&str[1]); free(str); return poperand_new_imm(imm, loc); } else if (parser_eat(parser, TT_Str)) { - char* lit = parser_ident_val(parser, parser->eaten); + char* lit = parser_text_val(parser, parser->eaten); size_t lit_len = strlen(lit); char* str = calloc(lit_len - 1, sizeof(char)); size_t str_len = 0; @@ -337,7 +360,7 @@ static inline POperand* parser_parse_operand_0(Parser* parser) parser_report(parser, "expected identifier", parser->tok.loc); return NULL; } - char* ident = parser_ident_val(parser, parser->eaten); + char* ident = parser_text_val(parser, parser->eaten); return poperand_new_str(PoTy_SubLabel, ident, parser->eaten.len, loc); } else if (parser_eat(parser, '(')) { POperand* operand = parser_parse_operand_2(parser, parser_binary_prec); @@ -431,7 +454,7 @@ static inline POperand* parser_parse_operand_3(Parser* parser) if (!parser_test(parser, TT_Ident)) { return parser_parse_operand_2(parser, parser_binary_prec); } - char* ident = parser_ident_val(parser, parser->tok); + char* ident = parser_text_val(parser, parser->tok); if (strcmp(ident, "u8") == 0) { free(ident); parser_step(parser); @@ -473,15 +496,14 @@ static inline void parser_skip_to_next_line(Parser* parser) } } -PLine* parser_next(Parser* parser) +PLine* parser_next_line(Parser* parser) { char* ident; Loc loc; PLabel* labels = parser_parse_labels(parser, &ident, &loc); const size_t max_ops_size = 64; - // TODO: Move allocation out-of-band. - POperand** ops = malloc(sizeof(POperand) * max_ops_size); + POperand* ops[64]; size_t ops_size = 0; if (!parser_test(parser, TT_Eof) && !parser_test(parser, '\n')) { @@ -520,15 +542,77 @@ PLine* parser_next(Parser* parser) parser_skip_newlines(parser); PLine* line = pline_new(ident, labels, loc, ops_size, ops); - free(ops); return line; error_free_ops: for (size_t i = 0; i < ops_size; ++i) if (ops[i]) poperand_free(ops[i]); - free(ops); plabel_free(labels); free(ident); return NULL; } + +static inline PStmtTy pstmt_keyword_ty(const char* ident) +{ + const PStmtTy tys[] = { + PStmtTy_Global, + PStmtTy_Extern, + PStmtTy_Const, + }; + const char* keywords[] = { + "global", + "extern", + "const", + }; + static_assert( + sizeof(keywords) / sizeof(keywords[0]) == sizeof(tys) / sizeof(tys[0]), + "mismatch"); + + size_t amount = sizeof(tys) / sizeof(tys[0]); + for (size_t i = 0; i < amount; ++i) { + if (strcmp(ident, keywords[i]) == 0) { + return tys[i]; + } + } + return PStmtTy_Line; +} + +PStmt* parser_next_stmt(Parser* parser) +{ + parser_skip_newlines(parser); + Loc loc = parser->tok.loc; + if (!parser_test(parser, TT_Ident)) { + PLine* line = parser_next_line(parser); + if (!line) + return NULL; + return pstmt_new_line(loc, line); + } + char* keyword = parser_text_val(parser, parser->tok); + PStmtTy ty = pstmt_keyword_ty(keyword); + free(keyword); + switch (ty) { + case PStmtTy_Global: + case PStmtTy_Extern: + case PStmtTy_Const: { + parser_step(parser); + if (!parser_eat(parser, TT_Ident)) { + parser_report(parser, "expected identifier", parser->tok.loc); + return NULL; + } + char* ident = parser_text_val(parser, parser->eaten); + if (ty != PStmtTy_Const) { + return pstmt_new_ident(ty, loc, ident); + } + POperand* value = parser_parse_operand_3(parser); + return pstmt_new_const(ty, loc, ident, value); + break; + } + default: + break; + } + PLine* line = parser_next_line(parser); + if (!line) + return NULL; + return pstmt_new_line(loc, line); +} diff --git a/asm/parse.h b/asm/parse.h index 005c67a..21de608 100644 --- a/asm/parse.h +++ b/asm/parse.h @@ -84,17 +84,24 @@ typedef enum { PStmtTy_Line, PStmtTy_Global, PStmtTy_Extern, - PStmtTy_Define, + PStmtTy_Const, } PStmtTy; typedef struct { PStmtTy ty; + Loc loc; union { PLine* line; - char* ident; + struct { + char* ident; + POperand* value; + }; }; } PStmt; +PStmt* pstmt_new_line(Loc loc, PLine* line); +PStmt* pstmt_new_ident(PStmtTy ty, Loc loc, char* ident); +PStmt* pstmt_new_const(PStmtTy ty, Loc loc, char* ident, POperand* value); void pstmt_free(PStmt* stmt); typedef struct { @@ -107,4 +114,5 @@ typedef struct { void parser_construct(Parser* parser, const char* filename, const char* text); bool parser_done(const Parser* parser); bool parser_error_occured(const Parser* parser); -PLine* parser_next(Parser* parser); +PLine* parser_next_line(Parser* parser); +PStmt* parser_next_stmt(Parser* parser); diff --git a/asm/resolve.c b/asm/resolve.c index 39f5333..eba9489 100644 --- a/asm/resolve.c +++ b/asm/resolve.c @@ -9,6 +9,7 @@ void ident_resol_destroy(IdentResol* resol) break; case IdentResolTy_Label: case IdentResolTy_SubLabel: + case IdentResolTy_Const: free(resol->ident); break; } @@ -77,6 +78,18 @@ void ident_resolver_define_sublabel( }; } +void ident_resolver_define_const( + IdentResolver* resolver, char* ident, Loc loc, uint16_t value) +{ + size_t i = ident_resolver_first_empty(resolver); + resolver->resols[i] = (IdentResol) { + .ident = ident, + .loc = loc, + .ty = IdentResolTy_Const, + .value = value, + }; +} + const IdentResol* ident_resolver_resolve( const IdentResolver* resolver, const char* ident) { diff --git a/asm/resolve.h b/asm/resolve.h index 0936ebb..d31be46 100644 --- a/asm/resolve.h +++ b/asm/resolve.h @@ -7,6 +7,7 @@ typedef enum { IdentResolTy_None, IdentResolTy_Label, IdentResolTy_SubLabel, + IdentResolTy_Const, } IdentResolTy; typedef struct IdentResol IdentResol; @@ -17,6 +18,7 @@ struct IdentResol { IdentResolTy ty; union { uint16_t ip; + uint16_t value; }; }; @@ -36,5 +38,7 @@ void ident_resolver_define_label( IdentResolver* resolver, char* ident, Loc loc, uint16_t asm_ip); void ident_resolver_define_sublabel( IdentResolver* resolver, char* ident, Loc loc, uint16_t asm_ip); +void ident_resolver_define_const( + IdentResolver* resolver, char* ident, Loc loc, uint16_t value); const IdentResol* ident_resolver_resolve( const IdentResolver* resolver, const char* ident); diff --git a/kern/main.asm b/kern/main.asm index 21f1b1f..aa27796 100644 --- a/kern/main.asm +++ b/kern/main.asm @@ -1,17 +1,41 @@ +const Fl_Zero 0 +const Fl_Eq 1 +const Fl_Be 2 +const Fl_Lt 3 +const Fl_Err 4 +const Fl_Int 5 +const Fl_Vcd 6 + +const Int_DiskRead 0 +const Int_DiskWrite 1 +const Int_Key 32 + +const Device_Keyboard 0 + +const vcd_ch_width 8 +const vcd_ch_height 8 +const vcd_width_in_ch 40 +const vcd_height_in_ch 12 + +const vcd_px_width 4 +const vcd_px_height 8 +const vcd_width_in_px vcd_width_in_ch * vcd_ch_width * vcd_px_width +const vcd_height_in_px vcd_height_in_ch * vcd_ch_height * vcd_px_height + start: ; rsp points *at* the top element mov rbp, 2048 mov rsp, 2048 - 2 lit interrupt_table - or rfl, rfl, 1 << 5 ; Fl_Int + or rfl, rfl, 1 << Fl_Int - or rfl, rfl, 1 << 6 ; Fl_Vcd + or rfl, rfl, 1 << Fl_Vcd mov r0, 512 mov r1, 1 - int 0 ; Int_DiskRead + int Int_DiskRead main_loop: hlt @@ -24,7 +48,7 @@ interrupt_table: nop keyboard_interrupt: - and rfl, rfl, !(1 << 5) ; Fl_Int + and rfl, rfl, !(1 << Fl_Int) push rbp mov rbp, rsp push r0 @@ -32,21 +56,21 @@ keyboard_interrupt: push r2 push r3 - in r0, 0 ; Device_Keyboard + in r0, Device_Keyboard cmp r0, 44 mov r1, rfl - and r1, r1, 1 << 1 ; Fl_Eq + and r1, r1, 1 << Fl_Eq jnz r1, .L0 cmp r0, 42 mov r1, rfl - and r1, r1, 1 << 1 ; Fl_Eq + and r1, r1, 1 << Fl_Eq jnz r1, .L1 cmp r0, 40 mov r1, rfl - and r1, r1, 1 << 1 ; Fl_Eq + and r1, r1, 1 << Fl_Eq jnz r1, .L2 jmp .L3 @@ -60,7 +84,7 @@ keyboard_interrupt: mov r1, u16 [screen_x] cmp r1, 0 mov r2, rfl - and r2, r2, 1 << 1 ; Fl_Eq + and r2, r2, 1 << Fl_Eq jnz r2, .L4 sub r1, r1, 1 mov u16 [screen_x], r1 @@ -92,7 +116,7 @@ keyboard_interrupt: pop r0 mov rsp, rbp pop rbp - or rfl, rfl, 1 << 5 ; Fl_Int + or rfl, rfl, 1 << Fl_Int iret put_char: @@ -102,7 +126,7 @@ put_char: push r2 mov r2, u16 [screen_y] - mul r2, r2, 40 ; vcd_width_in_ch + mul r2, r2, vcd_width_in_ch mov r1, u16 [screen_x] add r1, r1, 0x0c00 add r1, r1, r2 @@ -112,9 +136,9 @@ put_char: add r1, r1, 1 mov u16 [screen_x], r1 - cmp r1, 40 ; vcd_width_in_ch + cmp r1, vcd_width_in_ch mov r2, rfl - and r2, r2, 1 << 1 ; Fl_Eq + and r2, r2, 1 << Fl_Eq jnz r2, .L0 jmp .L1