新しい難解な言語PointerLangのインタープリターを作成する


8

私は、ポインター演算がプログラミングの主要ツールである言語を設計しました。

下記は用例です。

(print 0 to 8)
=9[>1=9-*-1.>-1-1]

(print 1 to 10 with spaces in between, character literal extension used)
=1[.>1=10-*-1[>1=' '!>-2+1;-2];1]='\n'!

(compute the factorial of 10)
=10>1=*-1-1[>-1**1>1-1]>-1.

(print "hi")
=104!=105!

(print "hi" with extension for arrays)
={104,105,0}[!>1]

(print "Hello, world!" with extension for C-style string literals)
="Hello, world!"[!>1]

言語仕様

言語の定義は非常に簡単です。Cの経験があれば簡単に理解できますが、私はそうは思いません。

PointerLangのすべてのプログラムには、ポインタ、つまりがありますPコマンドを使用して制御できる非表示の単一のグローバル変数と考えることができますP最初は配列の先頭を指します。配列内のすべての要素には、32ビットの符号付き整数である型があります。int

Cプログラマ向け

int32_t *P = malloc(1000);

PointerLangには、コマンド引数があります。引数は、intコマンドの後に来る必要があります。特に指定がない限り、すべてのコマンドは左から右に実行されます。以下はコマンドのリストです。A引数を表します。なしのコマンドAは、引数を取りません。のコマンドAは引数を取る必要があります。括弧内は同等のC式です。

  • =A:AをPに割り当てます(*P = A
  • +A:AをPに追加(*P += A
  • -A:PでAを引く(*P -= A
  • *A:PでAを乗算します(*P *= A
  • /A:PでAで除算(*P /= A
  • >A:移動PによってAP += A
  • .:Pの整数を出力(printf("%d", *P)
  • !:Pの整数をASCII(printf("%c", (char)*P))として出力します
  • [:Pの値が0の場合、次の]while (*P) {)の後でコマンドに移動します
  • ][一致するペアである前に移動します(}
  • ;A次の場合A正である、後のコマンドに行くA番目は、]次の来て。A負の場合は、前のAth に移動し[ます。Aが0の場合、何もしません。

整数リテラルは引数です。

次の2つは、引数を取る特別な引数です。

  • -A:と同じ絶対値Aとの反対符号を持つ引数として評価されAます。単項マイナス
  • *A:移動PによってAで値を評価し、P移動し、P-AP[A]

PointerLang内のすべてのコメントは括弧内にあり(comment)ます。

プログラム例

1から10まで数えるこのプログラムは、理解を深めるための良い例です。

(print 1 to 10 with spaces in between)
=1[.>1=10-*-1[>1=32!>-2+1;-2];1]=10!

解釈するときは注意してください-*-1-コマンドで*-1あり、引数です。整数リテラルは、コマンドと引数のペアの終わりを効果的に示します。

次のように1対1対応でCに変換できます。

int main(void) {
    int32_t *P = malloc(1000);
    *P = 1; // =1
l:
    while (*P) { // [
        printf("%d", *P); // .
        P += 1; // > 1
        *P = 10; // =10
        *P -= P[-1]; // -*-1
        while (*P) { // [
            P += 1; // >1
            *P = 32; // =32
            printf("%c", (char)*P); // !
            P += -2; // >-2
            *P += 1; // +1
            goto l; // ;-2
        } // ]
        break; // ;1
    } // ]
    *P = 10; // =10
    printf("%c", (char)*P); // !
    return 0;
}

文字リテラル、配列、文​​字列リテラルなどの拡張機能をこの言語に適用できますが、簡単にするためにこれらを実装する必要はありません。

チャレンジ

言語仕様のセクションと以下の注で詳述されているコア機能を実装する必要があります。可能な限り短いプログラムを記述して、お気に入りのプログラミング言語で試してみてください。

注1:配列のサイズは未定義です。しかし、ほとんどの問題を解決するのに十分な大きさでなければなりません。

注2:整数オーバーフローは定義されていません。

注3:仕様では、特定の言語構成体の結果または効果のみを定義しています。たとえば、引数の定義の手順に厳密に従う必要はありません*

注4:コマンド、引数、コメント以外の文字は空白は無視されます。例えば=104!=105!と同じ= 1 0 4! = 1 05 !です。

注5:コメントはネストされません。((comment))構文エラーです。

注6:私の言語の穴を修正するために、重大な変更を加えました。~コマンドは現在使用されず、;常に引数を取ります。

注7:すべての整数リテラルは10進数です。


13
それは私だけですか、これは基本的にはブレインファックですか?
Claudiu

渡されたすべてのステートメントが有効であると想定できますか?つまり、すべてのブレースが閉じています
Levi

最初の例で=9[>1=9-*-1.>-1-1]は0から9が印刷されますか?P [0] = 1であるため8を指定した後、ループの最後の直前で1を減算し、P [0] = 0にします。次に、ループを再び開始すると、P [0] = 0であるため終了します。例では0から8だけを出力する必要がありますか、それとも本当に混乱していますか?
ジェリージェレミア

@JerryJeremiahうーん..私の間違いのようですが、今すぐ修正します。
xiver77 2015

これは、BrainFuckがなりたかったようなものです。
SSアン

回答:


4

C 413

素晴らしいゴルフをしてくれた@ceilingcatに感謝-今ではさらに短い

#define L strtol(I++,&I,10)
#define A*I==42?I++,P[L]:L
#define F(a)-91-a|i;i-=*I-93+a?*I==91+a:-1);}
i;char*I;X[999],*P=X;Y(){for(;*I++F(2)B(){for(i=!--I;*--I F(0)Z(c){for(c=A;c;c+=c<0?1:-1)if(i=c<1)B();else for(;*I++F(2)main(j,a)char**a;{for(I=a[1];j=*I++;printf(j-4?j+9?j==19?*P=A:j==1?*P+=A:j==3?*P-=A:!j?*P*=A:j==5?*P/=A:j==20?P+=A:j-17?j-51?j-49?I=j+2?I:index(I,41)+1:*P||Y(i=1):B():Z(),"":P:"%d",*P))j-=42;}

オンラインでお試しください!

そして、私の元の答えの少しゴルフの少ないバージョン:

#include <stdio.h>
#include <stdlib.h>
#define L strtol(I++,&I,10)
#define A *I=='*'?I++,P[L]:L
int X[999],*P=X;
int main(int i, char *a[])
{
  char* I=a[1];
  while(*I)
  {
    switch(*I++)
    {
      case '(': while(*I++!=')'); break;
      case '.': printf("%d",*P); break;
      case '!': printf("%c",(char*)*P); break;
      case '[': if(!*P)
                  for(i=1;*I++!=']'||i;)
                  {
                    if(*I=='[')
                      i+=1;
                    if(*I==']')
                      i-=1;
                  }
                break;
      case ']': for(--I,i=0;*--I !='['||i;)
                {
                  if(*I==']')
                    i+=1;
                  if(*I=='[')
                    i-=1;
                }
                break;
      case '=': *P=A; break;
      case '+': *P+=A; break;
      case '-': *P-=A; break;
      case '*': *P*=A; break;
      case '/': *P/=A; break;
      case '>': P+=A; break;
      case ';': for(int c=A; c; c+=c<0?1:-1)
                {
                  if(c>0)
                    for(i=0;*I++!=']'||i;)
                    {
                      if(*I=='[')
                        i+=1;
                      if(*I==']')
                        i-=1;
                    }
                  else
                    for(--I,i=0;*--I !='['||i;)
                    {
                      if(*I==']')
                        i+=1;
                      if(*I=='[')
                        i-=1;
                    }
                }
    }
  }
  return 0;
}

@ceilingcatわかりました。これでアンゴルフはできなくなりました。どのように短くし続けるのですか?
ジェリージェレミア

三項演算子に収まるように、関数呼び出しに置き換えswitch(...){case'(':...case'.':...j=='('?...:j=='.'?...分解しました。
ceilingcat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.