Convert tabs to spaces
[oota-llvm.git] / examples / BFtoLLVM / BFtoLLVM.cpp
1 //===-- BFtoLLVM.cpp - BF language Front End for LLVM ---------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
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.
7 //
8 //===----------------------------------------------------------------------===//
9 //
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").
14 //
15 //===----------------------------------------------------------------------===//
16
17 #include <iostream>
18 #include <vector>
19 #include <fstream>
20 #include <cerrno>
21 #include <cstring>
22 #include <string>
23 #include <cstdio>
24 #include <cassert>
25
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(sbyte*, ubyte, uint, uint)\n"
33        << "\n";
34 }
35
36 void emitMainFunctionProlog(std::ofstream &dest) {
37   dest << "\n; Main function\n"
38        << "int %main(int %argc, sbyte** %argv) {\n"
39        << "\nentry:\n"
40        << "%arr = alloca sbyte, uint 30000\n"
41        << "call void (sbyte*, ubyte, uint, uint)* %llvm.memset(sbyte* %arr, ubyte 0, uint 30000, uint 1)\n"
42        << "%ptrbox = alloca sbyte*\n"
43        << "store sbyte* %arr, sbyte **%ptrbox\n"
44        << "\n";
45 }
46
47 void emitMainFunctionEpilog(std::ofstream &dest) {
48   dest << "ret int 0\n"
49        << "}\n";
50 }
51
52 std::string gensym (const std::string varName, bool percent = true) {
53   char buf[80];
54   static unsigned int SymbolCounter = 0;
55   sprintf (buf, "%s%s%u", percent ? "%" : "", varName.c_str(), SymbolCounter++);
56   return std::string (buf);
57 }
58
59 void emitArith (std::string op, char delta, std::ofstream &dest) {
60   std::string ptr = gensym (op + "ptr"),
61               val = gensym (op + "val"),
62               result = gensym (op + "result");
63   dest << ptr << " = load sbyte** %ptrbox\n"
64        << val << " = load sbyte* " << ptr << "\n"
65        << result << " = add sbyte " << val << ", " << (int)delta << "\n"
66        << "store sbyte " << result << ", sbyte* " << ptr << "\n";
67 }
68
69 // + becomes ++*p; and - becomes --*p;
70 void emitPlus  (std::ofstream &dest, int ct) { emitArith ("plus",  +ct, dest); }
71 void emitMinus (std::ofstream &dest, int ct) { emitArith ("minus", -ct, dest); }
72
73 void emitLoadAndCast (std::string ptr, std::string val, std::string cast,
74                       std::string type, std::ofstream &dest) {
75   dest << ptr << " = load sbyte** %ptrbox\n"
76        << val << " = load sbyte* " << ptr << "\n"
77        << cast << " = cast sbyte " << val << " to " << type << "\n";
78 }
79
80 // , becomes *p = getchar();
81 void emitComma(std::ofstream &dest, int ct) {
82   assert (ct == 1);
83   std::string ptr = gensym("commaptr"), read = gensym("commaread"),
84               cast = gensym("commacast");
85   dest << ptr << " = load sbyte** %ptrbox\n"
86        << read << " = call int %getchar()\n"
87        << cast << " = cast int " << read << " to sbyte\n"
88        << "store sbyte " << cast << ", sbyte* " << ptr << "\n";
89 }
90
91 // . becomes putchar(*p);
92 void emitDot(std::ofstream &dest, int ct) {
93   assert (ct == 1);
94   std::string ptr = gensym("dotptr"), val = gensym("dotval"),
95               cast = gensym("dotcast");
96   emitLoadAndCast (ptr, val, cast, "int", dest);
97   dest << "call int %putchar(int " << cast << ")\n";
98 }
99
100 void emitPointerArith(std::string opname, int delta, std::ofstream &dest) {
101   std::string ptr = gensym(opname + "ptr"), result = gensym(opname + "result");
102   dest << ptr << " = load sbyte** %ptrbox\n"
103        << result << " = getelementptr sbyte* " << ptr << ", int " << delta
104        << "\n"
105        << "store sbyte* " << result << ", sbyte** %ptrbox\n";
106 }
107
108 // < becomes --p; and > becomes ++p;
109 void emitLT(std::ofstream &dest, int ct) { emitPointerArith ("lt", -ct, dest); }
110 void emitGT(std::ofstream &dest, int ct) { emitPointerArith ("gt", +ct, dest); }
111
112 static std::vector<std::string> whileStack;
113
114 // [ becomes while (*p) {
115 void emitLeftBracket(std::ofstream &dest, int ct) {
116   assert (ct == 1);
117   std::string whileName = gensym ("While", false);
118   whileStack.push_back (whileName);
119   dest << "br label %testFor" << whileName << "\n"
120        << "\ninside" << whileName << ":\n";
121 }
122
123 // ] becomes }
124 void emitRightBracket(std::ofstream &dest, int ct) {
125   assert (ct == 1);
126   std::string whileName = whileStack.back (),
127               ptr = gensym("bracketptr"),
128               val = gensym("bracketval"),
129               cast = gensym("bracketcast");
130   whileStack.pop_back ();
131   dest << "br label %testFor" << whileName << "\n"
132        << "\ntestFor" << whileName << ":\n";
133   emitLoadAndCast (ptr, val, cast, "bool", dest);
134   dest << "br bool " << cast << ", label %inside" << whileName << ", "
135        << "label %after" << whileName << "\n"
136        << "\nafter" << whileName << ":\n";
137 }
138
139 typedef void (*FuncTy)(std::ofstream &, int);
140 static FuncTy table[256];
141 static bool multi[256];
142
143 void consume (int ch, int repeatCount, std::ofstream &dest) {
144   FuncTy func = table[ch];
145   if (!func)
146     return;
147   else if (multi[ch])
148     func (dest, repeatCount);
149   else
150     for (int i = 0; i < repeatCount; ++i)
151       func (dest, 1);
152 }
153
154 void initializeTable() {
155   memset (table, 0, 256);
156   memset (multi, 0, 256);
157   table[(int)'+'] = emitPlus;          multi[(int)'+'] = true;
158   table[(int)'-'] = emitMinus;         multi[(int)'-'] = true;
159   table[(int)','] = emitComma;         multi[(int)','] = false;
160   table[(int)'.'] = emitDot;           multi[(int)'.'] = false;
161   table[(int)'<'] = emitLT;            multi[(int)'<'] = true;
162   table[(int)'>'] = emitGT;            multi[(int)'>'] = true;
163   table[(int)'['] = emitLeftBracket;   multi[(int)'['] = false;
164   table[(int)']'] = emitRightBracket;  multi[(int)']'] = false;
165 }
166
167 int main (int argc, char **argv) {
168   if (argc != 3) {
169     std::cerr << "usage: " << argv[0] << " input-source output-llvm\n";
170     return 1;
171   }
172
173   char *sourceFileName = argv[1];
174   char *destFileName = argv[2];
175
176   std::ifstream src (sourceFileName);
177   if (!src.good()) {
178     std::cerr << sourceFileName << ": " << strerror(errno) << "\n";
179     return 1;
180   }
181
182   std::ofstream dest (destFileName);
183   if (!dest.good()) {
184     std::cerr << destFileName << ": " << strerror(errno) << "\n";
185     return 1;
186   }
187
188   emitDeclarations(dest);
189   emitMainFunctionProlog(dest);
190
191   initializeTable();
192   char ch, lastCh;
193   src >> lastCh;
194   int repeatCount = 1;
195   for (src >> ch; !src.eof (); src >> ch, ++repeatCount)
196     if (ch != lastCh) {
197       consume (lastCh, repeatCount, dest);
198       lastCh = ch;
199       repeatCount = 0;
200     }
201   consume (lastCh, repeatCount, dest);
202
203   emitMainFunctionEpilog(dest);
204
205   src.close();
206   dest.close();
207   return 0;
208 }