작은 언어는 작은 통역사가 필요합니다


21

매우 간단한 언어 정의는 다음과 같습니다.

A Variable is any string that does not contain ^, <, >, !, or ?
The empty string is a valid variable identifier
The value of every variable starts at 0.
A Statement is one of (var is a Variable, P is a Program):
    var^   -> changes var to be equal to 1 more than itself
    var<P> -> while var > 0, changes var to be equal to 1 less than itself, then runs P
    var! -> output value of var
    var? -> ask for non-negative integer as input, increase var by that value
A Program is a concatenation of Statements, running a Program means running each Statement in order

예제 프로그램 (빈 문자열은 변수이지만 명확성을 위해 드물게 사용하고 일부 변수는 기본적으로 기본적으로 0 일 때 프로그램에서 0으로 설정됩니다).

<>: sets the value of the empty string variable to 0
b<>b?b<a^>: asks for b, then adds the value stored in b to a, zeroing b in the process
b<>b?a<>b<a^>: asks for b, then sets a to the value of b, zeroing b in the process
a<>c<>b<a^c^>c<b^> : copies the value in b into a without zeroing it
b<>c<>a<c^c^c<b^>>b! : outputs a multiplied by 2
b^b<a<>a?a!b^> : outputs what you input, forever

귀하의 목표는이 언어에 대해 가장 작은 통역사를 작성하는 것입니다.

  1. 변수의 값은 임의로 클 수 있으며 이론상 언어가 액세스 할 수있는 총 메모리에 의해서만 제한되어야하지만 최대 2 ^ 256까지의 값만 처리하면됩니다.

  2. 프로그램은 이론적으로 임의로 긴 프로그램을 처리 할 수 ​​있어야하지만 2 ^ 32 자 미만의 프로그램에서만 작업해야합니다. 최대 2 ^ 32의 중첩 깊이 루프도 처리해야합니다.

  3. 프로그램이 유효한 프로그램이고 입력을 요청할 때 음이 아닌 정수만 얻게된다고 가정 할 수 있습니다. 입력 문자열에 ASCII 인쇄 가능 문자 만 포함되어 있다고 가정 할 수도 있습니다.

  4. 당신이 해석하는 프로그램의 속도는 중요하지 않습니다. 최적화없이 5 자리 곱셈처럼 단순한 것은 이미 고통스럽게 느려질 것입니다.

  5. 언어에 설명 된 방식으로 입력을 합리적으로 받아들이거나 출력을 생성 할 수없는 언어를 사용하려는 경우 가능한 해석을 사용하십시오. 이는 언어가 필요한 동작을 구현할 수없는 모든 이유에 적용됩니다. 모든 언어가 경쟁하기를 원합니다.

  6. 최단 프로그램이 이깁니다. 표준 허점이 적용됩니다.


부수적으로 나는 2016 년 숫자를 출력하는 프로그램을 얼마나 짧게 작성할 수 있는지 알고 싶지만 먼저 코드를 테스트 할 수 있도록 인터프리터가 작성 될 때까지 기다려야합니다.
Neil

1
파이썬 2.7에 통역사가 있습니다 .
마찰의 멜론

2
이 언어는 무엇입니까? 그것은 esolangs.org에
wizzwizz4

@Neil 저는 72 자로 처리했습니다
Fricative Melon

@FricativeMelon 72? 43 개로 할 수있다!
Neil

답변:


4

루비, 182 바이트

$h=Hash.new 0
def r(c)c.scan(/(([^!?^<>]*)(<(\g<1>*)>|[!?^]))/){$4?($1=~/(.*?)<(.*)>/
($h[$1]-=1;r$2)while$h[$1]>0):$3<?"?p($h[$2]):$h[$2]+=$3<?@?STDIN.gets.to_i:
1}end
r IO.read *$*

다음과 같이 시도하십시오.

$ cat code
a?b<>c<>a<c^c^c<b^>>b!

$ ruby lynn.rb code
3                           <-- input
6                           <-- output

작동 원리

r함수는 입력 문자열을 토큰 화하고 각 토큰을 실행합니다.

