Break up huge line so that this file is almost readable.
[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.i32(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.i32"
42        << "(sbyte* %arr, ubyte 0, uint 30000, uint 1)\n"
43        << "%ptrbox = alloca sbyte*\n"
44        << "store sbyte* %arr, sbyte **%ptrbox\n"
45        << "\n";
46 }
47
48 void emitMainFunctionEpilog(std::ofstream &dest) {
49   dest << "ret int 0\n"
50        << "}\n";
51 }
52
53 std::string gensym (const std::string varName, bool percent = true) {
54   char buf[80];
55   static unsigned int SymbolCounter = 0;
56   sprintf (buf, "%s%s%u", percent ? "%" : "", varName.c_str(), SymbolCounter++);
57   return std::string (buf);
58 }
59
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";
68 }
69
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); }
73
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";
79 }
80
81 // , becomes *p = getchar();
82 void emitComma(std::ofstream &dest, int ct) {
83   assert (ct == 1);
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";
90 }
91
92 // . becomes putchar(*p);
93 void emitDot(std::ofstream &dest, int ct) {
94   assert (ct == 1);
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";
99 }
100
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
105        << "\n"
106        << "store sbyte* " << result << ", sbyte** %ptrbox\n";
107 }
108
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); }
112
113 static std::vector<std::string> whileStack;
114
115 // [ becomes while (*p) {
116 void emitLeftBracket(std::ofstream &dest, int ct) {
117   assert (ct == 1);
118   std::string whileName = gensym ("While", false);
119   whileStack.push_back (whileName);
120   dest << "br label %testFor" << whileName << "\n"
121        << "\ninside" << whileName << ":\n";
122 }
123
124 // ] becomes }
125 void emitRightBracket(std::ofstream &dest, int ct) {
126   assert (ct == 1);
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";
138 }
139
140 typedef void (*FuncTy)(std::ofstream &, int);
141 static FuncTy table[256];
142 static bool multi[256];
143
144 void consume (int ch, int repeatCount, std::ofstream &dest) {
145   FuncTy func = table[ch];
146   if (!func)
147     return;
148   else if (multi[ch])
149     func (dest, repeatCount);
150   else
151     for (int i = 0; i < repeatCount; ++i)
152       func (dest, 1);
153 }
154
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;
166 }
167
168 int main (int argc, char **argv) {
169   if (argc != 3) {
170     std::cerr << "usage: " << argv[0] << " input-source output-llvm\n";
171     return 1;
172   }
173
174   char *sourceFileName = argv[1];
175   char *destFileName = argv[2];
176
177   std::ifstream src (sourceFileName);
178   if (!src.good()) {
179     std::cerr << sourceFileName << ": " << strerror(errno) << "\n";
180     return 1;
181   }
182
183   std::ofstream dest (destFileName);
184   if (!dest.good()) {
185     std::cerr << destFileName << ": " << strerror(errno) << "\n";
186     return 1;
187   }
188
189   emitDeclarations(dest);
190   emitMainFunctionProlog(dest);
191
192   initializeTable();
193   char ch, lastCh;
194   src >> lastCh;
195   int repeatCount = 1;
196   for (src >> ch; !src.eof (); src >> ch, ++repeatCount)
197     if (ch != lastCh) {
198       consume (lastCh, repeatCount, dest);
199       lastCh = ch;
200       repeatCount = 0;
201     }
202   consume (lastCh, repeatCount, dest);
203
204   emitMainFunctionEpilog(dest);
205
206   src.close();
207   dest.close();
208   return 0;
209 }