diff --git a/asm/main.c b/asm/main.c index 452bde1..3413d44 100644 --- a/asm/main.c +++ b/asm/main.c @@ -37,6 +37,8 @@ typedef enum { TT_Int, TT_Binary, TT_Hex, + TT_Char, + TT_Str, TT_Newline = '\n', TT_DoubleLt, TT_DoubleGt, @@ -119,6 +121,18 @@ static inline Tok lexer_tok(const Lexer* lexer, TokTy ty, Loc loc) return (Tok) { .ty = ty, .loc = loc, .len = lexer->idx - loc.idx }; } +static inline int lexer_skip_literal_char(Lexer* lexer) +{ + char ch = lexer->ch; + lexer_step(lexer); + if (ch == '\\') { + if (lexer_done(lexer)) + return -1; + lexer_step(lexer); + } + return 0; +} + static inline void lexer_report(Lexer* lexer, const char* msg, Loc loc) { lexer->error_occured = true; @@ -138,7 +152,7 @@ static inline void lexer_report(Lexer* lexer, const char* msg, Loc loc) int line_len = (int)line_end - (int)line_start; fprintf(stderr, - "error: %s\n --> %s:%d:%d\n |\n%5d|%.*s\n |%*c^\n", + "error: %s\n --> %s:%d:%d\n |\n%5d|%.*s\n |%*c^\n", msg, lexer->filename, loc.line, @@ -146,14 +160,14 @@ static inline void lexer_report(Lexer* lexer, const char* msg, Loc loc) loc.line, line_len, line, - loc.col - 2, + loc.col - 1, ' '); } Tok lexer_next(Lexer* lexer) { const char* ident_chars = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$"; const char* int_chars = "1234567890"; const char* hex_chars = "01234567889abcdefABCDEF"; @@ -212,6 +226,26 @@ Tok lexer_next(Lexer* lexer) } else { return lexer_tok(lexer, TT_Int, loc); } + } else if (lexer->ch == '\'') { + lexer_step(lexer); + lexer_skip_literal_char(lexer); + if (lexer_done(lexer) || lexer->ch != '\'') { + lexer_report(lexer, "malformed character literal", loc); + return lexer_tok(lexer, TT_Err, loc); + } + lexer_step(lexer); + return lexer_tok(lexer, TT_Char, loc); + } else if (lexer->ch == '"') { + lexer_step(lexer); + while (!lexer_done(lexer) && lexer->ch != '"') { + lexer_skip_literal_char(lexer); + } + if (lexer_done(lexer) || lexer->ch != '"') { + lexer_report(lexer, "malformed string literal", loc); + return lexer_tok(lexer, TT_Err, loc); + } + lexer_step(lexer); + return lexer_tok(lexer, TT_Str, loc); } else if (lexer->ch == '<') { lexer_step(lexer); if (!lexer_done(lexer) && lexer->ch == '<') { @@ -235,9 +269,9 @@ Tok lexer_next(Lexer* lexer) lexer_step(lexer); return lexer_tok(lexer, (TokTy)ch, loc); } else { - lexer_report(lexer, "illegal character '%c'", loc); + lexer_report(lexer, "illegal character", loc); lexer_step(lexer); - return lexer_next(lexer); + return lexer_tok(lexer, TT_Err, loc); } } @@ -293,6 +327,7 @@ typedef enum { PoTy_Imm, PoTy_Ident, PoTy_SubLabel, + PoTy_Str, PoTy_MemU8, PoTy_MemU16, PoTy_Not, @@ -317,7 +352,7 @@ struct POperand { union { Reg reg; uint16_t imm; - char* ident; + char* str; POperand* operand; struct { POperand* left; @@ -338,10 +373,10 @@ POperand* poperand_new_imm(uint16_t imm, Loc loc) *operand = (POperand) { .ty = PoTy_Imm, .loc = loc, .imm = imm }; return operand; } -POperand* poperand_new_ident(POperandTy ty, char* ident, Loc loc) +POperand* poperand_new_str(POperandTy ty, char* str, Loc loc) { POperand* operand = malloc(sizeof(POperand)); - *operand = (POperand) { .ty = ty, .loc = loc, .ident = ident }; + *operand = (POperand) { .ty = ty, .loc = loc, .str = str }; return operand; } POperand* poperand_new_unary(POperandTy ty, POperand* inner, Loc loc) @@ -366,7 +401,8 @@ void poperand_free(POperand* operand) break; case PoTy_Ident: case PoTy_SubLabel: - free(operand->ident); + case PoTy_Str: + free(operand->str); break; case PoTy_MemU8: case PoTy_MemU16: @@ -399,40 +435,19 @@ typedef struct { POperand* ops[]; } PLine; -PLine* pline_new_0(char* op, PLabel* labels, Loc loc) +PLine* pline_new( + char* op, PLabel* labels, Loc loc, size_t ops_size, POperand** ops) { - PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * 0); - *line = (PLine) { .labels = labels, .op = op, .loc = loc, .ops_size = 0 }; - return line; -} -PLine* pline_new_1(char* op, PLabel* labels, Loc loc, POperand* op0) -{ - PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * 1); - *line = (PLine) { .labels = labels, .op = op, .loc = loc, .ops_size = 1 }; - line->ops[0] = op0; - return line; -} -PLine* pline_new_2( - char* op, PLabel* labels, Loc loc, POperand* op0, POperand* op1) -{ - PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * 2); - *line = (PLine) { .labels = labels, .op = op, .loc = loc, .ops_size = 2 }; - line->ops[0] = op0; - line->ops[1] = op1; - return line; -} -PLine* pline_new_3(char* op, - PLabel* labels, - Loc loc, - POperand* op0, - POperand* op1, - POperand* op2) -{ - PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * 3); - *line = (PLine) { .labels = labels, .op = op, .loc = loc, .ops_size = 3 }; - line->ops[0] = op0; - line->ops[1] = op1; - line->ops[2] = op2; + PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * ops_size); + *line = (PLine) { + .labels = labels, + .op = op, + .loc = loc, + .ops_size = ops_size, + }; + for (size_t i = 0; i < ops_size; ++i) { + line->ops[i] = ops[i]; + } return line; } void pline_free(PLine* pline) @@ -515,7 +530,7 @@ static inline void parser_report(Parser* parser, const char* msg, Loc loc) int line_len = (int)line_end - (int)line_start; fprintf(stderr, - "error: %s\n --> %s:%d:%d\n |\n%5d|%.*s\n |%*c^\n", + "error: %s\n --> %s:%d:%d\n |\n%5d|%.*s\n |%*c^\n", msg, parser->lexer.filename, loc.line, @@ -523,7 +538,7 @@ static inline void parser_report(Parser* parser, const char* msg, Loc loc) loc.line, line_len, line, - loc.col - 2, + loc.col - 1, ' '); } @@ -572,6 +587,24 @@ 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); @@ -590,7 +623,7 @@ static inline POperand* parser_parse_operand_0(Parser* parser) return poperand_new_reg(reg_val[i], loc); } } - return poperand_new_ident(PoTy_Ident, ident, loc); + return poperand_new_str(PoTy_Ident, ident, loc); } else if (parser_eat(parser, TT_Int)) { char* str = parser_ident_val(parser, parser->eaten); uint16_t imm = (uint16_t)strtoul(str, NULL, 10); @@ -606,13 +639,28 @@ static inline POperand* parser_parse_operand_0(Parser* parser) uint16_t imm = (uint16_t)strtoul(&str[2], NULL, 16); free(str); return poperand_new_imm(imm, loc); + } else if (parser_eat(parser, TT_Char)) { + char* str = parser_ident_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); + 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); + return poperand_new_str(PoTy_Str, str, loc); } else if (parser_eat(parser, '.')) { if (!parser_eat(parser, TT_Ident)) { parser_report(parser, "expected identifier", parser->tok.loc); return NULL; } char* ident = parser_ident_val(parser, parser->eaten); - return poperand_new_ident(PoTy_SubLabel, ident, loc); + return poperand_new_str(PoTy_SubLabel, ident, loc); } else if (parser_eat(parser, '(')) { POperand* operand = parser_parse_operand_2(parser, parser_binary_prec); if (!parser_eat(parser, ')')) { @@ -697,13 +745,18 @@ static inline POperand* parser_parse_operand_2(Parser* parser, int prec) static inline POperand* parser_parse_operand_3(Parser* parser) { + Loc loc = parser->tok.loc; + if (parser_eat(parser, TT_LBracket)) { + parser_report(parser, "expected 'u8' or 'u16'", loc); + return NULL; + } if (!parser_test(parser, TT_Ident)) { return parser_parse_operand_2(parser, parser_binary_prec); } - Loc loc = parser->tok.loc; - char* ident = parser_ident_val(parser, parser->eaten); + char* ident = parser_ident_val(parser, parser->tok); if (strcmp(ident, "u8") == 0) { free(ident); + parser_step(parser); if (!parser_eat(parser, '[')) { parser_report(parser, "expected '['", parser->tok.loc); return NULL; @@ -717,6 +770,7 @@ static inline POperand* parser_parse_operand_3(Parser* parser) return poperand_new_unary(PoTy_MemU8, operand, loc); } else if (strcmp(ident, "u16") == 0) { free(ident); + parser_step(parser); if (!parser_eat(parser, '[')) { parser_report(parser, "expected '['", parser->tok.loc); return NULL; @@ -740,7 +794,9 @@ PLine* parser_next(Parser* parser) Loc loc; PLabel* labels = parser_parse_labels(parser, &ident, &loc); - POperand* ops[3]; + const size_t max_ops_size = 64; + // TODO: Move allocation out-of-band. + POperand** ops = malloc(sizeof(POperand) * max_ops_size); size_t ops_size = 0; if (!parser_test(parser, TT_Eof) && !parser_test(parser, '\n')) { @@ -751,6 +807,12 @@ PLine* parser_next(Parser* parser) ops[ops_size++] = operand; while (!parser_test(parser, TT_Eof) && !parser_test(parser, '\n') && ops_size < 3) { + if (ops_size >= max_ops_size) { + parser_report(parser, + "exceeded maximum number of operands (64)", + parser->tok.loc); + goto error_free_ops; + } if (!parser_eat(parser, ',')) { parser_report(parser, "expected ','", parser->tok.loc); goto error_free_ops; @@ -768,22 +830,15 @@ PLine* parser_next(Parser* parser) } parser_skip_newlines(parser); - switch (ops_size) { - case 0: - return pline_new_0(ident, labels, loc); - case 1: - return pline_new_1(ident, labels, loc, ops[0]); - case 2: - return pline_new_2(ident, labels, loc, ops[0], ops[1]); - case 3: - default: - return pline_new_3(ident, labels, loc, ops[0], ops[1], ops[2]); - } + 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; diff --git a/kern/main.asm b/kern/main.asm index b5f601b..338d777 100644 --- a/kern/main.asm +++ b/kern/main.asm @@ -1,7 +1,7 @@ start: ; rsp points *at* the top element - mov Rbp, 2048 + mov rbp, 2048 mov rsp, 2048 - 2 lit interrupt_table @@ -25,12 +25,22 @@ interrupt_table: keyboard_interrupt: and rfl, rfl, !(1 << Fl_Int) - push rbp + ; push rbp + add rsp, rsp, 2 + mov u16 [rsp], rbp mov rbp, Rsp - push r0 - push r1 - push r2 - push r3 + ; push r0 + add rsp, rsp, 2 + mov u16 [rsp], r0 + ; push r1 + add rsp, rsp, 2 + mov u16 [rsp], r1 + ; push r2 + add rsp, rsp, 2 + mov u16 [rsp], r2 + ; push r3 + add rsp, rsp, 2 + mov u16 [rsp], r3 in r0, Device_Keyboard @@ -52,7 +62,7 @@ keyboard_interrupt: jmp .L3 .L0: - mov R0, 32 ; ' ' + mov R0, ' ' call put_char jmp .L4 @@ -80,26 +90,42 @@ keyboard_interrupt: jmp .L4 .L3: - ; add r0, r0, 'A' - 4 + add r0, r0, 'A' - 4 call put_char jmp .L4 .L4: - pop r3 - pop r2 - pop r1 - pop r0 + ; pop r3 + mov r3, u16 [rsp] + sub rsp, rsp, 2 + ; pop r2 + mov r2, u16 [rsp] + sub rsp, rsp, 2 + ; pop r1 + mov r1, u16 [rsp] + sub rsp, rsp, 2 + ; pop r0 + mov r0, u16 [rsp] + sub rsp, rsp, 2 mov rsp, rbp - pop rbp + ; pop rbp + mov rbp, u16 [rsp] + sub rsp, rsp, 2 or rfl, rfl, 1 << Fl_Int iret put_char: - push rbp + ; push rbp + add rsp, rsp, 2 + mov u16 [rsp], rbp mov rbp, rsp - push r1 - push r2 + ; push r1 + add rsp, rsp, 2 + mov u16 [rsp], r1 + ; push r2 + add rsp, rsp, 2 + mov u16 [rsp], r2 mov r2, screen_y mul r2, r2, vcd_width_in_ch @@ -126,10 +152,16 @@ put_char: mov screen_x, r1 .L1: - pop r1 - pop r2 + ; pop r1 + mov r1, u16 [rsp] + sub rsp, rsp, 2 + ; pop r2 + mov r2, u16 [rsp] + sub rsp, rsp, 2 mov rsp, rbp - pop rbp + ; pop rbp + mov rbp, u16 [rsp] + sub rsp, rsp, 2 ret screen_x: