diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-08-13 23:37:08 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-08-15 10:06:21 +0900 |
| commit | cefe477fdf8c8a7a081e08add9cafbe1d8a2acf0 (patch) | |
| tree | eb0e53cfebe273636ebaf3d6b5e50936903302ad | |
| parent | 7685bff588632a486a9e677c63ae7123b112ba9e (diff) | |
| download | ducc-cefe477fdf8c8a7a081e08add9cafbe1d8a2acf0.tar.gz ducc-cefe477fdf8c8a7a081e08add9cafbe1d8a2acf0.tar.zst ducc-cefe477fdf8c8a7a081e08add9cafbe1d8a2acf0.zip | |
feat: implement shift operators
| -rw-r--r-- | codegen.c | 7 | ||||
| -rw-r--r-- | parse.c | 23 | ||||
| -rw-r--r-- | preprocess.c | 12 | ||||
| -rw-r--r-- | tests/089.sh | 25 |
4 files changed, 63 insertions, 4 deletions
@@ -174,6 +174,13 @@ void codegen_binary_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) { printf(" mov rax, rdx\n"); } else if (ast->node_op == TokenKind_or) { printf(" or rax, rdi\n"); + } else if (ast->node_op == TokenKind_lshift) { + printf(" mov rcx, rdi\n"); + printf(" shl rax, cl\n"); + } else if (ast->node_op == TokenKind_rshift) { + // TODO: check if the operand is signed or unsigned + printf(" mov rcx, rdi\n"); + printf(" sar rax, cl\n"); } else if (ast->node_op == TokenKind_eq) { printf(" cmp rax, rdi\n"); printf(" sete al\n"); @@ -597,21 +597,36 @@ AstNode* parse_additive_expr(Parser* p) { return lhs; } -AstNode* parse_relational_expr(Parser* p) { +AstNode* parse_shift_expr(Parser* p) { AstNode* lhs = parse_additive_expr(p); while (1) { TokenKind op = peek_token(p)->kind; - if (op == TokenKind_lt || op == TokenKind_le) { + if (op == TokenKind_lshift || op == TokenKind_rshift) { next_token(p); AstNode* rhs = parse_additive_expr(p); lhs = ast_new_binary_expr(op, lhs, rhs); + } else { + break; + } + } + return lhs; +} + +AstNode* parse_relational_expr(Parser* p) { + AstNode* lhs = parse_shift_expr(p); + while (1) { + TokenKind op = peek_token(p)->kind; + if (op == TokenKind_lt || op == TokenKind_le) { + next_token(p); + AstNode* rhs = parse_shift_expr(p); + lhs = ast_new_binary_expr(op, lhs, rhs); } else if (op == TokenKind_gt) { next_token(p); - AstNode* rhs = parse_additive_expr(p); + AstNode* rhs = parse_shift_expr(p); lhs = ast_new_binary_expr(TokenKind_lt, rhs, lhs); } else if (op == TokenKind_ge) { next_token(p); - AstNode* rhs = parse_additive_expr(p); + AstNode* rhs = parse_shift_expr(p); lhs = ast_new_binary_expr(TokenKind_le, rhs, lhs); } else { break; diff --git a/preprocess.c b/preprocess.c index 776fe4b..cfc8659 100644 --- a/preprocess.c +++ b/preprocess.c @@ -68,6 +68,7 @@ enum TokenKind { TokenKind_keyword__Imaginary, TokenKind_le, + TokenKind_lshift, TokenKind_lt, TokenKind_literal_int, TokenKind_literal_str, @@ -82,6 +83,7 @@ enum TokenKind { TokenKind_percent, TokenKind_plus, TokenKind_plusplus, + TokenKind_rshift, TokenKind_semicolon, TokenKind_slash, TokenKind_star, @@ -220,6 +222,8 @@ const char* token_kind_stringify(TokenKind k) { return "_Imaginary"; else if (k == TokenKind_le) return "le"; + else if (k == TokenKind_lshift) + return "<<"; else if (k == TokenKind_lt) return "lt"; else if (k == TokenKind_literal_int) @@ -248,6 +252,8 @@ const char* token_kind_stringify(TokenKind k) { return "+"; else if (k == TokenKind_plusplus) return "++"; + else if (k == TokenKind_rshift) + return ">>"; else if (k == TokenKind_semicolon) return ";"; else if (k == TokenKind_slash) @@ -616,6 +622,9 @@ void pp_tokenize_all(Preprocessor* pp) { if (pp->src[pp->pos] == '=') { ++pp->pos; tok->kind = TokenKind_le; + } else if (pp->src[pp->pos] == '<') { + ++pp->pos; + tok->kind = TokenKind_lshift; } else { tok->kind = TokenKind_lt; } @@ -623,6 +632,9 @@ void pp_tokenize_all(Preprocessor* pp) { if (pp->src[pp->pos] == '=') { ++pp->pos; tok->kind = TokenKind_ge; + } else if (pp->src[pp->pos] == '>') { + ++pp->pos; + tok->kind = TokenKind_rshift; } else { tok->kind = TokenKind_gt; } diff --git a/tests/089.sh b/tests/089.sh new file mode 100644 index 0000000..d0faca3 --- /dev/null +++ b/tests/089.sh @@ -0,0 +1,25 @@ +set -e + +cat <<'EOF' > expected +8 +336 +EOF +bash ../../test_diff.sh <<'EOF' +int printf(); +int main() { + printf("%d\n", 1 << 3); + printf("%d\n", 21 << 4); +} +EOF + +cat <<'EOF' > expected +13 +0 +EOF +bash ../../test_diff.sh <<'EOF' +int printf(); +int main() { + printf("%d\n", 111 >> 3); + printf("%d\n", 15 >> 14); +} +EOF |
