Commits

Anonymous committed a3c0e76

Beginnings of a C backend.

Comments (0)

Files changed (5)

 
 Should there be an expression form of `=`?  (`:=`?)
 
-Should a block be a valid statement, with block scope?  (Meaningless if
-all variables must be declared at start of function, as is the case right now.)
+Block scope in blocks; if the first assignment to a variable occurs inside
+a block, its scope is that block.  It cannot be seen after that block closes.
+(Shadowing is not possible; if the first assignment was before, that outer
+variable is what gets updated.)

src/castile/backends/__init__.py

+import castile.backends.c
 #import castile.backends.cil
 import castile.backends.javascript
 import castile.backends.stackmac

src/castile/backends/c.py

+# nascent! embryonic! inchoate! alpha! wip!
+
+OPS = {
+}
+
+
+class Compiler(object):
+    def __init__(self, out):
+        self.out = out
+
+    def commas(self, asts, sep=','):
+        if asts:
+            for child in asts[:-1]:
+                self.compile(child)
+                self.out.write(sep)
+            self.compile(asts[-1])
+
+    def c_type(self, type):
+        return 'int'
+
+    def compile(self, ast):
+        if ast.tag == 'Program':
+            self.out.write(r"""\
+/* AUTOMATICALLY GENERATED -- EDIT AT OWN RISK */
+
+#include <stdio.h>
+
+void print(char *s)
+{
+  printf("%s\n", s);
+}
+
+""")
+            for child in ast.children:
+                self.compile(child)
+            self.out.write("""\
+
+int main(int argc, char **argv)
+{
+    int x = castile_main();
+    printf("%d\n", x);
+    exit(0);
+}
+
+""")
+        elif ast.tag == 'Defn':
+            thing = ast.children[0]
+            name = ast.value
+            if name == 'main':
+                name = 'castile_main'
+            if thing.tag == 'FunLit':
+                self.out.write('%s %s' % (self.c_type(thing.type.return_type), ast.value))
+                self.compile(ast.children[0])
+            else:
+                self.out.write('%s = ' % ast.value)
+                self.compile(ast.children[0])
+                self.out.write(';\n')
+        elif ast.tag == 'Forward':
+            self.out.write('extern %s;\n' % ast.value)
+        elif ast.tag == 'StructDefn':
+            self.out.write('struct %s {}\n' % ast.value)
+        elif ast.tag == 'FunLit':
+            self.out.write('(')
+            self.compile(ast.children[0])
+            self.out.write(') {\n')
+            self.compile(ast.children[1])
+            self.out.write('}\n')
+        elif ast.tag == 'Args':
+            self.commas(ast.children)
+        elif ast.tag == 'Arg':
+            self.out.write(ast.value)
+        elif ast.tag == 'Body':
+            self.compile(ast.children[0])
+            self.compile(ast.children[1])
+        elif ast.tag == 'VarDecls':
+            for child in ast.children:
+                self.compile(child)
+        elif ast.tag == 'VarDecl':
+            self.out.write('%s %s;\n' % (self.c_type(ast.type), ast.value))
+        elif ast.tag == 'Block':
+            self.out.write('{\n')
+            for child in ast.children:
+                self.compile(child)
+                self.out.write(';\n')
+            self.out.write('}\n')
+        elif ast.tag == 'While':
+            self.out.write('while (')
+            self.compile(ast.children[0])
+            self.out.write(')\n')
+            self.compile(ast.children[1])
+        elif ast.tag == 'Op':
+            self.out.write('(')
+            self.compile(ast.children[0])
+            self.out.write(' %s ' % OPS.get(ast.value, ast.value))
+            self.compile(ast.children[1])
+            self.out.write(')')
+        elif ast.tag == 'VarRef':
+            self.out.write(ast.value)
+        elif ast.tag == 'FunCall':
+            self.compile(ast.children[0])
+            self.out.write('(')
+            self.commas(ast.children[1:])
+            self.out.write(')')
+        elif ast.tag == 'If':
+            self.out.write('if (')
+            self.compile(ast.children[0])
+            self.out.write(')\n')
+            if len(ast.children) == 3:  # if-else
+                self.compile(ast.children[1])
+                self.out.write(' else\n')
+                self.compile(ast.children[2])
+            else:  # just-if
+                self.compile(ast.children[1])
+        elif ast.tag == 'Return':
+            self.out.write('return ')
+            self.compile(ast.children[0])
+        elif ast.tag == 'Break':
+            self.out.write('break')
+        elif ast.tag == 'Not':
+            self.out.write('!(')
+            self.compile(ast.children[0])
+            self.out.write(')')
+        elif ast.tag == 'None':
+            self.out.write('nil')
+        elif ast.tag == 'BoolLit':
+            if ast.value:
+                self.out.write("1")
+            else:
+                self.out.write("0")
+        elif ast.tag == 'IntLit':
+            self.out.write(str(ast.value))
+        elif ast.tag == 'StrLit':
+            self.out.write('"%s"' % ast.value)
+        elif ast.tag == 'Assignment':
+            self.compile(ast.children[0])
+            self.out.write(' = ')
+            self.compile(ast.children[1])
+        elif ast.tag == 'Make':
+            self.out.write('malloc()<--{')
+            self.commas(ast.children[1:])
+            self.out.write('}')
+        elif ast.tag == 'FieldInit':
+            self.out.write("'%s'," % ast.value)
+            self.compile(ast.children[0])
+        elif ast.tag == 'Index':
+            self.compile(ast.children[0])
+            self.out.write('["%s"]' % ast.value)
+        elif ast.tag == 'TypeCast':
+            self.out.write("['%s'," % str(ast.children[0].type))
+            self.compile(ast.children[0])
+            self.out.write(']')
+        elif ast.tag == 'TypeCase':
+            self.out.write('if (')
+            self.compile(ast.children[0])
+            self.out.write("[0] == '%s')" % str(ast.children[1].type))
+            self.out.write('then save=')
+            self.compile(ast.children[0])
+            self.out.write('\n')
+            self.compile(ast.children[0])
+            self.out.write('=')
+            self.compile(ast.children[0])
+            self.out.write('[1]\n')
+            self.compile(ast.children[2])
+            self.compile(ast.children[0])
+            self.out.write(' = save end')
+        else:
+            raise NotImplementedError(repr(ast))

