#include "ast.h"
#include "parse.h"
-static const char *binop_str[] = {
+const char *binop_str[] = {
[binor] = "||", [binand] = "&&", [eq] = "==", [neq] = "!=",
[leq] = "<=", [le] = "<", [geq] = ">=", [ge] = ">", [cons] = ":",
[plus] = "+", [minus] = "-", [times] = "*", [divide] = "/",
[modulo] = "%", [power] = "^",
};
-static const char *fieldspec_str[] = {
+const char *fieldspec_str[] = {
[fst] = "fst", [snd] = "snd", [hd] = "hd", [tl] = "tl"};
-static const char *unop_str[] = { [inverse] = "!", [negate] = "-", };
+const char *unop_str[] = { [inverse] = "!", [negate] = "-", };
static const char *basictype_str[] = {
[btbool] = "Bool", [btchar] = "Char", [btint] = "Int",
[btvoid] = "Void",
safe_fprintf(out, "while (");
expr_print(stmt->data.swhile.pred, out);
safe_fprintf(out, ") {\n");
- for (int i = 0; i<stmt->data.swhile.nbody; i++) {
+ for (int i = 0; i<stmt->data.swhile.nbody; i++)
stmt_print(stmt->data.swhile.body[i], indent+1, out);
- }
pindent(indent, out);
safe_fprintf(out, "}\n");
break;
--- /dev/null
+#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;
+}
#include <getopt.h>
#include "ast.h"
-#include "gen.h"
+#include "genc.h"
#include "parse.h"
#include "scan.h"
#include "type.h"
"Options:\n"
"\t-p\tPretty print the parsed abstract syntax tree\n"
"\t-t\tPretty print the typed abstract syntax tree\n"
+ "\t-g LANG\tGenerate LANG code (default: C)\n"
+ "\t \tSupported languages: C\n"
+ "\t-o FILE\tOutput code to FILE (default: a.suf)\n"
"\t-h\tShow this help\n"
, arg0);
}
int main(int argc, char *argv[])
{
- int opt;
+ int opt, r;
bool pparse = false, ptype = false;
+ char *cfile = NULL;
+ enum {langc} lang = langc;
+ const char *suffix[] = { [langc] = "c" };
+ struct ast *result = NULL;
+ FILE *cout;
- while ((opt = getopt(argc, argv, "hpt")) != -1) {
+ while ((opt = getopt(argc, argv, "g:ho:tp")) != -1) {
switch (opt) {
+ case 'g':
+ if (strcmp(optarg, "c") == 0
+ || strcmp(optarg, "C") == 0) {
+ lang = langc;
+ } else {
+ usage(stderr, argv[0]);
+ }
+ break;
+ case 'o':
+ cfile = safe_strdup(optarg);
+ break;
case 'p':
pparse = true;
break;
if ((yyin = fopen(argv[optind], "r")) == NULL)
pdie("fopen");
- struct ast *result = NULL;
- int r = yyparse(&result);
- if (r != 0)
- return 1;
+ //Parse
+ r = yyparse(&result);
+ if (yyin != stdin)
+ safe_fclose(yyin);
yylex_destroy();
+ if (r != 0)
+ return r;
if (pparse)
ast_print(result, stdout);
+
+ //Typecheck
if ((result = type(result)) == NULL) {
- r = 1;
- goto end;
+ return 1;
}
if (ptype)
ast_print(result, stdout);
- if (!gen(result)) {
- r = 1;
- goto end;
+
+ //Generate code
+ if (cfile == NULL)
+ sprintf(cfile = safe_malloc(10), "a.%s", suffix[lang]);
+ cout = safe_fopen(cfile, "w+");
+ free(cfile);
+ switch(lang) {
+ case langc:
+ r = genc(result, cout);
+ break;
+ default:
+ die("unsupported language\n");
}
+ safe_fclose(cout);
ast_free(result);
-end:
- if (yyin == stdin)
- if (fclose(yyin) == -1)
- perror("fclose");
return r;
}