diff --git a/asm/main.c b/asm/main.c index 563e331..346bebb 100644 --- a/asm/main.c +++ b/asm/main.c @@ -6,53 +6,27 @@ #include "str.h" #include #include +#include #include #include #include #include #include -static inline int define_labels( - IdentResolver* resolver, PLabel* label, uint16_t asm_ip, Reporter* rep) -{ - if (label == NULL) - return 0; - int res = define_labels(resolver, label->next, asm_ip, rep); - const IdentResol* existing = ident_resolver_resolve(resolver, label->ident); - if (existing != NULL) { - REPORTF_ERROR("redefinition of identifier '%s'", label->ident); - reporter_print_loc(rep, label->loc); - REPORTF_INFO("original definition of '%s'", label->ident); - reporter_print_loc(rep, existing->loc); - return 1; - } - if (label->sub_label) { - ident_resolver_define_sublabel( - resolver, asm_strdup(label->ident), label->loc, asm_ip); - } else { - ident_resolver_define_label( - resolver, asm_strdup(label->ident), label->loc, asm_ip); - } - return res; -} - -static inline void use_labels(IdentResolver* resolver, PLabel* label) -{ - if (label == NULL) - return; - use_labels(resolver, label->next); - const IdentResol* existing = ident_resolver_resolve(resolver, label->ident); - if (existing->ty == IdentResolTy_Label) { - resolver->current_parent = existing; - } -} - typedef struct { const char* input_file; const char* output_file; } Args; static inline Args parse_args(int argc, char** argv); +static inline char* read_text_file(const char* filename); +static inline int include_file(IdentResolver* resolver, + OperandEvaluator* evaluator, + const char* origin, + const char* filename); +static inline int define_labels( + IdentResolver* resolver, PLabel* label, uint16_t asm_ip, Reporter* rep); +static inline void use_labels(IdentResolver* resolver, PLabel* label); int main(int argc, char** argv) { @@ -60,26 +34,7 @@ int main(int argc, char** argv) Args args = parse_args(argc, argv); - FILE* input_fp = fopen(args.input_file, "r"); - if (!input_fp) { - REPORTF_ERROR("could not open input file '%s': %s", - args.input_file, - strerror(errno)); - return -1; - } - fseek(input_fp, 0L, SEEK_END); - size_t file_size = (size_t)ftell(input_fp); - rewind(input_fp); - - char* input_text = calloc(file_size + 1, sizeof(char)); - size_t bytes_read = fread(input_text, sizeof(char), file_size, input_fp); - fclose(input_fp); - if (bytes_read != file_size) { - REPORTF_ERROR("could not read input file '%s': %s", - args.input_file, - strerror(errno)); - return -1; - } + char* input_text = read_text_file(args.input_file); bool errors_occured = false; @@ -132,6 +87,7 @@ int main(int argc, char** argv) if (existing != NULL) { REPORTF_ERROR("redefinition of constant '%s'", stmt->ident); reporter_print_loc(&rep, stmt->loc); + errors_occured = true; pstmt_free(stmt); continue; } @@ -139,13 +95,26 @@ int main(int argc, char** argv) = eval_operand_to_imm(&evaluator, stmt->value); if (evaled.ty == EoTy_Err) { pstmt_free(stmt); + errors_occured = true; continue; } - ident_resolver_define_const( - &resolver, asm_strdup(stmt->ident), stmt->loc, evaled.imm); + ident_resolver_define_const(&resolver, + asm_strdup(stmt->ident), + stmt->loc, + evaled.imm, + asm_strdup(args.input_file)); pstmt_free(stmt); break; } + case PStmtTy_Include: { + int include_res = include_file( + &resolver, &evaluator, args.input_file, stmt->str); + pstmt_free(stmt); + if (include_res != 0) { + errors_occured = true; + } + break; + } } } @@ -257,3 +226,153 @@ static inline Args parse_args(int argc, char** argv) output_file, }; } + +static inline int include_file(IdentResolver* resolver, + OperandEvaluator* evaluator, + const char* origin_filename, + const char* include_filename) +{ + + char* origin_dir_buf = asm_strdup(origin_filename); + const char* origin_dir = dirname(origin_dir_buf); + + char* filepath = calloc( + strlen(origin_dir) + strlen(include_filename) + 2, sizeof(char)); + + strcat(filepath, origin_dir); + free(origin_dir_buf); + + strcat(filepath, "/"); + strcat(filepath, include_filename); + + char* text = read_text_file(filepath); + if (!text) + return -1; + + Parser parser; + parser_construct(&parser, filepath, text); + + Reporter rep = { + .filename = parser.lexer.filename, + .text = parser.lexer.text, + .text_len = parser.lexer.text_len, + }; + + bool errors_occured = false; + + while (!parser_done(&parser)) { + PStmt* stmt = parser_next_stmt(&parser); + if (!stmt) { + continue; + } + switch (stmt->ty) { + 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); + errors_occured = true; + pstmt_free(stmt); + continue; + } + EvaledOperand evaled + = eval_operand_to_imm(evaluator, stmt->value); + if (evaled.ty == EoTy_Err) { + pstmt_free(stmt); + errors_occured = true; + continue; + } + ident_resolver_define_const(resolver, + asm_strdup(stmt->ident), + stmt->loc, + evaled.imm, + asm_strdup(filepath)); + break; + } + case PStmtTy_Include: { + int include_res + = include_file(resolver, evaluator, filepath, stmt->str); + pstmt_free(stmt); + if (include_res != 0) { + errors_occured = true; + } + break; + } + default: + break; + } + pstmt_free(stmt); + } + + errors_occured &= parser_error_occured(&parser); + + free(filepath); + free(text); + return errors_occured; +} + +static inline char* read_text_file(const char* filename) +{ + FILE* fp = fopen(filename, "r"); + if (!fp) { + REPORTF_ERROR("could not open file '%s' for reading: %s", + filename, + strerror(errno)); + return NULL; + } + fseek(fp, 0L, SEEK_END); + size_t file_size = (size_t)ftell(fp); + rewind(fp); + + char* text = calloc(file_size + 1, sizeof(char)); + size_t bytes_read = fread(text, sizeof(char), file_size, fp); + fclose(fp); + if (bytes_read != file_size) { + REPORTF_ERROR( + "could not read input file '%s': %s", filename, strerror(errno)); + return NULL; + } + return text; +} + +static inline int define_labels( + IdentResolver* resolver, PLabel* label, uint16_t asm_ip, Reporter* rep) +{ + if (label == NULL) + return 0; + int res = define_labels(resolver, label->next, asm_ip, rep); + const IdentResol* existing = ident_resolver_resolve(resolver, label->ident); + if (existing != NULL) { + REPORTF_ERROR("redefinition of identifier '%s'", label->ident); + reporter_print_loc(rep, label->loc); + + const char* filename = rep->filename; + if (existing->ty == IdentResolTy_Const) { + rep->filename = existing->src_filename; + } + REPORTF_INFO("original definition of '%s'", existing->ident); + reporter_print_loc(rep, existing->loc); + rep->filename = filename; + return 1; + } + if (label->sub_label) { + ident_resolver_define_sublabel( + resolver, asm_strdup(label->ident), label->loc, asm_ip); + } else { + ident_resolver_define_label( + resolver, asm_strdup(label->ident), label->loc, asm_ip); + } + return res; +} + +static inline void use_labels(IdentResolver* resolver, PLabel* label) +{ + if (label == NULL) + return; + use_labels(resolver, label->next); + const IdentResol* existing = ident_resolver_resolve(resolver, label->ident); + if (existing->ty == IdentResolTy_Label) { + resolver->current_parent = existing; + } +} diff --git a/asm/parse.c b/asm/parse.c index 25df574..1ef522b 100644 --- a/asm/parse.c +++ b/asm/parse.c @@ -139,6 +139,7 @@ PStmt* pstmt_new_ident(PStmtTy ty, Loc loc, char* ident) *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)); @@ -146,6 +147,13 @@ PStmt* pstmt_new_const(PStmtTy ty, Loc loc, char* ident, POperand* value) return stmt; } +PStmt* pstmt_new_include(Loc loc, char* str) +{ + PStmt* stmt = malloc(sizeof(PStmt)); + *stmt = (PStmt) { .ty = PStmtTy_Include, .loc = loc, .str = str }; + return stmt; +} + void pstmt_free(PStmt* stmt) { switch (stmt->ty) { @@ -160,6 +168,9 @@ void pstmt_free(PStmt* stmt) free(stmt->ident); poperand_free(stmt->value); break; + case PStmtTy_Include: + free(stmt->str); + break; } free(stmt); } @@ -212,6 +223,38 @@ static inline char* parser_text_val(const Parser* parser, Tok tok) return asm_strndup(&parser->lexer.text[tok.loc.idx], tok.len); } +static inline char literal_char_val(const char* str) +{ + if (str[0] == '\\') { + switch (str[1]) { + case '0': + return 0; + case 't': + return '\t'; + case 'n': + return '\n'; + default: + return str[1]; + } + } else { + return str[0]; + } +} + +static inline char* parser_str_val( + const Parser* parser, size_t* str_len, Tok tok) +{ + char* lit = parser_text_val(parser, tok); + char* str = calloc(tok.len - 1, sizeof(char)); + *str_len = 0; + for (size_t i = 1; i < tok.len - 1; ++i) { + str[*str_len] = literal_char_val(&lit[i]); + *str_len += 1; + } + free(lit); + return str; +} + static inline void parser_report(Parser* parser, const char* msg, Loc loc) { parser->error_occured = true; @@ -267,24 +310,6 @@ static inline PLabel* parser_parse_labels( return labels; } -static inline char literal_char_val(const char* str) -{ - if (str[0] == '\\') { - switch (str[1]) { - case '0': - return 0; - case 't': - return '\t'; - case 'n': - return '\n'; - default: - return str[1]; - } - } else { - return str[0]; - } -} - static const int parser_binary_prec = 6; static inline POperand* parser_parse_operand_2(Parser* parser, int prec); @@ -346,14 +371,8 @@ static inline POperand* parser_parse_operand_0(Parser* parser) free(str); return poperand_new_imm(imm, loc); } else if (parser_eat(parser, TT_Str)) { - 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; - for (size_t i = 1; i < lit_len - 2; ++i) { - str[i] = literal_char_val(&lit[i]); - } - free(lit); + size_t str_len; + char* str = parser_str_val(parser, &str_len, parser->eaten); return poperand_new_str(PoTy_Str, str, str_len, loc); } else if (parser_eat(parser, '.')) { if (!parser_eat(parser, TT_Ident)) { @@ -559,11 +578,13 @@ static inline PStmtTy pstmt_keyword_ty(const char* ident) PStmtTy_Global, PStmtTy_Extern, PStmtTy_Const, + PStmtTy_Include, }; const char* keywords[] = { "global", "extern", "const", + "include", }; static_assert( sizeof(keywords) / sizeof(keywords[0]) == sizeof(tys) / sizeof(tys[0]), @@ -608,6 +629,17 @@ PStmt* parser_next_stmt(Parser* parser) return pstmt_new_const(ty, loc, ident, value); break; } + case PStmtTy_Include: { + parser_step(parser); + if (!parser_eat(parser, TT_Str)) { + parser_report(parser, "expected string", parser->tok.loc); + return NULL; + } + size_t str_len; + char* str = parser_str_val(parser, &str_len, parser->eaten); + return pstmt_new_include(loc, str); + break; + } default: break; } diff --git a/asm/parse.h b/asm/parse.h index 21de608..048e6fb 100644 --- a/asm/parse.h +++ b/asm/parse.h @@ -85,6 +85,7 @@ typedef enum { PStmtTy_Global, PStmtTy_Extern, PStmtTy_Const, + PStmtTy_Include, } PStmtTy; typedef struct { @@ -96,12 +97,14 @@ typedef struct { char* ident; POperand* value; }; + char* str; }; } 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); +PStmt* pstmt_new_include(Loc loc, char* str); void pstmt_free(PStmt* stmt); typedef struct { diff --git a/asm/resolve.c b/asm/resolve.c index eba9489..ee65c0f 100644 --- a/asm/resolve.c +++ b/asm/resolve.c @@ -9,8 +9,11 @@ void ident_resol_destroy(IdentResol* resol) break; case IdentResolTy_Label: case IdentResolTy_SubLabel: + free(resol->ident); + break; case IdentResolTy_Const: free(resol->ident); + free(resol->src_filename); break; } } @@ -78,8 +81,11 @@ void ident_resolver_define_sublabel( }; } -void ident_resolver_define_const( - IdentResolver* resolver, char* ident, Loc loc, uint16_t value) +void ident_resolver_define_const(IdentResolver* resolver, + char* ident, + Loc loc, + uint16_t value, + char* src_filename) { size_t i = ident_resolver_first_empty(resolver); resolver->resols[i] = (IdentResol) { @@ -87,6 +93,7 @@ void ident_resolver_define_const( .loc = loc, .ty = IdentResolTy_Const, .value = value, + .src_filename = src_filename, }; } diff --git a/asm/resolve.h b/asm/resolve.h index d31be46..ef40472 100644 --- a/asm/resolve.h +++ b/asm/resolve.h @@ -18,7 +18,10 @@ struct IdentResol { IdentResolTy ty; union { uint16_t ip; - uint16_t value; + struct { + uint16_t value; + char* src_filename; + }; }; }; @@ -38,7 +41,10 @@ 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); +void ident_resolver_define_const(IdentResolver* resolver, + char* ident, + Loc loc, + uint16_t value, + char* src_filename); const IdentResol* ident_resolver_resolve( const IdentResolver* resolver, const char* ident); diff --git a/kern/arch.asm b/kern/arch.asm new file mode 100644 index 0000000..df6ea16 --- /dev/null +++ b/kern/arch.asm @@ -0,0 +1,26 @@ + +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 + +; vim: syntax=nasm diff --git a/kern/main.asm b/kern/main.asm index aa27796..d3e8807 100644 --- a/kern/main.asm +++ b/kern/main.asm @@ -1,27 +1,5 @@ -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 +include "arch.asm" start: ; rsp points *at* the top element