*/ | */ | ||||
L2_OP_POP, | 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. | * Duplicate the top element on the stack. | ||||
* Push <word at <sptr> - 1> | * Push <word at <sptr> - 1> | ||||
/* | /* | ||||
* Look up a value from an array. | * Look up a value from an array. | ||||
* Pop <key> | * Pop <key> | ||||
* Pop <arr> | |||||
* Push <arr[<key>]> | |||||
* Read <val> | |||||
* Read <arr> | |||||
* Assign <val> to <arr[<key>]> | |||||
*/ | */ | ||||
L2_OP_DIRECT_ARRAY_LOOKUP, | 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. | * Halt execution. | ||||
*/ | */ |
void l2_gen_halt(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_rjmp(struct l2_generator *gen, l2_word len); | ||||
void l2_gen_pop(struct l2_generator *gen); | 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_push(struct l2_generator *gen, l2_word word); | ||||
void l2_gen_ret(struct l2_generator *gen); | void l2_gen_ret(struct l2_generator *gen); | ||||
void l2_gen_number(struct l2_generator *gen, double num); | void l2_gen_number(struct l2_generator *gen, double num); | ||||
void l2_gen_namespace_set(struct l2_generator *gen, char **ident); | 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_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_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_lookup(struct l2_generator *gen, char **ident); | ||||
void l2_gen_stack_frame_set(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); | void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident); |
put(gen, L2_OP_POP); | 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) { | void l2_gen_push(struct l2_generator *gen, l2_word word) { | ||||
put(gen, L2_OP_PUSH); | put(gen, L2_OP_PUSH); | ||||
put(gen, word); | put(gen, word); | ||||
put(gen, L2_OP_DIRECT_ARRAY_LOOKUP); | 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) { | void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | ||||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
put(gen, L2_OP_PUSH); | put(gen, L2_OP_PUSH); |
char *ident = l2_token_extract_str(tok2); | char *ident = l2_token_extract_str(tok2); | ||||
l2_lexer_consume(lexer); // '.' | l2_lexer_consume(lexer); // '.' | ||||
l2_lexer_consume(lexer); // ident | l2_lexer_consume(lexer); // ident | ||||
l2_lexer_consume(lexer); // equals | |||||
l2_lexer_consume(lexer); // '=' | |||||
if (parse_expression(lexer, gen, err) < 0) { | if (parse_expression(lexer, gen, err) < 0) { | ||||
return -1; | return -1; | ||||
} | } | ||||
l2_gen_namespace_set(gen, &ident); | l2_gen_namespace_set(gen, &ident); | ||||
l2_gen_swap_pop(gen); | |||||
} else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT) { | } else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT) { | ||||
l2_trace_scope("namespace lookup"); | l2_trace_scope("namespace lookup"); | ||||
l2_trace("ident '%s'", tok2->v.str); | l2_trace("ident '%s'", tok2->v.str); | ||||
l2_lexer_consume(lexer); // ident | l2_lexer_consume(lexer); // ident | ||||
l2_gen_namespace_lookup(gen, &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) { | } else if (tok->kind == L2_TOK_DOT_NUMBER) { | ||||
l2_trace_scope("direct array lookup"); | l2_trace_scope("direct array lookup"); | ||||
int number = tok->v.integer; | int number = tok->v.integer; |
switch (opcode) { | switch (opcode) { | ||||
case L2_OP_NOP: | case L2_OP_NOP: | ||||
printf("NOP\n"); | printf("NOP\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_PUSH: | case L2_OP_PUSH: | ||||
printf("PUSH "); | printf("PUSH "); | ||||
print_op_num(ops, opcount, (*ptr)++); | print_op_num(ops, opcount, (*ptr)++); | ||||
printf("\n"); | printf("\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_PUSH_2: | case L2_OP_PUSH_2: | ||||
printf("PUSH2 "); | printf("PUSH2 "); | ||||
printf(" "); | printf(" "); | ||||
print_op_num(ops, opcount, (*ptr)++); | print_op_num(ops, opcount, (*ptr)++); | ||||
printf("\n"); | printf("\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_POP: | case L2_OP_POP: | ||||
printf("POP\n"); | printf("POP\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_SWAP_POP: | |||||
printf("SWAP_POP\n"); | |||||
return; | |||||
case L2_OP_DUP: | case L2_OP_DUP: | ||||
printf("DUP\n"); | printf("DUP\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_ADD: | case L2_OP_ADD: | ||||
printf("ADD\n"); | printf("ADD\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_FUNC_CALL: | case L2_OP_FUNC_CALL: | ||||
printf("FUNC_CALL\n"); | printf("FUNC_CALL\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_RJMP: | case L2_OP_RJMP: | ||||
printf("RJMP\n"); | printf("RJMP\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_STACK_FRAME_LOOKUP: | case L2_OP_STACK_FRAME_LOOKUP: | ||||
printf("STACK_FRAME_LOOKUP\n"); | printf("STACK_FRAME_LOOKUP\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_STACK_FRAME_SET: | case L2_OP_STACK_FRAME_SET: | ||||
printf("STACK_FRAME_SET\n"); | printf("STACK_FRAME_SET\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_STACK_FRAME_REPLACE: | |||||
printf("STACK_FRAME_REPLACE\n"); | |||||
return; | |||||
case L2_OP_RET: | case L2_OP_RET: | ||||
printf("RET\n"); | printf("RET\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_ALLOC_ATOM: | case L2_OP_ALLOC_ATOM: | ||||
printf("ALLOC_ATOM\n"); | printf("ALLOC_ATOM\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_ALLOC_REAL: | case L2_OP_ALLOC_REAL: | ||||
printf("ALLOC_REAL\n"); | printf("ALLOC_REAL\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_ALLOC_BUFFER_STATIC: | case L2_OP_ALLOC_BUFFER_STATIC: | ||||
printf("ALLOC_BUFFER_STATIC\n"); | printf("ALLOC_BUFFER_STATIC\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_ALLOC_BUFFER_ZERO: | case L2_OP_ALLOC_BUFFER_ZERO: | ||||
printf("ALLOC_BUFFER_ZERO\n"); | printf("ALLOC_BUFFER_ZERO\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_ALLOC_ARRAY: | case L2_OP_ALLOC_ARRAY: | ||||
printf("ALLOC_ARRAY\n"); | printf("ALLOC_ARRAY\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_ALLOC_NAMESPACE: | case L2_OP_ALLOC_NAMESPACE: | ||||
printf("ALLOC_NAMESPACE\n"); | printf("ALLOC_NAMESPACE\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_ALLOC_FUNCTION: | case L2_OP_ALLOC_FUNCTION: | ||||
printf("ALLOC_FUNCTION\n"); | printf("ALLOC_FUNCTION\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_NAMESPACE_SET: | case L2_OP_NAMESPACE_SET: | ||||
printf("NAMESPACE_SET\n"); | printf("NAMESPACE_SET\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_NAMESPACE_LOOKUP: | case L2_OP_NAMESPACE_LOOKUP: | ||||
printf("NAMESPACE_LOOKUP\n"); | printf("NAMESPACE_LOOKUP\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_DIRECT_ARRAY_LOOKUP: | case L2_OP_DIRECT_ARRAY_LOOKUP: | ||||
printf("DIRECT_ARRAY_LOOKUP\n"); | printf("DIRECT_ARRAY_LOOKUP\n"); | ||||
break; | |||||
return; | |||||
case L2_OP_DIRECT_ARRAY_SET: | |||||
printf("DIRECT_ARRAY_SET\n"); | |||||
return; | |||||
case L2_OP_HALT: | case L2_OP_HALT: | ||||
printf("HALT\n"); | 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) { | void l2_vm_print_bytecode(l2_word *ops, size_t opcount) { |
vm->sptr -= 1; | vm->sptr -= 1; | ||||
break; | break; | ||||
case L2_OP_SWAP_POP: | |||||
vm->stack[vm->sptr - 2] = vm->stack[vm->sptr - 1]; | |||||
vm->sptr -= 1; | |||||
break; | |||||
case L2_OP_DUP: | case L2_OP_DUP: | ||||
vm->stack[vm->sptr] = vm->ops[vm->sptr - 1]; | vm->stack[vm->sptr] = vm->ops[vm->sptr - 1]; | ||||
vm->sptr += 1; | vm->sptr += 1; | ||||
} | } | ||||
break; | 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: | case L2_OP_HALT: | ||||
break; | break; | ||||
} | } |