Skip to content

Commit

Permalink
feat: support constant expression
Browse files Browse the repository at this point in the history
  • Loading branch information
diohabara committed Jul 26, 2023
1 parent 4c3f2de commit 9e5c76b
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
63 changes: 57 additions & 6 deletions parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Node *declaration();
bool is_typename();
Node *stmt();
Node *expr();
long const_expr();
Node *assign();
Node *conditional();
Node *bitand();
Expand Down Expand Up @@ -353,7 +354,7 @@ Type *abstract_declarator(Type *ty) {
return type_suffix(ty);
}

// type-suffix = ("[" num? "]" type-suffix)?
// type-suffix = ("[" const-expr? "]" type-suffix)?
Type *type_suffix(Type *ty) {
if (!consume("[")) {
return ty;
Expand All @@ -362,7 +363,7 @@ Type *type_suffix(Type *ty) {
int sz = 0;
bool is_incomplete = true;
if (!consume("]")) {
sz = expect_number();
sz = const_expr();
is_incomplete = false;
expect("]");
}
Expand Down Expand Up @@ -460,7 +461,8 @@ Type *struct_decl() {

// enum-specifier = "enum" ident
// | "enum" ident? "{" enum-list? "}"
// enum-list = ident ("=" num)? ("," ident ("=" num)?)* ","?
// enum-list = enum-elem ("," enum-elem)* ","?
// enum-elem = ident ("=" const-expr)?
Type *enum_specifier() {
expect("enum");
Type *ty = enum_type();
Expand All @@ -485,7 +487,7 @@ Type *enum_specifier() {
for (;;) {
char *name = expect_ident();
if (consume("=")) {
count = expect_number();
count = const_expr();
}
VarScope *sc = push_scope(name);
sc->enum_ty = ty;
Expand Down Expand Up @@ -669,7 +671,7 @@ bool is_typename() {
// stmt = "return" expr ";"
// | "if" "(" expr ")" stmt ("else" stmt)?
// | "switch" "(" expr ")" stmt
// | "case" num ":" stmt
// | "case" const-expr ":" stmt
// | "default" ":" stmt
// | "while" "(" expr ")" stmt
// | "for" "(" (expr? ";" | declaration) expr? ";" expr? ")" stmt
Expand Down Expand Up @@ -776,7 +778,7 @@ Node *stmt() {
if (!current_switch) {
error_tok(tok, "stray case");
}
int val = expect_number();
int val = const_expr();
expect(":");

Node *node = new_unary(ND_CASE, stmt(), tok);
Expand Down Expand Up @@ -821,6 +823,55 @@ Node *expr() {
}
return node;
}

long eval(Node *node) {
switch (node->kind) {
case ND_ADD:
return eval(node->lhs) + eval(node->rhs);
case ND_SUB:
return eval(node->lhs) - eval(node->rhs);
case ND_MUL:
return eval(node->lhs) * eval(node->rhs);
case ND_DIV:
return eval(node->lhs) / eval(node->rhs);
case ND_BITAND:
return eval(node->lhs) & eval(node->rhs);
case ND_BITOR:
return eval(node->lhs) | eval(node->rhs);
case ND_BITXOR:
return eval(node->lhs) | eval(node->rhs);
case ND_SHL:
return eval(node->lhs) << eval(node->rhs);
case ND_SHR:
return eval(node->lhs) >> eval(node->rhs);
case ND_EQ:
return eval(node->lhs) == eval(node->rhs);
case ND_NE:
return eval(node->lhs) != eval(node->rhs);
case ND_LT:
return eval(node->lhs) < eval(node->rhs);
case ND_LE:
return eval(node->lhs) <= eval(node->rhs);
case ND_TERNARY:
return eval(node->cond) ? eval(node->then) : eval(node->els);
case ND_COMMA:
return eval(node->rhs);
case ND_NOT:
return !eval(node->lhs);
case ND_BITNOT:
return ~eval(node->lhs);
case ND_LOGAND:
return eval(node->lhs) && eval(node->rhs);
case ND_LOGOR:
return eval(node->lhs) || eval(node->rhs);
case ND_NUM:
return node->val;
}
error_tok(node->tok, "not a constant expression");
}

long const_expr() { return eval(conditional()); }

// assign = conditional (assign-op assign)?
// assign-op = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>="
Node *assign() {
Expand Down
6 changes: 6 additions & 0 deletions tests
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,12 @@ int main() {
assert(2, 0?1:2, "0?1:2");
assert(1, 1?1:2, "0?1:2");

assert(10, ({ enum { ten=1+2+3+4, }; ten; }), "enum { ten=1+2+3+4, }; ten;");
assert(1, ({ int i=0; switch(3) { case 5-2+0*3: i++; } i; }), "int i=0; switch(3) { case 5-2+0*3: i++; ); i;");
assert(8, ({ int x[1+1]; sizeof(x); }), "int x[1+1]; sizeof(x);");
assert(2, ({ char x[1?2:3]; sizeof(x); }), "char x[0?2:3]; sizeof(x);");
assert(3, ({ char x[0?2:3]; sizeof(x); }), "char x[1?2:3]; sizeof(x);");

printf("OK\n");
return 0;
}

0 comments on commit 9e5c76b

Please sign in to comment.