@@ -30,6 +30,14 @@ enum l2_opcode { | |||
*/ | |||
L2_OP_POP, | |||
/* | |||
* Swap the top and second-top elements, then pop the new top element. | |||
* Pop <word1> | |||
* Pop <word2> | |||
* Push <word1> | |||
*/ | |||
L2_OP_SWAP_POP, | |||
/* | |||
* Duplicate the top element on the stack. | |||
* Push <word at <sptr> - 1> | |||
@@ -173,11 +181,20 @@ enum l2_opcode { | |||
/* | |||
* Look up a value from an array. | |||
* Pop <key> | |||
* Pop <arr> | |||
* Push <arr[<key>]> | |||
* Read <val> | |||
* Read <arr> | |||
* Assign <val> to <arr[<key>]> | |||
*/ | |||
L2_OP_DIRECT_ARRAY_LOOKUP, | |||
/* | |||
* Set a value in an array. | |||
* Pop <key> | |||
* Read <arr> | |||
* Push <arr[<key>]> | |||
*/ | |||
L2_OP_DIRECT_ARRAY_SET, | |||
/* | |||
* Halt execution. | |||
*/ |
@@ -25,6 +25,7 @@ void l2_gen_free(struct l2_generator *gen); | |||
void l2_gen_halt(struct l2_generator *gen); | |||
void l2_gen_rjmp(struct l2_generator *gen, l2_word len); | |||
void l2_gen_pop(struct l2_generator *gen); | |||
void l2_gen_swap_pop(struct l2_generator *gen); | |||
void l2_gen_push(struct l2_generator *gen, l2_word word); | |||
void l2_gen_ret(struct l2_generator *gen); | |||
void l2_gen_number(struct l2_generator *gen, double num); | |||
@@ -36,6 +37,7 @@ void l2_gen_namespace(struct l2_generator *gen); | |||
void l2_gen_namespace_set(struct l2_generator *gen, char **ident); | |||
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident); | |||
void l2_gen_direct_array_lookup(struct l2_generator *gen, int number); | |||
void l2_gen_direct_array_set(struct l2_generator *gen, int number); | |||
void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident); | |||
void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident); | |||
void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident); |
@@ -45,6 +45,10 @@ void l2_gen_pop(struct l2_generator *gen) { | |||
put(gen, L2_OP_POP); | |||
} | |||
void l2_gen_swap_pop(struct l2_generator *gen) { | |||
put(gen, L2_OP_SWAP_POP); | |||
} | |||
void l2_gen_push(struct l2_generator *gen, l2_word word) { | |||
put(gen, L2_OP_PUSH); | |||
put(gen, word); | |||
@@ -145,6 +149,12 @@ void l2_gen_direct_array_lookup(struct l2_generator *gen, int number) { | |||
put(gen, L2_OP_DIRECT_ARRAY_LOOKUP); | |||
} | |||
void l2_gen_direct_array_set(struct l2_generator *gen, int number) { | |||
put(gen, L2_OP_PUSH); | |||
put(gen, number); | |||
put(gen, L2_OP_DIRECT_ARRAY_SET); | |||
} | |||
void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | |||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | |||
put(gen, L2_OP_PUSH); |
@@ -294,13 +294,14 @@ static int parse_arg_level_expression( | |||
char *ident = l2_token_extract_str(tok2); | |||
l2_lexer_consume(lexer); // '.' | |||
l2_lexer_consume(lexer); // ident | |||
l2_lexer_consume(lexer); // equals | |||
l2_lexer_consume(lexer); // '=' | |||
if (parse_expression(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
l2_gen_namespace_set(gen, &ident); | |||
l2_gen_swap_pop(gen); | |||
} else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT) { | |||
l2_trace_scope("namespace lookup"); | |||
l2_trace("ident '%s'", tok2->v.str); | |||
@@ -309,6 +310,18 @@ static int parse_arg_level_expression( | |||
l2_lexer_consume(lexer); // ident | |||
l2_gen_namespace_lookup(gen, &ident); | |||
} else if (tok->kind == L2_TOK_DOT_NUMBER && tok2->kind == L2_TOK_EQUALS) { | |||
l2_trace_scope("direct array assign"); | |||
int number = tok->v.integer; | |||
l2_lexer_consume(lexer); // dot-number | |||
l2_lexer_consume(lexer); // '=' | |||
if (parse_expression(lexer, gen, err) < 0) { | |||
return -1; | |||
} | |||
l2_gen_direct_array_set(gen, number); | |||
l2_gen_swap_pop(gen); | |||
} else if (tok->kind == L2_TOK_DOT_NUMBER) { | |||
l2_trace_scope("direct array lookup"); | |||
int number = tok->v.integer; |
@@ -117,13 +117,13 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) { | |||
switch (opcode) { | |||
case L2_OP_NOP: | |||
printf("NOP\n"); | |||
break; | |||
return; | |||
case L2_OP_PUSH: | |||
printf("PUSH "); | |||
print_op_num(ops, opcount, (*ptr)++); | |||
printf("\n"); | |||
break; | |||
return; | |||
case L2_OP_PUSH_2: | |||
printf("PUSH2 "); | |||
@@ -131,96 +131,105 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) { | |||
printf(" "); | |||
print_op_num(ops, opcount, (*ptr)++); | |||
printf("\n"); | |||
break; | |||
return; | |||
case L2_OP_POP: | |||
printf("POP\n"); | |||
break; | |||
return; | |||
case L2_OP_SWAP_POP: | |||
printf("SWAP_POP\n"); | |||
return; | |||
case L2_OP_DUP: | |||
printf("DUP\n"); | |||
break; | |||
return; | |||
case L2_OP_ADD: | |||
printf("ADD\n"); | |||
break; | |||
return; | |||
case L2_OP_FUNC_CALL: | |||
printf("FUNC_CALL\n"); | |||
break; | |||
return; | |||
case L2_OP_RJMP: | |||
printf("RJMP\n"); | |||
break; | |||
return; | |||
case L2_OP_STACK_FRAME_LOOKUP: | |||
printf("STACK_FRAME_LOOKUP\n"); | |||
break; | |||
return; | |||
case L2_OP_STACK_FRAME_SET: | |||
printf("STACK_FRAME_SET\n"); | |||
break; | |||
return; | |||
case L2_OP_STACK_FRAME_REPLACE: | |||
printf("STACK_FRAME_REPLACE\n"); | |||
return; | |||
case L2_OP_RET: | |||
printf("RET\n"); | |||
break; | |||
return; | |||
case L2_OP_ALLOC_ATOM: | |||
printf("ALLOC_ATOM\n"); | |||
break; | |||
return; | |||
case L2_OP_ALLOC_REAL: | |||
printf("ALLOC_REAL\n"); | |||
break; | |||
return; | |||
case L2_OP_ALLOC_BUFFER_STATIC: | |||
printf("ALLOC_BUFFER_STATIC\n"); | |||
break; | |||
return; | |||
case L2_OP_ALLOC_BUFFER_ZERO: | |||
printf("ALLOC_BUFFER_ZERO\n"); | |||
break; | |||
return; | |||
case L2_OP_ALLOC_ARRAY: | |||
printf("ALLOC_ARRAY\n"); | |||
break; | |||
return; | |||
case L2_OP_ALLOC_NAMESPACE: | |||
printf("ALLOC_NAMESPACE\n"); | |||
break; | |||
return; | |||
case L2_OP_ALLOC_FUNCTION: | |||
printf("ALLOC_FUNCTION\n"); | |||
break; | |||
return; | |||
case L2_OP_NAMESPACE_SET: | |||
printf("NAMESPACE_SET\n"); | |||
break; | |||
return; | |||
case L2_OP_NAMESPACE_LOOKUP: | |||
printf("NAMESPACE_LOOKUP\n"); | |||
break; | |||
return; | |||
case L2_OP_DIRECT_ARRAY_LOOKUP: | |||
printf("DIRECT_ARRAY_LOOKUP\n"); | |||
break; | |||
return; | |||
case L2_OP_DIRECT_ARRAY_SET: | |||
printf("DIRECT_ARRAY_SET\n"); | |||
return; | |||
case L2_OP_HALT: | |||
printf("HALT\n"); | |||
break; | |||
return; | |||
} | |||
default: | |||
{ | |||
l2_word word = (l2_word)opcode; | |||
char bytes[sizeof(word)]; | |||
memcpy(&bytes, &word, sizeof(word)); | |||
printf("?"); | |||
for (size_t i = 0; i < sizeof(bytes); ++i) { | |||
printf(" %02x", bytes[i]); | |||
} | |||
printf("\n"); | |||
} | |||
l2_word word = (l2_word)opcode; | |||
char bytes[sizeof(word)]; | |||
memcpy(&bytes, &word, sizeof(word)); | |||
printf("?"); | |||
for (size_t i = 0; i < sizeof(bytes); ++i) { | |||
printf(" %02x", bytes[i]); | |||
} | |||
printf("\n"); | |||
} | |||
void l2_vm_print_bytecode(l2_word *ops, size_t opcount) { |
@@ -226,6 +226,11 @@ void l2_vm_step(struct l2_vm *vm) { | |||
vm->sptr -= 1; | |||
break; | |||
case L2_OP_SWAP_POP: | |||
vm->stack[vm->sptr - 2] = vm->stack[vm->sptr - 1]; | |||
vm->sptr -= 1; | |||
break; | |||
case L2_OP_DUP: | |||
vm->stack[vm->sptr] = vm->ops[vm->sptr - 1]; | |||
vm->sptr += 1; | |||
@@ -437,6 +442,16 @@ void l2_vm_step(struct l2_vm *vm) { | |||
} | |||
break; | |||
case L2_OP_DIRECT_ARRAY_SET: | |||
{ | |||
l2_word key = vm->stack[--vm->sptr]; | |||
l2_word val = vm->stack[vm->sptr - 1]; | |||
l2_word arr = vm->stack[vm->sptr - 2]; | |||
// TODO: Error if out of bounds or incorrect type | |||
vm->values[arr].array->data[key] = val; | |||
} | |||
break; | |||
case L2_OP_HALT: | |||
break; | |||
} |