3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GAME言語コンパイラ on python3 'beam'

3
Last updated at Posted at 2024-08-25

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'

サンプルプログラム 素因数分解

factor.gm
#!/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

トランスパイル後のコード

factor.c
#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 
$ 

一言

僕はもう、疲労困憊らです。

参考文献など

ゲーム言語ドキュメント
コンパイラ構成論 近代科学社

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?