def r(c)
    c.scan(/(([^!?^<>]*)(<(\g<1>*)>|[!?^]))/){
        ...
    }
end

변수 이름이 $2일치하는지 찾은 [^!?^<>]*다음

  • <...>여기서 ...0 개 이상의 프로그램을 일치 ( \g경우에하는, 재귀입니다) $4되지 않습니다nil
  • !, ?또는 ^에 의해 캡쳐 캐릭터 $3경우가있는, $4이다 nil.

그런 다음 약간의 들여 쓰기를 할 때 토큰을 실행하는 논리는 매우 간단합니다.

$4 ? (                                    # If it's a loop:
    $1 =~ /(.*?)<(.*)>/                   #   Re-match token*
    ($h[$1]-=1; r $2) while $h[$1] > 0    #   Recurse to run loop
) :                                       # Else:
    $3 < ?"                               #   If it's an !:
      ? p($h[$2])                         #     Print the var
      : $h[$2] +=                         #   Else, increment it by:
          $3 < ?@                         #     If it's a ?:
              ? STDIN.gets.to_i           #       User input
              : 1                         #     Else: 1

* There's an oniguruma bug, I think, that keeps me from simply using $3 here.

이것이 어떻게 작동하는지 정말로 궁금합니다.
Jerry Jeremiah

1

자바 스크립트 (ES6) 184 194 209

단순화 된 편집 (입력 및 출력에 함수 매개 변수를 사용하는 것은 좋은 생각 같지만 그렇지 않았습니다), 1 바이트 더 절약 thx @ ӍѲꝆΛҐӍΛПҒЦꝆ

수정 된 2 개의 구문 분석을 편집하십시오 . 증가 / 입력 논리는 @Lynn의 답변에서 빌려 왔습니다.

F=(p,i=0,v={},n='')=>eval("for(;c='>?^!<'.indexOf(q=p[i++]||'');n=~c?'':n+q)if(c>3){for(;v[n]--;)F(p,i,v);i=F(p,i,v[n]=0)}else~c&&v?c>2?alert(v[n]|0):v[n]=~~v[n]+(--c||+prompt()):0;i")

덜 골프

