mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-28 09:57:59 +03:00
Implement more string instructions
Implement all of the string instructions that I could get the compiler to generate code for. Still ASCII-only.
This commit is contained in:
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
+9
-3
@@ -21,15 +21,21 @@
|
||||
#include <stddef.h>
|
||||
|
||||
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user