-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathYABOC.nw
190 lines (160 loc) · 6.15 KB
/
YABOC.nw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
\section{YABOC}
\gls{YABOC} is a toy project with three main goals :
\begin{enumerate}
\item Getting familiar with \tsl{literate programming},
\item getting familiar with code optimization,
\item getting familiar with code generation via \tsl{LLVM}.
\end{enumerate}
\newpar To fill this goals, I created a program to generate optimized
\footnote{Before LLVM optimized it} native code from Brainfuck code.
The program can also :
\begin{itemize}
\item Display the preprocessed\pref{significantLexemes} \brainfuck
source code,
\item display the optimized Brainfuck (at different stages) source code,
\item and display the generated LLVM bytecode.
\end{itemize}
\paragraph{Tools}
Obviously, I do not attempt to develop a cutting-edge \brainfuck compiler
(especially since many exist yet !) but I will try to code in the most generic
way. For this purpose, I will only use standard tools such as :
\begin{itemize}
\item \tbf{TCLAP} for command line arguments parsing
\item \tbf{make} for build pipeline,
\item \tbf{C++} as programming language,
\item \tbf{\LaTeX} as typesetting language,
\item \tbf{CLang++} as compiler (which can be switch to g++
any without code modification),
\item \tbf{LLVM} as code generator,
\item and \tbf{weave} \& \tbf{tangle} as code dispatchers.
\end{itemize}
\subsection{Architecture}
The architecture of \gls{YABOC} if fairly simple because it's pipeline is
linear (\cf \fref{fig1}).
\image[Architecture of YABOC]{img/Architecture.eps}{.2}
It's composed by :
\begin{itemize}
\item The scanner, which read every caracter, transform into \gls{lexeme} and
keep only the significant ones\pref{significantLexemes}.
\item The parser, which generate \gls{IL} from tokens.
\item The optimizer, which transform \gls{IL} into a better efficient
form\pref{optimizations}.
\item The code generator, which interpret every lexemes to it's LLVM
representation.
\item The LLVM, which generate the byte code.
\item The compiler, which generate the native code.
\end{itemize}
\newpar Each stage is detailed in the following document.
\subsection{Features}
\subsubsection{Argument handler}
To choose which feature to enable and which feature to disable, the program
need an argument handler to translate the command arguments to values that
YABOC could manage easily. To perform this task, YABOC uses a well-done and
well-documented library called TCALP \footnote{\cf
\url{http://tclap.sourceforge.net/} for further information.}.
There is two types of arguments :
\begin{itemize}
\item Switches, wich enable or disable features
\item Values, which parametrize a particular behavior of the program
\end{itemize}
\paragraph{Switches}
The following switches are available :
\begin{itemize}
\item \ttt{-p / --preprocess} : If set, the program will display the
preprocessed stream of BF code. It not, the program do nothing concerning
preprocessed stream.
\end{itemize}
\paragraph{Values}
The following values can be set :
\begin{itemize}
\item \ttt{-i / --input} : If set, the value will be used to read the
brainfuck code from. The program will also check that the file exists. If
not, the standard input is return as input stream.
\item \ttt{-s / --cell-size} : Must be 16, 32 or 64 and set the size of values
(memory cells).\ti
\item \ttt{-r / --cell-range} : Set the number of the statically allocated cell.
Must be greater than 0.\ti
\end{itemize}
<<YABOC : ArgumentHandler>>=
istream& ArgumentHandler
(
int argc,
char** argv,
bool* optPreprocess,
unsigned int* cellSize,
unsigned int* cellRange
) {
// Set default values
*optPreprocess = false;
try {
TCLAP::CmdLine cmd("YABOC, Yet Another Brainfuck Optimizer & Compiler.", ' ' , VERSION_NUMBER);
TCLAP::ValueArg<std::string> inputArg("i","input", "Input file to read the brainfuck code from.", false, "","filename");
TCLAP::ValueArg<unsigned int> sizeArg("s","cell-size", "Set the size of \
memory cells. Must be 16, 32 or 64.", false, 16,"Cell-size");
TCLAP::ValueArg<unsigned int> rangeArg("r","cell-range", "Set the number \
of statically allocated cell. Must be greater than 0.", false, 60000,
"Cell-range");
TCLAP::SwitchArg pSwitch("p", "preprocessed","Display the preprocessed stream.", cmd, false);
cmd.add (inputArg);
cmd.add (sizeArg);
cmd.add (rangeArg);
cmd.parse ( argc, argv );
*optPreprocess = pSwitch.getValue();
if(sizeArg.getValue() == 16
|| sizeArg.getValue() == 32
|| sizeArg.getValue() == 64) *cellSize= sizeArg.getValue();
else cerr << "Error: Cell size must be 16, 32 or 64." << endl;
*cellRange= rangeArg.getValue();
if(inputArg.getValue() == "") return cin;
else {
ifstream* inputFileStream = new ifstream(inputArg.getValue().c_str());
if(*inputFileStream) return *inputFileStream;
cerr << "Error: File not found." << endl;
}
} catch (TCLAP::ArgException &e) {
cerr << "Error: " << e.error() << " for arg " << e.argId() << endl;
}
return cin;
}
@
\subsubsection{Preprocessing}
The preprocessing feature display the kept tokens one following another from
the input stream. Because the token out of the scanner are already known to be
valid, the method only output the result of [[Scanner : Next]]. After the
display of all available tokens, a carriage return is printed.
\newpar If the option was the only specified, the program exits. Otherwise, the
other options are handled.
<<YABOC : DisplayPreprocessStream>>=
void DisplayPreprocessStream ( Scanner& scanner ) {
char buffer = scanner.Pop();
while(buffer != TOKEN_EOF) {
if(buffer != TOKEN_OTHER) cout << buffer;
buffer = scanner.Pop();
}
cout << endl;
}
@
\subsection{Listing}
<<YABOC : Implementation>>=
#include <string>
#include <iostream>
#include <fstream>
#include <tclap/CmdLine.h>
#include "Scanner.hh"
#define VERSION_NUMBER "0.1"
using namespace std;
<<YABOC : DisplayPreprocessStream>>
<<YABOC : ArgumentHandler>>
int main (int argc, char** argv) {
bool optPreprocess = false;
unsigned int cellSize=0;
unsigned int cellRange=0;
istream& inputStream = ArgumentHandler(argc, argv, &optPreprocess,
&cellSize, &cellRange);
Scanner scanner(inputStream);
if(optPreprocess) DisplayPreprocessStream(scanner);
return 0;
}
@
<<YABOC : Header>>=
@