F=(p,      // program 
   i = 0,  // initial instruction pointer  
   v = {}, // variables (default to empty) or if 0, flag of dummy execution
   n = ''    // name of current variable (has to be local for recursive calls)
{
  for(; c='>?^!<'.indexOf(q=p[i++]||''); )
  // q = current character
  // c = current command (int 0..4 or -1 id not recognized)
  //     note 0 end of subprogram or end of program
  {
    if(c>3) // 4='<' call subprogram - recursive
    {
      for(;v[n]--;)
        F(p,i,v); // conditional call, repeated - using real environment
      v[n] = 0; // Reset variable at loop end
      i=F(p,i,0) // one more unconditional dummy call, just to advance i
    }
    else
      ~c&&v? // if valid command (1..3) and not dummy
      c>2?
        alert(v[n]|0) // output, undefined becomes 0
        :v[n]=~~v[n]+(--c||+prompt()) // inc with 1 or user input
      :0     // not valid command or dummy, do nothing
    n=~c?'':n+q // reset or update current variable name
  }
  return i // return current istruction pointer (for recursive calls)
}

테스트 스 니펫은 @Neil이 게시 한 프로그램을 사용하여 2016 년 평가를 시작합니다. 인내심 ...

F=(p,i=0,v={},n='')=>eval("for(;c='>?^!<'.indexOf(q=p[i++]||'');n=~c?'':n+q)if(c>3){for(;v[n]--;)F(p,i,v);i=F(p,i,v[n]=0)}else~c&&v?c>2?alert(v[n]|0):v[n]=~~v[n]+(--c||+prompt()):0;i")

// TEST
function definput(){  I.disabled = KI.checked; }
function defoutput(){  O.disabled = KO.checked; }

function run()
{
  var prog=P.value, irows = I.value.split('\n'), pi=0;
  var fout=x=>O.value+=x+'\n';
  var fin=x=>irows[pi++];
  var saveAlert=alert, savePrompt=prompt
  if (!KO.checked) alert=fout,O.value=''
  if (!KI.checked) prompt=fin
  
  F(prog);
  
  alert=saveAlert
  prompt=savePrompt
}

P.value="^^^^<a^a^>a<^^^^><a^b^>a<c<b^^>b<c^^>>!"

run()
Program <button onclick="run()">RUN</button><br>
<textarea id=P></textarea><br>
Input (or <input type=checkbox id=KI onclick="definput()"> interactive prompt)<br>
<textarea id=I>5</textarea><br>
Output (or <input type=checkbox id=KO onclick="defoutput()"> popup)<br>
<textarea id=O readonly></textarea><br>


옵션 eval을 피하기 위해 사용 하고 return있습니까?
Mama Fun Roll

@ ӍѲꝆΛҐӍΛПҒЦꝆ 예, eval은 1 바이트를 절약합니다. 나는 아직도 더 실질적인 뭔가를 찾고 있어요
edc65의

0

펄, 251 바이트

@p=split/([<>!?^])/,<>;for$c(0..$#p){$_=$p[$c];/</&&push@j,$c;if(/>/){$a=pop@j;$p[$c]=">$a";$p[$a]="<$c";}}while($c<$#p){$_=$p[$c];/\^/&&$v{$l}++;/!/&&print$v{$l};/\?/&&($v{$l}=<>);/<(\d+)/&&($v{$l}?$v{$l}--:($c=$1));/>(\d+)/&&($c=$1-2);$l=$_;$c++;} 

더 읽기 쉬운 버전 :

# treat the first line of input as a program

# split on punctuation keywords; @p will contain the program as a list
# of tokens (including whitespace between adjacent punctuation)
@p = split /([<>!?^])/, <>;

# rewrite jump addresses

# the interpreter could scan backwards to avoid this, but that idea
# makes me feel dirty
for $c (0..$#p) {
    $_ = $p[$c];
    # save loop-start address on stack
    /</ && push @j, $c;
    if (/>/) {
        # if we encounter a loop-end instruction, rewrite it and the
        # corresponding loop-start to include the address (of the
        # instruction---jumps have to offset from this)
        $a = pop @j;
        $p[$c] = ">$a";
        $p[$a] = "<$c";
    }
}

# execute the program

# our program is already in @p

# $c will contain our program counter

# $l will contain the name of the last-referenced variable

while ($c < $#p) {
    # move current instruction into $_ for shorter matching
    $_ = $p[$c];

    # increment instruction
    /\^/ && $v{$l}++;

    # output instruction
    /!/ && print $v{$l};

    # input instruction
    /\?/ && ($v{$l} = <>);

    # loop start, including address
    /<(\d+)/ && ($v{$l} ? $v{$l}-- : ($c = $1));

    # loop end, including address
    />(\d+)/ && ($c = $1-2);

    # copy current instruction into "last variable name"---this will
    # sometimes contain operators, but we have null-string
    # instructions between adjacent operators, so it'll be fine
    $l = $_;

    # advance the program counter
    $c++;
}

이것은 루프를 직접 점프하도록 고정하는 많은 바이트를 낭비하지만 루프 시작을 뒤로 스캔하면 내 미적 감각을 상하게했습니다.


0

표준 C ++, 400 바이트

이 컴파일 g++ -g test.cpp -Wall -Wextra -pedantic -std=gnu++11

#include<map>
#include<cstring>
#define b ;break;case
#define u unsigned long long
std::map<std::string,u>V;void r(char*s){char*p,*q,*e;for(u c;*s;s=p){p=strpbrk(s,"^<?!");c=*p;*p++=0;switch(c){b'^':V[s]++b'<':for(e=p,c=0;*e!='>'||c;e++)c+=(*e=='<')-(*e=='>');*e++=0;while(V[s]>0){V[s]--;r(q=strdup(p));free(q);}p=e;b'?':scanf("%llu",&V[s])b'!':printf("%llu",V[s]);}}}int main(int,char*v[]){r(v[1]);}

더 짧아 질 수 있습니다. 당신이 몇 가지 제안 사항이 있으면 의견을 주시기 바랍니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.