인쇄, 증가, 감소, 별명-Prindeal 해석


30

Prindeal (발음 인쇄용 - 디 - 알은 )는 새로운 비전 : 네 개의 명령이 프로그래밍 언어 홍보 INT를 , crement , crement , 그리고 IAS . 미니멀리즘에도 불구하고 복잡한 수학 연산은 Prindeal에서 4 가지 명령을 영리하게 결합하여 수행 할 수 있습니다.

코드 골프 도전 과제는 Prindeal 코드를 실행할 수있는 가장 짧은 프로그램을 작성하는 것입니다.

사양은 길지만 가능한 한 명확하게 만들려고 노력했으며 Prindeal을 배우려고 노력하면 매우 우아하다고 생각합니다!


이해하기 어려운 Prindeal

전처리

Prindeal 프로그램을 해석하기 전에 다음 사항을 순서대로 제거해야합니다.

  1. #줄 끝의 부호 뒤에 나오는 것 외에 그 #자체. (이것은 의견입니다.)
  2. 모든 줄에서 후행 공백.
  3. 완전히 빈 줄.

예를 들어 Prindeal 프로그램

p cat #The next line has 7 trailing spaces.
p dog       

#p mouse

전처리 될 것

p cat
p dog

여기에서이 전처리 단계가 완료되었다고 가정합니다.

변수

사용 방법을 보여주기 전에 변수를 신속하게 정의해야합니다.

변수 (및 변수에 대한 참조)는 Prindeal 명령의 인수로 전달되는 것입니다. 변수는 항상 전역 변수 이므로 변수에 대한 수정 사항은 위치에 관계없이 모든 곳에 반영됩니다.

각 변수에는 아닌 임의 정밀도 정수 (0, 1, 2, 3, ...)가 있습니다. 변수는 사전 초기화 할 필요가 없습니다. 변수는 처음 사용하거나 호출 할 때 항상 값 0으로 시작 합니다.

- 변수의 이름은 숫자로 시작하지 않는 영숫자와 밑줄이 아닌 빈 문자열이 될 수 있습니다 [a-zA-Z_][0-9a-zA-Z_]*에서 정규 표현식 . 그들은 대소 문자를 구분하므로 spiny_lumpsuck3rSpiny_lumpsuck3r다른 변수입니다.

실행

Prindeal은 명령형 프로그래밍 언어입니다. Prindeal 프로그램이 실행될 때 명령문 은 위에서 아래로 순서대로 실행 된 다음 프로그램이 종료됩니다.

Prindeal 프로그램의 들여 쓰기되지 않은 모든 줄은 인수를 받거나받지 않을 수있는 단일 명령의 실행을 포함하는 명령문입니다.

들여 쓰기 된 줄은 별칭 명령 뒤에 만 나타납니다 . 특히, 단일 공백으로 들여 쓰기 된 정확히 세 줄모든 별명 명령 후에 발생 하며 그 일부로 간주됩니다. 그래서 별명 문은 긴 네 줄은 정말입니다. (그들은 한 줄이 될 수 있고, 4는 더 읽기 쉽습니다.)

별칭이 아닌 문장

alias를 제외 하고 Prindeal 프로그램의 모든 명령문은 다음과 같은 형식을 갖습니다.

[command name] [argument 1] [argument 2] [argument 3] ...

임의의 수의 인수가있을 수 있습니다 (아무 것도 포함하지 않음). 각 인수는 항상 변수 이거나 ( 별명을 논의 할 때 알 수 있듯이 ) 변수에 대한 참조 입니다.

실행이 완료되면 각 문은 오류 발생 여부 에 따라 실패 또는 성공 으로 표시됩니다 . (이것은 alias 사용을 할 때만 중요 합니다.)

내장 print , incrementdecrement 는 위 형식의 명령문입니다. 그들이하는 일은 다음과 같습니다.

  1. print 는 명령 이름을 p가지며 하나의 인수를 취합니다. 전달 된 변수의 이름과 값 (10 진수)을 "="로 구분 한 다음 줄 바꿈을 인쇄합니다. 그것은 항상 성공으로 표시됩니다 .

    예를 들어 Prindeal 프로그램

    p _MyVariable_321
    p screaming_hairy_armadillo
    

    출력 할 것이다

    _MyVariable_321 = 0
    screaming_hairy_armadillo = 0
    

    모든 변수는 0에서 시작하기 때문에 (등호 앞뒤 공백이 필요합니다.)

  2. incremental 에는 명령 이름이 i있으며 하나의 인수를 사용합니다. 1에 의해 전달 된 변수의 값을 증가시킵니다. 항상 성공으로 표시됩니다 .

    예를 들어, 프로그램

    i alpaca
    p alpaca
    i alpaca
    p alpaca
    

    출력 할 것이다

    alpaca = 1
    alpaca = 2
    

    alpaca이전에 액세스 한 적이 없어도 0에서 1로 증가한 방법 에 유의하십시오 .

  3. 감소 는 명령 이름을 d가지며 하나의 인수를 취합니다. 전달 된 변수가 0이 아닌 경우 값은 1 씩 감소하고 명령문은 성공으로 표시됩니다 . 전달 된 변수가 0이면 아무 것도 수행되지 않고 명령문이 실패 로 플래그됩니다 .

    예를 들어, 프로그램

    i malamute
    p malamute
    d malamute    #success
    p malamute
    d malamute    #failure
    p malamute
    d akita       #failure
    p akita
    

    출력 할 것이다

    malamute = 1
    malamute = 0
    malamute = 0
    akita = 0
    

    값이 0 인 변수를 줄이는 것이 실패 를 일으키는 유일한 방법 입니다.

별명 성명 및 별칭 명령

별칭 명령은 특수 구문을 가지고 있으며,이 새 명령을 정의하는 데 사용할 수 있기 때문에 가장 강력하다. 별명 명령 이름입니다 a별칭 문장의 형식은 다음과 같습니다

a [name of new command]
 [statement A]
 [statement B]
 [statement C]

여기서 각각 [statement X]별칭이 아닌 문장, 즉 형식이있는 문장을 나타냅니다 [command name] [argument 1] [argument 2] [argument 3] ....

