diff --git a/string.c b/string.c index bbd8c11..bc5d3c8 100644 --- a/string.c +++ b/string.c @@ -36,7 +36,7 @@ void free_string(struct string *str) free(str); } -struct string *string_dup(struct string *in) +struct string *string_dup(const struct string *in) { struct string *out = xmalloc(sizeof(struct string) + in->size + 1); out->size = in->size; @@ -45,7 +45,24 @@ struct string *string_dup(struct string *in) return out; } -struct string *string_append(struct string *a, struct string *b) +void string_append(struct string **_a, const struct string *b) +{ + struct string *a = *_a; + size_t a_size = a->size; + + if (a->literal) { + a = xmalloc(sizeof(struct string) + a->size + b->size + 1); + a->literal = false; + memcpy(a->text, (*_a)->text, a_size+1); + } else { + a = xrealloc(a, sizeof(struct string) + a->size + b->size + 1); + } + a->size = a_size + b->size; + memcpy(a->text + a_size, b->text, b->size + 1); + *_a = a; +} + +struct string *string_concatenate(const struct string *a, const struct string *b) { struct string *s = xmalloc(sizeof(struct string) + a->size + b->size + 1); s->size = a->size + b->size; @@ -55,6 +72,47 @@ struct string *string_append(struct string *a, struct string *b) return s; } +struct string *string_copy(const struct string *s, int index, int len) +{ + if (index < 0) + index = 0; + if (index >= s->size || len <= 0) + return make_string("", 0); + if (index + len > s->size) + len = s->size - index; + return make_string(s->text + index, len); +} + +int string_find(const struct string *haystack, const struct string *needle) +{ + char *r = strstr(haystack->text, needle->text); + if (!r) + return -1; + return r - haystack->text; +} + +void string_push_back(struct string **s, int c) +{ + *s = xrealloc(*s, sizeof(struct string) + (*s)->size + 2); + (*s)->text[(*s)->size++] = c & 0xFF; + (*s)->text[(*s)->size] = '\0'; +} + +void string_pop_back(struct string *s) +{ + s->text[--s->size] = '\0'; +} + +void string_erase(struct string *s, int index) +{ + if (index < 0) + index = 0; + if (index >= s->size) + return; + memcpy(s->text + index, s->text + index + 1, s->size - index - 1); + s->text[--s->size] = '\0'; +} + struct string *integer_to_string(int n) { char buf[512]; diff --git a/vm.c b/vm.c index c3d327e..aacb683 100644 --- a/vm.c +++ b/vm.c @@ -223,9 +223,9 @@ static void stack_push_string(struct string *s) stack[stack_ptr++].i = heap_slot; } -static struct string *stack_peek_string(void) +static struct string *stack_peek_string(int n) { - return heap[stack_peek(0).i].s; + return heap[stack_peek(n).i].s; } /* @@ -253,9 +253,21 @@ static void function_call(int32_t no) // create local page heap[page_slot].page = page_stack + new_pp; for (int i = f->nr_args - 1; i >= 0; i--) { - page_stack[new_pp + i] = stack_pop(); + int32_t slot; + switch (f->vars[i].data_type) { + case AIN_STRING: + slot = heap_alloc_slot(VM_STRING); + heap[slot].s = string_dup(heap[stack_pop().i].s); + page_stack[new_pp + i].i = slot; + break; + default: + page_stack[new_pp + i] = stack_pop(); + break; + } + // TODO: when argument is heap-backed, and not a reference + // need to either copy or set some kind of COW flag } - // heap-backed variables need a allocate a slot + // heap-backed variables need to allocate a slot for (int i = f->nr_args; i < f->nr_vars; i++) { int32_t slot; switch (f->vars[i].data_type) { @@ -280,7 +292,7 @@ static void function_return(void) // unref slots for heap-backed variables struct ain_function *f = &ain->functions[call_stack[call_stack_ptr].fno]; - for (int i = f->nr_args; i < f->nr_vars; i++) { + for (int i = 0; i < f->nr_vars; i++) { switch (f->vars[i].data_type) { case AIN_STRING: heap_unref(local_get(i)); @@ -304,7 +316,7 @@ static void system_call(int32_t code) sys_exit(stack_pop().i); break; case 0x6: // system.Output(string szText) - sys_message("%s", stack_peek_string()->text); + sys_message("%s", stack_peek_string(0)->text); // XXX: caller S_POPs break; case 0x14: // system.Peek() @@ -321,6 +333,7 @@ static void execute_instruction(int16_t opcode) { int32_t index, a, b, c, v; float f; + struct string *s; union vm_value val; union vm_value *ref; const char *opcode_name = "UNKNOWN"; @@ -348,18 +361,19 @@ static void execute_instruction(int16_t opcode) // Dereference a reference to a value. stack_push(stack_pop_ref()[0]); break; + case REFREF: + //case S_REFREF: // ??? + // Dereference a reference to a reference. + ref = stack_pop_ref(); + stack_push(ref[0].i); + stack_push(ref[1].i); + break; case S_REF: // Dereference a reference to a string index = stack_pop_ref()->i; heap_ref(index); stack_push(index); break; - case REFREF: - // Dereference a reference to a reference. - ref = stack_pop_ref(); - stack_push(ref[0].i); - stack_push(ref[1].i); - break; case DUP: // A -> AA stack_push(stack_peek(0).i); @@ -662,13 +676,96 @@ static void execute_instruction(int16_t opcode) heap[a].s = string_dup(heap[b].s); heap_unref(b); break; + case S_PLUSA2: + b = stack_pop().i; + a = stack_peek(0).i; + string_append(&heap[a].s, heap[b].s); + heap_unref(b); + break; case S_ADD: b = stack_pop().i; a = stack_pop().i; - stack_push_string(string_append(heap[a].s, heap[b].s)); + stack_push_string(string_concatenate(heap[a].s, heap[b].s)); heap_unref(a); heap_unref(b); break; + case S_LT: + v = strcmp(stack_peek_string(1)->text, stack_peek_string(0)->text) < 0; + heap_unref(stack_pop().i); + heap_unref(stack_pop().i); + stack_push(v); + break; + case S_GT: + v = strcmp(stack_peek_string(1)->text, stack_peek_string(0)->text) > 0; + heap_unref(stack_pop().i); + heap_unref(stack_pop().i); + stack_push(v); + break; + case S_LTE: + v = strcmp(stack_peek_string(1)->text, stack_peek_string(0)->text) <= 0; + heap_unref(stack_pop().i); + heap_unref(stack_pop().i); + stack_push(v); + break; + case S_GTE: + v = strcmp(stack_peek_string(1)->text, stack_peek_string(0)->text) >= 0; + heap_unref(stack_pop().i); + heap_unref(stack_pop().i); + stack_push(v); + break; + case S_NOTE: + v = !!strcmp(stack_peek_string(1)->text, stack_peek_string(0)->text); + heap_unref(stack_pop().i); + heap_unref(stack_pop().i); + stack_push(v); + break; + case S_EQUALE: + v = !strcmp(stack_peek_string(1)->text, stack_peek_string(0)->text); + heap_unref(stack_pop().i); + heap_unref(stack_pop().i); + stack_push(v); + break; + case S_LENGTH: + // TODO: handle sjis + case S_LENGTHBYTE: + a = stack_pop_ref()->i; + stack_push((int32_t)heap[a].s->size); + break; + case S_EMPTY: + v = !stack_peek_string(0)->size; + heap_unref(stack_pop().i); + stack_push(v); + break; + case S_FIND: + v = string_find(stack_peek_string(1), stack_peek_string(0)); + heap_unref(stack_pop().i); + stack_push(v); + break; + case S_GETPART: + b = stack_pop().i; // length + a = stack_pop().i; // index + s = string_copy(stack_peek_string(0), a, b); + heap_unref(stack_pop().i); + stack_push_string(s); + break; + //case S_PUSHBACK: // ??? + case S_PUSHBACK2: + v = stack_pop().i; + string_push_back(&heap[stack_peek(0).i].s, v); + heap_unref(stack_pop().i); + break; + //case S_POPBACK: // ??? + case S_POPBACK2: + string_pop_back(stack_peek_string(0)); + heap_unref(stack_pop().i); + break; + //case S_ERASE: // ??? + case S_ERASE2: + b = stack_pop().i; // ??? + a = stack_pop().i; // index + string_erase(stack_peek_string(0), a); + heap_unref(stack_pop().i); + break; case I_STRING: stack_push_string(integer_to_string(stack_pop().i)); break; diff --git a/vm_string.h b/vm_string.h index c4ae7cd..d963857 100644 --- a/vm_string.h +++ b/vm_string.h @@ -21,15 +21,21 @@ #include struct string { - unsigned int size; + int size; bool literal; char text[]; }; struct string *make_string(const char *str, unsigned int len); void free_string(struct string *str); -struct string *string_dup(struct string *in); -struct string *string_append(struct string *a, struct string *b); +struct string *string_dup(const struct string *in); +void string_append(struct string **a, const struct string *b); +struct string *string_concatenate(const struct string *a, const struct string *b); +struct string *string_copy(const struct string *s, int index, int len); +int string_find(const struct string *haystack, const struct string *needle); +void string_push_back(struct string **s, int c); +void string_pop_back(struct string *s); +void string_erase(struct string *s, int index); struct string *integer_to_string(int n); struct string *float_to_string(float f, int precision);