Commit 6c23fc33 authored by Masahiko Sakai's avatar Masahiko Sakai

Initial commit

parents
2016/06/17
bug fix : init[59049][2] to init[59050][2]
malbolg20: malbolge20.c
CC -o malbolge20 malbolge20.c -lm
clean:
rm -rf malbolge20 malbolge20.o
Malbolge20 interpreter
Compile:
make
Usage:
./malbolge prog-file
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#define ALLOCATED 1
#define UNALLOCATED 0
#ifdef __GNUC__
static inline
#endif
void exec(int flag[59049], unsigned long **mem, unsigned long init[59049][2] );
#ifdef __GNUC__
static inline
#endif
unsigned long op( unsigned long x, unsigned long y );
void make_init_mem(int id, unsigned long **mem, unsigned long init[59049][2]);
const char xlat1[] =
"+b(29e*j1VMEKLyC})8&m#~W>qxdRp0wkrUo[D7,XTcA\"lI"
".v%{gJh4G\\-=O@5`_3i<?Z';FNQuY]szf$!BS/|t:Pn6^Ha";
const char xlat2[] =
"5z]&gqtyfr$(we4{WP)H-Zn,[%\\3dL+Q;>U!pJS72FhOA1C"
"B6v^=I_0/8|jsb9m<.TVac`uY*MK'X~xDl}REokN:#?G\"i@";
FILE *f;
int main( int argc, char **argv )
{
unsigned long **mem;
int flag[59049];// ブロックが使用済みか否か
unsigned long init[59050][2]; // 各ブロックの最初2つ分の初期値を記憶
unsigned long i,ii = 0;
int x;
for(i=0;i<59049;i++){// フラグ初期化
flag[i]=UNALLOCATED;
}
if ( argc != 2 )
{
fputs( "invalid command line\n", stderr );
return ( 1 );
}
if ( ( f = fopen( argv[1], "r" ) ) == NULL )
{
fputs( "can't open file\n", stderr );
return ( 1 );
}
mem = (unsigned long **)malloc( sizeof(unsigned long) * 59049 );
if ( mem == NULL )
{
fclose( f );
fputs( "can't allocate memory\n", stderr );
return ( 1 );
}
int id=0;
//第0ブロックのメモリ領域確保
mem[id] = (unsigned long *)malloc( sizeof(unsigned long) * 59049 );
if ( mem[id] == NULL )
{
fclose( f );
fputs( "can't allocate memory\n", stderr );
return ( 1 );
}
flag[id]=ALLOCATED;
//以下で入力プログラムの読み込み
i=0;
while ( ( x = getc( f ) ) != EOF )
{
if ( isspace( x ) ) continue;
if ( x < 127 && x > 32 )
{
if ( strchr( "ji*p</vo", xlat1[( x - 33 + ii ) % 94] ) == NULL )
{
fputs( "invalid character in source file\n", stderr );
free( mem );
fclose( f );
return ( 1 );
}
}else{
fputs( "invalid character in source file\n", stderr );
free( mem );
fclose( f );
return ( 1 );
}
mem[id][i++] = x;
ii++;//通しの文字数
if(i == 59049){//ブロック内の文字数が59049となった場合
id++;//次のブロックに移る
if ( id==59049 )//第59049ブロックとなった場合、メモリ不足
{
fputs( "input file too long\n", stderr );
free( mem );
fclose( f );
return ( 1 );
}
//次ブロックのメモリ領域を確保
mem[id] = (unsigned long *)malloc( sizeof(unsigned long) * 59049 );
if ( mem[id] == NULL )
{
fclose( f );
fputs( "can't allocate memory\n", stderr );
return ( 1 );
}
flag[id]=ALLOCATED;//第idブロックを使用済みに変更
i=0;//ブロック内文字数を0に戻す
}
}
fclose( f );//入力の読み込み終了
//以下は使用中ブロックの余ったメモリの初期化処理
if(i==0){
mem[id][0] = op( mem[id-1][59048], mem[id-1][59047] );
mem[id][1] = op( mem[id][0], mem[id-1][59048] );
i=2;
}else if(i==1){
mem[id][1] = op( mem[id][0], mem[id-1][59048] );
i=2;
}
while ( i < 59049 ){
mem[id][i] = op( mem[id][i - 1], mem[id][i - 2] );
i++;
}//初期化処理ここまで
make_init_mem(id, mem, init);//以降のブロックの遅延初期化を行うための準備
exec( flag, mem, init );//実行
free( mem );
return ( 0 );
}
/* 各ブロックの遅延初期化を行うための準備をする関数 */
/* 各ブロックの最初の2ワードを計算し, initに格納 */
void make_init_mem(int id, unsigned long **mem, unsigned long init[59049][2]){
int i,j;
int x, y, temp0, temp1;
int num0[3][3] = {{0, 1, 2}, {0, 1, 1}, {0, 2, 2}, };
int num1[3][3] = {{1, 0, 0}, {1, 0, 2}, {2, 1, 2}, };
init[id+1][0]=op( mem[id][59048], mem[id][59047] );
init[id+1][1]=op( init[id+1][0], mem[id][59048] );
id++;
for(i=id;i<59049;i++){
temp0=init[id][0];
temp1=init[id][1];
init[id+1][0]=0;
init[id+1][1]=0;
for(j=0;j<20;j++){
x = temp0 % 3;
y = temp1 % 3;
init[id+1][0] += num0[x][y]*pow(3.0,j);
init[id+1][1] += num1[x][y]*pow(3.0,j);
temp0 = temp0/3;
temp1 = temp1/3;
}
id++;
}
}
#ifdef __GNUC__
static inline
#endif
/* JMPとMOV_Dの時に呼ばれ, その処理を実行する. */
void mem_manage(unsigned long *reg_addr, unsigned long num, int *id, unsigned long **mem, unsigned long init[59049][2], int flag[59049]){
int new_reg_addr=0;
int new_id;
int i;
new_id=num/59049;
for(i=0;i<10;i++){
new_reg_addr += (num % 3)*pow(3.0,i);
num = num/3;
}
*reg_addr=new_reg_addr;
/* 初期化されていないブロックだった場合、初期化する*/
if(flag[new_id]==UNALLOCATED){ //すでに初期化済みかチェック
mem[new_id] = (unsigned long *)malloc( sizeof(unsigned long) * 59049 );
if ( mem[new_id] == NULL ){
fclose( f );
free(mem);
fputs( "can't allocate memory\n", stderr );
exit ( 1 );
}
mem[new_id][0] = init[new_id][0];
mem[new_id][1] = init[new_id][1];
i=2;
while ( i < 59049 ){
mem[new_id][i] = op( mem[new_id][i-1], mem[new_id][i-2] );
i++;
}
flag[new_id]=ALLOCATED;
}
*id=new_id;
}
/* 命令実行後のインクリメント. increment(c, c_id)*/
void increment(unsigned long *reg_addr, int *id, int flag[59049], unsigned long **mem, unsigned long init[59049][2]){
int i;
if ( *reg_addr == 59048 ){
if(*id == 59048){
*id = 0; *reg_addr = 0;
}else{
*id+=1; *reg_addr=0;
if(flag[*id]==UNALLOCATED){ //すでに初期化済みかチェック
mem[*id] = (unsigned long *)malloc( sizeof(unsigned long) * 59049 );
if ( mem[*id] == NULL ){
fclose( f );
fputs( "can't allocate memory\n", stderr );
exit ( 1 );
}
mem[*id][0] = init[*id][0];
mem[*id][1] = init[*id][1];
for(i=2; i<59049; i++ ){
mem[*id][i] = op( mem[*id][i-1], mem[*id][i-2] );
}
flag[*id]=ALLOCATED;
}
}
}else {
*reg_addr += 1;
}
}
void exec( int flag[59049], unsigned long **mem, unsigned long init[59049][2] )
{
unsigned long a = 0, c = 0, d = 0;
int x;
int c_id=0, d_id=0;
for (;;)
{
if ( mem[c_id][c] < 33 || mem[c_id][c] > 126 ) {
printf("Enter into an infinite loop. exit(1). ");
exit(1);
//continue; // もともとの処理
}
switch ( xlat1[( mem[c_id][c] - 33 + (c+c_id*59049) ) % 94] )
{
case 'j': //MOV_D
mem_manage(&d, mem[d_id][d], &d_id, mem, init, flag);
break;
case 'i': //JMP
mem_manage(&c, mem[d_id][d], &c_id, mem, init, flag);
break;
case '*': //ROT
a = mem[d_id][d] = mem[d_id][d] / 3 + mem[d_id][d] % 3 * pow(3,19);
break;
case 'p': // OPR
a = mem[d_id][d] = op( a, mem[d_id][d] );
break;
case '<'://OUTPUT
#if '\n' != 10
if ( x == 10 ) putc( '\n', stdout );else
#endif
putc( a, stdout );
break;
case '/'://INPUT
x = getc( stdin );
#if '\n' != 10
if ( x == '\n' ) a = 10; else
#endif
if ( x == EOF ) a = 59049 ; else a = x;
break;
case 'v':return;//HALT
}
mem[c_id][c] = xlat2[mem[c_id][c] - 33];
increment(&c, &c_id, flag, mem, init);
increment(&d, &d_id, flag, mem, init);
}
}
#ifdef __GNUC__
static inline
#endif
unsigned long op( unsigned long x, unsigned long y )
{
unsigned long i = 0, j;
static const unsigned long p9[10] =
{ 1, 9, 81, 729, 6561 ,59049, 531441, 4782969, 43046721, 387420489};
static const unsigned long o[9][9] =
{
{ 4, 3, 3, 1, 0, 0, 1, 0, 0 },
{ 4, 3, 5, 1, 0, 2, 1, 0, 2 },
{ 5, 5, 4, 2, 2, 1, 2, 2, 1 },
{ 4, 3, 3, 1, 0, 0, 7, 6, 6 },
{ 4, 3, 5, 1, 0, 2, 7, 6, 8 },
{ 5, 5, 4, 2, 2, 1, 8, 8, 7 },
{ 7, 6, 6, 7, 6, 6, 4, 3, 3 },
{ 7, 6, 8, 7, 6, 8, 4, 3, 5 },
{ 8, 8, 7, 8, 8, 7, 5, 5, 4 },
};
for ( j = 0; j < 10 ; j++ )
i += o[y / p9[j] % 9][x / p9[j] % 9] * p9[j];
return ( i );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment