Brainfuck Hello World는 실제로 어떻게 작동합니까?


118

누군가가 나에게 이것을 보냈고 그것이 Brainfuck의 hello world라고 주장했습니다.

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

포인터를 움직이고 물건을 늘리고 줄임으로써 작동하는 기본 사항을 알고 있습니다.

그러나 여전히 알고 싶습니다. 실제로 어떻게 작동합니까? 처음에 화면에 무엇을 인쇄합니까? 텍스트를 어떻게 인코딩합니까? 전혀 이해가 안 돼요 ...


31
이 언어로 작성된 응용 프로그램을 유지하기가 꽤 어려울 것 같습니다 ..
e2-e4

17
@ ring0 : 아뇨, 쓰기 전용 언어입니다.
LetMeSOThat4U 2015 년

실용적인 용도는 무엇입니까?
Yash Kumar Verma

10
@YashVerma는 .. 하나 필요하지 않습니다
미친

49
@YashVerma 언어 명에 명확하게 명시되어 있습니다.
Mateen Ulhaq

답변:


255

1. 기본

Brainfuck을 이해하려면 0각각에 의해 초기화되는 무한한 셀 배열을 상상해야합니다 .

...[0][0][0][0][0]...

brainfuck 프로그램이 시작되면 모든 세포를 가리 킵니다.

...[0][0][*0*][0][0]...

포인터를 오른쪽 >으로 이동하면 포인터를 X 셀에서 X + 1 셀로 이동하는 것입니다.

...[0][0][0][*0*][0]...

셀 값을 늘리면 +다음을 얻습니다.

...[0][0][0][*1*][0]...

셀 값을 다시 늘리면 +다음을 얻습니다.

...[0][0][0][*2*][0]...

셀 값을 줄이면 -다음을 얻을 수 있습니다.

...[0][0][0][*1*][0]...

포인터를 왼쪽 <으로 이동하면 포인터를 X 셀에서 X-1 셀로 이동하는 것입니다.

...[0][0][*0*][1][0]...

2. 입력

문자를 읽으려면 쉼표를 사용 ,합니다. 그것이하는 일 : 표준 입력에서 문자를 읽고 실제 셀에 10 진수 ASCII 코드를 씁니다.

ASCII 테이블을 살펴보십시오 . 예를 들어, 소수점 코드로 !33반면이 a있다 97.

음, BF 프로그램 메모리가 다음과 같다고 상상해 봅시다.

...[0][0][*0*][0][0]...

표준 입력이를 의미한다고 가정하면 a쉼표 ,연산자 를 사용하면 BF가 수행하는 작업은 a10 진수 ASCII 코드 97를 메모리로 읽는 것입니다 .

...[0][0][*97*][0][0]...

일반적으로 그렇게 생각하고 싶지만 진실은 조금 더 복잡합니다. 진실은 BF는 문자가 아니라 바이트 (그 바이트가 무엇이든)를 읽습니다. 예를 보여 드리겠습니다.

리눅스에서

$ printf ł

인쇄물:

ł

특정 폴란드어 캐릭터입니다. 이 문자는 ASCII 인코딩으로 인코딩되지 않습니다. 이 경우 UTF-8 인코딩이므로 컴퓨터 메모리에서 1 바이트 이상을 차지했습니다. 16 진수 덤프를 만들어 증명할 수 있습니다.

$ printf ł | hd

다음을 보여줍니다.

00000000  c5 82                                             |..|

0은 오프셋입니다. 82첫 번째이고 c5두 번째 바이트를 나타냅니다 ł(읽기 위해).|..|이 경우에는 불가능한 그래픽 표현입니다.

글쎄, 당신이 ł단일 바이트를 읽는 BF 프로그램에 입력으로 전달하면 프로그램 메모리는 다음과 같습니다.

...[0][0][*197*][0][0]...

197? 음의 197진수는 c5진수. 익숙한 것 같습니까? 물론이야. 의 첫 번째 바이트입니다 ł!

3. 출력

문자를 인쇄하려면 점을 사용합니다 .. 실제 셀 값을 10 진수 ASCII 코드처럼 취급한다고 가정하면 해당 문자를 표준 출력으로 인쇄합니다.

음, BF 프로그램 메모리가 다음과 같다고 상상해 봅시다.

...[0][0][*97*][0][0]...

이제 도트 (.) 연산자를 사용하면 BF가 수행하는 작업은 다음과 같습니다.

때문에 aASCII의 진수 코드입니다 97.

예를 들어 다음과 같은 BF 프로그램 (97 + 2 개의 점) :

++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++ ..

97까지 가리키는 셀의 값을 증가시키고 2 번 인쇄합니다.

aa

4. 루프

BF에서 루프는 루프 시작 [과 루프 끝으로 구성됩니다 ]. 조건이 실제 셀 값인 C / C ++ 에서처럼 생각할 수 있습니다.

아래 BF 프로그램을 살펴보십시오.

++[]

++ 실제 셀 값을 두 번 증가시킵니다.

...[0][0][*2*][0][0]...

그리고 []처럼 while(2) {}그래서 무한 루프입니다.

