1 //===-- BFtoLLVM.cpp - BF language Front End for LLVM ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This is a simple front end for the BF language. It is compatible with the
11 // language as described in "The BrainF*** Language Specification (01 January
12 // 2002)", which is available from http://esoteric.sange.fi/ENSI . It does not
13 // implement the optional keyword # ("Output partial tape state").
15 //===----------------------------------------------------------------------===//
26 void emitDeclarations(std::ofstream &dest) {
27 dest << "; This assembly code brought to you by BFtoLLVM\n"
28 << "\nimplementation\n"
29 << "\n; Declarations\n"
30 << "\ndeclare int %getchar()\n"
31 << "declare int %putchar(int)\n"
32 << "declare void %llvm.memset.i32(sbyte*, ubyte, uint, uint)\n"
36 void emitMainFunctionProlog(std::ofstream &dest) {
37 dest << "\n; Main function\n"
38 << "int %main(int %argc, sbyte** %argv) {\n"
40 << "%arr = alloca sbyte, uint 30000\n"
41 << "call void (sbyte*, ubyte, uint, uint)* %llvm.memset.i32"
42 << "(sbyte* %arr, ubyte 0, uint 30000, uint 1)\n"
43 << "%ptrbox = alloca sbyte*\n"
44 << "store sbyte* %arr, sbyte **%ptrbox\n"
48 void emitMainFunctionEpilog(std::ofstream &dest) {
53 std::string gensym (const std::string varName, bool percent = true) {
55 static unsigned int SymbolCounter = 0;
56 sprintf (buf, "%s%s%u", percent ? "%" : "", varName.c_str(), SymbolCounter++);
57 return std::string (buf);
60 void emitArith (std::string op, char delta, std::ofstream &dest) {
61 std::string ptr = gensym (op + "ptr"),
62 val = gensym (op + "val"),
63 result = gensym (op + "result");
64 dest << ptr << " = load sbyte** %ptrbox\n"
65 << val << " = load sbyte* " << ptr << "\n"
66 << result << " = add sbyte " << val << ", " << (int)delta << "\n"
67 << "store sbyte " << result << ", sbyte* " << ptr << "\n";
70 // + becomes ++*p; and - becomes --*p;
71 void emitPlus (std::ofstream &dest, int ct) { emitArith ("plus", +ct, dest); }
72 void emitMinus (std::ofstream &dest, int ct) { emitArith ("minus", -ct, dest); }
74 void emitLoadAndCast (std::string ptr, std::string val, std::string cast,
75 std::string type, std::ofstream &dest) {
76 dest << ptr << " = load sbyte** %ptrbox\n"
77 << val << " = load sbyte* " << ptr << "\n"
78 << cast << " = cast sbyte " << val << " to " << type << "\n";
81 // , becomes *p = getchar();
82 void emitComma(std::ofstream &dest, int ct) {
84 std::string ptr = gensym("commaptr"), read = gensym("commaread"),
85 cast = gensym("commacast");
86 dest << ptr << " = load sbyte** %ptrbox\n"
87 << read << " = call int %getchar()\n"
88 << cast << " = cast int " << read << " to sbyte\n"
89 << "store sbyte " << cast << ", sbyte* " << ptr << "\n";
92 // . becomes putchar(*p);
93 void emitDot(std::ofstream &dest, int ct) {
95 std::string ptr = gensym("dotptr"), val = gensym("dotval"),
96 cast = gensym("dotcast");
97 emitLoadAndCast (ptr, val, cast, "int", dest);
98 dest << "call int %putchar(int " << cast << ")\n";
101 void emitPointerArith(std::string opname, int delta, std::ofstream &dest) {
102 std::string ptr = gensym(opname + "ptr"), result = gensym(opname + "result");
103 dest << ptr << " = load sbyte** %ptrbox\n"
104 << result << " = getelementptr sbyte* " << ptr << ", int " << delta
106 << "store sbyte* " << result << ", sbyte** %ptrbox\n";
109 // < becomes --p; and > becomes ++p;
110 void emitLT(std::ofstream &dest, int ct) { emitPointerArith ("lt", -ct, dest); }
111 void emitGT(std::ofstream &dest, int ct) { emitPointerArith ("gt", +ct, dest); }
113 static std::vector<std::string> whileStack;
115 // [ becomes while (*p) {
116 void emitLeftBracket(std::ofstream &dest, int ct) {
118 std::string whileName = gensym ("While", false);
119 whileStack.push_back (whileName);
120 dest << "br label %testFor" << whileName << "\n"
121 << "\ninside" << whileName << ":\n";
125 void emitRightBracket(std::ofstream &dest, int ct) {
127 std::string whileName = whileStack.back (),
128 ptr = gensym("bracketptr"),
129 val = gensym("bracketval"),
130 cast = gensym("bracketcast");
131 whileStack.pop_back ();
132 dest << "br label %testFor" << whileName << "\n"
133 << "\ntestFor" << whileName << ":\n";
134 emitLoadAndCast (ptr, val, cast, "bool", dest);
135 dest << "br bool " << cast << ", label %inside" << whileName << ", "
136 << "label %after" << whileName << "\n"
137 << "\nafter" << whileName << ":\n";
140 typedef void (*FuncTy)(std::ofstream &, int);
141 static FuncTy table[256];
142 static bool multi[256];
144 void consume (int ch, int repeatCount, std::ofstream &dest) {
145 FuncTy func = table[ch];
149 func (dest, repeatCount);
151 for (int i = 0; i < repeatCount; ++i)
155 void initializeTable() {
156 memset (table, 0, 256);
157 memset (multi, 0, 256);
158 table[(int)'+'] = emitPlus; multi[(int)'+'] = true;
159 table[(int)'-'] = emitMinus; multi[(int)'-'] = true;
160 table[(int)','] = emitComma; multi[(int)','] = false;
161 table[(int)'.'] = emitDot; multi[(int)'.'] = false;
162 table[(int)'<'] = emitLT; multi[(int)'<'] = true;
163 table[(int)'>'] = emitGT; multi[(int)'>'] = true;
164 table[(int)'['] = emitLeftBracket; multi[(int)'['] = false;
165 table[(int)']'] = emitRightBracket; multi[(int)']'] = false;
168 int main (int argc, char **argv) {
170 std::cerr << "usage: " << argv[0] << " input-source output-llvm\n";
174 char *sourceFileName = argv[1];
175 char *destFileName = argv[2];
177 std::ifstream src (sourceFileName);
179 std::cerr << sourceFileName << ": " << strerror(errno) << "\n";
183 std::ofstream dest (destFileName);
185 std::cerr << destFileName << ": " << strerror(errno) << "\n";
189 emitDeclarations(dest);
190 emitMainFunctionProlog(dest);
196 for (src >> ch; !src.eof (); src >> ch, ++repeatCount)
198 consume (lastCh, repeatCount, dest);
202 consume (lastCh, repeatCount, dest);
204 emitMainFunctionEpilog(dest);