별명으로 된 명령의 이름 [name of new command]은 비어 있지 않은 영숫자 및 밑줄로, 숫자로 시작하지 않습니다 ( [a-zA-Z_][0-9a-zA-Z_]*정규식에서).

(이것은 변수와 동일한 이름 세트이지만 별명 명령과 변수는 다른 위치에서 사용되는 것과 다릅니다 . 변수는 아무런 결과없이 명령과 동일하게 이름을 지정할 수 있습니다.)

별칭 문이 실행될 때 새 명령이 원래 네 개의 p i d a명령 과 함께 추가 됩니다. 새 명령은 [command name]in 문 으로 사용될 수 있으며 다른 별칭이 아닌 명령 과 마찬가지로 인수와 함께 호출 될 수 있습니다 .

별명이 지정된 명령 이름을 가진 명령문이 실행될 때 원래 별명 명령문 에서 정확히 두 개의 명령문이 더 실행됩니다.

  • [statement A] 항상 실행
  • [statement B]경우 실행 [statement A]이었다 성공
  • [statement C]경우 실행 [statement A]했다 실패

명령문 A, B 및 C는 항상 느리게 실행됩니다 . 즉, 실행시 즉시 평가됩니다.

실행이 완료되면, 별명 지정된 명령은 명령문 B 또는 C 와 동일한 성공 또는 실패 플래그로 플래그 가 지정 됩니다 (실행 된 명령 중 하나) . ( 별명 문장 자체는 내부에서 발생할 수 없으므로 플래그를 지정할 필요가 없습니다.)

별명 예 1

변수를 frog두 번 증가시키는 새로운 명령을 원한다고 가정 해보십시오 . 이 별명은 다음을 달성합니다.

a increment_frog_twice
 i frog
 i frog
 d frog

명령문 A ( i frog)는 항상 실행되고 항상 성공으로 플래그 지정 되므로 명령문 B ( i frog)도 항상 실행 frog 되므로 변수 는 2 씩 증가합니다. 명령문 B는 항상 실행되고 B는 항상 a이므로 increment_frog_twice명령은 항상 성공으로 플래그됩니다 성공 . 명령문 C ( d frog)는 실행되지 않습니다.

출력은

a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog

될 것이다

frog = 0
frog = 2

그래서 우리는이 예제를 일반화 할 수 있는 변수가 앨리어스 명령을 인수함으로써 두 배 증가 할 수 있습니다.

별칭 문 내 에서 양의 정수 1, 2, 3 등은 별칭 명령에 전달 된 1, 2, 3 등의 인수를 나타냅니다. (이 인수는 일반 변수이거나 변수 자체에 대한 참조 일 수 있습니다.)이 숫자는 별명 명령문 의 명령문 A, B 및 C의 인수 내에서만 나타날 수 있습니다 . 그들이 다른 곳에 나타나는 것은 의미가 없습니다.

별명 예 2

이것은 마지막 예제를 일반화합니다. 전달 된 모든 변수는 전달 된 첫 번째 인수에 대한 참조 increment_twice이므로 2 씩 증가합니다 1.

a increment_twice
 i 1
 i 1
 d 1 #never reached
p toad
increment_twice toad
p toad

이 프로그램의 출력은

toad = 0
toad = 2

그런 다음 두 개의 인수를 사용하여 두 명령을 increment_twice모두 호출하는 다른 명령의 별명을 지정할 수 있습니다.

a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck

여기서 출력은

platypus = 2
duck = 2

앨리어싱 된 명령은 재귀적일 수 있다는 점을 명심해야합니다. 예를 들어, 전달 된 변수를 0으로 설정하는 명령을 만들 수 있습니다.

별명 예 3

set_to_zero명령은 하나의 인수를 사용하여 변수를 0으로 설정하고 완료되면 성공으로 표시됩니다.

a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx

이 프로그램의 출력은

oryx = 3
oryx = 0

일어나는 일은 성공적으로 set_to_zero oryx실행되면 3에서 2로 d 1성공적으로 감소 oryx한 다음 다시 set_to_zero 1호출하는 것과 같습니다 set_to_zero oryx. 따라서 프로세스는 실패d 1 가 될 때까지 반복 되어 재귀를 중지하고 변수를 증가시켜 성공 합니다._dummy_


도전

위에서 설명한대로 정확하게 Prindeal 코드를 실행할 수있는 프로그램을 작성하십시오. 표준 코드, 명령 행 또는 텍스트 파일을 통해 Prindeal 코드를 가져옵니다. Prindeal 프로그램의 출력물을 stdout 또는 가장 가까운 언어로 인쇄하십시오.

또는 코드를 문자열로 받아서 출력 문자열을 인쇄하거나 반환하는 함수를 작성할 수 있습니다.

또한 다음과 같이 가정 할 수 있습니다.

  • 입력 Prindeal 코드에는 줄 바꿈 및 인쇄 가능한 ASCII 만 포함 되며 선택적으로 빈 줄로 끝납니다.
  • 입력 코드는 유효한 Prindeal이며 형식이 정확하고 구문 적으로 정확합니다.
  • 코드를 실행하면 정의되지 않은 명령이나 제공되지 않은 인수에 대한 무한 루프 나 유효하지 않은 참조가 생성되지 않습니다.
  • 명령 이름은 p, i, d, 및 a이상 별명되지 않습니다. 변수에 이러한 이름이 없다고 가정 하지 않을 수 있습니다 .

또한 약 1000 미만의 숫자 만 테스트되므로 변수 값이 실제로 임의의 정밀도가 아닌지 여부는 중요하지 않습니다. 아래의 테스트 프로그램이 작동하는 한 더 복잡한 Prindeal 프로그램이 발생할 수있는 언어에 Python 과 같은 재귀 제한이 있으면 괜찮습니다 .

테스트 프로그램

다음은 더미 변수 ( _규칙으로 시작 )와 많은 도우미 별명을 사용하여 더하기, 곱하기 및 지수화 작업을 작성하는 대규모 Prindeal 프로그램입니다 .

#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C

(이 코드를 가지고 놀고 있다면 같은 변수가 인수로 여러 번 주어지면 많은 명령이 실패한다는 것을 알고 있습니다. 이것은 쉽게 고칠 수 있지만 결과 코드는 더 길다.)

