diff --git a/assets/prelude.h b/assets/prelude.h index cfe03be..41d4091 100644 --- a/assets/prelude.h +++ b/assets/prelude.h @@ -111,6 +111,6 @@ Value display(Value v) { return v; } -Value numEqual(Value a, Value b) { +Value equal(Value a, Value b) { return MakeInt(a.z.value == b.z.value); } diff --git a/examples/test.lisp b/examples/test.lisp index b2f783b..a005cb2 100644 --- a/examples/test.lisp +++ b/examples/test.lisp @@ -1,5 +1,6 @@ (define x 1) -(define inc (lambda (n) (sum n 1))) +(define incr 1) +(define inc (lambda (n) (sum n incr))) (display (inc x)) diff --git a/main.c b/main.c index ac0972a..a2604f2 100644 --- a/main.c +++ b/main.c @@ -28,8 +28,13 @@ int main(int argc, char** argv) { inp[size] = '\0'; sc_ast* ast = sc_parse(inp); + char* out = compile(ast); - printf("%s\n", compile(ast)); + printf("%s\n", out); + + free(inp); + free(out); + sc_ast_free(ast); return 0; } diff --git a/src/ast.c b/src/ast.c new file mode 100644 index 0000000..9e2d341 --- /dev/null +++ b/src/ast.c @@ -0,0 +1,31 @@ +#include "ast.h" + +void sc_ast_free(sc_ast* ast) { + int i; + + for (i = 0; i < ast->n_children; ++i) sc_ast_free(ast->children[i]); + + free(ast->children); + free(ast->value); + free(ast); +} + +const char* tag_to_string(int x) { + switch(x) { + case PSEUDO: return "pseudo"; + case ATOM: return "atom"; + case STRING: return "string"; + case INT: return "int"; + case FLOAT: return "float"; + case LIST: return "list"; + default: {char* t=malloc(3); snprintf(t, 3, "%d", x); return t;} + } +} + +void sc_ast_print(sc_ast* ast) { + int i; + + printf("%s: %s\n", tag_to_string(ast->tag), ast->value); + + for (i = 0; i < ast->n_children; ++i) sc_ast_print(ast->children[i]); +} diff --git a/src/ast.h b/src/ast.h index ca9afb4..3671568 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1,4 +1,8 @@ #pragma once + +#include +#include + enum tag { PSEUDO, ATOM, @@ -18,4 +22,6 @@ typedef struct sc_ast { struct sc_ast** children; } sc_ast; +void sc_ast_free(sc_ast*); +void sc_ast_print(sc_ast*); diff --git a/src/compiler.c b/src/compiler.c index 18ac00b..2ddff5a 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -1,8 +1,26 @@ #include "compiler.h" +const char* primitives[5] = { + "sum", + "product", + "difference", + "display", + "equal" +}; + +int n_primitives = 5; + +char* sc_strcpy(char* src) { + char* dst = malloc(strlen(src)+1); + strcpy(dst, src); + return dst; +} + typedef struct sc_global { sc_ast* ast; char* name; + char** args; + int n_args; } sc_global; int n_globals = 0; @@ -33,16 +51,83 @@ char* get_prelude() { char* compile_expr(sc_ast* ast); +int in_list(char* elem, char** list, int len) { + int i; + + for (i = 0; i < len; i++) if (!strcmp(elem, list[i])) return 1; + + return 0; +} + +char** get_vars(sc_ast* body, char** args, int args_len, int* len) { + int i; + int j; + char** ret = NULL; + int tmplen = 0; + char** tmp; + + for (i = 0; i < body->n_children; i++) { + if (body->children[i]->tag == ATOM && + !in_list(body->children[i]->value, args, args_len) && + !in_list(body->children[i]->value, (char**)primitives, n_primitives)) { + (*len)++; + ret = realloc(ret, *len*sizeof(char*)); + ret[*len-1] = sc_strcpy(body->children[i]->value); + } else if (body->children[i]->tag == LIST) { + tmp = get_vars(body->children[i], args, args_len, &tmplen); + + ret = realloc(ret, (*len+tmplen)*sizeof(char*)); + for (j = 0; j < tmplen; j++) { + ret[*len+j] = tmp[j]; + } + len += tmplen; + tmplen = 0; + free(tmp); + } + } + + return ret; +} + +sc_global* find_global(char* name) { + int i; + + for (i = 0; i < n_globals; i++) { + if (!strcmp(name, globals[i]->name)) return globals[i]; + } + + return NULL; +} + void add_global(char* name, sc_ast* ast) { + int i; + int len = 0; + char** body_vars; globals = realloc(globals, ++n_globals*sizeof(sc_global*)); sc_global* g = malloc(sizeof(sc_global)); g->name = name; - g->ast = ast; + g->ast = ast->children[ast->n_children-1]; + + sc_ast* arg_list = ast->children[1]; + g->args = malloc(sizeof(char*)*arg_list->n_children); + for (i = 0; i < arg_list->n_children; i++) { + g->args[i] = sc_strcpy(arg_list->children[i]->value); + } + + body_vars = get_vars(g->ast, g->args, arg_list->n_children, &len); + g->args = realloc(g->args, sizeof(char*)*(arg_list->n_children+len)); + for (i = 0; i < len; i++) { + g->args[arg_list->n_children+i] = body_vars[i]; + } + free(body_vars); + g->n_args = arg_list->n_children+len; + + globals[n_globals-1] = g; } char* compile_lambda(sc_ast* ast) { - char* name = ast->children[1]->value; + char* name = sc_strcpy(ast->children[1]->value); add_global(name, ast->children[2]); return NULL; } @@ -56,6 +141,7 @@ char* compile_define(sc_ast* ast) { char* name = ast->children[1]->value; char* res = malloc(strlen(rhs)+strlen(name)+10); sprintf(res, "Value %s = %s", name, rhs); + free(rhs); return res; } @@ -72,12 +158,28 @@ char* compile_list(sc_ast* ast) { reslen += strlen(tmp)+2; res = realloc(res, reslen); snprintf(res, reslen, "%s%s", res, tmp); + free(tmp); for (i = 2; i < ast->n_children; i++) { tmp = compile_expr(ast->children[i]); reslen += strlen(tmp)+2; res = realloc(res, reslen); snprintf(res, reslen, "%s, %s", res, tmp); + free(tmp); + } + + sc_global* g = find_global(ast->children[0]->value); + + if (g) { + int start = ast->n_children-1; + int end = g->n_args; + for (i = start; i < end; i++) { + tmp = sc_strcpy(g->args[i]); + reslen += strlen(tmp)+2; + res = realloc(res, reslen); + snprintf(res, reslen, "%s, %s", res, tmp); + free(tmp); + } } res = realloc(res, reslen+1); @@ -93,22 +195,26 @@ char* compile_global(sc_global* global) { sprintf(res, "Value %s(", global->name); int reslen = strlen(res)+1; - sc_ast* args = global->ast->children[1]; - for (i = 0; i < args->n_children; i++) { + for (i = 0; i < global->n_args; i++) { if (i > 0) { - reslen += strlen(args->children[i]->value)+8; + reslen += strlen(global->args[i])+8; res = realloc(res, reslen); - snprintf(res, reslen, "%s, Value %s", res, args->children[i]->value); + snprintf(res, reslen, "%s, Value %s", res, global->args[i]); } else { - reslen += strlen(args->children[i]->value)+6; + reslen += strlen(global->args[i])+6; res = realloc(res, reslen); - snprintf(res, reslen, "%sValue %s", res, args->children[i]->value); + snprintf(res, reslen, "%sValue %s", res, global->args[i]); } + free(global->args[i]); } - tmp = compile_expr(global->ast->children[2]); + free(global->args); + + tmp = compile_expr(global->ast); reslen += strlen(tmp)+14; res = realloc(res, reslen); snprintf(res, reslen, "%s) { return %s; }", res, tmp); + free(tmp); + free(global->name); return res; } @@ -128,6 +234,7 @@ char* compile(sc_ast* ast) { mainlen += strlen(tmp)+1; main = realloc(main, mainlen); snprintf(main, mainlen, "%s;%s", main, tmp); + free(tmp); } for (i = 0; i < n_globals; i++) { @@ -136,10 +243,14 @@ char* compile(sc_ast* ast) { reslen += strlen(tmp); res = realloc(res, reslen); snprintf(res, reslen, "%s%s", res, tmp); + free(globals[i]); + free(tmp); } + free(globals); res = realloc(res, reslen+mainlen+1); snprintf(res, reslen+mainlen+1, "%s%s;}", res, main); + free(main); return res; } @@ -160,7 +271,7 @@ char* compile_expr(sc_ast* ast) { sprintf(tmp, "MakeInt(%s)", ast->value); return tmp; case ATOM: - return ast->value; + return sc_strcpy(ast->value); case STRING: ret = malloc(strlen(ast->value)+3); sprintf(ret, "\"%s\"", ast->value); @@ -169,7 +280,7 @@ char* compile_expr(sc_ast* ast) { return compile_list(ast); case PSEUDO: for (i = 0; i < ast->n_children; i++) { - tmp = compile(ast->children[i]); + tmp = compile_expr(ast->children[i]); if (!tmp) continue; retlen += strlen(tmp); if (ret) { diff --git a/src/compiler.h b/src/compiler.h index 58c13cd..c6e1b34 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1,5 +1,3 @@ -#include -#include #include #include "ast.h" diff --git a/src/parser.c b/src/parser.c index 96ea2c1..4e52ccd 100644 --- a/src/parser.c +++ b/src/parser.c @@ -86,7 +86,7 @@ sc_ast* read_token(char* inp) { return make_atom(inp); } -parse_state* read_tokens(parse_state* state) { +void read_tokens(parse_state* state) { char* token = state->tokens[0]; state->tokens++; int n = state->node->n_children++; @@ -100,7 +100,7 @@ parse_state* read_tokens(parse_state* state) { nstate->tokens = state->tokens; while (strncmp(nstate->tokens[0], ")", 2)) { - nstate = read_tokens(nstate); + read_tokens(nstate); } state->node->children[n] = nstate->node; @@ -109,8 +109,6 @@ parse_state* read_tokens(parse_state* state) { } else { state->node->children[n] = read_token(token); } - - return state; } sc_ast* sc_parse(char* input) { @@ -119,27 +117,16 @@ sc_ast* sc_parse(char* input) { state->tokens = tokens; state->node = make_pseudo(); - while (state->tokens[0]) state = read_tokens(state); + while (state->tokens[0]) read_tokens(state); - return state->node; -} - -const char* tag_to_string(int x) { - switch(x) { - case PSEUDO: return "pseudo"; - case ATOM: return "atom"; - case STRING: return "string"; - case INT: return "int"; - case FLOAT: return "float"; - case LIST: return "list"; - default: {char* t=malloc(3); snprintf(t, 3, "%d", x); return t;} + char** t = tokens; + while(t[0]) { + if (!strcmp(t[0], "(") || !strcmp(t[0], ")")) free(t[0]); + t++; } -} - -void sc_ast_print(sc_ast* ast) { - int i; - - printf("%s: %s\n", tag_to_string(ast->tag), ast->value); - - for (i = 0; i < ast->n_children; ++i) sc_ast_print(ast->children[i]); + free(tokens); + + sc_ast* ast = state->node; + free(state); + return ast; } diff --git a/src/parser.h b/src/parser.h index ac43b46..156c33d 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,9 +1,6 @@ #include -#include -#include #include #include "ast.h" sc_ast* sc_parse(char*); -void sc_ast_print(sc_ast*);