src/castile/transformer.py

             for child in ast.children:
                 children.append(self.lift_functions(child))
             return ast.copy(children=children)
+
+
+class VarDeclTypeAssigner(object):
+    def __init__(self):
+        self.current_funlit = None
+
+    def find_vardecl(self, name):
+        vardecls = self.current_funlit.children[0]
+        assert vardecls.tag == 'VarDecls'
+        for child in vardecls.children:
+            if child.value == name:
+                return child
+
+    def assign_types(self, ast):
+        if ast.tag == 'FunLit':
+            save = self.current_funlit
+            self.current_funlit = ast
+            for child in ast.children:
+                self.assign_types(child)
+            self.current_funlit = save
+        elif ast.tag == 'Assignment':
+            if ast.aux == 'defining instance':
+                vardecl = self.find_vardecl(ast.children[0].value)
+                vardecl.type = ast.children[1].type
+            for child in ast.children:
+                self.assign_types(child)
+        else:
+            for child in ast.children:
+                self.assign_types(child)
 EOF
 fi
 
+if [ "x$1" = "xc" ]; then
+  cat >>test_config <<EOF
+    -> Functionality "Run Castile Program" is implemented by shell command
+    -> "bin/castile -c c %(test-file) > foo.c && gcc foo.c && ./a.out"
+
+EOF
+fi
+
 falderal -b test_config README.markdown
-rm -f test_config foo.*
+rm -f test_config foo.* a.out