**브레인퍽**(Brainfuck)은 우어반 뮐러(Urban Müller)가 1993년 경에 만든 최소주의 컴퓨터 프로그래밍 언어이다. 이름에 포함된 fuck이 욕설이기 때문에 **Brainf\*ck**, **Brainf\*\*\***, 혹은 단순히 **BF**라고 부르기도 한다.

언어의 설계
------

뮐러는 가장 작은 컴파일러로 구현할 수 있는 간단하면서도 튜링 완전한 프로그래밍 언어를 만드는 것이 목적이었다. 이 언어는 여덟 개의 명령어로 구성되어 있다. 아미가 컴퓨터에서 작동하는 원래 컴파일러의 둘째 판은 크기가 240 바이트 밖에 안 된다. 그는 다른 난해한 프로그래밍 언어이자, 컴파일러 크기가 1024바이트인 False의 영향을 받았다.

이름이 말해 주듯이, 브레인퍽 프로그램은 이해하기 어려운 경향이 있다. 하지만 튜링 기계는 컴퓨터가 할 수 있는 모든 작업을 할 수 있고, 브레인퍽이 튜링 완전하기 때문에 브레인퍽 또한 복잡하기는 해도 컴퓨터가 할 수 있는 모든 작업을 할 수 있다.

이 언어는 프로그램 외에, 0으로 초기화된 바이트 단위의 배열과, 처음에 배열의 맨 첫 바이트를 가리키는 포인터, 그리고 입출력 스트림으로 구성된 간단한 기계 모델에 기반을 두고 있다.

### 명령어들

여덟 개의 명령어들은 각각 한 개의 문자로 구성되어 있으며 다음과 같다:

| 문자 | 의미 |
| --- | --- |
| `>` | 포인터를 증가시킨다. |
| `<` | 포인터를 감소시킨다. |
| `+` | 포인터가 가리키는 바이트의 값을 증가시킨다. |
| `-` | 포인터가 가리키는 바이트의 값을 감소시킨다. |
| `.` | 포인터가 가리키는 바이트의 값을 ASCII 문자로 출력한다. |
| `,` | 포인터가 가리키는 바이트에 입력받은 문자의 ASCII 값을 넣는다. |
| `[` | 포인터가 가리키는 바이트의 값이 0이면 짝이 되는 뒤쪽의 `]`로 이동한다. |
| `]` | 포인터가 가리키는 바이트의 값이 0이 아니면 짝이 되는 앞쪽의 `[`로 이동한다. |

위의 정의 대신에, `]`에 ‘짝이 되는 앞쪽의 `[`로 이동한다’는 의미를 사용할 수 있다. 이는 간단하지만 대칭적이지 못 하고 효율적이지도 않다. 이 두 정의는 모든 브레인퍽 프로그램에 대해서 동일한 행동을 보인다. 거의 사용되지 않지만 동일한 또 다른 정의로는, `[`가 ‘짝이 되는 뒤쪽의 `]`로 이동한다’는 의미를 가지고, `]`가 ‘포인터가 가리키는 바이트의 값이 0이 아니면 짝이 되는 앞쪽의 `[` 다음 명령어로 이동한다’는 의미를 가지도록 하는 것이 있다.

브레인퍽 프로그램들은 `ptr`이 `unsigned char*` 형이라 가정할 때 다음과 같은 치환을 사용해서 C 언어로 번역할 수 있다:

| 브레인퍽 | C |
| --- | --- |
|  `>`  |  `++ptr;`  |
|  `<`  |  `--ptr;`  |
|  `+`  |  `++*ptr;`  |
|  `-`  |  `--*ptr;`  |
|  `.`  |  `putchar(*ptr);`  |
|  `,`  |  `*ptr = getchar();`  |
|  `[`  |  `while (*ptr) {`  |
|  `]`  |  `}`  |
|

해설
--

참고로 여기서는 배열의 각각의 원소들을 바이트로 서술했기 때문에, - 명령은 필요가 없으며 255개의 + 명령으로 고칠 수 있다. 비슷하게, 만약 배열이 유한하고 환형이면, < 명령은 (배열 크기 - 1)개의 > 명령으로 고칠 수 있다. 하지만 이 언어가 튜링 완전하려면 배열의 크기와 각각의 원소들의 크기가 모두 제한이 없어야 한다. (이는 엄밀히 말할 때 현대의 PC가 튜링 완전하지 않은 이유와 동일하다.)

예제
--

### 헬로 월드 프로그램

명령어에 쓰이는 8개의 문자(+-<>[],.)만 사용한 코드는 다음과 같다.

```
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

```

브레인퍽은 이 8개의 문자외에는 모두 무시하므로, 가독성을 위해 공백과 줄바꿈을 넣고 주석을 추가하여 다시 쓴 코드는 다음과 같다.

```
+++++ +++++ initialize counter (cell #0) to 10
[ use loop to set the next four cells to 70/100/30/10
 > +++++ ++ add 7 to cell #1
 > +++++ +++++ add 10 to cell #2
 > +++ add 3 to cell #3
 > + add 1 to cell #4
 <<<< - decrement counter (cell #0)
]
> ++. print 'H'
> +. print 'e'
+++++ ++. print 'l'
. print 'l'
+++. print 'o'
> ++. print ' '
<< +++++ +++++ +++++. print 'W'
>. print 'o'
+++. print 'r'
----- -. print 'l'
----- ---. print 'd'
> +. print '!'
>. print '\n'

```

### ROT13

```
-,+[ Read first character and start outer character reading loop
 -[ Skip forward if character is 0
 >>++++[>++++++++<-] Set up divisor (32) for division loop
 (MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero)
 <+<-[ Set up dividend (x minus 1) and enter division loop
 >+>+>-[>>>] Increase copy and remainder / reduce divisor / Normal case: skip forward
 <[[>+<-]>>+>] Special case: move remainder back to divisor and increase quotient
 <<<<<- Decrement dividend
 ] End division loop
 ]>>>[-]+ End skip loop; zero former divisor and reuse space for a flag
 >--[-[<->+++[-]]]<[ Zero that flag unless quotient was 2 or 3; zero quotient; check flag
 ++++++++++++<[ If flag then set up divisor (13) for second division loop
 (MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero)
 >-[>+>>] Reduce divisor; Normal case: increase remainder
 >[+[<+>-]>+>>] Special case: increase remainder / move it back to divisor / increase quotient
 <<<<<- Decrease dividend
 ] End division loop
 >>[<+>-] Add remainder back to divisor to get a useful 13
 >[ Skip forward if quotient was 0
 -[ Decrement quotient and skip forward if quotient was 1
 -<<[-]>> Zero quotient and divisor if quotient was 2
 ]<<[<<->>-]>> Zero divisor and subtract 13 from copy if quotient was 1
 ]<<[<<+>>-] Zero divisor and add 13 to copy if quotient was 0
 ] End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3)
 <[-] Clear remainder from first division if second division was skipped
 <.[-] Output ROT13ed character from copy and clear it
 <-,+ Read next character
] End character reading loop

```