이 루프가 무한하지 않기를 원한다고 가정 해 봅시다. 예를 들어 다음과 같이 할 수 있습니다.

++[-]

따라서 루프가 반복 될 때마다 실제 셀 값이 감소합니다. 실제 셀 값이 0루프 종료 되면 :

...[0][0][*2*][0][0]...        loop starts
...[0][0][*1*][0][0]...        after first iteration
...[0][0][*0*][0][0]...        after second iteration (loop ends)

유한 루프의 또 다른 예를 살펴 보겠습니다.

++[>]

이 예제는 루프가 시작된 셀에서 루프를 완료하지 않았 음을 보여줍니다.

...[0][0][*2*][0][0]...        loop starts
...[0][0][2][*0*][0]...        after first iteration (loop ends)

그러나 우리가 시작한 곳에서 끝내는 것이 좋습니다. 왜 ? 루프가 다른 셀을 끝내면 시작되기 때문에 셀 포인터가 어디에 있을지 추측 할 수 없습니다. 솔직히 말해서,이 연습은 brainfuck을 덜 brainfuck하게 만듭니다.


4
쿨, 이제 나는 그것을 이해했다 :)
speeder

25
이 언어 이데올로기를 이해하려는 초보자에게 완벽한 해결책이었습니다. 축하합니다. 멋진 게시물입니다.
Casey

4
내가 본 최고의 Brainfuck 소개. 솔직히 당신은 당신의 우편으로 BF를 조금 취소
보양

3
여가 시간에 프로젝트가 필요하면 언제든지 Brainfuck에 유니 코드 지원을 추가 할 수 있습니다.
Álvaro González

3
게시물 후 BF는 더 이상! BF입니다!
thanos.a apr.

52

Wikipedia 에는 주석이 달린 코드 버전이 있습니다.

+++++ +++++             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'

귀하의 질문에 답하기 위해 ,.문자가 I / O에 사용됩니다. 텍스트는 ASCII입니다.

위키 백과의 문서뿐만 아니라, 좀 더 깊이에 간다.

첫번째 라인의 처음 상태 a[0] = 10단순히 라인 (2)로부터의 루프는 효과적으로 어레이의 초기 값으로 설정 0 후 10 배 증가되어 : a[1] = 70(근접 72를, 문자 'H'을위한 ASCII 코드) a[2] = 100(확대 101 또는 'E' ), a[3] = 30(32에 가까움, 공백 코드) 및 a[4] = 10(줄 바꿈). 루프는 7, 10, 3, 1, 세포에 첨가하여 작동 a[1], a[2], a[3]a[4]10 개를 추가 셀마다 총 (주기 - 루프를 각각마다 a[1]=70등). 루프가 끝나면 a[0]0입니다.>++.그런 다음 포인터를a[1] 70을 보유하고 여기에 2를 더하고 (대문자 H의 ASCII 문자 코드 인 72를 생성 함) 출력합니다.

다음 줄은 배열 포인터를 a[2] 하고 여기에 하나를 추가하여 101, 소문자 'e'를 생성 한 다음 출력합니다.

'l'은 'e'뒤의 일곱 번째 문자이므로 'll'을 출력하려면 또 다른 7 개가 추가되고 ( +++++++) a[2]결과가 두 번 출력됩니다.

'o'는 'l'뒤의 세 번째 문자이므로 a[2] 세 번 더 증가하여 결과를 출력합니다.

나머지 프로그램도 같은 방식으로 진행됩니다. 공백 및 대문자의 경우 다른 배열 셀이 선택되고 필요에 따라 증가 또는 감소합니다.


그러나 왜 인쇄됩니까? 또는 어떻게? 댓글은 그 라인의 의도, 이제 그것이 무엇을하는지 설명하고 있습니다.
speeder 2013 년

8
컴파일러는 것을 알고 있기 때문에 인쇄 ,.사용하여 많은 C 인쇄와 같은 I / O에 사용됩니다 putchar. 컴파일러가 처리하는 구현 세부 사항입니다.
ken

1
또한 필요한 셀을 "Hello World"의 ASCII 문자에 대한 정수 값으로 설정하기 때문에
slugonamission

나는 더 자세한 설명을 기대했지만 ... : /
speeder

1
@speeder-Wikipedia의 코드에 대한 자세한 설명을 답변에 추가했습니다. 자세한 내용은 링크 된 기사를 참조하십시오.
ken

9

인쇄 할 내용을 아는 방법에 대한 질문에 답하기 위해 인쇄가 발생하는 코드 오른쪽에 ASCII 값 계산을 추가했습니다.

> just means move to the next cell
< just means move to the previous cell
+ and - are used for increment and decrement respectively. The value of the cell is updated when the increment/decrement happens

+++++ +++++             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' (ascii: 70+2 = 72) //70 is value in current cell. The two +s increment the value of the current cell by 2

> + .                   print 'e' (ascii: 100+1 = 101)

+++++ ++ .              print 'l' (ascii: 101+7 = 108)

.                       print 'l' dot prints same thing again

+++ .                   print 'o' (ascii: 108+3 = 111)

> ++ .                  print ' ' (ascii: 30+2 = 32)

