aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.c
blob: a019af6b385838a68244711e9198888e0dd6023a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include "all.h"

static void emit_prelude(str *out) {
  str_append(out, "void _start(void){"
                  "uint8_t tape[30000]={0};"
                  "uint8_t*ptr=tape+15000;");
}

static void emit_runtime(str *out) {
  str_append(out, "typedef unsigned long size_t;"
                  "typedef unsigned char uint8_t;");

  str_append(out,
             "static inline long syscall3(long n, long a1, void *a2, long a3){"
             "long ret;"
             "__asm__ volatile ("
             "\"syscall\""
             ":\"=a\"(ret)"
             ":\"a\"(n),\"D\"(a1),\"S\"(a2),\"d\"(a3)"
             ":\"rcx\",\"r11\",\"memory\""
             ");"
             "return ret;"
             "}");
}

static void emit_epilogue(str *out) { str_append(out, "syscall3(60,0,0,0);}"); }

void emit_node(str *out, ast_node_t *node, int indent) {
  for (; node; node = node->next) {
    switch (node->type) {
    case AST_INC:
      str_appendf(out, "*ptr+=%d;", node->val);
      break;

    case AST_DEC:
      str_appendf(out, "*ptr-=%d;", node->val);
      break;

    case AST_PTR_INC:
      str_appendf(out, "ptr+=%d;", node->val);
      break;

    case AST_PTR_DEC:
      str_appendf(out, "ptr-=%d;", node->val);
      break;

    case AST_OUT:
      str_appendf(out, "syscall3(1,1,ptr,1);");
      break;

    case AST_IN:
      str_appendf(out, "syscall3(0,0,ptr,1);");
      break;

    case AST_LOOP:
      str_append(out, "while(*ptr){");

      for (size_t i = 0; i < node->children.len; i++) {
        emit_node(out, node->children._data[i], indent + 1);
      }

      str_append(out, "}");
      break;
    }
  }
}

str gen_code(ast_node_t *ast) {
  str out = {0};

  emit_runtime(&out);
  emit_prelude(&out);
  emit_node(&out, ast, 1);
  emit_epilogue(&out);

  return out;
}