Prindeal 통역사가 정확한 결과를 산출 할 수 있어야합니다.

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

채점

바이트 단위의 가장 짧은 코드가 이깁니다. Tiebreaker는 이전 제출로 이동합니다.

브라우니 보너스 : Prindeal에서 멋진 프로그램을 작성하십시오. 덧셈과 곱셈을 구현했습니다. 뺄셈이나 나눗셈을 할 수 있습니까?


오, 일단 Pyth를 내버려두고 Lisp를 꺼낼 것 같아요! 하나의 질문-함수와 변수는 완전히 다른 네임 스페이스에 존재합니다. 그래서을 증가시킨 p다음 p p1을 인쇄 할 수 있습니다.
orlp

@orlp 맞습니다. (거기에 대한 몇 가지 메모가 있습니다.)
Calvin 's Hobbies

2
언어 이름을 볼 때 PRNDL을 생각하는 유일한 사람은 될 수 없습니다.
Downgoat

앨리어싱 된 명령에 전달 될 최대 개수의 인수가 있습니까?
Zach Gates

@ZachGates Nope
캘빈의 취미

답변:


9

Pyth, 162 136 바이트

JfTmchcd\#).zKHW<ZlJI!e=T@J~+Z1=@Tk)=k0 .x=J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0,=Y.x@H=eT0?qN\pps[Td\=dYb)?xGN?qN\iXHThY?YXTH_1=k1XKT:JZ=+Z3

데모.

변수를 인라인 I하고 E제어 흐름 ?과 제어 흐름을 기반으로 제어 흐름을 변경하여 26자를 골라냅니다 .x.

처음으로 Pyth의 변수가 부족했습니다. Pyth ( bdkGHNTYJK)의 모든 단일 변수가 사용 중이며 b줄 바꿈 으로 사용 하고 싶었습니다 . 다행스럽게도 저는 N프로그램의 다른 부분에서 완전히 다른 두 가지를 의미하는 데 사용할 수 있었으므로 여전히 작동합니다.

ungolfed (-m으로 실행) :

JfTmchcd\#).z
KH
W<ZlJ
  I!e=T@J~+Z1
    =@Tk)
  =k0
     .x
      =J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0
      ,
        =Y.x@H=eT0
        ?qN\p
          ps[Td\=dYb)
          ?xGN
            ?qN\i
              XHThY
              ?Y
                XTH_1
                =k1
            XKT:JZ=+Z3

3
나는 아직도 그것도 ungolfed와 어떻게하는지 말할 수없는 방법을 사랑합니다 ...
Jerry Jeremiah

글쎄, 그 결론 Pyth은 ... 비 튜링 - 완료
에릭 Outgolfer

8

Python 2, 600 584 397 373 바이트

이것은 내 자신의 골프 기준 솔루션입니다. 귀속이 제공되는 한 누구나 개선하거나 자체 답변에서 논리를 따를 수 있습니다.

그것에 대한 좋은 부분은 재귀가 수행되지 않으므로 파이썬의 재귀 제한에 아무런 문제가 없다는 것입니다. 예를 들어 Sp의 Countup Prindeal 프로그램은 무기한으로 실행될 수 있습니다.

p=filter(len,[l.split('#')[0].split()for l in input().split('\n')]);m={};v={};i=0
while i<len(p):
 s=p[i]
 if'('in`s`:s=s[f]
 n,f=s[0],0
 if n in m:a,b,c=([s[int(g)]if g.isdigit()else g for g in t]for t in m[n]);p=[a,(b,c)]+p[i+1:];i=0;continue
 s=s[1]
 q=v.get(s,0)
 if'd'>n:m[s]=p[i+1:i+4];i+=3
 elif'i'<n:print s,'=',q
 elif'd'<n:v[s]=q+1
 elif q:v[s]-=1
 else:f=1
 i+=1

개행이 이스케이프 된 인용 된 프로그램 문자열을받는 프로그램입니다 (예 :)
'p _MyVariable_321\np screaming_hairy_armadillo'.

Sp 'sPietu의 답변 에서 다양한 골프 신호를 받았습니다 . 고마워요 :)


6

파이썬 3, 345 336 335 328 바이트

a=0
A={}
V={}
def f(l):
 if l[0]in"d p i":c,u=l;U=V[u]=V.get(u,0)+"pi".find(c);S=U<0;V[u]+=S;c<"p"or print(u,"=",U)
 else:d=lambda q:[w.isdigit()and l[int(w)]or w for w in A[l[0]][q]];S=f(d(1+f(d(0))))
 return S
for z in open("P"):
 l=z.split("#")[0].split()
 if"a "==z[:2]:a,s,*x=3,l[1]
 elif l*a:x+=l,;a-=1;A[s]=x
 elif l:f(l)

(@orlp 덕분에 6 바이트)

아직도 골프. 프로그램이라는 파일에 저장되어 있다고 가정합니다 P.

호출을 f람다 안에 넣으면 d몇 바이트가 절약되지만 마지막 테스트 사례는 최대 재귀 깊이에 도달합니다.

일부 Prindeal 프로그램

쓸모없는 빼기 프로그램

쓸모없는 빼기 프로그램 은 다음과 같습니다 . 제대로 빼더라도 성공 / 실패를 반환하지 않기 때문에 쓸모가 없습니다.

출력은 다음과 같아야합니다.

a = 15
b = 6
__________ = 0
a = 9
b = 6

카운트 업

a helper
 p 1
 countup 1
 i success

a countup
 i 1
 helper 1
 d failure

countup n

위로 세어 n영원히 인쇄합니다 . 인터프리터 속도 테스트로 작동 할 수 있습니다 (키보드 인터럽트의 긴 역 추적에주의하십시오).


2
이 질문에 대한 모든 사람들이이 골프를 놓쳤습니다. 왜 그런지 모르겠습니다. l[:(l+"#").find("#")]모든 변형은 간단한 것으로 대체 할 수 있습니다 l.split('#')[0].
orlp

@orlp는 너무 집중되어 있었기 때문에 s가 없어도 find할 수 없었습니다. 감사합니다 :)split#
Sp3000

