start with c codegen
[ccc.git] / genc.c
diff --git a/genc.c b/genc.c
new file mode 100644 (file)
index 0000000..10f3d4f
--- /dev/null
+++ b/genc.c
@@ -0,0 +1,255 @@
+#include <stdbool.h>
+
+#include "ast.h"
+
+#define gdie(msg) { fprintf(stderr, "%s", msg); return 1; }
+
+int expr_genc(struct expr *expr, FILE *cout);
+
+void binop_genc(char *fun, struct expr *l, struct expr *r, FILE *cout)
+{
+       safe_fprintf(cout, "%s(", fun);
+       expr_genc(l, cout);
+       safe_fprintf(cout, ", ");
+       expr_genc(r, cout);
+       safe_fprintf(cout, ")");
+}
+
+int expr_genc(struct expr *expr, FILE *cout)
+{
+       int r = 0;
+       char buf[] = "\\x55";
+       if (expr == NULL)
+               return 0;
+       switch(expr->type) {
+       case ebinop:
+               if (expr->type == ebinop && expr->data.ebinop.op == cons) {
+                       binop_genc("splc_cons", expr->data.ebinop.l,
+                               expr->data.ebinop.r, cout);
+               } else if (expr->type == ebinop && expr->data.ebinop.op == power) {
+                       binop_genc("splc_power", expr->data.ebinop.l,
+                               expr->data.ebinop.r, cout);
+               } else {
+                       safe_fprintf(cout, "(");
+                       expr_genc(expr->data.ebinop.l, cout);
+                       safe_fprintf(cout, "%s", binop_str[expr->data.ebinop.op]);
+                       expr_genc(expr->data.ebinop.r, cout);
+                       safe_fprintf(cout, ")");
+               }
+               break;
+       case ebool:
+               safe_fprintf(cout, "%s", expr->data.ebool ? "true" : "false");
+               break;
+       case echar:
+               safe_fprintf(cout, "'%s'",
+                       escape_char(expr->data.echar, buf, false));
+               break;
+       case efuncall:
+               safe_fprintf(cout, "%s(", expr->data.efuncall.ident);
+               for(int i = 0; i<expr->data.efuncall.nargs; i++) {
+                       expr_genc(expr->data.efuncall.args[i], cout);
+                       if (i+1 < expr->data.efuncall.nargs)
+                               safe_fprintf(cout, ", ");
+               }
+               safe_fprintf(cout, ")");
+               for (int i = 0; i<expr->data.efuncall.nfields; i++)
+                       fprintf(cout, "->%s",
+                               fieldspec_str[expr->data.efuncall.fields[i]]);
+               break;
+       case eint:
+               safe_fprintf(cout, "%d", expr->data.eint);
+               break;
+       case eident:
+               fprintf(cout, "%s", expr->data.eident.ident);
+               for (int i = 0; i<expr->data.eident.nfields; i++)
+                       fprintf(cout, "->%s",
+                               fieldspec_str[expr->data.eident.fields[i]]);
+               break;
+       case enil:
+               safe_fprintf(cout, "NULL");
+               break;
+       case etuple:
+               binop_genc("splc_tuple", expr->data.etuple.left,
+                       expr->data.etuple.right, cout);
+               break;
+       case estring:
+               safe_fprintf(cout, "\"");
+               for (int i = 0; i<expr->data.estring.nchars; i++)
+                       safe_fprintf(cout, "%s", escape_char(
+                               expr->data.estring.chars[i], buf, true));
+               safe_fprintf(cout, "\"");
+               break;
+       case eunop:
+               safe_fprintf(cout, "(%s", unop_str[expr->data.eunop.op]);
+               expr_genc(expr->data.eunop.l, cout);
+               safe_fprintf(cout, ")");
+               break;
+       default:
+               die("Unknown expression node\n");
+       }
+       return r;
+}
+
+int type_genc(struct type *type, FILE *cout)
+{
+       if (type == NULL) {
+               fprintf(cout, "WORD ");
+       } else {
+               switch(type->type) {
+               case tbasic:
+                       fprintf(cout, "WORD ");
+                       break;
+               case tlist:
+                       fprintf(cout, "struct splc_list *");
+                       break;
+               case ttuple:
+                       fprintf(cout, "struct splc_tuple *");
+                       break;
+               case tvar:
+                       fprintf(cout, "WORD ");
+                       break;
+               default:
+                       die("Unsupported type node\n");
+               }
+       }
+       return 0;
+}
+
+int vardecl_genc(struct vardecl *vardecl, int indent, FILE *cout)
+{
+       int r = 0;
+       if (vardecl == NULL)
+               return 0;
+       pindent(indent, cout);
+       type_genc(vardecl->type, cout);
+       fprintf(cout, "%s = ", vardecl->ident);
+       r = expr_genc(vardecl->expr, cout);
+       fprintf(cout, ";\n");
+       return r;
+}
+
+void stmt_genc(struct stmt *stmt, int indent, FILE *cout)
+{
+       if (stmt == NULL)
+               return;
+       switch(stmt->type) {
+       case sassign:
+               pindent(indent, cout);
+               fprintf(cout, "%s", stmt->data.sassign.ident);
+               for (int i = 0; i<stmt->data.sassign.nfields; i++)
+                       fprintf(cout, "->%s", stmt->data.sassign.fields[i]);
+               safe_fprintf(cout, " = ");
+               expr_genc(stmt->data.sassign.expr, cout);
+               safe_fprintf(cout, ";\n");
+               break;
+       case sif:
+               pindent(indent, cout);
+               safe_fprintf(cout, "if (");
+               expr_genc(stmt->data.sif.pred, cout);
+               safe_fprintf(cout, ") {\n");
+               for (int i = 0; i<stmt->data.sif.nthen; i++)
+                       stmt_genc(stmt->data.sif.then[i], indent+1, cout);
+               pindent(indent, cout);
+               safe_fprintf(cout, "} else {\n");
+               for (int i = 0; i<stmt->data.sif.nels; i++)
+                       stmt_genc(stmt->data.sif.els[i], indent+1, cout);
+               pindent(indent, cout);
+               safe_fprintf(cout, "}\n");
+               break;
+       case sreturn:
+               pindent(indent, cout);
+               safe_fprintf(cout, "return ");
+               expr_genc(stmt->data.sreturn, cout);
+               safe_fprintf(cout, ";\n");
+               break;
+       case sexpr:
+               pindent(indent, cout);
+               expr_genc(stmt->data.sexpr, cout);
+               safe_fprintf(cout, ";\n");
+               break;
+       case svardecl:
+               vardecl_genc(stmt->data.svardecl, indent, cout);
+               break;
+       case swhile:
+               pindent(indent, cout);
+               safe_fprintf(cout, "while (");
+               expr_genc(stmt->data.swhile.pred, cout);
+               safe_fprintf(cout, ") {\n");
+               for (int i = 0; i<stmt->data.swhile.nbody; i++)
+                       stmt_genc(stmt->data.swhile.body[i], indent+1, cout);
+               pindent(indent, cout);
+               safe_fprintf(cout, "}\n");
+               break;
+       default:
+               die("Unsupported stmt node\n");
+       }
+}
+
+int decl_genc(struct decl *decl, FILE *cout)
+{
+       switch (decl->type) {
+       case dfundecl:
+               type_genc(decl->data.dfun.rtype, cout);
+               safe_fprintf(cout, "%s (", decl->data.dfun.ident);
+               for (int i = 0; i<decl->data.dfun.nargs; i++) {
+                       if (i < decl->data.dfun.natypes)
+                               type_genc(decl->data.dfun.atypes[i], cout);
+                       safe_fprintf(cout, "%s", decl->data.dfun.args[i]);
+                       if (i < decl->data.dfun.nargs - 1)
+                               safe_fprintf(cout, ", ");
+               }
+               safe_fprintf(cout, ") /*");
+               if (decl->data.dfun.rtype != NULL) {
+                       safe_fprintf(cout, " :: ");
+                       for (int i = 0; i<decl->data.dfun.natypes; i++) {
+                               type_print(decl->data.dfun.atypes[i], cout);
+                               safe_fprintf(cout, " ");
+                       }
+                       safe_fprintf(cout, "-> ");
+                       type_print(decl->data.dfun.rtype, cout);
+               }
+               safe_fprintf(cout, "*/ {\n");
+               for (int i = 0; i<decl->data.dfun.nbody; i++)
+                       stmt_genc(decl->data.dfun.body[i], 1, cout);
+               safe_fprintf(cout, "}\n");
+               break;
+       case dvardecl:
+               return vardecl_genc(decl->data.dvar, 0, cout);
+       }
+       return 0;
+}
+
+int genc(struct ast *ast, FILE *cout)
+{
+       fprintf(cout,
+               "#include <stdint.h>\n"
+               "#include <stdlib.h>\n"
+               "#define WORD intptr_t\n"
+               "struct splc_tuple { WORD fst; WORD snd; };\n"
+               "struct splc_list { WORD hd; struct splc_list *tl; };\n"
+               "struct splc_tuple *splc_tuple(WORD fst, WORD snd) {\n"
+               "\tstruct splc_tuple *res = malloc(sizeof(splc_tuple));\n"
+               "\tres->fst = fst;\n"
+               "\tres->snd = snd;\n"
+               "\treturn res;\n"
+               "}\n"
+               "struct splc_list *splc_cons(WORD hd, struct splc_list *tl) {\n"
+               "\tstruct splc_list *res = malloc(sizeof(splc_tuple));\n"
+               "\tres->hd = hd;\n"
+               "\tres->tl = tl;\n"
+               "\treturn res;\n"
+               "}\n"
+               "WORD splc_power(WORD l, WORD r) {\n"
+               "\tWORD res = 1;\n"
+               "\twhile(l-- >= 0)\n"
+               "\t\tres *= r;\n"
+               "\treturn res;\n"
+               "}\n"
+               );
+       int r = 0;
+       for (int i = 0; i<ast->ndecls && r == 0; i++) {
+               fprintf(cout, "\n");
+               r = decl_genc(ast->decls[i], cout);
+       }
+       return r;
+}