Schreiben Sie einen Dolmetscher für meine neue esoterische Sprache PointerLang

8

Ich habe eine Sprache entworfen, in der Zeigerarithmetik das Hauptwerkzeug der Programmierung ist.

Hier sind einige Beispiele.

(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]

Sprachspezifikation

Die Sprachdefinition ist sehr einfach. Sie werden es sehr leicht verstehen, wenn Sie Erfahrung mit C haben, aber ich werde es nicht annehmen.

Jedes Programm in PointerLang hat den Zeiger , kurz gesagt P. Sie können es sich als eine versteckte einzelne globale Variable vorstellen, die Sie mithilfe von Befehlen steuern können . Pzeigt zunächst auf den Anfang des Arrays . Jedes Element im Array hat den Typ inteiner 32-Bit-Ganzzahl mit Vorzeichen.

Für C-Programmierer

int32_t *P = malloc(1000);

In PointerLang gibt es Befehle und Argumente . Ein Argument ist ein Argument, intdas nach einem Befehl kommen muss. Alle Befehle werden von links nach rechts ausgeführt, sofern nicht anders angegeben. Das Folgende ist die Liste der Befehle. Asteht für Argument. Ein Befehl ohne Abedeutet, dass er kein Argument benötigt. Ein Befehl mit Amuss ein Argument enthalten. In den Klammern steht der äquivalente C-Ausdruck.

  • =A: A bei P zuweisen ( *P = A)
  • +A: füge A bei P hinzu ( *P += A)
  • -A: subtrahiere A bei P ( *P -= A)
  • *A: multipliziere mit A bei P ( *P *= A)
  • /A: dividiere durch A bei P ( *P /= A)
  • >A: bewege dich Pum A( P += A)
  • .: drucke die ganze Zahl bei P ( printf("%d", *P))
  • !: drucke die ganze Zahl bei P als ASCII ( printf("%c", (char)*P))
  • [: Wenn der Wert bei P 0 ist, gehe zum Befehl nach dem nächsten ]( while (*P) {)
  • ]: gehe zum vorherigen [, das das passende Paar ist ( })
  • ;A: Wenn Apositiv ist, auf den Befehl gehen nach dem Ath ]nächsten kommt; Wenn Aes negativ ist, gehe zum Avorhergehenden [. Wenn A 0 ist, nichts tun.

Ein ganzzahliges Literal ist ein Argument.

Die folgenden zwei sind spezielle Argumente, die ein Argument annehmen.

  • -A: bewertet als Argument mit dem gleichen absoluten Wert wie Aund dem entgegengesetzten Vorzeichen von A; unäres Minus
  • *A: bewege Pdich vorbei A, bewerte den Wert bei P, bewege dich Pdurch -A( P[A])

Alle Kommentare in PointerLang stehen in Klammern (comment).

Beispielprogramm

Dieses Programm, das von 1 bis 10 zählt, ist ein gutes Beispiel, um Ihr Verständnis zu vervollständigen.

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

Seien Sie vorsichtig, wenn Sie interpretieren -*-1. -ist der Befehl und *-1ist das Argument. Ein ganzzahliges Literal zeigt effektiv das Ende eines Befehl-Argument-Paares an.

Es kann mit 1-zu-1-Entsprechung als nach C übersetzt werden

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;
}

Auf diese Sprache können Erweiterungen angewendet werden, z. B. Zeichenliterale, Arrays, Zeichenfolgenliterale usw., die Sie jedoch der Einfachheit halber nicht implementieren müssen.

Die Herausforderung

Sie haben die Kernfunktionen im Detail zu implementieren Language Specification Abschnitt und die nachfolgenden Ausführungen . Probieren Sie es mit Ihrer bevorzugten Programmiersprache aus und schreiben Sie das kürzestmögliche Programm.

HINWEIS 1: Die Größe des Arrays ist undefiniert. Aber es sollte groß genug sein, um die meisten Probleme zu lösen.

HINWEIS 2: Der Integer-Überlauf ist undefiniert.

HINWEIS 3: Die Spezifikation definiert nur das Ergebnis oder den Effekt bestimmter Sprachkonstrukte. Beispielsweise müssen Sie die Schritte in der Definition des Arguments nicht genau befolgen *.

HINWEIS 4: Alle Zeichen, die keine Befehle, Argumente oder Kommentare sind, werden ignoriert. =104!=105!ist wie = 1 0 4! = 1 05 !zum Beispiel.

HINWEIS 5: Kommentare sind nicht verschachtelt. ((comment))ist ein Syntaxfehler.

HINWEIS 6: Ich habe eine wichtige Änderung vorgenommen, um eine Lücke in meiner Sprache zu schließen. Der ~Befehl wird jetzt nicht verwendet und ;nimmt immer ein Argument an.

HINWEIS 7: Jedes ganzzahlige Literal ist dezimal.

xiver77
quelle
13
Ist es nur ich oder ist das im Grunde genommen Brainfuck?
Claudiu
Können wir davon ausgehen, dass alle übergebenen Aussagen gültig sind? dh alle Zahnspangen sind geschlossen
Levi
Sind Sie sicher, dass das erste Beispiel =9[>1=9-*-1.>-1-1]0 bis 9 druckt? Nachdem es 8 Punkte gegeben hat, weil P [0] = 1 ist, subtrahiert es 1 kurz vor dem Ende der Schleife, wodurch P [0] = 0 wird, und wenn es die Schleife erneut startet, sollte es beendet werden, weil P [0] = 0, also die Beispiel sollte nur 0 bis 8 drucken. Oder bin ich nur wirklich verwirrt?
Jerry Jeremiah
@ JerryJeremiah hmm .. sicher, es scheint wie mein Fehler, wird jetzt beheben.
Xiver77
So wollte BrainFuck sein.
SS Anne

Antworten:

4

C 413

Vielen Dank an @ceilingcat für einige sehr schöne Golfstücke - jetzt noch kürzer

#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;}

Probieren Sie es online aus!

und die etwas weniger Golfversion meiner ursprünglichen Antwort:

#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;
}
Jerry Jeremiah
quelle
@ceilingcat Ok, jetzt ist Ungolfing nicht mehr möglich, also habe ich keine Ahnung, wie es funktioniert. Wie machst du es immer kürzer?
Jerry Jeremiah
Gerade ersetzt switch(...){case'(':...case'.':...mit j=='('?...:j=='.'?...und Funktionsaufrufe innerhalb des ternären Operator passen herausgerechnet .
Deckenkatze