summaryrefslogtreecommitdiff
path: root/examples/TracingBrainF/BrainFInterpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/TracingBrainF/BrainFInterpreter.cpp')
-rw-r--r--examples/TracingBrainF/BrainFInterpreter.cpp116
1 files changed, 116 insertions, 0 deletions
diff --git a/examples/TracingBrainF/BrainFInterpreter.cpp b/examples/TracingBrainF/BrainFInterpreter.cpp
new file mode 100644
index 0000000000..c059afd354
--- /dev/null
+++ b/examples/TracingBrainF/BrainFInterpreter.cpp
@@ -0,0 +1,116 @@
+//===-- BrainFInterpreter.cpp - BrainF trace compiler interpreter -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+
+#include "BrainF.h"
+#include "BrainFVM.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdio>
+using namespace llvm;
+
+//Command line options
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<input brainf>"));
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv, " BrainF compiler\n");
+
+ if (InputFilename == "") {
+ errs() << "Error: You must specify the filename of the program to "
+ "be compiled. Use --help to see the options.\n";
+ abort();
+ }
+
+ // Read the input file.
+ MemoryBuffer *Code = MemoryBuffer::getFileOrSTDIN(InputFilename);
+ const uint8_t *CodeBegin = (const uint8_t*)(Code->getBufferStart());
+
+ // Create a new buffer to hold the preprocessed code.
+ MemoryBuffer *ParsedCode =
+ MemoryBuffer::getNewMemBuffer(sizeof(opcode_func_t) *
+ (Code->getBufferSize()+1));
+ BytecodeArray = (opcode_func_t*)(ParsedCode->getBufferStart());
+ size_t BytecodeOffset = 0;
+
+ // Create JumpMap, a special on-the-side data array used to implement
+ // efficient jumps in the interpreter.
+ JumpMap = new size_t[Code->getBufferSize()];
+ memset(JumpMap, 0, sizeof(size_t) * Code->getBufferSize());
+ std::vector<size_t> Stack;
+
+ // Preprocess the input source code, performing three tasks:
+ // 1 - Remove non-instruction characters
+ // 2 - Replace character literals with opcode function pointers
+ // 3 - Precompute the jump targets for [ and ] instructions in JumpMap
+ for (size_t i = 0; i < Code->getBufferSize(); ++i) {
+ uint8_t opcode = CodeBegin[i];
+ switch (opcode) {
+ case '>':
+ BytecodeArray[BytecodeOffset++] = &op_right;
+ break;
+ case '<':
+ BytecodeArray[BytecodeOffset++] = &op_left;
+ break;
+ case '+':
+ BytecodeArray[BytecodeOffset++] = &op_plus;
+ break;
+ case '-':
+ BytecodeArray[BytecodeOffset++] = &op_minus;
+ break;
+ case '.':
+ BytecodeArray[BytecodeOffset++] = &op_put;
+ break;
+ case ',':
+ BytecodeArray[BytecodeOffset++] = &op_get;
+ break;
+ case '[':
+ Stack.push_back(BytecodeOffset);
+ BytecodeArray[BytecodeOffset++] = &op_if;
+ break;
+ case ']':
+ JumpMap[Stack.back()] = BytecodeOffset;
+ JumpMap[BytecodeOffset] = Stack.back();
+ Stack.pop_back();
+ BytecodeArray[BytecodeOffset++] = &op_back;
+ break;
+ default:
+ continue;
+ }
+ }
+
+ // Fill in the suffix of the preprocessed source for op_exit.
+ // Thus, if we reach the end of the source, the program will terminate.
+ while (BytecodeOffset < Code->getBufferSize()+1) {
+ BytecodeArray[BytecodeOffset++] = &op_end;
+ }
+
+ // Setup the array.
+ uint8_t *BrainFArray = new uint8_t[32768];
+ memset(BrainFArray, 0, 32768);
+
+ // Setup the trace recorder.
+ Recorder = new BrainFTraceRecorder();
+
+ // Main interpreter loop.
+ // Note the lack of a explicit loop: every opcode is a tail-recursive
+ // function that calls its own successor by indexing into BytecodeArray.
+ uint8_t* data = BrainFArray;
+ BytecodeArray[0](0, data);
+
+ //Clean up
+ delete Recorder;
+ delete Code;
+ delete ParsedCode;
+ delete[] BrainFArray;
+ delete[] JumpMap;
+
+ return 0;
+}