Skip to content

Commit

Permalink
Support else if
Browse files Browse the repository at this point in the history
  • Loading branch information
RobDangerous committed Aug 19, 2024
1 parent b4cedba commit 749945e
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 22 deletions.
20 changes: 15 additions & 5 deletions Sources/backends/cstyle.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,21 @@ void cstyle_write_opcode(char *code, size_t *offset, opcode *o, type_string_func
break;
}
case OPCODE_IF: {
*offset += sprintf(&code[*offset], "\tif (_%" PRIu64 ")\n", o->op_if.condition.index);
break;
}
case OPCODE_ELSE: {
*offset += sprintf(&code[*offset], "\telse\n");
if (o->op_if.condition.index != 0) {
*offset += sprintf(&code[*offset], "\tif (_%" PRIu64, o->op_if.condition.index);
}
else {
*offset += sprintf(&code[*offset], "\tif (");
}
for (uint8_t i = 0; i < o->op_if.exclusions_size; ++i) {
if (i == 0 && o->op_if.condition.index == 0) {
*offset += sprintf(&code[*offset], "!_%" PRIu64, o->op_if.exclusions[i].index);
}
else {
*offset += sprintf(&code[*offset], " && !_%" PRIu64, o->op_if.exclusions[i].index);
}
}
*offset += sprintf(&code[*offset], ")\n");
break;
}
case OPCODE_WHILE_START: {
Expand Down
40 changes: 33 additions & 7 deletions Sources/compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,30 +539,56 @@ void emit_statement(opcodes *code, block *parent, statement *statement) {
break;
}
case STATEMENT_IF: {
variable previous_conditions[64];
uint8_t previous_conditions_size = 0;

{
opcode o;
o.type = OPCODE_IF;
o.size = OP_SIZE(o, op_if);

variable v = emit_expression(code, parent, statement->iffy.test);
variable initial_condition = emit_expression(code, parent, statement->iffy.test);

o.op_if.condition = v;
o.op_if.condition = initial_condition;
o.op_if.exclusions_size = 0;

emit_op(code, &o);

previous_conditions[previous_conditions_size] = initial_condition;
previous_conditions_size += 1;
}

emit_statement(code, parent, statement->iffy.if_block);

if (statement->iffy.else_block != NULL) {
for (uint16_t i = 0; i < statement->iffy.else_size; ++i) {
opcode o;
o.type = OPCODE_ELSE;
o.size = OP_SIZE(o, op_nothing);
o.type = OPCODE_IF;
o.size = OP_SIZE(o, op_if) + sizeof(variable) * i;

for (uint8_t previous_condition_index = 0; previous_condition_index < previous_conditions_size; ++previous_condition_index) {
o.op_if.exclusions[previous_condition_index] = previous_conditions[previous_condition_index];
}
o.op_if.exclusions_size = previous_conditions_size;

if (statement->iffy.else_tests[i] != NULL) {
variable v = emit_expression(code, parent, statement->iffy.else_tests[i]);
o.op_if.condition = v;

previous_conditions[previous_conditions_size] = v;
previous_conditions_size += 1;
}
else {
o.op_if.condition.index = 0;
o.op_if.condition.kind = VARIABLE_GLOBAL;
o.op_if.condition.type.name = NO_NAME;
o.op_if.condition.type.type = NO_TYPE;
}

emit_op(code, &o);

emit_statement(code, parent, statement->iffy.else_block);
emit_statement(code, parent, statement->iffy.else_blocks[i]);
}

break;
}
case STATEMENT_WHILE: {
Expand Down
3 changes: 2 additions & 1 deletion Sources/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ typedef struct opcode {
OPCODE_AND,
OPCODE_OR,
OPCODE_IF,
OPCODE_ELSE,
OPCODE_WHILE_START,
OPCODE_WHILE_CONDITION,
OPCODE_WHILE_END,
Expand Down Expand Up @@ -102,6 +101,8 @@ typedef struct opcode {
} op_binary;
struct {
variable condition;
uint8_t exclusions_size;
variable exclusions[1];
} op_if;
struct {
variable condition;
Expand Down
7 changes: 5 additions & 2 deletions Sources/kong.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,11 @@ void resolve_types_in_block(statement *parent, statement *block) {
case STATEMENT_IF: {
resolve_types_in_expression(block, s->iffy.test);
resolve_types_in_block(block, s->iffy.if_block);
if (s->iffy.else_block != NULL) {
resolve_types_in_block(block, s->iffy.else_block);
for (uint16_t i = 0; i < s->iffy.else_size; ++i) {
if (s->iffy.else_tests[i] != NULL) {
resolve_types_in_expression(block, s->iffy.else_tests[i]);
}
resolve_types_in_block(block, s->iffy.else_blocks[i]);
}
break;
}
Expand Down
31 changes: 25 additions & 6 deletions Sources/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,14 +306,33 @@ static statement *parse_statement(state_t *state, block *parent_block) {
s->iffy.test = test;
s->iffy.if_block = if_block;

if (current(state).kind == TOKEN_ELSE) {
s->iffy.else_size = 0;

while (current(state).kind == TOKEN_ELSE) {
advance_state(state);

statement *else_block = parse_statement(state, parent_block);
s->iffy.else_block = else_block;
}
else {
s->iffy.else_block = NULL;
if (current(state).kind == TOKEN_IF) {
advance_state(state);
match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket");
advance_state(state);

expression *test = parse_expression(state);
match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket");
advance_state(state);

statement *if_block = parse_statement(state, parent_block);

s->iffy.else_tests[s->iffy.else_size] = test;
s->iffy.else_blocks[s->iffy.else_size] = if_block;
}
else {
statement *else_block = parse_statement(state, parent_block);
s->iffy.else_tests[s->iffy.else_size] = NULL;
s->iffy.else_blocks[s->iffy.else_size] = else_block;
}

s->iffy.else_size += 1;
assert(s->iffy.else_size < 64);
}

return s;
Expand Down
4 changes: 3 additions & 1 deletion Sources/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ typedef struct statement {
struct {
expression *test;
struct statement *if_block;
struct statement *else_block;
expression *else_tests[64];
struct statement *else_blocks[64];
uint16_t else_size;
} iffy;
struct {
expression *test;
Expand Down

0 comments on commit 749945e

Please sign in to comment.