X-Git-Url: https://code.kerkeslager.com/?p=fur;a=blobdiff_plain;f=templates%2Fprogram2.c;h=01203fd92eb47ac133e0667280bc3759ef84d05c;hp=76fc2f804db601251d93ecb63d7f6f95c8165f10;hb=c24be69b26aedc427c7831f150e86ca00182d8e0;hpb=379bdcf727cc66ee58d36a112e306b81e427fcf1 diff --git a/templates/program2.c b/templates/program2.c index 76fc2f8..01203fd 100644 --- a/templates/program2.c +++ b/templates/program2.c @@ -8,9 +8,14 @@ enum Type; typedef enum Type Type; enum Type { + BOOLEAN, BUILTIN, + CLOSURE, INTEGER, - STRING + LIST, + STRING, + STRUCTURE, + SYMBOL }; enum Builtin; @@ -21,21 +26,55 @@ enum Builtin { PRINT }; +struct Object; +typedef struct Object Object; +struct Environment; +typedef struct Environment Environment; +struct Thread; +typedef struct Thread Thread; + +struct Closure; +typedef struct Closure Closure; +struct Closure { + Environment* environment; + size_t entry; +}; + +struct List; +typedef struct List List; + +struct Structure; +typedef struct Structure Structure; + union Value; typedef union Value Value; union Value { Builtin builtin; - char* string; + bool boolean; + Closure closure; int32_t integer; + List* list; + char* string; + Structure* structure; + char* symbol; }; -struct Object; -typedef struct Object Object; struct Object { Type type; Value value; }; +struct List { + Object head; + List* tail; +}; + +struct Structure { + char* key; + Object value; + Structure* next; +}; + #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL } void Object_deinitialize(Object* self) { @@ -43,26 +82,39 @@ void Object_deinitialize(Object* self) { {% include "environment.c" %} {% include "stack.c" %} +{% include "frame.c" %} -struct Thread; -typedef struct Thread Thread; struct Thread { - Environment* environment; + Frame frame; Stack stack; - size_t program_counter; }; -void Thread_initialize(Thread* self, size_t program_counter) { - self->environment = Environment_construct(); +void Thread_initialize(Thread* self, size_t programCounter) { + Frame_initialize(&(self->frame), Environment_construct(NULL), NULL, programCounter); Stack_initialize(&(self->stack)); - self->program_counter = program_counter; } void Thread_deinitialize(Thread* self) { - Environment_destruct(self->environment); + Frame_deinitialize(&(self->frame)); Stack_deinitialize(&(self->stack)); } +Environment* Thread_getEnvironment(Thread* self) { + return self->frame.environment; +} + +void Thread_setProgramCounter(Thread* self, size_t programCounter) { + self->frame.programCounter = programCounter; +} + +void Thread_incrementProgramCounter(Thread* self) { + self->frame.programCounter++; +} + +size_t Thread_getProgramCounter(Thread* self) { + return self->frame.programCounter; +} + union Argument; typedef const union Argument Argument; union Argument { @@ -70,66 +122,108 @@ union Argument { void* pointer; char* string; int32_t integer; + char* symbol; }; -void call(struct Thread* thread, const union Argument argument) { +void callBuiltinPow(Thread* thread, size_t argumentCount) { + assert(argumentCount == 2); + assert(!Stack_isEmpty(&(thread->stack))); + Object exponent = Stack_pop(&(thread->stack)); + assert(exponent.type == INTEGER); + assert(exponent.value.integer >= 0); + + assert(!Stack_isEmpty(&(thread->stack))); + Object base = Stack_pop(&(thread->stack)); + assert(base.type == INTEGER); + + Object result; + result.type = INTEGER; + result.value.integer = 1; + + while(exponent.value.integer > 0) { + result.value.integer *= base.value.integer; + exponent.value.integer--; + } + + Stack_push(&(thread->stack), result); +} + +void callBuiltinPrint(Thread* thread, size_t argumentCount) { + assert(argumentCount > 0); + + Object arguments[argumentCount]; + size_t count; + + for(count = 0; count < argumentCount; count++) { + assert(!Stack_isEmpty(&(thread->stack))); + arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack)); + } + + for(count = 0; count < argumentCount; count ++) { + Object arg = arguments[count]; + + switch(arg.type) { + case BOOLEAN: + if(arg.value.boolean) printf("true"); + else printf("false"); + break; + + case INTEGER: + printf("%i", arg.value.integer); + break; + + case STRING: + printf("%s", arg.value.string); + break; + + default: + assert(false); + } + } + + Stack_push(&(thread->stack), BUILTIN_NIL); +} + +void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) { + switch(b) { + case POW: + callBuiltinPow(thread, argumentCount); + break; + + case PRINT: + callBuiltinPrint(thread, argumentCount); + break; + + default: + assert(false); + } +} + +void callClosure(Thread* thread, Closure closure, size_t argumentCount) { + // TODO Find a way to assert the argument count + + Frame* returnFrame = malloc(sizeof(Frame)); + *returnFrame = thread->frame; + Frame_initialize( + &(thread->frame), + Environment_construct(Environment_reference(closure.environment)), + returnFrame, + closure.entry - 1 // We will increment the frame immediately after this + ); +} + +void inst_call(Thread* thread, Argument argument) { assert(!Stack_isEmpty(&(thread->stack))); Object f = Stack_pop(&(thread->stack)); size_t argumentCount = argument.label; switch(f.type) { case BUILTIN: - switch(f.value.builtin) { - case POW: - { - assert(argumentCount == 2); - assert(!Stack_isEmpty(&(thread->stack))); - Object exponent = Stack_pop(&(thread->stack)); - assert(exponent.type == INTEGER); - assert(exponent.value.integer >= 0); - - assert(!Stack_isEmpty(&(thread->stack))); - Object base = Stack_pop(&(thread->stack)); - assert(base.type == INTEGER); - - Object result; - result.type = INTEGER; - result.value.integer = 1; - - while(exponent.value.integer > 0) { - result.value.integer *= base.value.integer; - exponent.value.integer--; - } - - Stack_push(&(thread->stack), result); - } - break; - case PRINT: - { - // TODO Handle multiple arguments - assert(!Stack_isEmpty(&(thread->stack))); - Object arg = Stack_pop(&(thread->stack)); - - switch(arg.type) { - case INTEGER: - printf("%i", arg.value.integer); - break; - - case STRING: - printf("%s", arg.value.string); - break; - - default: - assert(0); - } - - Stack_push(&(thread->stack), BUILTIN_NIL); - } - break; - - default: - assert(false); - } + callBuiltin(thread, f.value.builtin, argumentCount); + break; + + case CLOSURE: + callClosure(thread, f.value.closure, argumentCount); break; default: @@ -137,24 +231,152 @@ void call(struct Thread* thread, const union Argument argument) { } } +void inst_concat(Thread* thread, Argument argument) { + assert(!Stack_isEmpty(&(thread->stack))); + Object left = Stack_pop(&(thread->stack)); + assert(!Stack_isEmpty(&(thread->stack))); + Object right = Stack_pop(&(thread->stack)); + + assert(left.type == STRING); + assert(right.type == STRING); + + char* resultString = malloc(strlen(left.value.string) + strlen(right.value.string) + 1); + resultString[0] = '\0'; + + strcat(resultString, left.value.string); + strcat(resultString, right.value.string); + + Object resultObject = (Object) { + STRING, + (Value)resultString + }; + + Stack_push(&(thread->stack), resultObject); +} + {% with name='add', operation='+' %} {% include "arithmetic_instruction.c" %} {% endwith %} +void inst_close(Thread* thread, Argument argument) { + Object result; + result.type = CLOSURE; + result.value.closure.environment = Thread_getEnvironment(thread); + result.value.closure.entry = argument.label; -void drop(struct Thread* thread, const union Argument argument) { + Stack_push(&(thread->stack), result); +} + +void inst_drop(Thread* thread, Argument argument) { assert(!Stack_isEmpty(&(thread->stack))); Object result = Stack_pop(&(thread->stack)); Object_deinitialize(&result); } -void end(struct Thread* thread, const union Argument argument) { +void inst_end(Thread* thread, Argument argument) { +} + +{% with name='eq', operation='==' %} + {% include "comparison_instruction.c" %} +{% endwith %} + +void inst_field(Thread* thread, Argument argument) { + assert(!Stack_isEmpty(&(thread->stack))); + Object key = Stack_pop(&(thread->stack)); + assert(key.type == SYMBOL); + + assert(!Stack_isEmpty(&(thread->stack))); + Object structure = Stack_pop(&(thread->stack)); + assert(structure.type == STRUCTURE); + + while(structure.value.structure != NULL) { + if(strcmp(structure.value.structure->key, key.value.string) == 0) { + Stack_push(&(thread->stack), structure.value.structure->value); + return; + } + structure.value.structure = structure.value.structure->next; + } + + assert(false); // Symbol wasn't found in structure } +void inst_get(Thread* thread, Argument argument) { + assert(!Stack_isEmpty(&(thread->stack))); + Object indexObject = Stack_pop(&(thread->stack)); + assert(indexObject.type == INTEGER); + int32_t index = indexObject.value.integer; + + assert(!Stack_isEmpty(&(thread->stack))); + Object listObject = Stack_pop(&(thread->stack)); + assert(listObject.type == LIST); + List* list = listObject.value.list; + + while(index > 0) { + assert(list != NULL); + list = list->tail; + index--; + } + + assert(list != NULL); + Stack_push(&(thread->stack), list->head); +} + +{% with name='gt', operation='>' %} + {% include "comparison_instruction.c" %} +{% endwith %} + +{% with name='gte', operation='>=' %} + {% include "comparison_instruction.c" %} +{% endwith %} + {% with name='idiv', operation='/' %} {% include "arithmetic_instruction.c" %} {% endwith %} +void inst_jump(Thread* thread, Argument argument) { + Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running +} + +void inst_jump_if_false(Thread* thread, Argument argument) { + assert(!Stack_isEmpty(&(thread->stack))); + Object result = Stack_pop(&(thread->stack)); + assert(result.type == BOOLEAN); + + if(!(result.value.boolean)) { + inst_jump(thread, argument); + } +} + +void inst_list(Thread* thread, Argument argument) { + Object result; + result.type = LIST; + result.value.list = NULL; + + int32_t count = argument.integer; + + while(count > 0) { + assert(!Stack_isEmpty(&(thread->stack))); + Object item = Stack_pop(&(thread->stack)); + + List* node = malloc(sizeof(List)); + node->head = item; + node->tail = result.value.list; + + result.value.list = node; + count--; + } + + Stack_push(&(thread->stack), result); +} + +{% with name='lt', operation='<' %} + {% include "comparison_instruction.c" %} +{% endwith %} + +{% with name='lte', operation='<=' %} + {% include "comparison_instruction.c" %} +{% endwith %} + {% with name='mod', operation='%' %} {% include "arithmetic_instruction.c" %} {% endwith %} @@ -163,7 +385,21 @@ void end(struct Thread* thread, const union Argument argument) { {% include "arithmetic_instruction.c" %} {% endwith %} -void pop(struct Thread* thread, const union Argument argument) { +{% with name='neq', operation='!=' %} + {% include "comparison_instruction.c" %} +{% endwith %} + +void inst_neg(Thread* thread, Argument argument) { + assert(!Stack_isEmpty(&(thread->stack))); + Object result = Stack_pop(&(thread->stack)); + assert(result.type == INTEGER); + + result.value.integer = -(result.value.integer); + + Stack_push(&(thread->stack), result); +} + +void inst_pop(Thread* thread, Argument argument) { char* argumentString = argument.string; assert(!Stack_isEmpty(&(thread->stack))); @@ -176,24 +412,31 @@ void pop(struct Thread* thread, const union Argument argument) { } - Environment_set(thread->environment, argumentString, result); + Environment_set(Thread_getEnvironment(thread), argumentString, result); } -void push(struct Thread* thread, const union Argument argument) { +void inst_push(Thread* thread, Argument argument) { char* argumentString = argument.string; - if(strcmp(argumentString, "print") == 0) { + if(strcmp(argumentString, "false") == 0) { + Stack_push(&(thread->stack), (Object){ BOOLEAN, false }); + } else if(strcmp(argumentString, "pow") == 0) { Object result; result.type = BUILTIN; - result.value.builtin = PRINT; + result.value.builtin = POW; Stack_push(&(thread->stack), result); - } else if(strcmp(argumentString, "pow") == 0) { + } else if(strcmp(argumentString, "print") == 0) { Object result; result.type = BUILTIN; - result.value.builtin = POW; + result.value.builtin = PRINT; Stack_push(&(thread->stack), result); + } else if(strcmp(argumentString, "true") == 0) { + Stack_push(&(thread->stack), (Object){ BOOLEAN, true }); } else { - Environment_get_Result result = Environment_get(thread->environment, argumentString); + Environment_get_Result result = Environment_get( + Thread_getEnvironment(thread), + argumentString + ); if(!result.found) { fprintf(stderr, "Variable `%s` not found", argumentString); assert(false); @@ -202,7 +445,7 @@ void push(struct Thread* thread, const union Argument argument) { } } -void push_integer(struct Thread* thread, const union Argument argument) { +void inst_push_integer(Thread* thread, Argument argument) { Object result; result.type = INTEGER; result.value.integer = argument.integer; @@ -210,7 +453,7 @@ void push_integer(struct Thread* thread, const union Argument argument) { Stack_push(&(thread->stack), result); } -void push_string(struct Thread* thread, const union Argument argument) { +void inst_push_string(Thread* thread, Argument argument) { Object result; result.type = STRING; result.value.string = argument.string; @@ -218,14 +461,66 @@ void push_string(struct Thread* thread, const union Argument argument) { Stack_push(&(thread->stack), result); } +void inst_push_symbol(Thread* thread, Argument argument) { + // TODO Store symbols in a symbol table so they can be looked up by reference + // without string comparison + Object result; + result.type = SYMBOL; + result.value.symbol = argument.symbol; + + Stack_push(&(thread->stack), result); +} + {% with name='sub', operation='-' %} {% include "arithmetic_instruction.c" %} {% endwith %} +void inst_return(Thread* thread, Argument argument) { + Frame* returnFrame = thread->frame.returnFrame; + + Frame_deinitialize(&(thread->frame)); + + Frame_initialize( + &(thread->frame), + returnFrame->environment, + returnFrame->returnFrame, + returnFrame->programCounter + ); + + free(returnFrame); +} + +void inst_structure(Thread* thread, Argument argument) { + Object result; + result.type = STRUCTURE; + result.value.structure = NULL; + + int32_t count = argument.integer; + + while(count > 0) { + assert(!Stack_isEmpty(&(thread->stack))); + Object key = Stack_pop(&(thread->stack)); + assert(key.type == SYMBOL); + + assert(!Stack_isEmpty(&(thread->stack))); + Object value = Stack_pop(&(thread->stack)); + + Structure* node = malloc(sizeof(Structure)); + node->key = key.value.string; + node->value = value; + node->next = result.value.structure; + + result.value.structure = node; + count--; + } + + Stack_push(&(thread->stack), result); +} + struct Instruction; typedef const struct Instruction Instruction; struct Instruction { - void (*instruction)(struct Thread*,const union Argument); + void (*instruction)(Thread*,Argument); Argument argument; }; @@ -235,18 +530,18 @@ struct Instruction { const Instruction program[] = { {% for instruction in instruction_list %} - (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} }, + (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} }, {% endfor %} }; int main() { Thread thread; - Thread_initialize(&thread, 0); + Thread_initialize(&thread, LABEL___main__); - for(; program[thread.program_counter].instruction != end; thread.program_counter++) { - program[thread.program_counter].instruction( + for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) { + program[Thread_getProgramCounter(&thread)].instruction( &thread, - program[thread.program_counter].argument + program[Thread_getProgramCounter(&thread)].argument ); }