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
);