6

자바 스크립트 (ES6), 273 (258)

수정 된 버그를 수정하고 실제 테스트 스위트를 추가했습니다.

선행 공백과 줄 바꿈은 포함하지 않습니다.

확실히 조금 더 골프를 칠 수 있습니다.

설명을 작성하기에 너무 피곤해, 나는 임시 값 (매개 변수)을 유지하기 위해 클로저를 사용하는 좋은 예라고 생각합니다.

EcmaScript 6 호환 브라우저에서 스 니펫 실행 테스트 (특히 MSIE가 아닌 Chrome이 아닙니다. Firefox에서 테스트 한 경우 Safari 9로 이동 가능)

F=p=>(
  p=p.match(/^[^#\n]+/gm).filter(r=>r.trim(o='',v=[])),
  s={
    '':_=>1,
    p:a=>o+=a+` = ${v[a]||0}\n`,
    i:a=>v[a]=-~v[a],
    d:a=>v[a]&&v[a]--,
    a:(n,j)=>s[n]=(u,t,a)=>x(p[!x(p[j+1],0,a,1)+j+2],0,a,1)
  },
  p.map(x=(r,i,w,l,a=r.split(/ +/).slice(l).map(x=>-x?w[x]:x))=>s[a[0]](a[1],i,a)),
  o
)

// TEST

$('#O tr').each(function() {
  var $cells = $(this).find('td')
  var prg = $cells.eq(0).text()
  console.log(prg)
  var output = F(prg)
  $cells.eq(1).text(output)
})
#O td { vertical-align:top; white-space: pre; border: 1px solid #888; font-family:monospace }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr><th>Program</th><th>Outpout</th></tr>
<tbody id=O>  
<tr><td>p _MyVariable_321
p screaming_hairy_armadillo</td><td></td></tr>
<tr><td>i alpaca
p alpaca
i alpaca
p alpaca</td><td></td></tr>
<tr><td>i malamute
p malamute
d malamute    #success
p malamute
d malamute    #failure
p malamute
d akita       #failure
p akita</td><td></td></tr>
<tr><td>a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog</td><td></td></tr>
<tr><td>a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck</td><td></td></tr>
<tr><td>a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx</td><td></td></tr>
<tr><td>#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C  
</td><td></td></tr>
</tbody>
</table>


테스트 프로그램에 주석을 더 추가했는데 코드가 작동하지 않는 것처럼 보입니다.
Calvin 's Hobbies

@ Calvin'sHobbies 최초의 빠른 패치
edc65

3

C # 6, 653 바이트

파이썬 바다 속에 내 입장이 있습니다 ...

class P{string[]l;string r="";Dictionary<string,int>v=new Dictionary<string,int>();Dictionary<string,int>s=new Dictionary<string,int>();public string R(string t){l=t.Split('\n');for(int i=0;i<l.Length;i++){var z=l[i].Split(' ');if(z[0]=="a"){s.Add(z[1],i);i+=3;}else E(i, null);}return r;}bool E(int n,string[]p){var z=l[n].Split(' ');var a=z.Skip(1).Select(x=>Char.IsDigit(x[0])?p[int.Parse(x)-1]:x).ToArray();if(a.Length>0&&!v.ContainsKey(a[0]))v[a[0]]=0;if (z[0]=="p")r+=$"{a[0]} = {v[a[0]]}\n";else if(z[0]=="i")v[a[0]]++;else if(z[0]=="d")if(v[a[0]]>0)v[a[0]]--;else return false;else{var y=s[z[0]];return E(y+1,a)?E(y+2,a):E(y+3,a);}return true;}}

확장 및 의견 :

class Prindeal
{
    string[] lines;
    string result = "";
    Dictionary<string, int> variables = new Dictionary<string, int>();
    Dictionary<string, int> statements = new Dictionary<string, int>();

    public string Run(string text)
    {
        lines = text.Split('\n');

        for (int i = 0; i < lines.Length; i++)
        {
            // Split on spaces to get the statement and any arguments
            var z = lines[i].Split(' ');

            // Are we defining a new statement?
            if (z[0] == "a")
            {
                // Add to the statements dictionary, step over definition statements
                statements.Add(z[1], i);
                i += 3;
            }
            else
            {
                // Execute the statement
                Execute(i, null);
            }
        }

        return result;
    }

    bool Execute(int lineNumber, string[] parameters)
    {
        // Split on spaces to get the statement and any arguments
        var z = lines[lineNumber].Split(' ');

        // Parse the arguments - if it's a number, get the corresponding 
        // parameter from the calling statement
        var arguments = z.Skip(1).Select(
            x => Char.IsDigit(x[0]) ? 
            parameters[int.Parse(x) - 1] : 
            x)
            .ToArray();

        // If the first argument isn't already in the variables dict, add it
        if (arguments.Length > 0 && !variables.ContainsKey(arguments[0])) variables[arguments[0]] = 0;

        // Print statement, using string interpolation
        if (z[0] == "p")
            result += $"{arguments[0]} = {variables[arguments[0]]}\n";
        // Increment statement
        else if (z[0] == "i")
            variables[arguments[0]]++;
        // Decrement statement
        else if (z[0] == "d")
            if (variables[arguments[0]] > 0)
                variables[arguments[0]]--;
            else
                return false;
        else
        {
            // Get the line number to jump to
            var y = statements[z[0]];

            // Execute A ? B : C
            return Execute(y + 1, arguments) ? Execute(y + 2, arguments) : Execute(y + 3, arguments);
        }

        // If we reach this point, it's from a 'p', 'i' or 'd' statement which has succeeded
        return true;
    }
}

이를 사용하려면 클래스를 인스턴스화하고 메소드를 호출하십시오 ( R()예 :

string prindealText = new StreamReader("prindeal.txt").ReadToEnd();
Console.WriteLine(new P().R(prindealText));

3

일반적인 Lisp, 758 646 619

(progn(set-macro-character #\#(get-macro-character #\;))(setf(readtable-case *readtable*):invert)(#3=defun v(s)(if(boundp s)(eval s)0))(#3# i(s)(set s(1+ (v s))))(#3# d(s)(and(plusp(v s))(set s(1-(v s)))))(#3# p(s)(format t"~A = ~A~%"s(v s)))(defmacro a(n . p)`(#3#,(cadr n)(&rest g)(if,@p)))(#3# k(s)(typecase s(integer`(nth,(1- s)g))(symbol `',s)(t(list*(car s)(mapcar 'k(cdr s))))))(#3# r()(prog(l p q)$(setf p()l(make-string-input-stream(or(read-line()()())(return))))@(when(setf p(read l()()))(push p q)(go @))(if q(return(k(reverse q)))(go $))))(do ((x(r)(r)))((not x))(eval(if(eq(car x)'a)`(,@x,(r),(r),(r))x))))

이것을 file.lisp넣고 예를 들어 sbcl --script file.lisp; 입력은 표준 입력 스트림에서 읽습니다.

이 버전 은 Prindeal 의 상위 집합 을 구문 분석합니다 . 별다른 어려움없이 Prindeal 소스에서 모든 Common Lisp에 액세스 할 수 있습니다. 나는 이것을 통역사 의 특징 으로 생각합니다 .

댓글 버전

;; copy-readtable is only used during development, so that I do not 
;; mess with my running environment. The real code starts with the
;; progn below, which is superfluous of course inside a let.
(let ((*readtable* (copy-readtable)))

  ;; I use PROGN in the golfed version so that I can have the whole
  ;; program as a unique tree. This allows me to define reader 
  ;; variables like #3=defun in order to gain a few bytes by writing
  ;; #3# instead of defun. Reader variables are removed in
  ;; this human-friendly version.
  (progn
    ;; Let # point to the same reader function as ;
    ;; Of course, ; is still usable as a comment delimiter
    (set-macro-character #\#
                         (get-macro-character #\;))

    ;; :invert does what is necessary to enable case-sensitive reading
    ;; and printing of symbols
    (setf (readtable-case *readtable*) :invert)

    ;; value of symbol, or zero
    (defun v(s)(if(boundp s)(eval s)0))

    ;; increment
    (defun i(s)(set s(1+ (v s))))

    ;; decrement
    (defun d(s)(and(plusp(v s))(set s(1-(v s)))))

    ;; print
    (defun p(s)(format t"~A = ~A~%"s(v s)))

    ;; alias: wrap an "if" inside a "defun".
    ;; YES, that means you can redefine ANY lisp function with "a" !
    ;; A safer version would properly intern symbols in a dedicated package.
    ;;
    ;; Notice the G variable.  We take advantage of the "unhygienic"
    ;; (what a bad adjective) nature of macros to create a context
    ;; where G is bound to the argument list. The same G is referenced
    ;; implicitely later.
    (defmacro a(n . p)`(defun,(cadr n)(&rest g)(if,@p)))

    ;; Canonicalize expressions:
    ;;
    ;; - if s is a symbol, return s quoted. All functions manipulate
    ;; symbols in order to allow the undeclared use of variables. With
    ;; symbols, we can check for boundness.
    ;;
    ;; - if s is an integer, then we are inside an alias definition. The
    ;; integer is replaced by an access to the s'th element of the
    ;; implicit argument list G using (nth (1- s) g). G will be bound
    ;; when the expressions is injected in the defun corresponding to
    ;; the alias, or else an error will be signaled: either because G
    ;; is unbound, or because you defined a variable named G which is
    ;; by construction not a list. Since we do not sanitize properly
    ;; the input, you could bind G globally to a list, but that would be
    ;; nasty.
    ;; 
    ;; - Finally, if s is a list, apply k to all but the first
    ;; elements of s.  The first element is a symbol but we do not
    ;; need to quote it because we want to call the function
    ;; associated with the symbol. Due to the Lisp-2-ness
    ;; of Common Lisp, functions and variables can coexist
    ;; with the same name.
    ;;
    (defun k(s)(typecase s
                 (integer`(nth,(1- s)g))
                 (symbol`',s)
                 (t(list*(car s)(mapcar #'k(cdr s))))))

    ;; Reader function
    (defun r()
      (prog (l ; current line, as an input-stream reading a string
             p ; current read form
             q ; whole line and return value, as a list
             )

         ;; PROG includes an implicit TAGBODY. Below, $ and @ are
         ;; labels for GO statements (gotos).

       $ (setf
          ;; emtpy p
          p ()

          ;; Read a whole line and if we do not fail, build an input
          ;; stream to read from it.
          l (make-string-input-stream
             (or (read-line()()()) ;; try to read a line,
                 (return)          ;; but return from prog if we reach
                                   ;; the end of file.
                 )))
       @ (when (setf p (read l()()))
           ;; Read a lisp expression, put it in p and if p is not nil
           ;; push it into q.  A nil could happen at the end of the
           ;; line or if someone (you know who) inserted an empty list
           ;; in the file being read.
           ;; 
           ;; Thanks to the readtable which now handles comments
           ;; and spaces for us, nothing needs to be done here to
           ;; preprocess the input.

           (push p q) (go @))

         ;; If we read an empty line, q can be nil. In this case, go
         ;; back to $ and read another line. If q is not nil, reverse
         ;; it (we pushed, remember), canonicalize it and return the
         ;; result.
         (if q (return(k(reverse q))) (go $)))
      )

    ;; Read/eval loop.  When reading "(a name)", we read the three
    ;; next lines and append them to the first so that it builds a
    ;; call the the alias definition macro a. Otherwise, just eval x.
    (do((x(r)(r))((not x))
      (eval (if (eq(car x'a))
                `(,@x,(r),(r),(r))
                x)))))

~$ sbcl --script file.lisp < testfile

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

우리는 교체하는 경우 evalprint 읽기 / 평가 루프에서, 우리는 평가되고있는 것을 볼 수 있습니다 :

(a 's (i '_) (d '_) (d '_)) 
(a 'f (d '_) (d '_) (d '_)) 
(a 'z (d (nth 0 g)) (z (nth 0 g)) (s)) 
(a 'n (z (nth 0 g)) (i (nth 0 g)) (s)) 
(a 'move (moveH (nth 0 g) (nth 1 g)) (move (nth 0 g) (nth 1 g)) (s)) 
(a 'moveH (d (nth 0 g)) (i (nth 1 g)) (f)) 
(a 'dupe (dupeH1 (nth 0 g) (nth 1 g) (nth 2 g))
   (dupe (nth 0 g) (nth 1 g) (nth 2 g)) (s)) 
(a 'dupeH1 (d (nth 0 g)) (dupeH2 (nth 1 g) (nth 2 g)) (f)) 
(a 'dupeH2 (i (nth 0 g)) (i (nth 1 g)) (s)) 
(a 'copy (z (nth 1 g)) (copyH (nth 0 g) (nth 1 g)) (s)) 
(a 'copyH (dupe (nth 0 g) (nth 1 g) '_copy) (move '_copy (nth 0 g)) (s)) 
(a 'addTo (copy (nth 1 g) '_add) (move '_add (nth 0 g)) (s)) 
(a 'add (z (nth 0 g)) (addH (nth 0 g) (nth 1 g) (nth 2 g)) (s)) 
(a 'addH (addTo (nth 0 g) (nth 1 g)) (addTo (nth 0 g) (nth 2 g)) (s)) 
(a 'mul (mulH1 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 2 g)) (s)) 
(a 'mulH1 (z (nth 0 g)) (copy (nth 1 g) '_mul) (s)) 
(a 'mulH2 (mulH3 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'mulH3 (d '_mul) (addTo (nth 0 g) (nth 1 g)) (f)) 
(a 'mulBy (mul '_mulBy (nth 0 g) (nth 1 g)) (copy '_mulBy (nth 0 g)) (s)) 
(a 'pow (powH1 (nth 0 g) (nth 2 g)) (powH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'powH1 (n (nth 0 g)) (copy (nth 1 g) '_pow) (s)) 
(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'powH3 (d '_pow) (mulBy (nth 0 g) (nth 1 g)) (f)) 
(p 'A) 
(p 'B) 
(p 'C) 
(n 'A) 
(n 'B) 
(add 'C 'A 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(add 'B 'A 'C) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(mul 'd 'B 'C) 
(p '____) 
(p 'd) 
(mulBy 'd 'B) 
(p '____) 
(p 'd) 
(d 'A) 
(mulBy 'd 'A) 
(p '____) 
(p 'd) 
(pow 'A 'C 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(pow 'A 'B 'C) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(pow 'C 'A 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C)

매크로 확장

다음과 같은 별칭 정의를 선택하면

(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s))

... g어휘 범위에서 찾을 수없는 이름의 변수에 대한 참조를 볼 수 있습니다 . 그러나 macroexpansion 후 실제 코드는 다음과 같습니다.

(defun powH2 (&rest g)
  (if (powH3 (nth 0 g) (nth 1 g))
      (powH2 (nth 0 g) (nth 1 g))
      (s))) 

이제 g정의 할 함수의 인수 목록을 참조하십시오.


2

파이썬 2, 486 바이트

이것이 내가 더 골프를 치는 참조 솔루션입니다 (현재 -98 바이트).

import sys;sys.setrecursionlimit(2000)
def r(s):
 n=s[0]
 if n in A:f=lambda i:r([s[int(t)]if'0'<t[0]<':'else t for t in A[n][i]]);return f(1+(f(0)or 0))
 k=s[1]
 if'i'<n:print k,'=',V.get(k,0)
 elif'd'<n:V[k]=-~V[k]if k in V else 1
 elif'a'<n:
    if~-(k in V)or V[k]<1:return 1
    V[k]-=1
 else:A[k]=s[2:]
A={};V={};c=filter(bool,([l,l[:l.find('#')]]['#'in l]for l in input().split('\n')))
while c:
 s=c[0].split();c=c[1:]
 if'a'!=s[0]:r(s)
 else:r(['a',s[1]]+map(str.split,c[:3]));c=c[3:]

변경 사항 (내가 기억하는) :

  • 자동 부울 정수 변환 ([l,l[:l.find('#')]]['#'in l] ).
  • 한 문장에서 설정 또는 증가V[k]=-~V[k]if k in V else 1 )
  • 더 긴 표현식에 대한 더 많은 별칭 (k=s[1] )
  • 메인 루프에 카운터가 없으며 대신 입력 목록을 지 웁니다.
  • print공백 자동 추가 ( print k,'=',V.get(k,0))
  • 확인 숫자 1-9 ( '0'<t[0]<':')
  • s r를 저장하기 위해 주변 의 반환 값을 뒤집기return
  • 슬라이싱 및 분할 반복 제거 ( map(str.split,c[:3])))

1

파이썬 3, 1322 바이트

골프 :

import re,sys;sys.setrecursionlimit(2000);F,L=filter,list
class P:
 N,O,F=0,{},{}
 def __init__(S,c):
  S.B,S.E={"p":S.P,"i":S.I,"d":S.D,"a":S.L},dict(enumerate(F(None,[i.split('#')[0].rstrip()for i in c.splitlines()])))
  while S.N in S.E:S.X(S.E[S.N])
 def V(S, v, y, z=0):
  if re.match("[\w_][\d\w_]*",v):
   if not v in y:
    if z is not None:y[v]=z
    else:return False
   return True
  return False
 def A(S):S.N+=1
 def P(S,v):
  if S.V(v,S.O):print("{0} = {1}".format(v, S.O[v]));return True
  return False
 def I(S,v):
  if S.V(v, S.O):S.O[v]+=1;return True
  return False
 def D(S,v):
  if S.V(v,S.O)and S.O[v]>0:S.O[v]-=1;return True
  return False
 def L(S,v):
  e=[]
  if S.V(v,S.F,e):
   for i in range(3):S.A();e.append(S.E[S.N].lstrip())
   return True
  return False
 def C(S,c,v):
  def R(Z,v):
   for i in re.findall("\s(\d+)", Z):Z=Z.replace(" %s"%i," %s"%v[int(i)-1])
   return Z
  Q,m,f=map(lambda l:R(l,v),S.F[c])
  if S.X(Q,False):return S.X(m,False)
  return S.X(f,False)
 def X(S,Z,C=True):
  u=re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?",Z)
  if u:
   c,v=map(lambda i:''if i is None else i,u.groups());v=L(F(None,v.split(' ')))
   if S.V(c,S.F,None):
    T=S.C(c, v)
    if C:S.A()
   elif S.V(c,S.B,None):
    T=S.B[c](*v)
    if C:S.A()
   else:return False
   return T
  return False

언 골프 드 :

import re

class Prindeal:
    iline = 0
    local = {}
    udef = {}
    content  = {}

    def __init__(self, c):
        self.built = {
            "p": self.print,
            "i": self.increment,
            "d": self.decrement,
            "a": self.alias,
        }
        self.content = dict(enumerate(filter(None, [i.split('#')[0].rstrip()for i in c.splitlines()])))
        while self.iline in self.content:
            self.execute_line(self.content[self.iline])

    def validate_name(self, varname, stack, default=0):
        if re.match("[\w_][\d\w_]*", varname):
            if not varname in stack:
                if default is not None:
                    stack[varname] = default
                else:
                    return False
            return True
        return False

    def advance_stack(self):
        self.iline += 1

    def print(self, varname):
        if self.validate_name(varname, self.local):
            print("{0} = {1}".format(varname, self.local[varname]))
            return True
        return False

    def increment(self, varname):
        if self.validate_name(varname, self.local):
            self.local[varname] += 1
            return True
        return False

    def decrement(self, varname):
        if self.validate_name(varname, self.local) and self.local[varname] > 0:
            self.local[varname] -= 1
            return True
        return False

    def alias(self, aliasname):
        indexed_lines = []
        if self.validate_name(aliasname, self.udef, indexed_lines):
            for i in range(3):
                self.advance_stack()
                indexed_lines.append(self.content[self.iline].lstrip())
            return True
        return False

    def execute_alias(self, cmd, variables):
        def parse_args(line, variables):
            for i in re.findall("\s(\d+)", line):
                line = line.replace(" %s" % i, " %s" % variables[int(i) - 1])
            return line
        init, success, failure = map(lambda l: parse_args(l, variables), self.udef[cmd])
        if self.execute_line(init, False):
            return self.execute_line(success, False)
        return self.execute_line(failure, False)

    def execute_line(self, line, cont=True):
        valid_execution = re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?", line)
        if valid_execution:
            cmd, variables = map(lambda i: '' if i is None else i, valid_execution.groups())
            variables = list(filter(None, variables.split(' ')))
            if self.validate_name(cmd, self.udef, None):
                temp = self.execute_alias(cmd, variables)
                if cont:
                    self.advance_stack()
            elif self.validate_name(cmd, self.built, None):
                temp = self.built[cmd](*variables)
                if cont:
                    self.advance_stack()
            else:
                return False
            return temp
        return False

용법:

P(c)

c텍스트 내용은 어디에 있습니까 ?

예 :

한 줄 문자열이 허용됩니다.

  • P("p cat")
  • P("p dog\ni dog\np dog")

여러 줄로 된 문자열도 허용됩니다.

P("""
p dog
i dog
p dog
""")

또는:

P("""p dog
i dog
p dog""")

기타.

노트:

이것은 모든 테스트 사례에서 올바르게 작동하지만 다음의 재귀 한계에 도달합니다.

pow C A B   #C = A ^ B = 9 ^ 3 = 729

따라서 sys.setrecursionlimit(2000).


1
일부 바이트를 사용하지만 sys.setrecursionlimit ()를 사용하여 pow 별칭으로 올바르게 작동하지 않습니까?
Corwin

나는 할 수 있지만 OP는 재귀 제한이있는 파이썬과 같은 언어는 그대로 받아 들여 진다고 언급했다. 그러나 OP에서 요청하면 수정 프로그램을 추가합니다. @ Corwin
Zach 게이츠

충분합니다. 사양에서 그것을 놓쳤다. @ZachGates
Corwin

1

파이썬 -695 688 바이트

def p(v):print v,"=",w.get(v,0)
def i(v):w[v]=w.get(v,0)+1
def d(v):
 if v in w:
<TAB>w[v]-=1
<TAB>if not w[v]:del w[v]
 else:return 1
def a(n,b,d,h):
 def g(*a):
<TAB>i=1;f=b;s=d;t=h
<TAB>for v in a:v=q+v+q;k=q+j(i)+q;f=c(f,k,v);s=c(s,k,v);t=c(t,k,v);i+=1
<TAB>y=u(t,e)if u(f,e)else u(s,e);i=1;return y
 e[n]=g
q="'";w=x={};u=eval;e={'a':a,'d':d,'i':i,'p':p};import sys;l=sys.stdin.readlines();r="";j=str;c=j.replace;sys.setrecursionlimit(2000)
for h in l:
 h = h.strip()
 if not h:continue
 l = h.split();f=l[0];n=f+"("
 if "#" in f:continue
 for g in l[1:]:
<TAB>b=g.find("#")+1
<TAB>if b:g=g[:b-1]
<TAB>if g:n+="'%s',"%g
<TAB>if b:break
 if x:x-=1;d+='"%s)",'%n
 else:x=(f=="a")*3;d=n
 if not x:d+=")\n";r+=d
exec r in e

<TAB> 리터럴 탭 문자입니다.


1

C ++, 1111 바이트

이것은 C ++입니다-내가 할 수있는 것처럼 관용적입니다.
즉, 더 C ++로하고 덜 C ish로 만드는 것을 의미합니다.
그것은 또한 동등한 C 프로그램보다 크다는 것을 의미합니다.
C ++이 자세한 표준 라이브러리에서 Java와 경쟁한다고 생각합니다.
VS2013 및 g ++ 4.9.2로 컴파일됩니다 (-std = c ++ 11 사용)

#include<array>
#include<iostream>
#include<map>
#include<regex>
#include<sstream>
#include<stack>
#define B std::
#define a first
#define b second
#define c(s);else if(x.a==s)
#define d(n)B getline(B cin,r##n)
#define e(n)r##n=B regex_replace(r##n,q,"$1");
#define f(n)do{d(n);e(n)}while(r##n.empty());
#define g B string
#define h B istream_iterator<g>
#define i p.top().a
#define j p.empty()
#define k B pair
#define u continue;
#define w B back_inserter
typedef B vector<g>s;typedef B array<g,3>A;typedef k<k<long,A>,s>t;B map<g,A>m;B map<g,long>n;B stack<t>p;B regex q("^ *(.*?) *(#.*)?$");int main(){g r0,r1,r2,r3;while(d(0)){e(0)if(r0.empty())u p.push(t{{0,{{r0,"",""}}},{}});bool z;while(!j){k<g,s>x;B istringstream ss(i.b[i.a]);ss>>x.a;B copy(h(ss),h(),w(x.b));s o;B transform(B begin(x.b),B end(x.b),w(o),[](g y){int v=atoi(y.c_str());return v>0?p.top().b[v-1]:y;});z=true;if(0)c("")c("p")B cout<<o[0]<<" = "<<n[o[0]]<<B endl c("i")n[o[0]]++c("d")n[o[0]]-=(z=n[o[0]])c("a"){f(1)f(2)f(3)m.insert(B make_pair(o[0],A{{r1,r2,r3}}));}else{p.push(t{{0,m[x.a]},o});u}while(!j&&i.a)p.pop();if(!j)i.a+=1+!z;}}}

아래는 원본입니다. 누구든지 동시에 관용적이고 짧게 만드는 방법을 생각할 수 있다면 알려주십시오.

#include <array>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <stack>

typedef std::vector<std::string> List;
typedef std::pair<std::string, List> Statement;
typedef std::array<std::string, 3> Alias;
typedef std::pair<long, Alias> IndexedAlias;
typedef std::pair<IndexedAlias, List> Item;

std::map<std::string, Alias> aliases;
std::map<std::string, long> variables;
std::stack<Item> stack;
std::regex re("^ *(.*?) *(#.*)?$");

int main()
{
    std::string line, line1, line2, line3;
    while (std::getline(std::cin, line)) // control-Z to exit
    {
        line = std::regex_replace(line, re, "$1");
        if (line.empty()) continue;
        stack.push(Item{ { 0, { { line, "", "" } } }, {} });

        bool flag;
        while (!stack.empty())
        {
            Statement statement;
            std::istringstream ss(stack.top().first.second[stack.top().first.first]);
            ss >> statement.first;
            std::copy(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>(), std::back_inserter(statement.second));

            List arguments;
            std::transform(std::begin(statement.second), std::end(statement.second), std::back_inserter(arguments),
                [](std::string arg){ int i = atoi(arg.c_str()); return i > 0 ? stack.top().second[i - 1] : arg; });

            flag = true;
            if (statement.first == "")
                ;
            else if (statement.first == "p")
                std::cout << arguments[0] << " = " << variables[arguments[0]] << std::endl;
            else if (statement.first == "i")
                variables[arguments[0]]++;
            else if (statement.first == "d")
                variables[arguments[0]] -= (flag = variables[arguments[0]]);
            else if (statement.first == "a")
            {
                do { std::getline(std::cin, line1); line1 = std::regex_replace(line1, re, "$1"); } while (line1.empty());
                do { std::getline(std::cin, line2); line2 = std::regex_replace(line2, re, "$1"); } while (line2.empty());
                do { std::getline(std::cin, line3); line3 = std::regex_replace(line3, re, "$1"); } while (line3.empty());
                aliases.insert(std::make_pair(arguments[0], Alias{ { line1, line2, line3 } }));
            }
            else
            {
                stack.push(Item{ { 0, aliases[statement.first] }, arguments });
                continue;
            }

            while (!stack.empty() && stack.top().first.first) stack.pop();
            if (!stack.empty()) stack.top().first.first += 1 + !flag;
        }
    }

    std::cout << "-- Variables --" << std::endl;
    std::transform(std::begin(variables), std::end(variables), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, long>::value_type pair){ std::ostringstream ss; ss << pair.first << " = " << pair.second; return ss.str(); });
    std::cout << "-- Aliases --" << std::endl;
    std::transform(std::begin(aliases), std::end(aliases), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, Alias>::value_type pair){ std::ostringstream ss; ss << pair.first << " = [1]:" << pair.second[0] << " [2]:" << pair.second[1] << " [3]:" << pair.second[1]; return ss.str(); });
    std::cout << "---------------" << std::endl;

    return 0;
}

0

하스켈, 1009

나는 골프를하기 위해 최선을 다했다. 내 ungolfed 코드는 3,000자를 넘었습니다. 이 시점에서 나는 모든 기능이 무엇을하고 있는지 기억할 수 없습니다.

import qualified Data.Map as M
import Control.Monad.State.Lazy
import Data.List
type A=M.Map String
data P=P(A Int)(A([String]->StateT P IO Int))
a f=evalStateT f(P M.empty$M.fromList[("i",\(b:_)->(+1)%b),("d",\(b:_)->pred%b),("p",\(b:_)->i b>>= \v->liftIO(putStrLn$b++"="++show v)>>q 1)])
e(k:l)=do{(P v a)<-get;put.P v$M.insert k(m l)a;q 1}
g t s f= \a->t a>>= \b->if b>0then s a else f a
f%k=f<$>i k>>= \v->if v<0then k#0>>q 0else k#v>>q 1
i k=get>>= \(P v _)->q$M.findWithDefault 0 k v
k#v=get>>= \(P b a)->put$P(M.insert k v b)a
l k=get>>= \(P _ a)->q$a M.!k
f s=let(f:a)=r s in($a)<$>l f>>=id
m(t:s:f:_)=g(k t)(k s)(k f)
k s=let(f:b)=r s in\a->($(map((\y z->if all(\c->c>'/'&&c<':')z then y!!(read z-1)else z)a)b))<$>l f>>=id
n=dropWhileEnd(==' ').takeWhile(not.(=='#')).dropWhile(==' ')
o[]=[]
o(l:ls)|(head.r$l)=="a"=(l:take 3 ls):(o$drop 3 ls)|1>0=[l]:o ls
p s|length s>1=e$(n.tail.head$s):tail s|1>0=f.head$s
q=return
main=join$a.(\s->mapM_ p(o.filter(not.null).map n.lines$s))<$>getContents
r=words
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.