mirror of
https://github.com/herumi/xbyak
synced 2024-11-21 16:09:11 -07:00
206 lines
4.3 KiB
C++
206 lines
4.3 KiB
C++
|
#include "xbyak/xbyak.h"
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stack>
|
||
|
#include <fstream>
|
||
|
#ifdef _MSC_VER
|
||
|
#pragma warning(disable : 4996) // scanf
|
||
|
#define snprintf _snprintf
|
||
|
#endif
|
||
|
|
||
|
class Brainfuck : public Xbyak::CodeGenerator {
|
||
|
private:
|
||
|
enum Direction { B, F };
|
||
|
const char *toStr(int labelNo, Direction dir)
|
||
|
{
|
||
|
static char num[64];
|
||
|
snprintf(num, sizeof(num), "%c%d", dir == B ? 'B' : 'F', labelNo);
|
||
|
return num;
|
||
|
}
|
||
|
public:
|
||
|
int getContinuousChar(std::istream& is, char c)
|
||
|
{
|
||
|
int count = 1;
|
||
|
char p;
|
||
|
while (is >> p) {
|
||
|
if (p != c) break;
|
||
|
count++;
|
||
|
}
|
||
|
is.unget();
|
||
|
return count;
|
||
|
}
|
||
|
Brainfuck(std::istream& is) : CodeGenerator(10000)
|
||
|
{
|
||
|
// void (*)(void* putchar, void* getchar, int *stack)
|
||
|
using namespace Xbyak;
|
||
|
#ifdef XBYAK32
|
||
|
#if defined(_MSC_VER) && (_MSC_VER <= 1200) // for VC6
|
||
|
const Reg32 pPutchar(esi);
|
||
|
const Reg32 pGetchar(edi);
|
||
|
const Reg32 stack(ebp);
|
||
|
#else
|
||
|
const Reg32& pPutchar(esi);
|
||
|
const Reg32& pGetchar(edi);
|
||
|
const Reg32& stack(ebp);
|
||
|
#endif
|
||
|
const Address cur = dword [stack];
|
||
|
push(ebp); // stack
|
||
|
push(esi);
|
||
|
push(edi);
|
||
|
const int P_ = 4 * 3;
|
||
|
mov(pPutchar, ptr[esp + P_ + 4]); // putchar
|
||
|
mov(pGetchar, ptr[esp + P_ + 8]); // getchar
|
||
|
mov(stack, ptr[esp + P_ + 12]); // stack
|
||
|
#elif defined(XBYAK64_WIN)
|
||
|
const Reg64& pPutchar(rsi);
|
||
|
const Reg64& pGetchar(rdi);
|
||
|
const Reg64& stack(rbp); // stack
|
||
|
const Address cur = dword [stack];
|
||
|
push(rsi);
|
||
|
push(rdi);
|
||
|
push(rbp);
|
||
|
mov(pPutchar, rcx); // putchar
|
||
|
mov(pGetchar, rdx); // getchar
|
||
|
mov(stack, r8); // stack
|
||
|
#else
|
||
|
const Reg64& pPutchar(rbx);
|
||
|
const Reg64& pGetchar(rbp);
|
||
|
const Reg64& stack(r12); // stack
|
||
|
const Address cur = dword [stack];
|
||
|
push(rbx);
|
||
|
push(rbp);
|
||
|
push(r12);
|
||
|
mov(pPutchar, rdi); // putchar
|
||
|
mov(pGetchar, rsi); // getchar
|
||
|
mov(stack, rdx); // stack
|
||
|
#endif
|
||
|
int labelNo = 0;
|
||
|
std::stack<int> keepLabelNo;
|
||
|
char c;
|
||
|
while (is >> c) {
|
||
|
switch (c) {
|
||
|
case '+':
|
||
|
case '-':
|
||
|
{
|
||
|
int count = getContinuousChar(is, c);
|
||
|
if (count == 1) {
|
||
|
c == '+' ? inc(cur) : dec(cur);
|
||
|
} else {
|
||
|
add(cur, (c == '+' ? count : -count));
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case '>':
|
||
|
case '<':
|
||
|
{
|
||
|
int count = getContinuousChar(is, c);
|
||
|
add(stack, 4 * (c == '>' ? count : -count));
|
||
|
}
|
||
|
break;
|
||
|
case '.':
|
||
|
#ifdef XBYAK32
|
||
|
push(cur);
|
||
|
call(pPutchar);
|
||
|
pop(eax);
|
||
|
#elif defined(XBYAK64_WIN)
|
||
|
mov(rcx, cur);
|
||
|
sub(rsp, 32);
|
||
|
call(pPutchar);
|
||
|
add(rsp, 32);
|
||
|
#else
|
||
|
mov(rdi, cur);
|
||
|
call(pPutchar);
|
||
|
#endif
|
||
|
break;
|
||
|
case ',':
|
||
|
#if defined(XBYAK32) || defined(XBYAK64_GCC)
|
||
|
call(pGetchar);
|
||
|
mov(cur, eax);
|
||
|
#elif defined(XBYAK64_WIN)
|
||
|
sub(rsp, 32);
|
||
|
call(pGetchar);
|
||
|
add(rsp, 32);
|
||
|
mov(cur, rax);
|
||
|
#endif
|
||
|
break;
|
||
|
case '[':
|
||
|
L(toStr(labelNo, B));
|
||
|
mov(eax, cur);
|
||
|
test(eax, eax);
|
||
|
jz(toStr(labelNo, F), T_NEAR);
|
||
|
keepLabelNo.push(labelNo++);
|
||
|
break;
|
||
|
case ']':
|
||
|
{
|
||
|
int no = keepLabelNo.top(); keepLabelNo.pop();
|
||
|
jmp(toStr(no, B));
|
||
|
L(toStr(no, F));
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#ifdef XBYAK32
|
||
|
pop(edi);
|
||
|
pop(esi);
|
||
|
pop(ebp);
|
||
|
#elif defined(XBYAK64_WIN)
|
||
|
pop(rbp);
|
||
|
pop(rdi);
|
||
|
pop(rsi);
|
||
|
#else
|
||
|
pop(r12);
|
||
|
pop(rbp);
|
||
|
pop(rbx);
|
||
|
#endif
|
||
|
ret();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void dump(const Xbyak::uint8 *code, size_t size)
|
||
|
{
|
||
|
puts("#include <stdio.h>\nstatic int stack[32768];\nstatic const unsigned char code[] = {");
|
||
|
for (size_t i = 0; i < size; i++) {
|
||
|
printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
|
||
|
}
|
||
|
puts("\n};");
|
||
|
#ifdef __linux__
|
||
|
puts("#include <unistd.h>");
|
||
|
puts("#include <sys/mman.h>");
|
||
|
#endif
|
||
|
puts("main()\n{");
|
||
|
#ifdef __linux__
|
||
|
puts("\tlong pageSize = sysconf(_SC_PAGESIZE) - 1;");
|
||
|
puts("\tmprotect((void*)code, (sizeof(code) + pageSize) & ~pageSize, PROT_READ | PROT_EXEC);");
|
||
|
#endif
|
||
|
puts(
|
||
|
"\t((void (*)(void*, void*, int *))code)((void*)putchar, (void*)getchar, stack);\n"
|
||
|
"}"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
#ifdef XBYAK32
|
||
|
puts("32bit mode");
|
||
|
#else
|
||
|
puts("64bit mode");
|
||
|
#endif
|
||
|
if (argc == 1) {
|
||
|
fprintf(stderr, "bf filename.bf [0|1]\n");
|
||
|
return 1;
|
||
|
}
|
||
|
std::ifstream ifs(argv[1]);
|
||
|
int mode = argc == 3 ? atoi(argv[2]) : 0;
|
||
|
Brainfuck bf(ifs);
|
||
|
if (mode == 0) {
|
||
|
static int stack[32768];
|
||
|
((void (*)(void*, void*, int *))bf.getCode())((void*)putchar, (void*)getchar, stack);
|
||
|
} else {
|
||
|
dump(bf.getCode(), bf.getSize());
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|