나무모에 미러 (일반/밝은 화면)
최근 수정 시각 : 2024-09-12 18:33:35

브레인퍽

1. 개요2. 명칭3. 명령어4. 메모리 구조5. 예제
5.1. Hello, world!
5.1.1. 해설
5.2. Hello, world! 노가다 출력
6. 구현의 난점7. 기타

1. 개요

BrainFuck

대표적인 난해한 프로그래밍 언어. 1993년 우어반 뮐러가 제작했으며 제작된 파일 확장자는 .b/.bf.

개발 목적은 가장 작은 컴파일러로 구현할 수 있는 튜링 완전[1] 프로그래밍 언어를 만드는 것이었다고 한다. 세상에서 가장 단순하면서 복잡한 언어라는 말이 어울리는 언어로, 프로그래밍에 사용되는 문자는 +-][><,. 로 딱 8개다.

프로그래밍 방법은 엄청나게 난해하지만, 일단 튜링 완전 타입의 언어이기 때문에 이론적으로는 컴퓨터가 할 수 있는 모든 일을 다 할 수 있다. 그리고 컴퓨터의 연산이 작동하는 방법을 이해하고 있다면, 일단 "배우는" 것은 매우 쉽고 단순하다. 실제로 사용하기가 노가다인데다 매우 난해한 게 문제다. 일단은 일반적인 난해한 프로그래밍 언어들이 다 그렇듯이 포인터를 기본으로 한 명령 체계를 사용하고 있으며 명령어들 역시 포인터를 옮기는 명령어들로 구성되어 있다.

2. 명칭

프로그래밍 언어치곤(?) 굉장히 독특하게 이름이 두 단어 이상으로 이루어진 점과 무엇보다 욕설이 들어간다는 점(...)으로도 유명한데, 원래 존재하던 영어 슬랭 속어 중 하나인 'Brainfuck'에서 유래되었다.[2] 단순히 '강간'[3] 정도로 번역하는 경우도 많지만 원래 뜻은 '정신사납게 하다', '(뇌 용량을 초과할 정도로) 혼란스럽게 하다' 정도의 의미이다. 굳이 번역하면 '머리 터질 것 같은', '정신나갈거같애' 정도에 가깝다. 그야말로 이 언어로 프로그래밍하는 사람들의 뇌를 조져버리겠다는 포부를 갖고 있다.

어쨌거나 이름에 fuck이 들어가기 때문에 웬만해선 욕설 필터에 걸리는 경우가 많다. 그러다보니 보통 돌려서 BrainF*** , 또는 약자만 따서 BF(확장자이기도 하다) 등으로 부르는 경우가 많다. 그런데 구글은 검색 자동완성에선 검열되어 brainf***까지만 자동완성이 뜨지만, 일단 검색하고 결과를 보면 대담하게도 대놓고 위키피디아 링크와 함께 brainfuck이라고 띄우는 것을 볼 수 있다.

3. 명령어

> 포인터 증가
< 포인터 감소
+ 포인터가 가리키는 바이트의 값을 증가
- 포인터가 가리키는 바이트의 값을 감소
. 포인터가 가리키는 바이트 값을 아스키 코드 문자로 출력한다.
, 포인터가 가리키는 바이트에 아스키 코드 값을 입력한다. 쉽게 말해서 입력 받는 역할이다.
[ 포인터가 가리키는 바이트의 값이 0이 되면 짝이 되는 ]로 이동한다. 의사코드로는 while(*ptr != 0) {...} 이다.
] 포인터가 가리키는 바이트의 값이 0이 아니면 짝이 되는 [로 이동한다.
EOF(\\0) 문자로 드러나지 않는 토큰이며 프로그램을 종료한다.

이외에 공백, 엔터 등 기타 문자는 모두 처리되지 않는다.[4]

4. 메모리 구조

1바이트 정수(char)로 이루어진 32768개의 배열과 포인터 하나가 메모리의 전부.
따라서 총 메모리 공간은 32KB + 4B이다.
물론 인터프린터의 구현체별로 당연히 차이가 있다. 한 자바 구현체의 경우는 65535개의 포인터가 있는 대신 4바이트가 아닌 1바이트로 처리한다.

5. 예제

5.1. Hello, world!

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

5.1.1. 해설

이 문단에서는 위 프로그램이 어떻게 동작하여 Hello, World!를 출력하는지를 설명한다. 포인터는 처음에 0번 주소를 가리키고 있으며, 모든 메모리의 초기값은 0임을 잊지 말자. 가독성을 위하여 필요한 부분에는 띄어쓰기를 하였다.
그 전에 잠깐 포인터에 대한 설명을 하자면, 포인터는 메모리의 주소를 가리키는 역할을 한다. 포인터가 가리키는 주소와 실제 그 주소의 값은 별개의 값으로 취급해야 함을 명심하자. 예를 들어 포인터가 5번 주소를 가리키고 있다면, 5번 주소의 값은 123 이런식이다.
  1. +++++ +++++
    포인터가 가리키는 주소(0)의 값을 10 증가시켰다. 메모리의 초기값은 0이므로, 최종적으로 포인터가 가리키는 값에 10이 들어간다.
  2. [>+++++ ++ >+++++ +++++ >+++ >+ <<<<
    포인터가 가리키는 주소(0)를 하나씩 증가시키며( > (1) > (2) > (3) > (4) ) 각 주소의 값을 7, 10, 3, 1씩 증가시킨다. 이후 다시 포인터가 가리키는 주소를 0으로 감소시킨다.
  3. -]
    포인터가 가리키는 주소(0)의 값을 1 감소시킨 후, 그 값이 0이 아닐 경우 2.의 [ 로 돌아간다. 즉 10회 루프문이 되며, 메모리의 1~4번째 주소에는 각각 70, 100, 30, 10의 값이 들어가게 된다.
  4. >++ .H
    포인터가 가리키는 주소를 1 증가시키고(1), 주소의 값(=70)에 2를 더한 후(=72) 그 값을 아스키 코드로 출력한다. 72에 대응되는 아스키 코드 문자는 H이다.
  5. >+ . +++++ ++ .. +++ .ello
    포인터가 가리키는 주소를 1 증가시키고(2), 주소의 값(=100)에 1을 더한 후(=101) 한 번 출력, 7을 더한 후(=108) 두 번 출력, 또다시 3을 더한 후(=111) 한 번 출력한다. 101, 108, 108, 111에 대응되는 아스키 코드 문자는 ello이다.
  6. >++++++++++++++.------------.<<+++++++++++++++.>.+++.------.--------.>+., World!
    4~5와 같다. 포인터가 가리키는 주소를 이리저리 바꾸고 그 주소의 값에 숫자를 더하고 빼 가면서 문자를 출력한다. 여기서 , World!가 출력되는 것.

5.2. Hello, world! 노가다 출력

위와는 다르게 이런 식으로 +를 도배해도 출력이 가능하다.
[-] H
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++ .
[-] e
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++ + .
[-] l 2
>++
[<
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++.
[-]
>-]< o
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ +.
[-]
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++.
[-] Space
++++++++++ ++++++++++ ++++++++++ ++.
[-] w
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ +++++++++.
[-] o
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ +.
[-] r
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++.
[-] l
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++.
[-] d
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++
++++++++++ ++++++++++ ++++++++++ ++++++++++ ++++++++++.
[-] !
++++++++++ ++++++++++ ++++++++++ +++.
[-] Lf
++++++++++.
[-]

6. 구현의 난점

다만 너무 명세가 간단하기 때문에, 상세한 내용에 대해서는 구현체를 만드는 개발자들 몫으로 남겨두었다. 대표적으로 구현체를 제작할 때 고민해야 하는 점들은 다음과 같다.

상황이 이렇기 때문에, 굉장히 길고 복잡한 코드라면 브레인퍽 구현체별로 다른 결과가 나오거나 에러가 발생하는 일이 많은 편이다.

7. 기타



[1] 어떤 프로그래밍 언어나 추상 기계가 튜링 기계와 동일한 계산 능력을 가진다는 뜻이다. 튜링 기계는 계산 가능한 모든 함수를 계산할 수 있는 추상적 모델을 말하는데, 쉽게 말해서 이상적인 컴퓨터를 생각하면 된다. 한 가지 태클이 걸릴 점은, 현실 역사에선 튜링 기계란 개념이 나온 뒤에 그 개념에 기초해서 컴퓨터가 나왔다는 것.[2] The language's name is a reference to the slang term brainfuck, which refers to things so complicated or unusual that they exceed the limits of one's understanding, as it was not meant or made for designing actual software but to challenge the boundaries of computer programming. - 위키피디아[3] 왜냐하면 fuck의 의미가 심한 욕설로 기능하지 않고 단순히 '성관계하다'라는 뜻을 비속하게 나타낼 때도 있기 때문이다. 물론 이것도 욕이다 이런경우에서의 fuck은 '따먹다'가 적절한 번역.[4] 이 덕분에 별도의 주석 명령어 없이 그냥 평문을 써도 주석이 되는 셈이다.[5] TMA 산하의 브랜드가 만들었다.