Skip to content

Commit

Permalink
Add left/right shift operator support (#3)
Browse files Browse the repository at this point in the history
Parse "<<" and ">>" operator. Relevant test cases were appended.
  • Loading branch information
yetingk authored and jserv committed May 8, 2019
1 parent dd552a4 commit 0d45ba1
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 4 deletions.
8 changes: 8 additions & 0 deletions codegen_x64.c
Expand Up @@ -314,6 +314,12 @@ static void emit_binop_int_arith(Ast *ast)
break;
case '/':
break;
case PUNCT_LSHIFT:
op = "sal";
break;
case PUNCT_RSHIFT:
op = "sar";
break;
default:
error("invalid operator '%d'", ast->type);
}
Expand All @@ -327,6 +333,8 @@ static void emit_binop_int_arith(Ast *ast)
if (ast->type == '/') {
emit("mov $0, %%edx");
emit("idiv %%rcx");
} else if (ast->type == PUNCT_LSHIFT || ast->type == PUNCT_RSHIFT) {
emit("%s %%cl, %%rax", op);
} else {
emit("%s %%rcx, %%rax", op);
}
Expand Down
6 changes: 4 additions & 2 deletions lexer.c
Expand Up @@ -173,8 +173,6 @@ static Token *read_token_int(void)
case ']':
case '{':
case '}':
case '<':
case '>':
case '!':
case '?':
case ':':
Expand All @@ -195,6 +193,10 @@ static Token *read_token_int(void)
return read_rep('&', '&', PUNCT_LOGAND);
case '|':
return read_rep('|', '|', PUNCT_LOGOR);
case '<':
return read_rep('<', '<', PUNCT_LSHIFT);
case '>':
return read_rep('>', '>', PUNCT_RSHIFT);
case '"':
return read_string();
case '\'':
Expand Down
2 changes: 2 additions & 0 deletions mzcc.h
Expand Up @@ -43,6 +43,8 @@ enum {
PUNCT_LOGAND,
PUNCT_LOGOR,
PUNCT_ARROW,
PUNCT_LSHIFT,
PUNCT_RSHIFT,
};

enum {
Expand Down
15 changes: 14 additions & 1 deletion parser.c
Expand Up @@ -321,6 +321,10 @@ static int eval_intexpr(Ast *ast)
return eval_intexpr(ast->left) * eval_intexpr(ast->right);
case '/':
return eval_intexpr(ast->left) / eval_intexpr(ast->right);
case PUNCT_LSHIFT:
return eval_intexpr(ast->left) >> eval_intexpr(ast->right);
case PUNCT_RSHIFT:
return eval_intexpr(ast->left) << eval_intexpr(ast->right);
default:
error("Integer expression expected, but got %s", ast_to_string(ast));
return 0; /* non-reachable */
Expand All @@ -343,6 +347,9 @@ static int priority(Token *tok)
case '+':
case '-':
return 4;
case PUNCT_LSHIFT:
case PUNCT_RSHIFT:
return 5;
case '<':
case '>':
return 6;
Expand Down Expand Up @@ -659,6 +666,11 @@ static Ast *read_expr_int(int prec)
Ast *rest = read_expr_int(prec2 + (is_right_assoc(tok) ? 1 : 0));
if (!rest)
error("second operand missing");
if (is_punct(tok, PUNCT_LSHIFT) || is_punct(tok, PUNCT_RSHIFT)) {
if ((ast->ctype != ctype_int && ast->ctype != ctype_char) ||
(rest->ctype != ctype_int && rest->ctype != ctype_char))
error("invalid operand to shift");
}
ast = ast_binop(get_punct(tok), ast, rest);
}
}
Expand Down Expand Up @@ -889,7 +901,8 @@ static Ast *read_if_stmt(void)
expect(')');
Ast *then = read_stmt();
Token *tok = read_token();
if (!tok || get_ttype(tok) != TTYPE_IDENT || strcmp(get_ident(tok), "else")) {
if (!tok || get_ttype(tok) != TTYPE_IDENT ||
strcmp(get_ident(tok), "else")) {
unget_token(tok);
return ast_if(cond, then, NULL);
}
Expand Down
8 changes: 7 additions & 1 deletion tests/arith.c
Expand Up @@ -61,6 +61,12 @@ int test_bitand()
expect(1, 1 & 3);
}

int test_shift()
{
expect(8, 4 << 1);
expect(3, 7 >> 1);
}

int main()
{
test_basic();
Expand All @@ -69,6 +75,6 @@ int main()
test_ternary();
test_logand();
test_bitand();

test_shift();
return 0;
}

0 comments on commit 0d45ba1

Please sign in to comment.