aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-13 23:37:08 +0900
committernsfisis <nsfisis@gmail.com>2025-08-15 10:06:21 +0900
commitcefe477fdf8c8a7a081e08add9cafbe1d8a2acf0 (patch)
treeeb0e53cfebe273636ebaf3d6b5e50936903302ad
parent7685bff588632a486a9e677c63ae7123b112ba9e (diff)
downloadducc-cefe477fdf8c8a7a081e08add9cafbe1d8a2acf0.tar.gz
ducc-cefe477fdf8c8a7a081e08add9cafbe1d8a2acf0.tar.zst
ducc-cefe477fdf8c8a7a081e08add9cafbe1d8a2acf0.zip
feat: implement shift operators
-rw-r--r--codegen.c7
-rw-r--r--parse.c23
-rw-r--r--preprocess.c12
-rw-r--r--tests/089.sh25
4 files changed, 63 insertions, 4 deletions
diff --git a/codegen.c b/codegen.c
index 92a8619..f717c25 100644
--- a/codegen.c
+++ b/codegen.c
@@ -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");
diff --git a/parse.c b/parse.c
index a0b2ff3..fb5c751 100644
--- a/parse.c
+++ b/parse.c
@@ -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