<< +++++ +++++ +++++ .  print 'W' (ascii: 72+15 = 87)

> .                     print 'o' (ascii: 111)

+++ .                   print 'r' (ascii: 111+3 = 114)

----- - .               print 'l' (ascii: 114-6 = 108)

----- --- .             print 'd' (ascii: 108-8 = 100)

> + .                   print '!' (ascii: 32+1 = 33)

> .                     print '\n'(ascii: 10)

9

이름과 같은 Brainfuck . 그것은 단지 8 자 사용 > [ . ] , - +가 만드는 빠른 프로그래밍 언어를 배울 수 있지만, 어려운에 구현하고 이해합니다. …. 그리고 마침내 당신의 뇌를 망쳐 버리게 만듭니다.

값을 배열에 저장합니다. [72] [101] [108] [111]

let, 처음에는 배열의 셀 1을 가리키는 포인터 :

  1. > 포인터를 오른쪽으로 1만큼 이동

  2. < 포인터를 왼쪽으로 1만큼 이동

  3. + 셀 값을 1 씩 증가

  4. - 요소의 값을 1 씩 증가

  5. . 현재 셀의 값을 인쇄합니다.

  6. , 현재 셀에 입력하십시오.

  7. [ ] loop, +++ [-] 카운터 3 카운트 bcz 앞에 3 '+'가 있고-카운트 변수를 1 값만큼 감소시킵니다.

셀에 저장된 값은 ASCII 값입니다.

따라서 위의 배열을 참조하면 : [72] [101] [108] [108] [111] ascii 값과 일치하면 Hello writtern임을 알 수 있습니다.

축하합니다! BF의 구문을 배웠습니다.

——- 뭔가 더 ———

첫 번째 프로그램 인 Hello World를 만들고 그 후에이 언어로 이름을 쓸 수 있습니다.

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

조각으로 나누기 :

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

4 개의 셀 (> 개수)의 배열을 만들고 카운터를 10으로 설정합니다. —- 의사 코드 —-

array =[7,10,3,1]
i=10
while i>0:
 element +=element
 i-=1

카운터 값은 셀 0에 저장되고> 셀 1로 이동하면 값이 +7만큼 업데이트되고> 셀 2로 이동하면 이전 값으로 10 씩 증가하는 식으로 계속됩니다.

<<< 셀 0으로 돌아가서 값을 1 씩 감소시킵니다.

따라서 루프 완료 후 배열이 있습니다. [70,100,30,10]

>++. 

첫 번째 요소로 이동하여 값을 2 ( '+'두 개) 씩 증가시킨 다음 해당 ASCII 값으로 문자를 인쇄 ( '.')합니다. 예를 들어 파이썬에서 : chr (70 + 2) # 'H'를 출력합니다.

>+.

두 번째 셀 증분 1로 이동하여 값 100 + 1로 인쇄 ( '.') 값 ie chr (101) chr (101) #prints 'e'이제 다음 조각에> 또는 <가 없으므로 현재 값 최신 요소의 증가 및 증가

+++++ ++..

따라서 latest element = 101, 101 + 7 그리고 두 번 인쇄합니다 (2 '..') chr (108) #prints l 두 번 사용할 수 있습니다.

for i in array:
    for j in range(i.count(‘.’)):
           print_value

——— 어디에 사용됩니까? ——-

프로그래머에게 도전하기 위해 만들어진 농담 언어 일 뿐이며 거의 모든 곳에서 사용되지 않습니다.


4

모든 대답은 철저하지만 인쇄라는 작은 세부 사항이 없습니다. brainfuck 번역기를 만들 때 캐릭터도 고려합니다 .. 이것은 실제로 brainfuck에서 인쇄 문이 어떻게 보이는지입니다. 그래서 당신의 brainfuck 번역가는 .문자를 만날 때마다 현재 가리키는 바이트를 인쇄합니다.

예:

-> char *ptr = [0] [0] [0] [97] [0]... 만약 이것이 brainfuck 문이라면 : >>>.포인터를 오른쪽으로 3 칸 이동해야합니다 : [97], 그래서 이제 *ptr = 97번역자가 a를 만나면 .다음을 호출해야합니다.

write(1, ptr, 1)

또는 현재 가리키는 바이트를 인쇄하는 동등한 인쇄 명령문으로 값이 97 이고 문자 astd_output.


1

당신이 묻는 것은 Brainfuck이 모든 코드로 무엇을해야하는지 어떻게 아는가하는 것입니다. 점이 무엇을 의미하는지 또는 코드에서 더하기 기호가 의미하는 바를 해석하기 위해 Python과 같은 상위 수준 언어로 작성된 파서가 있습니다.

그래서 파서는 당신의 코드를 한 줄씩 읽을 것이고> 기호가 있으므로 나는 메모리 위치를 전진해야한다고 말합니다. 코드는 단순히 if (해당 메모리 위치의 내용) ==>, memlocation = + memlocation입니다. 비슷하게 (메모리 위치의 내용) == "."이면 더 높은 수준의 언어로 작성된 다음 인쇄 (메모리 위치의 내용).

이것이 해결되기를 바랍니다. tc

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