GAME言語からCへ変換し、そして実行バイナリに落とすコンパイラをpythonで書いてみました。
GAME言語コンパイラ - beam.py
./beam.py file.gmとすると、GAME言語で書かれたfile.gmをCのソースにトランスパイルし、file.cに出力し、その後gccを呼び出して./fileに実行可能バイナリを書き出します。file.cはccでコンパイル可能です。
一般に冗長さを許せば、低級なプログラム言語で書かれたソースは、より高級なプログラム言語に翻訳することが容易です。
C言語はチューリング完全です。GAME言語はチューリング完全かどうかですが、brainfuckがチューリング完全で、GAME言語でbrainfuckの全てのインストラクションを記述できるので、GAME言語もチューリング完全です。
最適化はできていません。エラーチェックが甘いです。
動作検証はFreeBSD、Linuxです。
chmod +x beam.pyで実行権限を付加して動かしてください。
履歴
・一応完成 version 1.0.0 2024/8/26
・ちょっとヴァージョンアップ、改名。 version 1.0.1 2024/8/27
・剰余結果取得のバグ修正 version 1.0.2 2025/04/11
・FreeBSDの場合、サブルーチン呼び出しのとき、スタックが16バイトアライメント境界に位置していないとsegmentation faultになってしまうため、gosub文の処理を書き換え version 1.0.3 2025/08/31
・実行可能バイナリにまで変換するようにした。 version 1.1.0 2026/09/09
・gosub!=,return]を機械非依存にした。これで100% 機械独立のソースを出力するようになった。version 1.2.0
・ウェイトとキー入力のため、*で始まるオプショナルコマンド、&の項の処理を付け足し、$の項がある時はtermiosを付け足し、オリジナルのGAME言語に近いようにした。この3つは機械依存(linux/freebsd)である。version 1.3.0
・オプショナルコマンドや、&、$の項がないときには、100%機械独立の標準Cのコードを出力するように変更。 version 1.5.0
今後の課題の問題点
・for-next,do-untl文の、for文またはdo文一つに対して複数のnext文、until文がある場合には対応していません。
・for文の終値に変数を使うと、カウントアップとして扱われる。
・next文に2重以上の括弧があるとバグる。
本体 'beam.py'
サンプルプログラム 素因数分解
#!/usr/local/bin/miep
1000 "Input natural number : " N=?
1010 Z=$0000 !=1100
1020 ?=N ":"
1030 ;=J I=0,J-1 ?=Z(I) " " @=I+1
1040 /
1050 #=-1
1100#
1101# Sub routine of PrimeFactorization
1103#
1105 I=2 J=0 M=N
1110 ;=M=0 J=0 ]
1130 ;=M=1 ]
1135 H=M/I
1136 ;=%1=0 Z(J)=I M=H J=J+1 #=1130
1140 I=I+1 #=1130
トランスパイル後のコード
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
static int A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,reminder;
static unsigned char memory[65536];
static int tmp,ga,gw;
static int retstack[256];
static int retsp=0;
static int forto[4096];
static int fbase=0;
static int fbstack[256];
static void gosub_push(int k,int d) {
if (retsp>=256 || fbase+d>4032) { fprintf(stderr,"gosub stack overflow\n"); exit(1); }
fbstack[retsp]=fbase;
retstack[retsp++]=k;
fbase+=d;
}
static int w16(long v) {
unsigned long u=(unsigned long)v&0xFFFFUL;
return u>=0x8000UL ? (int)((long)u-65536L) : (int)u;
}
static unsigned gaddr(long a) {
return (unsigned)((unsigned long)a&0xFFFFUL);
}
static int gneg(int a) {
return w16(-(long)a);
}
static int gabs(int a) {
return a<0 ? gneg(a) : a;
}
static int peekw(long a) {
unsigned ad=gaddr(a);
return w16((long)memory[ad]|((long)memory[gaddr(ad+1L)]<<8));
}
static void pokeb(long a,int v) {
memory[gaddr(a)]=(unsigned char)((unsigned)v&0xFFu);
}
static void pokew(long a,int v) {
unsigned ad=gaddr(a);
memory[ad]=(unsigned char)((unsigned)v&0xFFu);
memory[gaddr(ad+1L)]=(unsigned char)(((unsigned)v>>8)&0xFFu);
}
static int input_num(void) {
char buf[256];
int c;
fflush(stdout);
if (fgets(buf,(int)sizeof(buf),stdin)==NULL) return 0;
if (strchr(buf,'\n')==NULL) while ((c=getchar())!='\n' && c!=EOF);
return w16(strtol(buf,NULL,10));
}
static int game_getch(void) {
int c;
fflush(stdout);
c=getchar();
return c==EOF ? 0 : c;
}
static int gdiv(int a,int b) {
long x=a,y=b,q,r;
if (y==0) { printf("Division by zero\n"); return -1; }
q=(x<0 ? -x : x)/(y<0 ? -y : y);
if ((x<0)!=(y<0)) q=-q;
r=x-q*y;
if (r!=0 && ((r<0)!=(y<0))) { r+=y; q--; }
reminder=w16(r);
return w16(q);
}
static int grand(int n) {
return n>0 ? rand()%n : 0;
}
int main(void) {
time_t now=time(NULL);
unsigned seed=0;
size_t i;
for (i=0;i<sizeof(now);i++) seed=seed*31u+((unsigned char *)&now)[i];
srand(seed);
l1000: ; fputs("Input natural number : ",stdout); N=input_num();
l1010: ; Z=0; gosub_push(0,0); goto l1105; r0: ;
l1020: ; printf("%d",(N)); fputs(":",stdout);
l1030: ; if (!(J)) goto l1040; I=0; forto[fbase+0]=w16((long)(J)-(1)); do { printf("%d",(peekw((long)Z+2L*(I)))); fputs(" ",stdout); I=w16((long)(I)+(1)); } while(I<=forto[fbase+0]);
l1040: ; putchar('\n');
l1050: ; { fflush(stdout); exit(0); }
l1105: ; I=2; J=0; M=N;
l1110: ; if (!(((M)==(0)))) goto l1130; J=0; goto game_return;
l1130: ; if (!(((M)==(1)))) goto l1135; goto game_return;
l1135: ; H=gdiv(M,I);
l1136: ; if (!((((reminder))==(0)))) goto l1140; pokew((long)Z+2L*(J),I); M=H; J=w16((long)(J)+(1)); goto l1130;
l1140: ; I=w16((long)(I)+(1)); goto l1130;
return 0;
game_return:
if (retsp<=0) exit(0);
fbase=fbstack[--retsp];
switch (retstack[retsp]) {
case 0: goto r0;
}
exit(0);
}
実行結果
$ ./beam.py factor.gm
$ ./factor
Input natural number : 999
999:3 3 3 37
$
一言
僕はもう、疲労困憊らです。
参考文献など
ゲーム言語ドキュメント
コンパイラ構成論 近代科学社