Skip to content

Commit

Permalink
Support global variable initialization
Browse files Browse the repository at this point in the history
Close #12

1. To initialize global variable, we need to decide the value before
   execution time. `read_global_assignment` help us evaluate this
   immediate value and store it in .data section where store the
   initial value of variable in generated ELF.

2. This commit doesn't support pointer and array initialization.

3. Add correspond test bench in line 250 of driver.sh.
  • Loading branch information
eecheng87 committed Oct 16, 2020
1 parent cd72dd4 commit 21b34b0
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 8 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ int fib(int n) fib: Reserve stack frame for function

1. Any non-zero value is NOT treated as logical truth by all ops.
That is, the expression `0 == strcmp(ptr, "hello")` is not equivalent to `!strcmp(ptr, "hello")`.
2. Global variable initialization is not supported.
Therefore, you can not initialize a global such as `int i = [expr]`.
2. The generated ELF lacks of .bss and .rodata section
3. Dereference is incomplete. Consider `int x = 5; int *ptr = &x;` and it is forbidden to use `*ptr`.
However, it is valid to use `ptr[0]`, which behaves the same of `*ptr`.
4. The support of varying number of function arguments is incomplete. No `<stdarg.h>` can be used.
Expand Down
148 changes: 144 additions & 4 deletions src/cfront.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ int read_numeric_constant(char buffer[])

void read_inner_var_decl(var_t *vd)
{
vd->init_val = 0;
if (lex_accept(T_asterisk))
vd->is_ptr = 1;
else
Expand Down Expand Up @@ -1308,6 +1309,140 @@ int read_body_assignment(char *token, block_t *parent)
return 0;
}

int read_numeric_sconstant()
{
/* return signed constant */
int isneg = 0, res;
char buffer[10];
if (lex_accept(T_minus))
isneg = 1;
if (lex_peek(T_numeric, buffer))
res = read_numeric_constant(buffer);
else
error("Invalid value after assignment");
lex_expect(T_numeric);
if (isneg)
return (-1) * res;
return res;
}

int eval_expression_imm(opcode_t op, int op1, int op2)
{
/* return immediate result */
int res;
switch (op) {
case OP_add:
res = op1 + op2;
break;
case OP_sub:
res = op1 - op2;
break;
case OP_mul:
res = op1 * op2;
break;
case OP_div:
res = op1 / op2;
break;
case OP_lshift:
res = op1 << op2;
break;
case OP_rshift:
res = op1 >> op2;
break;
default:
error("The requested operation is not supported.");
}
return res;
}

int read_global_assignment(char *token)
{
/* global initialization must be constant */
var_t *var = find_global_var(token);
if (var) {
opcode_t op_stack[10];
opcode_t op, next_op;
int val_stack[10];
int op_stack_index = 0, val_stack_index = 0;
int operand1, operand2;
operand1 = read_numeric_sconstant();
op = get_operator();
/* only one value after assignment */
if (op == OP_generic) {
var->init_val = operand1;
return 1;
}
operand2 = read_numeric_sconstant();
next_op = get_operator();
if (next_op == OP_generic) {
/* only two operands, apply and return */
var->init_val = eval_expression_imm(op, operand1, operand2);
return 1;
}

/* using stack if operands more than two */
op_stack[op_stack_index++] = op;
op = next_op;
val_stack[val_stack_index++] = operand1;
val_stack[val_stack_index++] = operand2;

while (op != OP_generic) {
if (op_stack_index > 0) {
/* we have a continuation, use stack */
int same_op = 0;
do {
opcode_t stack_op = op_stack[op_stack_index - 1];
if (get_operator_prio(stack_op) >= get_operator_prio(op)) {
operand1 = val_stack[val_stack_index - 2];
operand2 = val_stack[val_stack_index - 1];
val_stack_index -= 2;

/* apply stack operator and push result back */
val_stack[val_stack_index++] =
eval_expression_imm(stack_op, operand1, operand2);

/* pop op stack */
op_stack_index--;
} else {
same_op = 1;
}
/* continue util next operation is higher prio */
} while (op_stack_index > 0 && same_op == 0);
}
/* push next operand on stack */
val_stack[val_stack_index++] = read_numeric_sconstant();
/* push operator on stack */
op_stack[op_stack_index++] = op;
op = get_operator();
}
/* unwind stack and apply operations */
while (op_stack_index > 0) {
opcode_t stack_op = op_stack[op_stack_index - 1];

/* pop stack and apply operators */
operand1 = val_stack[val_stack_index - 2];
operand2 = val_stack[val_stack_index - 1];
val_stack_index -= 2;

/* apply stack operator and push value back on stack */
val_stack[val_stack_index++] =
eval_expression_imm(stack_op, operand1, operand2);

if (op_stack_index == 1) {
var->init_val = val_stack[0];
return 1;
}

/* pop op stack */
op_stack_index--;
}

var->init_val = val_stack[0];
return 1;
}
return 0;
}

int break_exit_ir_index[MAX_NESTING];

void read_code_block(func_t *func, block_t *parent);
Expand Down Expand Up @@ -1696,10 +1831,15 @@ void read_global_decl(block_t *block)
/* is a variable */
memcpy(&block->locals[block->next_local++], &_temp_var, sizeof(var_t));

if (lex_accept(T_assign))
/* global variable initialization is not supported at the moment. */
error("Global initialization not supported");
else if (lex_accept(T_comma))
if (lex_accept(T_assign)) {
if (_temp_var.is_ptr == 0 && _temp_var.array_size == 0) {
read_global_assignment(_temp_var.var_name);
lex_expect(T_semicolon);
return;
}
/* TODO: support global initialization for array and pointer */
error("Global initialization for array and pointer not supported");
} else if (lex_accept(T_comma))
/* TODO: continuation */
error("Global continuation not supported");
else if (lex_accept(T_semicolon))
Expand Down
7 changes: 6 additions & 1 deletion src/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ void size_funcs(int data_start)
blk->locals[i].offset = elf_data_idx; /* set offset in data section */
elf_add_symbol(blk->locals[i].var_name, strlen(blk->locals[i].var_name),
data_start + elf_data_idx);
elf_data_idx += size_var(&blk->locals[i]);
/* TODO: add .bss section */
if (strcmp(blk->locals[i].type_name, "int") == 0 &&
blk->locals[i].init_val != 0)
elf_write_data_int(blk->locals[i].init_val);
else
elf_data_idx += size_var(&blk->locals[i]);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ typedef struct {
char var_name[MAX_VAR_LEN];
int is_ptr;
int array_size;
int offset; /* offset from stack or frame */
int offset; /* offset from stack or frame */
int init_val; /* for global initialization */
} var_t;

/* function definition */
Expand Down
8 changes: 8 additions & 0 deletions src/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ void elf_write_data_str(char *vals, int len)
elf_data[elf_data_idx++] = vals[i];
}

void elf_write_data_int(int val)
{
elf_data[elf_data_idx++] = (val & 0x000000FF);
elf_data[elf_data_idx++] = (val & 0x0000FF00) >> 8;
elf_data[elf_data_idx++] = (val & 0x00FF0000) >> 16;
elf_data[elf_data_idx++] = (val & 0xFF000000) >> 24;
}

void elf_write_header_byte(int val)
{
elf_header[elf_header_idx++] = val;
Expand Down
10 changes: 10 additions & 0 deletions tests/driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,16 @@ int main() {
}
EOF

# global initialization
try_ 20 << EOF
int a = 5 * 2;
int b = -4 * 3 + 7 + 9 / 3 * 5;
int main()
{
exit(a + b);
}
EOF

# conditional operator
# expr 10 "1 ? 10 : 5"
# expr 25 "0 ? 10 : 25"
Expand Down

0 comments on commit 21b34b0

Please sign in to comment.