포쓰(Forth) 언어 한국어 번역 문서

cleansugar의 이미지

케이엘디피위키 로그인이 안되네요.

아래 글은 피그미 포스에 있는 안내서(TUTORIAL.TXT)를 번역한 것이다. IBM PC
에서 쓸 수 있는 포스인 Pygmy V1.14와 "왜 포스가 그렇게 대단한가?"와 "포스란
무엇인가?"라는 글을 Hitel에서 찾을 수 있다.
포스를 접해본 사람은 그렇게 많지 않을 것이다. 한국과학기술원의 변종홍님에
의해 애플 II 컴퓨터에 이식된 우리말 포스 "늘품"에 관한 기사가 잡지에 몇 번
소개되었고 교학사에서 1988년에 "FORTH 입문"이라는 책이 출판된 것 외에는 포스
가 우리나라에 소개된 것은 거의 없는 것 같다.* 포스는 우리말에 가장 어울리는
컴퓨터 언어이다. 베이식 언어에서 지정어를 한글로 바꾼다고 프로그램이 바로 우
리말이 되지는 않는다. 포스는 나중붙임 (postfix) 표기법을 쓰기 때문에 목적어
가 동사 앞에 오는 우리말에 가깝다. 하지만 그보다 더 중요한 것은 포스를 쓰면
사용자가 문법을 만들 수 있다는 것이다. 프로그래머에게 모든 것이 허용되어 있
기 때문에 __우리말에 맞추어 포스를 고쳐 쓰면 된다__. 옮긴이는 포스가 C나 C++
의 자리를 차지하리라고는 믿지 않지만 우리말 컴퓨터 언어를 만드는데는 가장 좋
은 출발점이라고 생각한다. 옮긴이의 바람은 어린이들이 우리의 생각틀로 프로그
램 만드는 법을 배울 수 있게 되는 것이다. 관심있는 분들의 연락을 바란다.

1993.10.12
고원용
대전시 유성구 장동 100 한국화학연구소 무기소재부 340-343
wykoh (HITEL)
F7WYK@CHEM.KRICT.RE.KR

* 박진묵;변종홍, "늘품" 마이크로소프트웨어 1987년 9월 178-189.
변종홍, "컴퓨터가 우리말을 알아듣는다" 과학동아 1988년 2월 157-161.
변종홍, "우리말 무른연모도 만들자" 과학동아 1988년 3월 156-161.
이태욱, "FORTH 입문" 교학사, 1988. -- 이 책만 가지고 포스를 배우기에는
내용이 충분치 못하지만 우리말로 출판된 유일한 책이다. 현재 시중에서
2쇄를 구할 수 있다.

피그미 편집기에서 글쇠코드의 8번째 비트를 펑션 글쇠와 Alt-글쇠를 표시하는 데
쓰기 때문에 한글 입력이 제대로 되지 않는다. 다음의 세 화면을 고치면 피그미
편집기에서 한글을 쓸 수 있다. 이것으로 포스의 힘을 맛 볼 수 있다. QBASIC의
편집기를 고치고 싶다면 어떻게 하겠는가? 포스에서 시스템을 입맛에 맞게 고치는
것은 이렇게 쉽다. 피그미를 시작하고 "49 EDIT"이라고 친다. 그리고 아래에 있는
것처럼 5번째와 8번째 줄을 고친다. 화살표로 반디(cursor)를 옮겨 다닐 수 있고
Insert 글쇠를 누르면 삽입 상태가 된다.

screen 49

> 5 : (INKEY ( - c) (KEY ?DUP 0= IF (KEY $100 * THEN ;
> 6 ( for the extended keys, scan code is in high byte )
7
> 8 ' (INKEY IS KEY ' (KEY? IS KEY? ' (CR IS CR

"110 EDIT"이라고 하고 아래처럼 6, 9, 10, 11번째 줄을 고친다. 9번째 줄에서
$80 OR은 화면 109를 고치지 않고 쓰려고 필요한 것이다. 피그미에 자신이 있으면
$80 OR를 없애고 화면 109를 고쳐 보라.

Screen 110

2 : ED ( -)
3 DECIMAL XIN OFF CLS L
4 BEGIN SET-CUR
5 KEY DUP 27 - WHILE ( not ESC)
> 6 DUP 01 = IF DROP ALTERNATE ELSE
7 DUP 08 = IF DROP XIN @ IF -1 XIN +! DELETE THEN ELSE
8 DUP 13 = IF DROP SPLIT ELSE
> 9 DUP $100 > IF 256 / $80 OR SPCL ELSE ( regular-key)
>10 INS @ IF INSERT ELSE S! THEN
>11 THEN THEN THEN THEN
12 REPEAT DROP 19 0 AT ;

"165 EDIT"이라고 하고 아래처럼 4, 5, 6번째 줄을 고친다.

Screen 165

1 : COLORS ( -) BASE @ HEX
2 BEGIN CLS CR CR ." This is attr $" ATTR @ DUP 2 U.R CR CR
3 ." F1 changes foreground, F2 changes background, Esc exits"
> 4 CR KEY DUP 27 - WHILE 256 /
> 5 60 ( F2) OF ( attr) $10 + $FF AND ( attr) ELSE
> 6 59 ( F1) OF ( attr) DUP 1+ $0F AND SWAP
7 $F0 AND OR ( attr) ELSE
8 DROP BEEP [ 2 ] THENS ATTR !
9 REPEAT 2DROP BASE ! ;

이제 "1 LOAD"라고 치고 BYE라고 쳐서 피그미를 빠져 나간다. A1.COM 파일이 생겨
있을 것이다. DOS에서 A1이라고 쳐서 A1.COM을 시작하고 "5 LOAD"라고 친다. BYE
를 치고 피그미를 빠져 나오면 A2.COM, A3.COM, A4.COM이 만들어져 있을 것이다.
"COPY A4.COM PYGMY.COM"이라고 치고 나면 편집기에서 한글을 쓸 수 있는 피그미
가 만들어진 것이다. 이해가 되지 않더라도 이대로 따라 해 보기 바란다. 이 과정
을 모두 이해했다면 피그미를 정복했다고 할 수 있다.

피그미에서 다음을 입력하면 우리말로 쓴 예들을 실행시킬 수 있다. 한글 DOS를
사용하고 있지 않다면 피그미를 실행시키기 전에 "다른안시한글"과 같은 에뮬레이
터를 먼저 올려야 한글을 쓸 수 있다.

COMPILER : 번돌아 \ FOR ; FORTH
COMPILER : 다음 \ NEXT ; FORTH
: 베껴 DUP ;
: 버려 DROP ;
: 다음줄 CR ;
: 말펴 WORDS ;
: 보이기 VIEW ;
: .철 .FILES ;
: 짜아 EDIT ;
: 짜 ED ;
: 올려 LOAD ;
: 열어 OPEN ;
: 안녕 BYE ;

============================================================================

완전 초보자를 위한 피그미 포스 쉬운 안내서

(또는 반초보자를 위한 불완전한 안내서)

발을 문에 걸치고

__당신이__ 포스를 배우려면 무엇을 알아야 하는가? 이것은 곤란한 문제다. 저 아
래 수준을 다룬다면 당신은 "그래, 그래, 그것은 벌써 알고 있어 그래도 나는 막
혀 있단 말이야"라고 말할 게다. 너무 높은 수준을 다룬다면 당신은 무슨 소리를
하는 건지 하나도 알아 들을 수 없을 게다. 책에 잡지에 디스켓에 BBS 게시판에
포스에 관한 많은 정보가 있다. (옮긴이: 안타깝게도 우리말로 된 정보는 아직까
지 드물다.) 이들 정보는 대부분 포스 동호회(Forth Interest Group)을 통해 구할
수 있다. 포스 동호회에 가입하거나 아니더라도 그들의 책목록을 구해서 가능한
한 많이 읽는 것이 좋다. 어쨌든 최소한 Leo Brodie의 "Starting Forth"를 공부하
고 피그미 포스의 사용설명서(PYGMY.TXT 파일)를 읽고 피그미 포스의 원시 코드를
공부해야 한다.

제발 응답하라

당신이 초보자이거나 포스를 공부하던 중에 어디선가 "막혀" 있다면 이 안내서를
읽고 여기에 나와 있는 보기들을 아무리 멍청해 보이더라도 실제로 해 보기 바란
다. 그리고 내게 편지를 보내라. 나는 당신이 어디서 어려움을 겪는지, 무엇을 이
해하고 무엇을 이해할 수 없는지 정확하게 알고 싶다. 당신이 어떤 것을 해 보았
는지, 어디서 문제가 생기는지, 어디서 생각대로 되는지 나에게 말해 달라. 당신
이 생각하기에 중요한 곳이 어디인지, 어떻게 하면 그것을 더 잘 설명할 수 있는
지 알려 달라. 이 안내서를 읽고 나서도 대답을 얻지 못한 중요한 물음과 어려움
은 무엇인가? 나에게 말하면 조만간 잡지에 쓸 기사에서 답을 하겠다.

달아나는 말 1

이 안내서는 한 길을 따라 당신을 포스에 이르게 할 것이다. 시작하는 지금, 나는
여러 다른 길이 있음을 안다. 그러나 여기서 이렇게 말하고 나서는 다른 길을 언
급하지 않을 것이다. 이 안내서를 끝낼 때까지 포스에 이르는 오직 한 길은 이것
뿐이라고 생각하자.

달아나는 말 2

이것은 포스 안내서, 더 자세하게는 PC 호환기종에서 쓸 수 있는 피그미 포스의
안내서이다. 이 안내서에서는 DOS를 어떻게 사용하는지, 컴퓨터를 어떻게 켜는지,
한 줄을 입력한 후에는 글쇠를 눌러야 한다든지, .EXE나 .COM나 .BAT가
무엇인지 어떻게 디스크에서 실행파일을 찾는지, 어떻게 ASCII 텍스트 파일을 읽
는지, ASCII가 무엇인지 등에 대해서 이야기하지 않을 것이다. 그러나 내가 무심
코 이런 주제에 대해 이야기하더라도 성내지 말기를 미리 부탁한다.

------------------------
단 하나의 바른길

포스를 정복하기 위해서 당신한테는 오로지

1. 넓고 쉬운 개념 몇 가지와
2. 보기들을 담은 "요리책"과
3. 내가 무엇을 하는지 왜 하는지를 평생토록 궁리하는 것이

필요하다. 다른 것들은 필요하지 않다.

------------------------
1. 넓고 쉬운 개념 몇 가지

## 포스는 칸칸 시스템이다. (Forth is modular.)

우리는 일들을 조그만 조각으로 나누어서 그것들을 피라미드처럼 쌓는다. 이렇게
해서 간단하고 강력하고 계층적인 구조를 만든다. "이것은 너무 쉬워서 잘못될 수
없다(It's so simple, it has to work)"는 Rob Chapman의 구호를 우리 모두 받아
들여야 한다. 우리가 할 일은 그렇게 쉽게 __만들고__ 그렇게 쉽게 __유지하는__
것이다.

## 포스는 대화식이다. (Forth is interactive.)

우리는 작은 조각을 만들어 그것을 바로 시험한다. 처음에 더 많이 시험할수록 나
중에 덜 덴다.

## 포스는 종교가 아니다.

포스는 너무 간단하기 때문에 이것을 신념으로 받아들일 필요가 없다. (어떤 언어
에서는 이 언어로 할 수 있다는 것을 믿어야 시작할 수 있다.) 우리는 그럴 거라
고 생각하거나 희망하거나 믿는 대신에 보고 시험할 수 있다. 우리는 시스템의 어
떤 부분도 조사하고 고칠 수 있다. 원시 코드가 다 있고 이것이 작고 칸칸이 잘
짜여 있기 때문에 관리하기 쉽다.

너무 파격적이어서 눈치채지 못하고 지나갈까 보아 다시 한 번 말한다. 피그미 포
스는 자신의 __모든__ 원시 코드를 포함한다. 당신은 이것을 이해할 수 있다. 당
신은 시스템을 연구하고 고칠 수 있다. (옮긴이: 당신은 벌써 포스 편집기에서 한
글을 입력할 수 있도록 고치는 것을 보았다.) 궁금한 어떤 부분도 조사할 수 있
다. 나는 포스 말고 이렇게 할 수 있는 언어를 들어 본 적이 없다.

## 포스에는 눈에 보이는 자료 더미(data stack)가 있다.

잡지를 한 묶음 꺼내서 바닥에서부터 한 권씩 차례차례 쌓아라. 꺼내기 가장 쉬운
것은 어떤 것인가 (맨 위에 있는 것)? 모두 흐뜨리고 한 권에 "3"이라고 써서 놓
고 그 위에 "5"라고 쓴 다른 권을 올려 놓아라. 쌓여진 더미 위에 무엇이 있는가
(3과 5)? 어떤 값이 위에 있는가 (5)? 이제 당신이 + (덧셈) 연산자라고 가정하
자. 당신이 할 일은 더미에서 두 값을 꺼내 더하고 더한 값을 더미에 올리는 것이
다. 이제 해 보라. 5와 3을 더미에서 꺼내고, 두 값을 더해서 8을 얻고, 8을 다시
더미에 올린다. 더미에 이제 몇 개가 있는가 (하나)? 그것은 얼마인가 (8)? (혹시
답하는 것이 어려우면 괄호 안을 보라.)

## 연습해야만 포스를 배울 수 있다.

컴퓨터로 연습을 해도 될만큼 당신은 벌써 충분히 알았다. 종이에 인쇄한 이 파일
을 들고 있다면 컴퓨터에서 피그미를 실행시키며 읽어 나갈 수 있다. 이제 피그미
(PYGMY.COM)를 실행시키자.

1 3 5 7 9 다음에 글쇠를 눌러서 더미에 수를 몇 개 올려 놓자.
( 글쇠를 누른다는 말을 이후로는 하지 않을 것이다.) 더미에 무엇이 있는
가? 맨 위에는 어떤 값이 있는가? ".더미"라고 쳐서 더미의 내용을 표시하고 당
신의 답이 맞는가 보라. 이제 "."을 치고 어떻게 되었는지 보라. ".더미"를 다시
치고 더미의 내용이 바뀌었는지 보라. 점은 더미의 맨 위 값을 없애고 그 값을 화
면에 보인다. 더미에 값을 올리고 없애는 것을 더 연습하라.

## 포스는 뒤붙임 (postfix) 표기법을 쓴다.

앞에서 + 연산자가 어떻게 작용하는지 보았기 때문에 당신은 그리 놀라지 않을 것
이다. 연산이 작용할 값들을 먼저 입력하고 __나서__ 연산자를 입력한다. 다음 보
기를 해 보자. (결과를 보려면 "."이나 ".더미"를 쓴다.)

3에 5를 곱한다. 3 5 *
9에서 7을 뺀다. 9 7 -

여기서 값들의 순서는 가운데붙임 표기법에서와-- 3*5, 9-7 --같다. 오직 다른 점
은 연산자가 가운데 오는 대신 뒤에 온다는 것이다. 더 연습해 보자.

(3+5)*(6+2)는 3 5 + 6 2 + * 로
3+5 * 6+2 는 3 5 6 * + 2 + 로 입력한다.

뒤붙임 표기법을 쓰면 곱셈이 덧셈보다 먼저라는 규칙도 필요 없고 괄호도 필요없
다. 바로 계산하므로 간단하다. 금방 여기에 익숙해질 수 있다. 위에서처럼 복잡
한 계산에서도 뒤붙임 표기법과 가운데붙임 표기법에서 값들의 순서는 같다는 것
을 눈여겨 봐 두자. 가운데붙임 표기법에서 곱셈이 덧셈보다 먼저이므로 마지막
보기는 8*8이 아니라 3+30+2을 나타낸다.

## 포스는 입력 흐름(input stream)에서 낱말들을 빈칸으로 구분한다.

낱말은 빈칸이 아닌 글자들의 묶음이다. 넓게 말해서 당신이 포스에 입력하는 모
든 것은 낱말로 간주된다. 입력된 모든 낱말은 다음 셋 중의 하나이다.

1. 포스가 알고 있는 낱말 (즉, 포스 사전에서 찾을 수 있는 낱말): 포스는 이
낱말을 실행한다.
2. 포스 사전에 없지만 값으로 바꿀 수 있는 낱말 (예를 들어 75): 포스는 이
낱말을 값으로 바꾸어 더미에 올린다.
3. 앞의 둘에 해당하지 않는 낱말: 포스는 뭔가 잘못되었음을--에러를--표시한
다.

다시 읽어 보기 바란다. 쉽고 매끈하지 않은가? 상어가 먹는 기계인 것처럼 포스
는 실행하는 기계이다. 입력을 한 낱말씩 먹고 값을 더미에 올리고 사전에 있는
낱말을 실행시키고 아니면 토해 낸다.

낱말들을 빈칸 하나로 구분하나 50 개로 구분하나 아무 차이가 없다. 여러 낱말을
한 줄에 넣거나 여러 줄에 나누어 넣는 것도 마찬가지이다.

## __당신이__ 포스 사전에 낱말을 더할 수 있다.

그리고 이렇게 당신이 넣은 낱말도 원래 있던 낱말과 똑같이 취급된다. 이 기능을
잘 쓰려면 아주 작은 낱말들을 사전에 더해 가야 한다. 커서 관리하기 어려운 낱
말을 쓰면 안된다. 낱말이 작아야 한다는 말은 이름이 짧아야 한다는 것이 아니라
그 낱말이 하는 일이 쉽고 빤해야 한다는 것이다. 나중에 뭐가뭔지 알 수 없는 데
에서 벌레를 찾기 보다는 처음부터 "나누어서 정복하려는" 것이다. 팔방미인 낱말
을 만들지 말라. 한 가지 일에 꼭맞는 낱말을 만들라.

사전에 낱말을 더하는 것을 낱말을 정의한다--짓는다--고 한다. 여러 가지 종류의
낱말을 정의할 수 있지만 먼저 하나만 생각하자. 이 한 가지로 지금 당신한테 필
요한 모든 일을 할 수 있다. 이것은 아래처럼 쌍점으로 정의를 시작하기 때문에
쌍점 정의(colon definition)이라고 불린다.

: SEVENTEEN 17 ;

: 열일곱 17 ;

이것을 글자판에서 쳐 넣자. 아무 일도 안 일어났다고? 아무 것도 안 일어 난 것
은 아니다. 포스는 이것을 삼키고 불평이 없다는 표시로 "ok"라고 보였다. 이제
새 낱말 "열일곱"이 사전에 수록되었다. "열일곱"이라고 치고 무슨 일이 일어 나
는지 보자. ( "."이나 ".더미"를 쓰라.) 이 낱말이 무슨 일을 할 거라고 생각했었
는가? 이것은 17을 더미에 올린다. 쌍점이 기호가 아니라 일을 하는 낱말이기 때
문에 정의는 :로 시작하고 그 뒤에는 빈칸이 있어야 한다. 값들은 그 값들을 사용
하는 낱말보다 먼저 오지만 (그래야 낱말이 일하려 할 때 값들이 더미에서 기다리
고 있다) 문자열은 보통 그 문자열을 사용하는 낱말 뒤에 온다. 이 경우에는 :이
입력 흐름으로부터 문자열을 예상하고 이 문자열을 새 낱말의 이름으로 사용한다.
그리고 나서 :는 ; 전에 있는 모든 낱말을 새 낱말의 정의에 차례차례 포함시킨
다. ;(반쌍점)은 : 정의를 끝내는 특별한 말이다. 익숙해질 때까지 다음을 해 보
라.

: 3* ( n - 3*n) 3 * ;
17 3* .
2 3* .
2 3* 3* 3* .

: FEET ( feet - inches) 12 * ;
6 FEET .
5 FEET .

: STAR ( -) ." *" ;
STAR
STAR STAR STAR

: STARS ( # -) FOR STAR NEXT ;
0 STARS
1 STARS
2 STARS
200 STARS

: DIGITS ( -) 0 10 FOR DUP . 1+ NEXT DROP ;
DIGITS
: DIGITS ( -) CR CR CR DIGITS CR CR CR ;

: 3* ( n - 3*n) 3 * ;
17 3* .
2 3* .
2 3* 3* 3* .

: 말 ( 말 - 되) 10 * ;
6 말 .
5 말 .

: 홑별 ( -) ." *" ;
홑별
홑별 홑별 홑별

: 별 ( # -) 번돌아 별 다음 ;
0 별
1 별
2 별
200 별

: 숫자 ( -) 0 10 번돌아 베껴 . 1+ 다음 버려 ;
숫자
: 숫자 ( -) 다음줄 다음줄 다음줄 숫자 다음줄 다음줄 다음줄 ;

자, 이제 설명을 해 보자. 낱말의 정의 안에 "( n -)"처럼 괄호에 싸인 것은 덧붙
임말이다. 왼쪽 괄호 뒤에 빈칸이 있는 것을 눈여겨 보자. 이제 당신도 알듯이 왼
쪽 괄호도 한 낱말이고 이것은 낱말 정의 안에서 실행된다. (가 뭘 하냐고? 오른
쪽 괄호를 만날 때까지 입력 흐름을 흘려보낸다. 왜 덧붙임말을 모든 낱말에 넣느
냐고? 몇 가지 이유가 있다. 첫째는 이 낱말이 무슨 일을 하는지를 최소한으로 표
시하는 것이다. 덧붙임말은 이 낱말이 실행될 때 더미에 무엇이 있어야 하는지 실
행되고 나면 더미에 무엇이 남는지를 표시한다. 낱말이 무슨 일을 하는지 알아야
낱말을 짓거나 시험할 수 있다. 예를 들어 "숫자"는 더미에서 아무 값도 가져오지
않고 아무 값도 올리지 않는다. 이러한 덧붙임말을 "더미 덧붙임말"이나 "더미 그
림"이라고 부른다. 당신이 짓는 모든 낱말에 이 덧붙임말을 넣는 습관을 들여라.
"홑별"에서 포스의 인쇄 명령을 볼 수 있다. ."(점-따옴표)도 낱말이어서 뒤에 빈
칸이 하나 있어야 하고 그 뒤에 출력할 문자들이 오고 따옴표로 끝낸다. "번돌아
... 다음 (FOR ... NEXT)"은 굳이 설명할 필요가 없을 것이다. "베껴(DUP)"는 더
미의 맨 위 값을 복사한다. 이것을 더미 덧붙임말로 표시하면 ( n - n n)이다.
"버려(DROP)"는 더미의 맨 위 값을 버린다. 즉, ( n -)이다. "다음줄(CR)"은 출력
을 다음 줄로 보낸다.

이제 당신의 이름을 인쇄하는 낱말을 정의하자. 그리고 이것을 다른 낱말을 짓는
데 써 보자. 다음 보기를 보라.

: ME ( -) ." FRANK" ;
: WHO? ( -) ME ." , THAT'S WHO!" CR ;

: 나 ( -) ." 홍길동" ;
(계속하기 전에 반드시 해 보아야 한다!) 그리고 나서
: 누구? ( -) 나 ." , 그게 나야!" 다음줄 ;

## 포스는 대소문자를 따진다.

적어도 피그미와 다른 포스 중 여럿은 대소문자를 따진다. 다음 네 줄을 치면 포
스가 어떤 것을 실행하고 어떤 것을 토해 내는지 보게 될 것이다.

CR
cr
cR
Cr

## 복습

어디에서 낱말을 찾는가 (사전)? 값(수)이 어디로 가는가 (더미)? 낱말 정의는 얼
마나 길어야 하는가 (길면 안된다)? 언제 낱말을 시험하는가 (낱말을 지은 직후)?
어떤 포스 낱말이 무슨 일을 하는지 어떻게 알 수 있는가 (그 낱말의 원시 코드를
보고 자판에서 그 낱말을 써 본다)?

이제 됐다. 당신은 이제 필요한 개념들을 익혔다. 이제 남은 것은 "어떻게 이것
저것을 할 수 있는가?"하는 구체적인 것들이고 아래 요리책에서 복사할--더 좋게
는 공부하고 고칠--보기들을 찾을 수 있다.

---------------------
요리책

어디에서 보기를 찾고 포스 시스템에 대한 물음의 답을 찾을 것인가? "말펴
(WORDS)"라고 치고 어떤 일이 벌어지나 보라. 이 낱말은 사전의 낱말들을 보인다.
너무 빨리 위로 지나가 버린다고? 다시 해 보고 아무 글쇠나 눌러서 흐르는 것을
멎게 해 보라. 다시 아무 글쇠나 눌러 계속하게 하라. 어떤 낱말이--보기로
EXPECT가--눈에 띠면 다음을 쳐 보라.

VIEW EXPECT

보이기 EXPECT

와! 당신은 편집기에서 EXPECT의 정의를 보고 있다. PgUp, PgDn 글쇠를 써서 원시
코드의 다른 화면으로 옮겨 다닐 수 있다. 더미 덧붙임말을 눈여겨 보라. 피그미
의 그림자 화면을 가지고 있다면 Ctrl-A 글쇠를 눌러 그림자 화면으로 왔다갔다
하며 더 자세한 정보를 볼 수 있다.

편집기에 대해 말하는 김에 ".철(.FILES)"이라고 쳐서 무슨 일이 일어 나는지 보
라. 이것은 지금 사용할 수 있는 파일들을 보이고 각 파일에 배당된 시작 화면과
끝화면의 번호와 DOS handle 번호를 보인다. (handle 번호가 -1인 파일은 사용할
수 없다.) PYGMY.SCR은 화면 0에서 시작하므로 다음을 쳐 보라.

0 EDIT

0 짜아

이 파일에 피그미의 __모든__ 원시 코드가 담겨 있다. PgUp, PgDn 글쇠로 이리저
리 옮겨다니며 (그림자 화면이 있다면 Ctrl-A로 그림자 화면으로 왔다갔다 하며)
원시 코드를 보라. 보는 것을 모두 이해하려고 애쓸 필요는 없다. 지금은 무엇이
어디에 있는지 구경만 하는 것이다. 계속하라. 거의 모든 낱말에 더미 덧붙임말이
있는 것을 눈여겨 보라. Esc 글쇠를 눌러 빠져 나오라.

"말펴", "짜아", "보이기" 세 낱말로 사전에 있는 모든 낱말의 원시 코드를 볼 수
있을 것이다. 이제 요리책을 어떻게 쓰는지 보자. "1 짜아"처럼 쳐서 편집기로 첫
화면 근처로 들어 가라. F3(펑션 글쇠 F3) 글쇠로 문자열을 정의하고 F10 글쇠로
그 문자열이 있는 화면으로 찾아 다닐 수 있다. 이렇게 해서 한 낱말이 다른 낱말
에서 어떻게 쓰이는지 금방 볼 수 있다.

이렇게 하면서 배우는 게 아주 많을 것이다. 게다가 이렇게 하는 동안 피그미에
더 편안해질 것이다. 그러나 편해지기 전까지, 피그미가 어떻게 움직이는지 잘 알
게 되기 전까지 무엇을 어떻게 하는지 모르겠으면 아래의 물음과 그에 대한 답을
보라.

물음: 낱말을 짓고 나면 화면 위로 올라가 버린다. 그리고 나면 당신이 그렇게 써
넣으라고 말했던 더미 덧붙임말도 볼 수 없다. DOS에서 피그미를 시작할 때마다
낱말 정의를 새로 쳐 넣어야 하는 데 지쳤다.

대답: 이것은 물음이 아니라 불평이다. 이제 당신은 편집기를 써서 당신의 원시
코드를 갈무리하고 고칠 단계에 이르렀다. 파일 하나가 당신 몫으로 준비되어 있
다. 이 파일의 이름은 YOURFILE.SCR이다. ".철(.FILES)"를 치면 이 파일이 화면에
보일 것이다. 이 파일이 화면 2000에서 시작하는 것을 눈여겨 보라. "2000 짜아"
라고 치고 PgUp, PgDn 글쇠를 써서 앞뒤 화면을 보라. 당신이 벌써 무엇을 써 넣
지 않았다면 모두 비어 있을 것이다. PYGMY.TXT에 있는 사용법 설명을 읽거나 맨
위의 상태 표시줄을 참조하여 이것저것 해보라. (옮긴이: 10개의 펑션 글쇠, 화살
표 글쇠, PgUp, PgDn, Insert, Delete 글쇠를 쓸 수 있다.) 당신의 원시 코드를
치라. 화면 2002의 원시 코드를 번역하려면 Esc를 눌러 편집기에서 빠져 나온 다
음 "2002 올려(2002 LOAD)"라고 친다. 편집기로 돌아 가고 싶으면 "2002 짜아"라
고 치거나 "짜(ED)"라고 쳐서 맨 나중에 편집하던 화면으로 간다. "안녕(BYE)"이
라고 쳐서 피그미에서 나가면 당신이 사전에 올렸던 낱말이 모두 없어지지만 화면
2002에는 그 낱말들의 정의가 남아 있다. 다음에 피그미를 실행할 때 "2002 올려"
라고 쳐서 그 낱말들을 사전에 다시 올릴 수 있다.

물음: 피그미를 실행시킬 때마다 내가 지은 낱말들을 올리려고 "2002 올려"라고
치는 것도 귀찮다. 다른 방법이 없는가?

답: 이번에는 불평이 아니라 물음이다. 다른 방법이 있다. 당신의 낱말을 올린 다
음 다음과 같이 친다.

SAVE A5.COM

갈무리 A5.COM

이렇게 하면 피그미를 시작하는 것과 비슷한 실행 파일이 A5.COM이라는 이름으로
만들어진다. 물론 A5말고 다른 이름을 쓸 수 있지만 확장자는 .COM이어야 한다.
다음에 피그미를 실행시킬 때는 DOS에서 A5라고 쳐서 A5.COM을 실행시킨다. 여기
에 당신이 매번 올리고 싶던 낱말들이 들어 있다.

물음: 피그미에서 어떻게 파일을 만드는가?

답: 무엇에 쓰려고? 당신의 원시코드를 담을 파일 YOURFILE.SCR이 벌써 준비되어
있다. 그걸 써라.

물음: 그렇지만 그게 다 찼다. 겨우 스크린 8 개 밖에 없는데 벌써 다 써 버렸다.

답: 간단하다. 편집기로 들어가 늘리고 싶은 곳으로 간다. F9 글쇠를 치면 화면을
몇 개나 넣을 거냐고 물을 것이다. 20을 입력하면 편집기는 지금 화면 뒤에 빈 화
면을 20 개 더해 파일을 늘릴 것이다.

물음: 그렇지만 내 코드를 __다른__ 파일에 담고 싶다면 어떻게 하는가?

답: 좋다. 꼭 그렇게 하고 싶다면 방법이 몇 가지 있다. DOS로 나와서 다음과 같
이 친다.

COPY YOURFILE.SCR NEWFILE.SCR
그리고 나서 피그미로 돌아가서 이렇게 친다.
" NEWFILE.SCR" 4 OPEN
SAVE A6.COM

" NEWFILE.SCR" 4 열어
갈무리 A6.COM

아니면 화면 136에서 NEWFILE을 올리면 피그미 안에서 이 낱말로 새 파일을 만들
수 있다. 보기를 보이면

" NEWFILE.SCR" NEWFILE

충분하지는 않지만 어떻게 하는지 감을 잡을 수 있을 것이다.

물음: 피그미에서 텍스트 파일을 올릴 수 있는가? 텍스트 파일과 즐겨 쓰던 편집
기가 내게는 더 익숙하다.

답: 뭐라고? 피그미 편집기에 익숙해질 때까지 더 연습하는 게 좋다. 어쨌든, 답
은 "할 수 있다"이다. FLOAD와 INCLUDE를 써서 텍스트 파일을 올릴 수 있다. 어떻
게 하는지는 당신에게 숙제로 남겨 놓겠다. PYGMY.SCR에서 원시 코드를 보거나
PYGMY.TXT를 읽어서 알아낼 수 있을 것이다. 화면 파일은 텍스트 파일보다 좋은
점이 훨씬 많다. 피그미에 들어 있는 편집기로 바로 편집할 수 있고 칸칸이 잘 나
뉘는 프로그램을 짜게 한다. 당신은 매우 짧은 낱말들을 만들고 __있지 않은가__?

물음: 그러나 __당신의__ 원시 코드에 있는 어떤 낱말은 화면 하나에 넘칠 것처럼
길지 않은가?

답: 내가 하는 대로 하지 말고 말하는 대로 하라. (옮긴이: 내가 "바담 풍" 해도
당신은 "바람 풍" 하라.)

결론

이제 감을 잡고 편안한가 (그렇다, 당신은 포스의 힘과 아름다움에 내 눈을 뜨게
했다!)?

Forums: 
cleansugar의 이미지

아래는 ForthNet에서 찾은 "Why is FORTH so great?"라는 제목의 글을 번역한
것이다. 글의 내용으로부터 지은이가 전산학과를 졸업한 직업적인
프로그래머라는 것을 알 수 있을 뿐 (최소한 ForthNet에 이 글을 올린
사람에게는) 누구인지 알려져 있지 않다. 1987년에 쓰인 글이라 어떤 부분은
시대에 뒤떨어진 감이 있지만 포스의 특징을 비교적 잘 설명하고 있다. 많은
사람이 이 글을 읽고 포스에 관심을 가지게 되기를 바란다.
포스를 접해본 사람은 그렇게 많지 않을 것이다. 한국과학기술원의
변종홍님에 의해 애플 II 컴퓨터에 이식된 우리말 포스 "늘품"에 관한 기사가
잡지에 몇 번 소개되었고 교학사에서 1988년에 "FORTH 입문"이라는 책이 출판된
것 외에는 포스가 우리나라에 소개된 것은 거의 없는 것 같다.* 포스는
우리말에 가장 어울리는 컴퓨터 언어이다. 베이식 언어에서 지정어를 한글로
바꾼다고 프로그램이 바로 우리말이 되지는 않는다. 포스는 나중붙임 (postfix)
표기법을 쓰기 때문에 목적어가 동사 앞에 오는 우리말에 가깝다. 하지만
그보다 더 중요한 것은 포스를 쓰면 사용자가 문법을 만들 수 있다는 것이다.
프로그래머에게 모든 것이 허용되어 있기 때문에 __우리말에 맞추어 포스를
고쳐 쓰면 된다__. 옮긴이는 포스가 C나 C++의 자리를 차지하리라고는 믿지
않지만 우리말 컴퓨터 언어를 만드는데는 가장 좋은 출발점이라고 생각한다.
옮긴이의 바람은 어린이들이 우리의 생각틀로 프로그램 만드는 법을 배울 수
있게 되는 것이다. 관심있는 분들의 연락을 바란다.

1993.10.7
고원용
대전시 유성구 장동 100 한국화학연구소 무기소재부 340-343
wykoh (HITEL)
F7WYK@CHEM.KRICT.RE.KR

* 박진묵;변종홍, "늘품" 마이크로소프트웨어 1987년 9월 178-189.
변종홍, "컴퓨터가 우리말을 알아듣는다" 과학동아 1988년 2월 157-161.
변종홍, "우리말 무른연모도 만들자" 과학동아 1988년 3월 156-161.
이태욱, "FORTH 입문" 교학사, 1988. -- 이 책만 가지고 포스를 배우기에는
내용이 충분치 못하지만 우리말로 출판된 유일한 책이다. 현재 시중에서
2쇄를 구할 수 있다.

IBM PC에서 쓸 수 있는 포스인 Pygmy V1.14가 Hitel에 올라 있다.

> 6351 pygmytut.lzh B 10241 word [FORTH] 한글 PYGMY 포스 TUTORIAL
> 6315 4thcmp21.lzh B 94771 subr [FORTH] .COM 파일을 만드는 포스 번역기
> 6260 forth.lzh B 5430 subr [FORTH] 우리말을 닮은 프로그램 언어 포스
> 6251 pygmy14.lzh B 87044 subr [FORTH] IBM-PC에서 쓸 수 있는 피그미 포스

피그미에서 다음을 입력하면 우리말로 쓴 예들을 실행시킬 수 있다. 한글 DOS를
사용하고 있지 않다면 피그미를 실행시키기 전에 "다른안시한글"과 같은
에뮬레이터를 먼저 올려야 한글을 쓸 수 있다.

: 0> 0 > ; ( 피그미에 들어 있지 않은 0>와 )
COMPILER : [COMPILE] \ \ ; FORTH ( [COMPILE]을 이렇게 정의한다. )

: 베껴 DUP ;
: 버려 DROP ;
: 맞바꿔 SWAP ;
: 낱말 WORD ;
: 값 NUMBER ;
COMPILER : 면 \ IF ; FORTH
COMPILER : 아니면 \ ELSE ; FORTH
COMPILER : 라 \ THEN ; FORTH
: 무른값 VARIABLE ;
: 다음줄 CR ;
: 번역기용어 COMPILER ;
: 포스용어 FORTH ;
: .더미 .S ;
: 번역 COMPILE COMPILE ;
: 되돌이> POP ;

==========================================================================

왜 포스가 그렇게 대단한가?
--------------------------

내가 지금까지 접해 본, 흔히 쓰이는 프로그램 언어 중에 포스(Forth)만큼
강력하고 내맘대로 바꿀 수 있는 언어는 없다. 어떻게 내가 이렇게 건방지고
일방적인 선언을 할 수 있느냐고? 나는 내 경험이 그렇다고 이야기하는 것이다.
당신은 아마 내가 다른 언어로는 프로그램을 하나도 짜 본 적이 없고 따라서 위
말은 귀담아 들을 필요가 없다고 생각할지 모른다. 그렇지 않다.

나는 펜실베니아 주립대학 전산학과를 졸업했다. 그 후 6 년 동안 취직해 있는
동안 많고 많은 프로그램 언어를 보았고 여러 가지 컴퓨터 언어로 프로그램을
짰다. 그 언어들에 대한 내 생각은 아래와 같다. 흘낏 보고 당신은 이렇게
말할지 모른다: "이 사람은 프로그램 언어 X를 써 본 적이 없고 X는 이렇게
좋은 점들을 많이 가지고 있기 때문에 이 사람의 말은 귀담아 들을 가치가
없다." 거기에 대한 내 대답은 이렇다.

프로그래머가 문법, 번역기(compiler)를 비롯하여 연산자와 자료형을 포함한
__모든__ 것을 바꾸고 늘릴 수 있는 언어는 포스밖에 없다. 다른 모든 언어는
작든 크든 간단하든 복잡하든 번역기가 __고정__되어 있다. 오직 번역기를 만든
사람만이 번역기의 내부 작용과 언어를 바꿀 수 있다. 처음 나온 번역기에 어떤
기능이 없어서 번역기 X의 다음 버전을 기다린 적이 있는 사람이 하나둘이 아닐
것이다. 포스에서는 그런 일이 없다. 필요할 때 필요한 기능을 __언제든지__
__당신이__ 포스에 더할 수 있다.

포트란(FORTRAN)

수를 다루는데는 좋지만 그밖에는 없는 것이 너무 많다. 많은 사람들이 여러 번
개선을 했지만 사용자 정의 자료형도 없고 내가 쓰기에는 부족하다.

PL/I

한동안은 계산 기능과 사무용 자료 처리 기능이 비교적 균형있게 갖춰진
언어라고 생각했었다. 그래도 사용자 정의 자료형을 쓰기에는 불편하다. 나쁜
언어라고 할 수는 없지만 계속 읽다 보면 왜 포스가 훨씬 나은지 보게 될
것이다.

파스칼(Pascal)

자료형을 쉽게 만들 수 있고 만든 프로그램을 읽을 수 있어서 오랫 동안 가장
즐겨 쓰던 언어였다. 시간이 지나자 자료형을 까다롭게 따지는 것이 오히려
걸치적거리기 시작했다. 파스칼에서는 자료형을 만들고 사용할 수 있지만
번역할 때 모든 이름과 연산의 자료형이 결정되어야 한다. 그래서 자료형이
까다롭다고 (strong typing) 하는 것이다.

까다로운 자료형의 장점은 자료형을 잘못 사용할 가능성이 작다는 것이다.
(예를 들어 두 문자를 더하기는 매우 어렵다.) 대부분의 경우 그런 시도는
프로그래머의 실수이다. 하지만 프로그램을 짜다 보니 필요한 때도 있었는데
파스칼은 기를 쓰고 그걸 막았다. 가변 레코드(variant record)를 써서 돌아갈
수 있지만 매우 불편하고 비효율적이다. 그나마 포인터(pointer)로 덧셈 뺄셈을
하려면 이 방법도 소용이 없다. 포인터를 쓰는 것도 완전하지 않다.

APL

APL은 매우 강력한 언어이다. 내가 본 언어 중 구문이 가장 간결하다. 문제는
원시 코드(source code)가 너무 간결하다는 것이다. 한두 줄 짜리 프로그램도
쓴지 한달이 지나면 이해하기가 쉽지 않다. APL에 나름대로의 장점이 있지만
범용 프로그램 언어로는 부적당하다.

C

C는 꽤 강력한 언어이다. C가 강력한 것은 포인터를 조작하는 기능을 모두
갖추었고 파스칼보다 자료형이 덜 까다롭기 때문이다. C가 다른 언어에 비해
옮기기 쉽지만 (portable) C 번역기를 파는 회사들이 주장하는 것만큼 쉽지는
않다. 옮길 수 있는 프로그램을 만드는 것은 프로그래머이지 언어 자체는
아니라는 것이 내 믿음이다. 내가 머리 속에서 계속 생각하고 있지 않으면
프로그램은 금방 옮길 수 없게 자라 버린다. 물론 마음먹으면 옮길 수 있는 C
프로그램을 쓰는 것도 똑같이 쉽다. 이것은 C뿐 아니라 거의 모든 프로그램
언어에 대해서 참이다. 프로그래머가 언어의 기능을 조심스럽게 골라 쓰면 옮길
수 있는 프로그램을 만들 수 있다. 물론 이렇게 하려면 특정한 번역기에만 있는
기능을 쓰면 안된다. 만들어진 프로그램은 아마도 덜 반짝거리겠지만 옮길 수
있게 만드려면 어쩔 수 없다. 프로그래머들이 C를 많이 쓰는 것을 보면 C가
아주 넓은 범위의 문제를 해결하는데 쓸모가 있는 것은 분명하다.

어셈블리어(Assembly Language)

어셈블리어에 대해 어떻게 생각하는가? 어떤 컴퓨터에 대해서도 이것이 가장
강력하고, 유연하고, 생각할 수 있는 좋은 말은 모두 갖다 붙인 프로그램
언어일 수__밖에 없다__. 모든 언어는 결국 기계어로 바뀌기 때문에 기계어에
1:1로 대응하는 어셈블리어로 안되는 일이라면 어떤 언어를 써도 컴퓨터는 그
일을 할 수 없다. 다시 말해 어셈블리어로 안된다면 안되는 것이다.

그러나 어셈블리어의 장점은 동시에 단점이다. 기계의 모든 면을 조작할 수
있다는 것은 매우 강력하지만 언제나 그래야 한다면 너무 번거롭다. 필요할
때는 모든 면을 조작하고 필요치 않을 때는 그렇게 하지 않아도 된다면
이상적이겠다.

매우 효율적이라는 것은 어셈블리어의 장점이다. 단 한 순간도 낭비하지 않는
응용 프로그램을 만들 수도 있다. 사람들이 쓰기 어렵다고 생각하는 것은 다른
단점이다. 나는 어렵다고 생각하지 않는데 많은 사람들은 그렇다고 말한다. 또
다른 단점은 프로세서가 다 다르기 때문에 한 프로세서에 쓰려고 짠 프로그램을
다른 프로세서에 쓰려면 완전히 새로 짜야 한다는 것이다. 이것은 또
프로세서가 바뀌면 프로그래머가 새로 공부를 해야 한다는 뜻이기도 하다.
공부하는데는 시간이 걸리고 처음에는 한 프로세서의 도사가 다른
프로세서에서는 덧셈도 할 줄 모르는 완전한 초보자이다.

코볼(COBOL)

나는 코볼로 프로그램 짜는 것을 배우지 않았다. 많은 사람들은 나보고 그래서
머리 상하는 걸 면했다고, 과거로 돌아갈 필요가 없다고 말한다. 이것은 사무
처리 분야에서 지금도 한창 날리고 있는 언어한테 너무 심한 말인지도 모른다.
전 세계에서 오늘도 수 십억 줄의 코볼 코드가 실행되는 걸로 보아서 코볼은
쓸모있는 언어인 것 같다. 하지만 내가 만나본 전문적인 코볼 프로그래머들은
코볼을 써서 문제를 해결할 수는 있지만 언어 때문에 자주 짜증이 난다고
말했다. 비록 문제를 해결할 수는 하지만 코볼 프로그래머들은 코볼을 좋아하지
않는다.

Ada

Ada는 아주 많은 기능을 가진 언어이다. Ada는 큰 무른모(software) 시스템을
개발 유지하기 위해 만들어졌다. 미국 국방성이 언어의 사양을 결정하고
국방성의 모든 프로그램을 Ada로 쓸 것을 요구했다. 당연히 Ada는 단번에
인기있는 언어가 되어 엄청난 양의 프로그램이 Ada로 작성되고 (다른 언어로
쓰였던 프로그램이) 재작성되었다. 그렇다고 해서 좋은 언어일까? 반드시
그렇다고는 말할 수 없다. 개선된 기능이 많이 있지만 내가 느끼기에 Ada는
너무 크다. 5 년 동안 날마다 Ada로 일을 하고도 Ada의 기능을 다 알지 못할
수도 있다. 마치 태평양 한 가운데 구명보트를 타고 있는 것 같이 느낄지
모른다. Ada는 파스칼의 단점을 보완했기 때문에 시스템은 칸칸이 잘 나뉘어서
유지하기 쉽다. 그렇지만 기능이 너무 많아서 프로그래머가 헤메기 쉽다. PL/I
프로그래머 중에 이렇게 느끼는 사람들이 있었지만 Ada의 경우 이것은 더욱
두드러진다. 작든 크든, 나라에서 하는 일치고 효율적인 게 있던가? 그리고
Ada에서도 번역기를 고칠 수 없다.

모듈라 2 (Modula 2)

모듈라 2는 Nichlaus Wirth가 자신이 만든 파스칼을 고쳐 쓴 것이다. Wirth는
전산학계에서 아주 존경받는 인물이고 그의 업적은 크고 많다. 다른 사람들이
파스칼에 대해 불평한 것을 고친 것이 모듈라 2이다. 어느 정도는 성공했다.
따로따로 번역했다가 합칠 수도 있고 필요하면 까다로운 자료형을 피하는
방법도 있다. 겉으로 보기에 파스칼보다 프로그램 짜기가 편할 것 같다. 책을
몇 권 읽었을 뿐 직접 모듈라 2로 프로그램을 짠 적이 없기 때문에 나는 모듈라
2의 장점도 단점도 말할 처지에 있지 않다. 단점을 지적하자면 이것도 위에
언급한 다른 언어들처럼 고정되어 있다는 것이다. 새 연산자를 더할 수도 없고
이미 정해진 기능을 바꿀 수도 없다.

포스(Forth)

왜 포스냐고? 앞의 언어들 모두가 상당한 공을 들여 만든 것인데 포스가
이것들보다 정말 나으냐고? 먼저 한 마디 해 두겠다. 다른 모든 언어들처럼
포스도 장점과 단점이 있다. 세상에 완전한 것은 없고 포스도 예외는 아니다.
내가 포스의 장점이라고 생각하는 것을 이야기하고 포스의 단점 내지는
약점이라고 생각하는 것을 이야기하겠다. 그리고 포스의 좋은 점을 몇 가지 더
이야기하고 이 글을 끝내겠다.

먼저 포스는 범용 프로그램 언어이다. 일상적인 문제를 해결하는데도 쓸 수
있고 특별한 굳은모(hardware)와 무른모를 써야 하는 특별한 응용에도 쓸 수
있다. '확장할 수 있다'는 것이 포스의 첫번째 특징이다. 프로그래머는 새 말을
자꾸자꾸 더해서 더욱 더 높은 단계로 프로그램을 짜 나간다.

그게 뭐 대단한 거냐고? 대부분의 현대적인 언어에서 이런 식으로 프로그램을
짤 수 있다고 당신은 생각할 것이다. 파스칼에서는 기존의 절차(procedure)와
함수로 새 절차와 새 함수를 만들고 이들을 차례차례 쌓아서 아주 높은 단계의
구조를 만들 수 있다.

C에서도 함수 라이브러리로 언어를 훨씬 더 쓸모있게 만들 수 있다. 실제로
얼마나 라이브러리가 잘 갖추어졌느냐가 C 번역기의 쓸모를 결정한다 해도
과언이 아니다. 이런 식의 '벽돌 쌓기' 프로그램 방법은 거의 모든 언어에
적용된다. 따라서 포스의 '확장성'이란 다른 모든 언어가 가진 특색--어떤
절차/함수가 다른 절차/함수를 부를 수 있는 기능--을 거창하게 포장한 말이다,
그렇지?

반은 맞고 반은 틀렸다. 지금부터 나는 포스를 C와 비교하겠다. 다른 언어들과
비교하는 것은 당신 몫으로 남겨 두겠다. C와 비교하는 첫번째 이유는 C가 매우
인기있는 언어이고 두번째 이유는 많은 사람들이 C가 고급어 중 가장
말랑말랑한 (flexible) 언어라고 믿기 때문이다.

이제 C에서 함수 라이브러리를 쓰는 능력과 포스의 확장성이 어떻게 다른가
보자. C로 프로그램을 짜다 보니 printf 함수가 수를 출력하는 방식이 마음에
들지 않는다고 가정하자. 마음에 들게 printf를 새로 쓰면 되니 큰 문제는 아닌
것 같다. 그런데 새로 쓰려는 printf의 대부분의 기능은 번역기의 printf에도
있는 것이다. 문자열을 다루는 방식은 특히 그렇다. 바꾸고 싶은 것은 수를
출력하는 방식이다.

그러나, printf의 원시 코드가 없기 때문에 바닥에서 출발해서 완전히 다시
짜야 한다. 상업적인 번역기의 라이브러리에 있는 함수들은 매우 공을 들여
다듬어진 것이기 때문에, 새로 만든 printf가 원하는 기능을 제공하기는 해도
너무 크거나 너무 느릴지 모른다. 그러면 별 수 없이 시간을 들여 새로 만든
함수를 다듬어야 한다. 참으로 큰 일이다.

포스에는 함수도 없고 파스칼에서의 절차도 없다. 포스에서는 C의 함수를
낱말(word)이라고 부른다. 포스는 자기가 '아는' (코드를 가진) 모든 '낱말'을
사전에 보관한다. 파스칼에서는 절차나 함수가 감싸일(nesting) 수 있어서 속의
함수/절차를 부르려면 그것을 싸고 있는 함수/절차를 불러야 하지만 C에서는
모든 함수가 한 층에 있다. 대부분의 사람들은 이렇게 한 층에 모든 게 있는
것을 좋아한다. 포스에서 모든 낱말은 사전에 들어 있고 C에서처럼 모두가 같은
층에 있다. 여기까지는 C와 포스가 동점이다.

앞의 예로 돌아가자. 비록 C 프로그래머가 printf를 다시 짤 수 있지만 어렵고
힘이 든다. 포스에는 문자열을 출력하는 낱말도 여러 개 있고 수를 출력하는
낱말도 여러 개 있다. 수를 출력하는 가장 기본적인 낱말은 따옴표를 뺀
"."이다. 이것은 "점"(dot)이라고 읽는다. 이제 점이 수를 출력하는 게 마음에
들지 않는다고 가정해 보자.

포스의 점은, 더미(스택, stack)의 맨 위에 있던 수를 지금 커서 위치에 왼쪽을
맞추어 출력하고 빈칸을 하나 출력한다. 수가 0보다 작을 때만 음수 부호가 수
앞에 출력된다.

한 예로 더미의 맨 위에 있는 수가 0보다 클 때만 그 수를 출력하고 0보다
작으면 잘못되었다는 표시로 -999를 더미의 맨 위에 남기도록 점을 고쳐 쓰고
싶다고 해보자. 이렇게 "점"을 고쳐 쓰는 것이 특별히 쓸모가 있을 것 같지는
않지만 예로는 충분하다.

포스에서 있는 낱말을 고쳐 지을 때 같은 이름의 '옛' 낱말을 써서 새 낱말을
정의 할 수 있다. 헷갈리는 말 같지만 그런게 아니고 아주 쓸모있다. 아래에
고쳐 쓴 점의 코드를 보이고 설명을 하겠다.

: . ( n -- | n -- -999 )
DUP 0> IF . ELSE DROP -999 THEN ;

: . ( n -- | n -- -999 )
베껴 0> 면 . 아니면 버려 -999 라 ;
(옮긴이: THEN을 왜 "라"로 바꾸었는지 얼른 안 들어올지 모르지만 -999를
무시하면 "버려 라"가 우리말로 자연스럽다.)

이것을 보고 당신은 배꼽을 잡고 웃거나 이 글을 그만 읽으려 할지 모르겠다.
그러나 __계속 읽어라__. 포스의 특색을 보이기 위해 일부러 이 예를 골랐다.

위 예를 차례로 설명하겠다.

1. : ("쌍점(colon)"이라고 읽는다.) ":"는 (믿거나 말거나) 번역기이다.
이것이 번역기의 실행을 시작한다.

2. . ("점(dot)"이라고 읽는다.) "."은 우리가 정의하려는 '새' 낱말의
이름이다. 내가 앞에서 말했듯이 이 낱말은 포스의 일부이다. 같은
이름의 낱말이 두 개가 있어도 포스는 아무 불평을 하지 않고 가장 나중
정의를 사용한다.

3. ( n -- | n -- -999 ) 이것은 덧붙임말이다.

포스 번역기는 괄호 안에 있는 것을 덧붙임말로 간주한다.
왜 이렇게 이상한 덧붙임말을 넣느냐고? 이것은 더미 효과
덧붙임말이라고 불리는 특별한 종류로 이 낱말이 더미에서
가져올 값과 (이 경우에는 n이라고 써서 수라는 것을
표시했다) 이 낱말이 실행된 후에 더미에 남기는 값을
표시한다. 이 경우 새 "점"은 아무 것도 남기지 않거나
잘못을 표시하는 -999를 남긴다.
번역기는 이 더미 효과 덧붙임말을 무시하지만 프로그래머는
이것을 보고 이 낱말에 무엇을 입력해야 하는지 알 수 있다.

4. DUP DUPlicate를 줄인 이 낱말은 더미의 맨 위 값을 베껴서 포개 놓는
베껴 다. 실행되고 나면 더미에는 같은 값이 두 개 남는다. 더미에 밑에
서부터 차례로 41, 16, 67이 있었다면 DUP를 실행하고 난 후에는
41, 16, 67, 67이 남는다.

+--------+ +--------+
| 67 | | 67 |
+--------+ DUP +--------+
| 41 | ---------> | 67 |
+--------+ +--------+
| 16 | | 41 |
+--------+ +--------+
| 16 |
+--------+

5. 0> 이 낱말은 더미의 맨 위 값과 0을 비교해서 크면 '참'값을 남기고
아니면 '거짓'값을 더미의 맨 위에 남긴다. (옮긴이: 피그미 포스가
0>를 모른다고 투덜거린다면 ": 0> 0 > ;"로 0>를 정의한다.)

6. IF 이 낱말로 IF문이 시작된다. 더미의 맨 위 값이 '참'이면 (0이 아니
면 면) IF와 ELSE 사이에 있는 코드가 실행되고 프로그램의 흐름은 ELSE
로부터 THEN 다음으로 건너 뛴다. 다른 언어에서와 반대라고? 두 가
지 해결책이 있다.

1. 결국 익숙해지거나
2. 마음에 들지 않는다면 바꾸면 된다! 이것이 바로
포스의 장점이다! 곧 이것에 대해 설명하겠다.

더미의 맨 위 값이 '거짓'이면 프로그램의 흐름은 ELSE와 THEN
사이에 있는 코드로 건너 뛴다. 어느 경우든 프로그램의 흐름은 THEN
뒤로 이어진다. 다른 언어에서처럼 ELSE문은 선택적이다. 있을 수도
있고 없을 수도 있다.

7. . 이것은 '옛' 점이다. 마음에 들지 않아 고치려 하지만 점을 새로
정의하는데 이 낱말을 쓸 수 있다. 이것은 아주 쓸모있는 특색으로
포스가 사전을 사용하는 방법에서 비롯된 것이다.

8. ELSE IF ... ELSE ... THEN 구조는 6 번에서 설명했다.
아니면

9. DROP 이 낱말은 더미의 맨 위 값을 없앤다.
버려

10. -999 이것은 수이고 이 값이 더미의 맨 위에 얹힌다.

11. THEN IF ... ELSE ... THEN 구조는 6 번에서 설명했다.

12. ; ("세미콜론(semicolon)"이라고 읽는다) 이 '낱말'로 모든 ":" 정의를
끝낸다. 이 낱말은 번역기에게 지금 번역하고 있는 낱말의 정의가
끝났다고 알린다.

당신이 지금 무슨 생각을 하고 있는지 나는 짐작할 수 있다. 이 이유로 많은
사람들이 과거에 포스에 대해 나쁘게 말했었다. "도대체 읽을 수가 없지
않은가?" 서로 닮은 다른 프로그램언어들을 배운 뒤에 포스를 처음 접했을 때의
내 반응도 이랬었다. 머리에 처음 떠오른 생각은 "딴세상" 거라는 것이었다.
당신을 진정시키려고 몇 마디 하겠다.

1. 익숙하지 않기 때문에 이상하게 보인다.

2. 포스에서는 언제나 이름을 바꿀 수 있다. "." 대신에 PRINT나
PRINT.NUMBER나 PRINT_NUMBER라고 하든 printf나 WRITE라고 하든 빈칸을
포함하지 않은 문자열이면 당신 마음대로이다. (옮긴이: 이때문에 포스에서
우리말 이름으로 낱말을 짓는데 아무 문제가 없다.)

빈칸을 (ASCII 32) 포함하지 않은 어떤 문자열도 포스 낱말로 쓸 수 있다.
포스는 빈칸으로 낱말과 낱말 사이를 구분한다. 따라서 *&^abdger`~도 포스
낱말로 쓸 수 있다. (하지만 당신이 이런 이름을 좋아한다면 병원에 가
보는 게 좋겠다.) 나한테는 CAVE보다 (CAVE는 Compute AVErage를 줄인
말이다) COMPUTE.AVERAGE가 좋지만 포스는 상관하지 않는다. 포스
프로그램을 읽을 수 없다고 불평하지만 실제로는 프로그래머가 원하는 만큼
읽기 쉽게 쓸 수 있다. 이것은 C에서도 마찬가지다. 어떤 함수를 cave라고
부를 수도 있겠지만 나는 comp_avg나 이와 비슷한 이름을 쓴다. 프로그램을
읽기 쉽거나 어렵게 만드는 것은 프로그래머이지 언어가 아니다. 실제로는
뜻이 통하는 이름을 짓는 데 포스가 덜 걸치적거린다. 잘만 쓴다면
프로그램 언어는 자유로울수록 좋다.

3. "더미"에 대해 뭘 그렇게 자주 이야기하냐고? 포스에는 자주 쓰는 스택이
최소한 두 개가 있다. 프로그래머는 필요하다고 생각하는 만큼 스택을 늘릴
수 있다. 대부분의 경우 두 개면 충분하다.

가장 자주 쓰는 스택은 포스 자료 더미(data stack)이다. 이것은 컴퓨터
용어에서 전통적인 의미의 스택이다. 즉, 나중 들고 먼저 나감 (last in
first out, LIFO) 자료 구조이다. 자료 더미는 포스의 거의 모든 낱말이
사용하는 자료를 보관한다. "더미의 맨 위 값"을 입력으로 가져 온다고
말할 때는 이 자료 더미를 말한다. 자료 더미는 유한하지만 컴퓨터의
메모리를 모두 차지할 만큼 커질 수도 있다. 하지만 순환문에서 잘못하여
더미에 값을 계속 올려 놓지 않는다면 보통의 경우 256 바이트로 충분하다.

다른 더미는 되돌이 더미(return stack)이다. 이것은 한 낱말이 다른
낱말을 부를 때 돌아올 주소를 보관한다. A 낱말이 B 낱말을 부를 때
돌아올 A 낱말 안의 주소가 되돌이 더미에 보관된다. B 낱말이 끝났을 때,
되돌이 더미에서 A의 주소가 꺼내진다. 포스의 장점 중의 하나는 되돌이
더미를 자료를 임시로 보관하는데 쓸 수도 있고 직접 되돌아 올 주소를
바꿀 수도 있다는 것이다. A 낱말이 B 낱말을 부르고 이것이 다시 C 낱말을
부를 경우 프로그래머가 원한다면 B와 A로 돌아가는 되돌이 주소를 모두
버리고 C 낱말이 운영 체제로 바로 돌아 올 수도 있다. 부른 곳으로
돌아가지 않는 것이 좋은 경우는 생각보다 잦다. 저 아래 수준에서 에러가
발생하면 부른 곳으로 돌아가는 것이 전혀 의미가 없을 수 있다. 아니면
A가 B를 부르고 B가 C를 불렀을 경우 C에서 에러가 발생해서 A에게 알리는
것이 필요할 수도 있다. 이 경우 B에 에러를 검사하는 코드를 잔뜩 집어
넣는 (이 조건이 발생하면 이렇게 하고 아니면 저렇게 하고, 저 조건이
발생하면 ...) 대신 B로 돌아가는 되돌이 주소를 없애 버리고 에러가
발생했음을 알리는 값을 자료 더미의 맨 위에 놓고 바로 프로그램의 흐름을
A로 가게 할 수 있다.

더미를 마음대로 조작하는 것에서 보듯 포스를 쓰면 프로그램으로
조종하려는 기계를 완전히 제어할 수 있다. 그리고 기계를 이렇게 완전히
제어할 수 있기 때문에 포스는 매우 강력하다.

포스는 더미와 뒤붙임 표기법(postfix notation, reverse Polish notation,
RPN)을 사용한다. 익숙해지면 뒤붙임 표기법은 '보통' 표기법보다 하나도
어렵지 않다. 보통 사람이 하루면 뒤붙임 표기법에 익숙해질 수 있다.
뒤붙임 표기법을 아래에 설명하겠다.

+, -, *, / 등의 모든 연산은 연산에 필요한 수를 더미의 위에서 꺼낸다.
덧셈을 하려면 두 수가 필요하기 때문에 + 연산자는 더미에서 두 수를
꺼내 더하고 그 결과를 더미의 맨 위에 얹는다.

따라서, 익숙한 표현인 "3 + 4"는 뒤붙임 표기법으로는 "3 4 +"가 된다.
(옮긴이: 이는 우리말 순서와 같다. "3과 4를 더하라.") 연산되는 수가
연산자 앞에 놓인다. + 연산자는 (더미의 맨 위에 있는) 4를 먼저 꺼내고
(이제 더미의 맨 위에 놓인) 3을 꺼내서 두 값을 더하고 결과를 더미의 맨
위에 놓는다. 다시 말하지만 수를 먼저 입력하고 __나서__ 연산자를
입력한다. "3 2 +"는 더미에 5를 남긴다.

이 자리에서 뒤붙임 표기법에 관해 더 자세히 설명하지는 않겠다. 뒤붙임
표기법을 전혀 본 적이 없는 사람이 이것에 아주 편안해지는 데 최대로
하루가 걸린다는 것만 말하고 지나가기로 한다.

포스에서 되돌이 더미의 내용을 바꿀 수 있다고 말한데 대해, C나 다른 언어를
써서도 한 함수(낱말)가 어떤 함수로 돌아갈 지 결정할 수 있다고 반박할 지
모른다. 그러나 포스에서는 애시당초 부른 적이 없는 낱말로도 프로그램의
흐름을 옮길 수 있다. 보통의 경우라면 이렇게 하는 것이 별 소용이 없을뿐
아니라 위험하지만 필요하다면 할 수 있다. 포스를 발명한 찰스 무어(Charles
Moore)는, 프로그래머가 시스템의 어떤 기능이라도 더하거나 빼거나 바꿀 수
없다면 어떤 언어도 모든 사람에게 모든 해답을 줄 수 없다는 것을 일찌기
알아차렸다. 그래서 그는 모든 것을 바꿀 수 있는 언어를 만들었다. 어떤 것도
바꿀 수 있고 더할 수 있고 없앨 수 있다. 심지어는 번역기도 바꿀 수 있다!

도대체 어떤 희한한 경우에 번역기를 바꾸려고 한단 말인가? 당연히 이런
의문을 품을 것이다. 그러나 이렇게 하는 것이 편리한 경우가 나한테 몇 번
있었고 틀림없이 다른 사람한테도 있었으리라고 생각한다. 번역기를 바꿀 수
있다면 그렇게 해서 짠 프로그램을 어떻게 다른 기계에서 실행시킬지 당연히
의문이 생길 것이다. 번역기를 바꿔서 짠 프로그래머 갑의 포스 프로그램은
전혀 포스처럼 보이지 않을 수도 있다. 프로그래머 을이 갑의 시스템에서 어떤
코드를 옮겨 오고 싶지만 을의 번역기로는 번역을 할 수 없을지도 모른다. 이
경우 을은 어떻게 해야겠는가? 을은 갑에게 어떻게 바꾸었는지를 물어서 을이
이미 고친 번역기에 갑이 한 모든 수정을 더하면 된다. 식은죽먹기다. C
프로그래머에게도 비슷한 상황이 생길 수 있다. 내가 C 프로그래머이고 당신이
짠 3차원 숨은 선 제거 함수를 쓰고 싶은데 당신이 그 함수를 짤 때 사용한
라이브러리가 없다면 그 라이브러리를 내가 구하기 전까지 나는 당신의 함수를
사용할 수 없다.

그래서 C와 포스는 마찬가지다, 맞지? 틀렸다. C에서는 번역기나 연산자나 다른
많은 것들을 당신이 원하는 대로 행동하게 바꿀 수 없다. 그래서 어쨌다는
거냐고 당신은 물을 것이다. 아래에 번역기를 바꾸는 것이 편리했던 내 경우를
예로 들겠다.

나는 프로그램 실행의 윤곽을 잡는 프로그램을 (profiler) 짜고 싶었다. 이
윤곽잡개 프로그램 A는 다른 프로그램 B가 실행되는 것을 '지켜 보고' 있다가
B가 끝난 후 표시한 낱말(함수)이 몇 번이나 불려졌는지 각각의 경우
실행시간이 몇 초였는지를 출력한다. 이 수치를 보고 코드의 어떤 부분을 빠를
게 해야 할 지 알 수 있다. 물론 원시 코드를 보고 알 수 있는 경우도 있다.
루프나 특히 감싸인 루프는 빤히 그런 곳이다. 하지만 어떤 경우는 원시코드를
보기만 하는 것으로는 병목이 어딘지 알 수 없다.

이런 프로그램을 번역기회사에서 제공하지 않는다면 다른 언어에서 당신은
상당한 노력을 들여야 만들 수 있을 것이다. 문제는 C에서 함수가 불릴 때마다
당신의 윤곽잡개 코드가 실행되어야 한다는 것이다. 필요한 코드를 당신 손으로
쓰는 것은 별 일이 아니지만 이렇게 하려면 그 코드를 모든 함수에 일일이
포함시켜야 한다. 내가 하고 싶은 것은 윤곽잡개 프로그램을 쓰지 않을 때와
똑같은 B의 원시 코드를 써서 "윤곽잡개 켜, 프로그램 돌려, 결과 보여"라고
시키려는 것이다. 이제 내가 무슨 소리를 하는 건지 알았을테니 번역기를
바꾸는 것이 왜 필요한지 보자.

위에서 말한대로 포스에서는 낱말 :로 번역기를 부른다. 명령통역기(command
interpreter)가 :를 보면 번역기를 부른다. (명령 통역기는 보통 줄여서
통역기라고만 부른다.) 나는 낱말 :를 바꿔서 아래처럼 행동하게 만들었다.

번역할 때 : 번역기는 불릴 때마다

1. 이 낱말이 불린 회수, 낱말 실행이 시작한 시각과 끝난 시각, 총
실행시간을 기록할 자리를 마련한다.

2. 실행 회수를 하나 증가시키고 실행 시작 시각을 기록할 코드를 낱말에
넣는다.

3. 앞에서 .을 고칠 때 '옛' .을 쓴 것과 마찬가지로, 원래 번역기를
써서 보통 때처럼 낱말을 번역한다. 포스에서는 이렇게 원래 번역기의
원시 코드가 없어도 낱말을 이용할 수 있다.

4. 실행이 끝난 시각을 기록하고 이 낱말이 실행되는데 걸린 시간을
계산해서 이를 총 실행시간에 더하는 코드를 낱말에 넣고 번역을
끝낸다.

실행할 때 이 낱말이 불려지면 번역기가 넣어둔 코드가 다음의 일을 한다.

1. 낱말의 실행 회수를 하나 증가시킨다.
2. 현 시각을 시작시각 자리에 기록한다.
3. 그 낱말의 원래 코드를 실행한다.
4. 현 시각을 종료시각 자리에 기록한다.
5. 지금까지 이 낱말을 실행시키는데 걸린 총시간을 계산하고 기록한다.

: 번역기를 바꾸는 것만으로 위의 모든 일을 할 수 있다. 다시 강조하지만
__윤곽잡개 프로그램이 지켜보는 프로그램의 원시코드는 단 한자도 바꿀 필요가
없다__. (위의 예에서 프로그램 A가 지켜보게 하기 위해 프로그램 B는 다른
일을 하나도 할 필요가 없다.) 포스는 낱말이 번역될 때의 행동도 실행될 때의
행동도 바꿀 수 있다. 이것은 아주 강력하다. 이것은 C
전처리기(preprocessor)가 마크로를 정의해서 사용하는 것과 닮은 점이 있지만
포스를 써서 할 수 있는 일은 그보다 훨씬 더 많다.

윤곽잡개 프로그램의 전체 원시코드는 겨우 4065 바이트이다. 번역할 때 이
프로그램의 사용법을 화면에 표시하는 코드를 포함하고도 그렇다. 프로그램이
번역될 때 사용법을 화면에 표시하는 것이 아주 편리하기 때문에 나는 보통
그렇게 한다. 이렇게 하는 것은 아주 쉽다. 사용법을 화면에 표시하는 코드를
낱말의 정의 밖에 놓으면--":"와 ";"의 바깥에 놓으면--통역기가 번역할 때 이
코드를 실행시킨다.

원시코드를 번역한 실행코드는 1057 바이트이다. 어떤 언어로 이렇게 짧은
윤곽잡개 프로그램을 짤 수 있겠는가? 내가 알기로 포스말고는 없다. 실은
나중에 설명할 이유 때문에 번역한 포스 코드는 어셈블리어로 짠 프로그램을
어셈블한 것보다 더 짧다. 내가 이 말을 처음 들었을 때는 말도 되지 않는
소리라고 생각했었다. 하지만 지금까지 만들어진 거의 모든 포스에 대해 이것은
맞는 말이다.

참으로 놀라운 것은 포스 언어를 확장하는 것이 이렇게 쉽다는 것이다. 물론 C
프로그래머도 내 윤곽잡개와 같은 일을 하는 프로그램을 만들 수 있을테지만
이렇게 짧고 쉽게 할 수는 없을 것이고 더구나 C 번역기를 바꿔서(!) 이 일을
할 수는 없을 것이다. 아마도 원래의 원시코드에 함수마다 코드를 더할 수밖에
없어서 원시 코드가 길다면 (수천 수만 행이라면) 아주 지루하고 시간이 많이
걸릴 것이다.

우리는 모두 C가 아주 인기있는 범용 언어라는 것을 안다. 따라서 C에서
번역기를 바꿀 수 없다면 그것은 중요한 게 아닐 거라고 주장할 수도 있다.
그러나, 포스가 강조하는 것은 당신이 원하는 것은 __무엇이든__ 할 수 있다는
것이다. 프로그래머는 포스의 어떤 성질이라도 아주 쉽게 바꿀 수 있다.
프로그래머는 포스를 찰흙처럼 주물러서 해답을 만든다. 프로그래머는 자료
구조나 함수(절차) 같이 언어가 규정하는 것들을 가지고 궁리하는 대신 문제를
묘사하는 낱말들을 포스에 더해서 문제를 해결한다.

지금까지 말한 포스의 장점은 C에서도 가능하다고 반박할지 모른다. (비록 더
길고 복잡하고 원시코드를 고쳐야 할지도 모르지만) 윤곽잡개 프로그램을 짤 수
있고 필요하다면 printf도 고쳐 쓸 수 있을 것이다. 이제 C로는 도저히 할 수
없는 일을 예로 들겠다.

printf가 마음에 들지 않는다면 앞의 예에서처럼 C 프로그래머는 이것을 고칠
수 있다. 그러나 + 연산자가 마음에 들지 않는다면 어떻게 하겠는가?
잠시동안만 덧셈의 의미를 바꿀 필요가 있다면 어떻게 하겠는가? C 번역기의
아주 깊숙한 부분에 이것이 있고 번역기의 원시코드를 가지고 있지 않기 때문에
C 프로그래머는 아무 것도 할 수 없다. 핵커가 되어 C 번역기를 역어셈블하고
실행코드를 바꿔서 C 번역기를 고칠 수 있을지 모르지만 이것은 정말로
극단적인 경우로 C 번역기 회사는 이것을 좋아하지 않을 것이고 문제가 생겼을
때 도와주지도 않을 것이다. 어떤 번역기 회사는 자기들의 권리을 침해했다고
주장할지도 모른다. 따라서 이것은 문제를 해결하는 옳은 방법일 수 없다. C
프로그래머는 어쩔 수 없이 그가 원하는 + 연산자를 제공하는 다른 C 번역기를
구할 수밖에 없다.

포스에서는 산수 연산자를 포함한 __모든__ 것이 낱말이다. 앞에서 .을
고쳤듯이 포스 프로그래머는 단지 +를 원하는 대로 다시 정의하면 된다. 전혀
어렵지 않다. 당신은 이렇게 말할 것이다. "제발 그만해 두라. 도대체 덧셈이
하는 일을 바꾸는게 당신한테 몇 번이나 필요했었는가?" 덧셈이 하는 일을
바꾸는 경우는 거의 없으리라는 것을 (그 드문 경우 중의 하나를 곧 예로
보이겠다) 나도 인정한다. 어쨌든 바꾸는 것은 가능하고 이 때문에 포스는 더
말랑말랑하고 더 강력한 언어이다. +를 고른 것은 단지 예를 보이기 위한
것이고 포스 프로그래머는 필요에 따라 어떤 낱말도 바꾸거나 없앨 수 있다.
__포스는 벽없는 방__이라고 말하는 사람도 있다. 포스 프로그래머가 어떤 일을
하는데 어려움을 겪는다면 그 자신의 문제이지 절대로 언어 때문이 아니다.
포스의 어떤 면도 마음대로 바꿀 수 있기 때문에 프로그래머가 문제를 해결하지
못하는 것은 전적으로 프로그래머가 무능력하기 때문이지 프로그래머한테
필요한 어떤 기능이 포스에 없기 때문이 아니다. 비록 쉽지는 않지만 포스
프로그램의 문법을 C나 파스칼 또는 다른 언어와 비슷하게 고치는 것도
가능하다.

그런데 당신이 뒤붙임 표기법을 좋아하지 않는다면 어떻게 하겠는가? 다른
언어라면 당신은 아무 것도 할 수 없다. 포스에서 모든 것을 바꿀 수 있다면
이것도 고칠 수 있어야 할 것 아닌가? __맞다__! 다른 언어처럼 "3 + 4"를
받아서 7을 출력하도록 포스를 고칠 수 있다. 지금 당신은 +의 행동이 바뀌기를
바라는 것이다. 새 + 연산자가 더미의 맨 위 값을 꺼내서 그것을 연산자의
__뒤에__ 오는 수와 더할 것을 당신이 바라는 것이다. 보라, 조금 전까지만
해도 +를 바꿀 필요가 전혀 없을 것 같았지만 벌써 바꾸려 하고 있지 않은가?
가운데붙임 (infix) 표기법을 쓰도록 + 연산자를 바꾸는 게 얼마나 힘드냐고?
식은죽먹기다.

: + 32 WORD NUMBER + ;
: + 32 낱말 값 + ;

쉽지 않은가? 이제 "3 + 4"를 입력하면 7이 더미의 맨 위에 남는다. 다른
연산자도 이렇게 쉽게 바꿀 수 있다. 앞붙임 (prefix) 표기법을 쓰고 싶다면
그렇게 바꾸면 된다.

포스의 확장성에 대해 몇 가지 더 짚고 넘어 가기로 하자. 알다시피 C는 0으로
끝난 (null-terminated) 문자열을 쓰고 파스칼은 센 (counted) 문자열을 쓴다.
어느쪽이 나은 지에 대해 격렬한 논쟁이 있었고 양쪽 다 일리가 있다. 어쨌든
C에서 센 문자열을 쓰는 것은 어렵다. 파스칼에서 0으로 끝난 문자열을 쓰는
것도 어렵기는 마찬가지다. 포스에서는 보통 센 문자열을 쓰지만 약간의 코드를
더해서 둘 다 쓰게 할 수 있다. 포스에서는 다른 낱말을 정의하는 낱말을
정의할 수 있다. 이것은 다른 언어에 없는 포스의 또 다른 장점이다. 이
'정의어(defining word)'를 설명하려면 한참이 걸릴 것이므로 이 글의 끝에
소개한 책을 찾아 이에 관한 부분을 모두 읽기 바란다. 정의어를 만드는 능력은
참으로 대단하고 __다른 언어에는 이와 비슷한 기능도 없다__. 아래에 짧은
예를 보인다.

다른 낱말을 정의하는 낱말을 정의할 수 있다고 했다. 배열를 정의하고 싶다고
하자. 이 배열은 좀 특별해서 지적한 원소의 값뿐 아니라 그 원소의 값이
꺼내진 회수와 메모리 주소도 돌려주어야 한다. 파스칼이나 C나 다른 언어라면
배열의 값을 꺼내기 전에 실행될 코드를 따로 아래처럼 작성해야 한다.

access_my_array ( xyz, element_num, count, address ) ; { 파스칼 }

이것은 파스칼에서 배열의 값을 꺼내는 보통 방법인

my_array [j] { 1차원 배열의 경우 }

보다 훨씬 불편하다. 포스에서는 배열을 아래처럼 정의하고

100 ARRAY Normal_Array
100 배열 보통배열

아래의 보통 문법으로 이 배열의 값을 꺼낸다.

45 Normal_Array @
45 보통배열 @

이것은 "보통배열"의 45번째 값을 더미의 맨 위에 올린다. 포스에서는 새
자료형을 만드는데 정의어를 쓸 수 있고 이 자료형이 실행될 때의 행동을
마음대로 바꿀 수 있다.

: super_array CREATE .... DOES> .... ;
: 수퍼배열 짓기 .... 하기> .... ;

super_array my_array ( super_array인 my_array를 만든다 )
수퍼배열 내배열

이 배열의 값을 꺼내는 방법은 보통 배열의 경우와 같다.

45 my_array @
45 내배열 @

하지만 이 경우에 "내배열"이 "수퍼배열"이기 때문에 한 값 대신 세 값이
(45번째 값, 지금까지 읽힌 회수, 45번째 값의 주소가) 더미에 얹힌다. 이렇게
(포스 프로그래머에게) 익숙한 문법이 한결같이 쓰이고 읽힌 회수를
증가시키거나 45번째 값의 주소가 얼마인지 당신이 신경쓸 필요가 없다.
이것들은 내배열이 수퍼배열이기 때문에 자동적으로 해결된다. (옮긴이: 어디서
들어본 말 같지 않은가? 1970년 근처에 만들어진 포스에 이미 객체 지향적인
개념이 들어있다.) 이 일을 하는 코드는 수퍼배열의 정의 안에 들어 있어야
한다. 어쨌든 수퍼배열과 보통배열을 사용하는 방법은 (프로그래머가 다르게
하고 싶지 않다면) 같다.

포스의 사전은 프로그래머가 요구하는대로 늘었다 줄었다 할 수 있다. 프로그램
1, 5, 10, 100 개를 사전에 올리고 원하는 순서대로 실행시킨 다음 잊어버리고
(잊기[FORGET]는 이때 사용하는 포스 낱말이다) 다른 프로그램을 올릴 수 있다.

포스에는 오직 하나의 사전이 있지만 프로그래머가 원하면 낱말들을 용어별로
나누어 놓을 수 있다. 이렇게 나눠놓으면 프로그래머가 정해 놓은 순서에 따라
어떤 용어를 먼저 찾고 다른 용어를 차례로 나중에 찾는다. 이렇기 때문에 같은
이름을 가진 낱말이 둘, 셋 이상 있어도 헷갈리지 않고 쓸 수 있다.

낱말의 이름과 그 낱말의 정의를 가리키는 포인터가 포스 사전에 들어 있다. 한
정의를 택해 하나하나 따라가며 어떻게 번역이 되는지를 보자.

: SQUARE ( n -- n*n ) ( 이 낱말은 n의 제곱값을 계산한다 )
DUP * ;
: 제곱 ( n -- n*n )
베껴 * ;

: 번역기가 SQUARE를 보면 이것이 새로 만들어질 낱말의 이름인 줄 안다.
번역기는 SQUARE라는 이름의 낱말이 들어갈 자리를 사전에 준비한다. 다음으로
번역기가 보는 낱말은 DUP이다. 번역기는 SQUARE의 내용이 될 낱말들의 주소를
두는 곳에 DUP의 주소를 찾아 써 넣는다. 지금까지 한 일을 아래에 보인다.

사전의 자리 포인터 메모리의 다른 곳
---------------- -------- -----------------------
메모리 주소 1005에
SQUARE 1005
197 ( DUP의 주소 )
9872 ( *의 주소 )
598 ( ;의 주소 )

이때 197, 9872, 598은 각각 낱말 DUP, *, ;의 코드가 있는 주소이다.

여기서 보면 SQUARE는 결과가 크든 작든 상관하지 않는다. 이 정의에서는
결과가 너무 커서 정수의 범위를 벗어나도 (넘쳐도) 알 수가 없다. 너무 커서
넘치지 않는지를 프로그래머가 알고 싶다면 약간의 코드를 더해 이를 확인할 수
있다. 그러나 프로그래머가 어떤 이유로 넘치는 경우가 생길 수 없다는 것을
미리 알고 있다면 굳이 두 번 확인해서 SQUARE를 느리게 만들 이유가 있겠는가?
이것은 포스가 빛나는 또 다른 경우이다. 실행 프로그램은 프로그래머가 원하지
않는 코드를 포함하지 않는다. 에러를 확인해야 한다면 필요한 자리에 써
넣으면 된다. 써 넣는 것은 간단하지만 실행시키는데는 (루프 안이라면 더욱)
시간이 걸리기 때문에 포스에서는 프로그래머가 이것을 결정한다. 포스를 쓰면
컴퓨터의 모든 자원을 사용하는 데 최대의 효과를 얻을 수 있다. 이 예에서는
프로세서가 불필요한 에러 확인을 하는데 시간을 낭비하지 않는다.

위에서 보았듯이 번역된 SQUARE의 코드는 실행시킬 수 있는 코드가 아니라
주소들의 리스트이다. 따라서 포스 프로그램을 실행시키려면 번역기가
필요하다. "이제 그만하자. 결국 이것은 베이식처럼 통역된단 말 아닌가?"라고
당신이 말하려 할 지 모르지만 __아니다__. 이것은 베이식과는 아주 다르다.
포스는 통역 베이식보다는 훨씬 빠르기 때문에 통역기가 있다는 것을 믿을 수
없을 것이다.

포스 프로그램이 실행되는 동안 실행되는 통역기는 엄청나게 빠르다. 이
통역기는 두가지 일만을 한다.

1. 프로그램 카운터를 증가시킨다.
2. 주소 리스트의 다음 주소로 뛰어간다.

이래서 이 통역기를 주소 통역기 (address interpreter) 또는 내부
통역기(inner interpreter)라고 부른다. 68000을 프로세서로 쓰는 기계의 경우
22 기계 주기(machine cycle)를 사용하는 기계 명령어 2 개로 이 일을 할 수
있다. 이것은 매우 매우 빠른 것이다. 실행시키는데 다른 일을 해야 하는 것은
사실이다. 그래서 포스 프로그램은 다른 언어로 짠 프로그램보다 느리다, 맞지?
평균적으로는 그렇다. 그러나 앞에서 말한 윤곽잡개 프로그램이 있다. 이것은
이런 때 아주 유용하다. 윤곽잡개로 어떤 낱말에서 가장 오랜 시간을 보내는지
알 수 있고 이 낱말을 어셈블리어로 다시 쓸 수 있기 때문에 (포스 환경에서
바로 어셈블리어를 쓸 수 있다) 결국 얻어진 포스 프로그램은 완전히
어셈블리어로 짠 프로그램 말고는 가장 빠르다.

뭐라고? 당신이 어셈블리어를 싫어한다고? 상관없다. 상품으로 나와 있는 포스
시스템 중에 최적화 기능이 든 것이 많이 있다. 이것을 쓰면 당신이 쓰는
기계의 기계 명령어를 모르더라도 프로그램의 일부를 (전부를 선택했다면
전부를) 기계어로 바꾸어 줄 것이다.

내가 앞에서 말했듯이 포스가 C만큼 널리 쓰이는 언어는 아니다. 그러나 기계의
능력을 최대로 발휘할 것을 요구하는 실시간 (real time) 프로세스 제어 만큼은
포스가 자주 쓰이는 분야이다. 포스가 느리다면 이 곳에 쓰일 리가 있겠는가?
미항공우주국(NASA)에서 스페이스 셔틀 연구를 하는데 포스를 쓰고 캘리포니아
파사데나에 있는 제트 추진 연구소(Jet Propulsion Laboratories)도 우주와
관련된 연구에 포스를 쓴다고 들었다. 포스는 엄청나게 효율이 좋고 기계에서
가장 많은 것을 얻어내는데는 (물론 어셈블리어를 빼고) 이보다 좋은 언어가
없다.

찰스 무어와 동료들은 기계어가 포스인 마이크로프로세서를 만들었다. NOVIX
4000이라고 불리는 이 칩은 눈부시게 빠르다. 이것은 포스 프로그램을
실행시키는데 통역기가 필요 없다. 포스가 이것의 기계어이다. 이것은 보통 10
MHz에서 4 MIPS의 속도를 낸다. IBM PC 호환 컴퓨터의 슬롯에 바로 끼울 수
있는 이 칩을 사용한 보드를 구할 수 있다. (옮긴이: 16비트 포스 프로세서는
NOVIX를 개량한 RTX2000으로 이어지고 32비트 포스 프로세서로는 SC32가 있다.
이들을 이용한 삽입 보드 [plug-in board] 컴퓨터와 한 보드 [single board]
컴퓨터를 Silicon Composers Inc.에서 구할 수 있다. 다른 프로세서를 이용한
한 보드 컴퓨터 중에도 포스를 쓸 수 있는 것이 많다.)

포스 코드는 매우 짧다. 앞에서 보았듯이 포스 번역기가 코드를 번역하는 방법
때문에 이렇게 된다. 포스 프로그램은 두 바이트 주소의 리스트로 번역이
되지만 어셈블리어는 둘, 넷, 여섯 바이트의 기계 명령으로 구성되기 때문에
번역된 포스 코드는 같은 일을 하는 어셈블리어 코드보다도 짧다. 두 바이트
주소를 쓴다면 어떻게 64 K바이트 이상의 메모리에 대해 주소를 지정하느냐고?
오래된 포스 시스템은 할 수가 없어서 64 K바이트밖에 쓸 수 없었다. 요즘의
포스 시스템들은 기계가 가진 모든 메모리를 사용할 수 있다. 사전의 구조와
관련된 이 기법은 상당히 고급이어서 여기서 다룰 수 없다. 이것이 가능하고
아주 효율적이라고만 말하고 지나 가기로 한다.

포스가 어셈블리어를 제외한 다른 어떤 언어보다도 빠르다는 것은 IBM PC
호환기종에 쓰는 HS/FORTH로 확인할 수 있다. 같이 따라오는 최적화 기능을
쓰면, 최적화 기능을 사용한 모든 회사의 C, 파스칼, 포트란을 비롯한 다른
어떤 언어보다도 빠르다. "에라스토테네스의 체"나 다른 벤치마크 시험으로
확인할 수 있다. 벤치마크 시험의 결과를 너무 믿어서는 안된다는 것은 나도
알지만 어쨌든 나를 믿어라. 최적화 기능을 사용한 포스는 (어셈블리어를
제외한) 다른 어떤 언어보다도 빠르다. 최적화 기능을 사용하지 않고도 포스는
최적화시킨 C 코드의 1/2 정도의 속도를 낸다. RF 안테나에 관한 무엇을
계산하고 그림을 그리는 (내가 이해하지 못 했기 때문에 더 자세히 설명할 수
없다) 프로그램을 짠 사람과 이야기해 본 적이 있다. 그는 (최적화하지 않은)
포스와 터보 파스칼과 Lattice C로 프로그램을 각각 짜 보았는데 포스가 가장
빨랐다고 말했다. 파스칼이 가장 느렸고 포스는 C보다 10 % 정도 빨랐다고
한다. 어떤 것들은 C나 파스칼로 짜는 것이 분명히 더 빠를 것이다. 당신이
하고 있는 일이 어떤 경우일지는 미리 알 수 없다. (옮긴이: 조금 뒤에
글쓴이가 말하겠지만 이 글은 1987년에 쓰인 것이다.)

포스의 다른 장점은 포스 시스템에는 보통 편집기, 번역기, 어셈블러, 통역기
(물론 주소 통역기와 명령 통역기 둘 다), 표준 사전이 모두 따라오고 이것들이
모두 합쳐서 50 K바이트밖에 차지하지 않는다는 것이다. 포스는 지금까지
만들어진 거의 모든 개인용 컴퓨터에서 실행시킬 수 있다. 메모리가 24
K바이트밖에 되지 않는 래디오색(Radio Shack) TRS-80 컴퓨터에서도 포스는
사용자가 쓸 메모리를 충분히 남겨 놓는다.

포스의 또 다른 좋은 점은 번역 속도가 빠르다는 것이다. 번역기가 해야 할
일이 간단하기 때문에 번역 속도가 상당히 빠르다. (볼란드사의 터보
번역기들을 제외하면) 대부분의 C나 파스칼 번역기는 원시코드 4000 행을
번역하는 데 3 내지 5 분이 걸린다. 포스는 1 분 정도밖에 걸리지 않는다.
볼란드사의 제품들은 포스보다 번역 속도가 더 빠를지도 모르지만 내가 써보지
않았기 때문에 뭐라고 말할 수 없다. HS/FORTH를 비롯한 어떤 포스는
해싱(hashing) 기법을 써서 분당 10,000 행까지 번역 속도를 높였다. 포스는
확장할 수 있기 때문에 어떤 포스에도 같은 기법을 써서 번역 속도를 높일 수
있다. (포스만이 진정한 의미에서 확장할 수 있다. 다른 언어도 확장할 수
있다고 주장하지만 포스에서 말하는 의미로는 아니다.)

포스의 다른 좋은 점은 바깥 통역기 즉 명령 통역기를 써서 프로그램을
대화식으로 짤 수 있다는 것이다. 사용하기 전에 원시 코드의 조각들을
입력하고 실행시켜서 완벽한지를 시험할 수 있다. 번역기와 통역기가 모두 있는
환경에서 C로 일해 본 사람이라면 내가 말하는 것이 얼마나 좋은지 알 것이다.

옛 포스 시스템은 자료의 블록을 편집하는 블록 편집기를 썼고 이것은 그
당시의 시스템과 잘 어울렸다. 지금은 컴퓨터가 운영 체제를 갖추고 있기
때문에 요즘의 포스는 원시코드를 운영 체제의 표준 텍스트 파일에 저장했다가
번역할 수 있다. 어느 쪽에도 각각의 장점이 있지만, 블록 편집기를 새로 배울
필요가 없고 손에 익은 편집기를 쓸 수 있기 때문에 나는 텍스트 파일을 즐겨
쓴다. 어는 쪽을 쓸 건 지는 쓰는 사람한테 달렸다. 가지고 있는 포스 시스템에
텍스트 파일을 다루는 기능이 없다면 당신이 더하면 된다.

지금까지 나는 내가 포스에서 좋아하는 점들을 말했다. 세상의 모든 것들처럼
좋은 게 있으면 나쁜 것도 있기 마련이다. 지금부터는 내가 보는 포스의 단점을
말하겠다.

1. 어떤 시스템에서는 원시 코드를 저장하는데 텍스트 파일을 쓸 수 없다.
물론 프로그래머가 더하면 되지만 하루만에 되는 일은 아니다. (아마도 일
주일이 걸릴 것이다.)

2. 어떤 포스 시스템은 기능이 고루 갖추어져 있고 어떤 것은 그렇지 못하다.
함수 라이브러리의 구멍을 메꾸는데 시간을 보내지 않으려면 C 번역기를 살
때 필요한 기능이 다 들어 있는지 미리 확인하고 싶을 것이다. 포스에서도
마찬가지다. 포스에는 몇 가지 표준이 있고 포스 시스템은 보통 그 중의
하나를 따르지만 프로그램을 짜는데 필요한 모든 것이 표준에 정해져
있지는 않다. (옮긴이: 대표적인 포스의 표준은 79년에 정해진 "79-표준"과
83년에 정한 "83-표준"이다. 새로 정하는 "미표준국 표준 포스[ANSI
Standard Forth]"가 거의 완성 단계에 있어 94년 중에 발표될 것이다.)
프로그래머는 포스 시스템의 구멍들을 자기가 짠 코드로 메워야 한다. 이
점은 바로 앞에서 말했듯이 C도 마찬가지다.

3. 포스는 아주 많은 자유를 준다. 어떤 사람은 밧줄이라고 말한다. 올가미를
만들어 거기에 당신 목을 맬 수도 있다. 포스가 당신한테 그 밧줄을 줄
때는 당신이 그걸로 다리 사이를 잇고 프로그램 세계의 가장 높은 봉우리에
올라 가라는 뜻이었다. 그러나 고의든 실수든 당신이 그것을 다른 목적에
쓰려고 한다면 포스는 당신의 목을 달아 맬 것이다. 포스를 쓸 때 개인용
컴퓨터를 먹통으로 만드는 것은 아주 쉽다. 포스를 써서 기계의 모든
부분을 마음 대로 조작할 수 있다. '당신 것이 아닌' 메모리에 어떤 값을
써 넣으려 한다면 포스는 상관하지 않는다. 그러나 운영체제는 그렇게
무심하지 않아서 결과는 에러 메시지이거나 그보다는 보통 기계가 먹통이
되는 것이다. 이것을 막기 위해 포스 프로그래머가 프로그램을 맨처음
실행시키기 전에 코드에 마련할 수 있는 방지장치가 있다. 실행시키고 나서
벌레가 없다고 생각될 때 (당신이 똑똑해서 프로그램을 잘 꾸몄다면)
스위치를 하나 바꾸어 이 방지장치를 끌 수 있다. 덜 똑똑한 프로그래머는
원시 코드에 코드를 덧붙였다가 나중에 없애야 할 것이다. 정의어와
"가리킴 실행(vectored execution)"이라 부르는 방법을 쓰면 원시 코드에
손을 댈 필요가 없다.

4. 어떤 포스에서는 실수 (부동소수점) 연산을 할 수가 없다. 찰스 무어가
포스를 만들 때는 실수 연산을 일부러 뺐다. 그 당시 (1970년 근처)에는
컴퓨터에 빠른 실수 연산 보조프로세서가 없어서 실수를 쓰려면 속도가
많이 떨어지는 것을 감수해야 했다. 그래서 찰스 무어는 고정 소수점
연산법을 개발해서 그것을 대신 썼다. 지금(1987년)은 실수 연산
보조프로세서가 많이 나와 있고 포스는 이것을 아주 잘 쓸 수 있다. 어떤
시스템에는 들어 있지만 어떤 시스템에서는 당신이 필요한 코드를 짜야
한다. 미리 알아 보는 것이 좋다.

5. 어떤 시스템에서 부동소수점 연산을 쓸 수 없는 것처럼 어떤 시스템에는
문자열을 다루는 낱말이 부족해서 프로그래머가 지어야 한다. 다시
말하지만 사기 전에 필요한 것이 다 들어 있는지 확인해야 한다. 내가 쓰는
문자열을 다루는 낱말들은 내가 만들었다. 어려운 일은 아니지만 이 일은
다른 사람에게 맡기고 바로 문제를 해결하는데 뛰어들고 싶은 사람도 있을
것이다.

이제 포스의 다른 장점들을 아래에 적는다.

1. 포스에서는 2 에서 72 사이의 어떠한 수도 진법의 밑으로 쓸 수 있다.
원하는 밑 xx를 골라서 "xx BASE !"라고 입력만 하면 된다. 그리고 나면
모든 연산이 그 수를 밑으로 해서 이루어진다. 얼른 생각하기에 밑으로
쓸모가 있는 것은 2 (이진법), 8 (팔진법), 10 (십진법, 디폴트), 16
(십육진법)이지만 다른 경우도 있을 수 있다. 60진법은 시간을 세는데
쓰인다.

2. 포스를 써서 올라가고 싶은만큼 높은 수준으로 올라갈 수 있다. 가장 낮은
수준의 일을 하는데도 포스는 똑같이 편리하다. 비트을 다루기도 쉽고
인터럽트 처리기를 짤 수도 있다. 포스를 써서 관계형 데이타 베이스 운영
시스템을 만들 수도 있다.

3. 한 낱말 안에 포스와 어셈블리어를 섞어 쓸 수 있다. 이것은 굉장히
편리하다. 벌레 잡기가 쉽고 키보드입력과 화면출력을 어셈블리어로 할
필요가 없다.

4. 자료로 얻은 것을 마치 코드인 것처럼 실행시킬 수 있는 LISP의 능력을
흉내낼 수 있다. 실행할 때 사용자로부터 문자열을 입력받는 프로그램을
짰다고 하자. 포스는 이 문자열을 포스 코드로 간주하고 번역, 실행시킨
다음 당신이 짠 프로그램으로 돌아올 수 있다. 프로그래머의 개입 없이 이
과정이 저절로 일어나게 할 수 있고 이것은 식은죽먹기처럼 쉽다. 당신의
응용에 필요하다면 이렇게 자료와 코드 사이의 구분을 없앨 수 있다.

5. 겨우 1,000 바이트 정도의 원시 코드를 더해서 객체 지향적 프로그램법을
쓸 수 있다. 나는 내 포스 시스템을 이렇게 확장했고 이것은
프롤로그(Prolog) 만큼 강력하다.

6. 포스를 쓰면 프로그래머의 능률은 엄청나게 높아진다. 다른 프로그램
환경이 이렇게 주장하는 것을 들은 적이 있겠지만 포스는 언어이면서
동시에 프로그램 환경이다. 포스가 개발된 방법 때문에 아주 쉽게 코드를
쏟아 낼 수 있다.

먼저 해결하려는 문제를 자세히 연구한다. 문제의 핵심을 파악한 후에 맨
나중에 얻을 답에서 쓸 적당한 낱말들을 고안한다. 이렇게 해서
'주제어'들을 찾으면 바닥에서부터 필요한 낱말을 차례로 지어서 문제를
해결하는 뼈대가 될 이 주제어들을 만든다. 한 번에 한 낱말씩 코드를 짜고
벌레를 잡는다. 아래 수준에서 필요한 낱말이 모두 만들어지면 한 단계
위에서 필요한 낱말을 만들어 나간다. 마침내 (당신이 생각하는 것보다
훨씬 빨리) 처음에 생각한 낱말들에 이르게 될 것이다. 이것은 꼭대기에서
내려오는 (top-down) 프로그램법과 바닥에서 올라가는 (bottom-up)
프로그램법을 결합한 것이다. 이 방법을 쓰면 놀랄만큼 일이 잘 된다.
만들어진 프로그램은 잘 나뉘어 (modular) 있기 때문에 유지 보수 하기도
쉽다.

포스에서 낱말은 아주 짧고 이해하기 쉽게 만드는 것이 좋다. 다른
언어에서는 함수를 부르고 값들을 확인하고 넘기는데 많은 일을 해야 하기
때문에 코드가 한 줄이나 두 줄인 함수를 쓰는 것이 비경제적이다. 그러나
포스에서는 이 댓가가 비싸지 않다. 포스는 이미 더미를 사용하고 있고
(프로그래머가 필요하다고 판단한 경우가 아니면) 값들을 확인하지 않는다.
결과적으로 포스 프로그래머는 다른 언어에 비해 아주 짧은 낱말을 많이
지을 수 있고 좋은 프로그래머라면 많이 지어야 한다. 이렇게 해서 다른
언어를 써서는 얻을 수 없는 잘 정리된 코드를 얻을 수 있다.

7. 포스에서 "가리킴 실행(vectored execution)"이라 불리는 방법을 쓸 수
있다. 이것은 한 포스 낱말의 포인터를 바꿔서 다른 코드를 가리키게 하는
것이다. 그 결과 어떤 낱말도 이 낱말의 포인터가 가리키는 것에 따라 다른
행동을 보일 수 있다. 지금은 이 낱말이 한 값을 출력하지만 조금 뒤에는
세 값을 출력하고 또 조금 지나면 한 값만을 출력한다! 이것은 __아주
아주__ 편리하다. (비록 덜 강력하기는 하지만) C에서도 함수를 가리키는
포인터 배열을 써서 비슷한 일을 할 수 있다.

8. 포스 사전에 수록된 낱말들은 모두 한 층에 있기 때문에 어떤 낱말도 부를
수 있다. 그러나 포스 프로그래머가 원하면 '머리없는' 낱말을 만들 수
있다. (다시 말하지만 __모든__ 것이 가능하다.) 포스 시스템을 파는
회사는 낱말의 머리를 자르지 않는다. 그런데 왜 머리를 자르냐고? 머리를
자르면 그 낱말을 사전에서 찾을 수 없게 되는 대신 몇 바이트를 절약할 수
있다. 어떤 프로그래머들은 잘못쓰면 아주 위험한 결과를 일으킬 수 있는
낱말의 머리를 잘라 실행시킬 수 없게 하지만 많은 사람들은 사용자에게
위험을 알리기만 하고 내버려 둔다.

9. 포스는 자료형을 까다롭게 따지지 않는다. 포스한테는 모든 것이 수이다.
모든 자유가 그렇듯이 이것은 축복이며 동시에 저주이다. 사용자에게
자신의 이름을 입력하라고 해 놓고 글자들을 더해서 이름의 제곱근을 구할
수도 있다. 나에게는 쓸모가 없지만 이것이 필요한 사람이 있을 지도
모른다. 포스는 상관하지 않는다. 결국은 컴퓨터한테는 모든 게 수
아니던가? 이름의 제곱근은 해싱 함수로 쓸 수 있을지도 모른다. 한 편으로
자료형을 까다롭게 따지고 싶다면 쉽게 그렇게 할 수 있다. 당신에게 달려
있다.

10. 포스를 써서 프로그래머는 원할 때 기계의 __모든__ 면을 제어할 수 있다.
이점은 어셈블리어보다 낫다. 어셈블리어에서는 당신이 언제나 모든 면을
제어__해야만 한다__. 프로그램에서 기계의 모든 면을 제어하는 것이
필요한 경우는 몇몇 순간일 것이다. 포스를 쓰면 필요할 때만 기계를
완전히 제어하고 그렇지 않은 경우에는 아래 수준에서 해야 할 상세한 일을
잊어 버릴 수 있다.

11. 포스에서도 C에서처럼 필요한 입력의 갯수가 고정되어 있지 않은 낱말을
만들 수 있다. C 프로그래머에게 물으면 이것이 얼마나 편리한지 이야기해
줄 것이다. 또 다시 말하지만 포스에서는 __모든__ 것이 가능하고 조금의
노력으로 거의 모든 경우에 원하는 것을 실현할 수 있다! 이 경우 포스
낱말은 더미에서 입력을 받고 더미로 출력을 하기 때문에 몇 개를 입력으로
받고 몇 개를 출력으로 얹을지는 전적으로 당신에게 달려 있다. 입력의
갯수를 고정할 지 가변으로 할 지 결정하는 것은 당신이다.

12. 어떤 포스 낱말도 실행할 때 실행되게 하거나 아니면 __번역할 때__
실행되게 할 수 있다. 이것은 믿어지지 않을 정도로 편리하다. 이것을 써서
다른 언어에서 들어본 적이 없을 정도로 시스템을 입맛에 맞게 고칠 수
있다.

__모든__ 것을 바꿀 수 있는 언어가 믿어지지 않을 정도로 편리하다는 것을
보이는 마지막 예로 다음을 보자. 나는 이 문제를 여러 전문적인
프로그래머에게 보였었다.

나는 다음을 어떻게 할 수 있는지 알고 싶다. 프로그램 언어는 무엇을 쓰더라도
관계없다.

다음 일을 하는 함수를 작성하라. (여기서 함수는 절차, 낱말, 코드 한
조각을 말한다.)

정수값을 갖는 한 변수가 있다고 하자. (이것을 TRACE라고 부르자.)
프로그램을 번역할 때 TRACE의 값이 0이면 정상적으로 번역한다.

그러나 TRACE의 값이 1이면 번역할 때 다음 일을 하는 코드가 실행
프로그램에 덧붙는다.

프로그램의 각 딸림함수(sub-fucntion)를 부를 때마다 프로그램의 흐름을
따라가는데 필요한 정보를 표시한다. 이 정보는 선택한 변수의 값, 어떤
메모리 주소의 내용 등을 포함한다. (프로그램이 실행되는 동안) 따라가기
정보를 보이고 나서 그 딸림함수의 정상적인 코드를 실행한다. 이
벌레잡기/따라가기 함수의 코드는 프로그래머가 작성한 것이어야 한다.
프로그래머는 이 함수를 마음대로 바꿀 수 있고 필요하다면 매분마다
그렇게 할 수 있어야 한다.

이때 딸림함수의 '정상 코드'를 바꿀 필요가 없어야 한다. 큰 응용
프로그램의 모든 딸림함수에 원시 코드를 덧붙이는 것은 너무 번거로우므로
이를 요구해서는 안된다. (이 따라가기 정보는 나중에 필요하게 된 것이지
프로그램을 짜기 시작할 때는 결정되어 있던 것은 아니다. 길게 보면
이것이 따라가기 프로그램을 사용하는 정상적인 상황이다.) 따라서 C
프로그래머는 전처리기나 IFDEF와 같은 조건부 번역문을 사용할 수 없다.
왜냐하면 이것을 쓰려면 필요한 모든 printf문을 원시 코드에 더해야 하기
때문이다. 각 딸림함수의 원시 코드는 '정상적인' (즉, 따라가기
프로그램을 쓰기 전) 모양 그대로 남아 있어야 한다.

이것을 해결했다면, 당신 프로그램의 원시 코드가 번역되는 동안 TRACE
변수의 값을 바꿀 수 있어서 선택된 딸림함수만이 따라가기 정보를
표시하도록 따라가기 함수를 고쳐라.

이것이 내가 여러 전문적인 프로그래머에게 보였던 문제이다. (그들이 다뤄본
프로그램 언어는 아주 많다.) 그들 모두가 똑같은 대답을 했다. "당신은
벌레잡개(debugger) 프로그램을 써야 한다. 벌레잡개 프로그램으로 당신은
원하는 것을 모두 할 수 있다." 내 대답은 "아니오"였다. 벌래잡개는 언어의
일부가 아니다. 그것은 어떤 번역기회사가 그 언어에 더한 것이다. 그리고 만약
벌레잡개 프로그램에 내가 원하는 기능이 없다면 나는 그 벌레잡개를 고칠 수
__없다__. 몇 사람은 번역기의 원시 코드를 구한다면 쉽게 (길게 잡아 수백 행
정도의 코드로) 그 일을 할 수 있을 거라고 말했다. 그것도 역시 해답일 수
없다. 번역기의 원시 코드는 엄청나게 비싸거나 (번역기 가격의 열 배 이상)
많은 회사들은 아무리 비싼 값에도 팔지 않는다.

따라서 사람들은 불가능한 일이라고 말했다. 글쎄... 당신은 이미 대답을 안다.
포스에 아주 쉽고 우아한 해결책이 있다.

다음은 이 문제를 해결하는 한 방법을 포스로 짠 것이다.

VARIABLE TRACE ( TRACE가 1이면 번역기가 지금 정의하는 낱말에 당신이 )
( 더하고 싶은 코드를 넣는다. )

: Line.of.Dashes ." --------------------------------------" CR ;

( Line.of.Dashes는 따라가기 정보를 예쁘게 보이기 위한 것이다. )

: My.Trace.Code

Line.of.Dashes
." Begin Trace Data." CR

( 여기에 알고 싶은 값들을 보이는 코드를 넣는다. )
( 아래 코드는 예로 보인 것이다. )

." Current Stack Contents:" CR .S CR
." End Trace Data." CR
Line.of.Dashes ;

: : [compile] :
TRACE @
IF
COMPILE My.Trace.Code
THEN ; IMMEDIATE

(옮긴이: 피그미 포스에서는 : 대신 ;에 My.Trace.Code를
포함시키는 것이 편하다.

COMPILER
: ; TRACE @
IF
COMPILE My.Trace.Code
THEN
POP DROP \ ; ; FORTH )

무른값 따라가기

: 긴.줄 ." --------------------------------------" 다음줄 ;

: 따라가며.보여

긴.줄
." 따라가며 보이기 시작." 다음줄
." 지금의 더미 내용:" 다음줄 .더미 다음줄
." 따라가며 보이기 끝" 다음줄
긴.줄 ;

번역기용어
: ; 따라가기 @ 면 번역 따라가며.보여 라 되돌이> 버려 \ ; ; 포스용어

이게 전부다. 이제 끝났다.

이게 어떻게 답이냐고? 번역기를 바꾸어서 번역기가 "따라가기"라고 불리는
변수의 값을 보게 한 것이다. 그 값이 0이 아니면 지금 번역되고 있는 루틴의
(즉, 프로그램의 각 함수[낱말]의) 정의에 "따라가며.보여"를 부르는 코드를
더한다. 이렇게 해결하는데 원시 코드는 하나도 바뀌지 않았다. 당신은 단지
"따라가기"의 값을 1로 바꾸고 ("1 따라가기 !"를 입력해서 바꿀 수 있다) 따라
갈 프로그램을 번역한 후 실행하면 된다.

포스에서 이 해답은 아주 짧고 아주 우아하다. 다른 언어로 해결할 수 있다
하더라도 이렇게 간결하지는 않을 것이다. 내 생각에 LISP에는 답이 있고
어쩌면 SMALLTALK-80에도 답이 있을지 모른다. (후자는 자신이 없다.
원시어[primitive]는 바꿀 수는 없는데 번역기가 어쩌면 원시어일지도 모른다.)
그러나 포스보다 인기있는 유력한 언어 중에는 답이 없는 게 확실하다. 포스로
당신은 무엇이든 할 수 있다. 포스 세계에는 벽이 없다--당신이 가지고 온 것을
빼고는.

위의 답이 너무 길다고 생각되면 알짜만을 남겨서 다음처럼 줄일 수 있다.

VARIABLE TRACE

: My.Trace.Code ." Current Stack Contents:" .S ;

: : [compile] : TRACE @ IF COMPILE My.Trace.Code THEN ; IMMEDIATE
(옮긴이: 피그미 포스에서는 다음처럼 한다.
COMPILER : ; TRACE @ IF COMPILE My.Trace.Code THEN POP DROP \ ; ; FORTH )

무른값 따라가기
: 따라가며.보여 ." 지금의 더미 내용:" .더미 ;
번역기용어 : ; 따라가기 @ 면 번역 따라가며.보여 라 되돌이> 버려 \ ; ;
포스용어

물론 당신이 프로그램을 따라가는데 필요하다고 생각하는 어떤 일도
"따라가며.보여"에 더 할 수 있다.

함수 (더 정확하게는 낱말) 정의 바깥에 넣은 말은 번역할 때 실행되므로
번역하는 동안 "따라가기"의 값을 바꿀 수 있다.

------------------ Start of File ----------------------------------
1 TRACE ! ( 번역하는 동안 TRACE를 1로 설정한다.)

: Show.Me ........ ; ( 실행될 때 따라가기 정보를 표시한다.)

0 TRACE ! ( 번역하는 동안 TRACE를 0으로 설정한다.)

: No.Show.Me ..... ; ( 실행할 때 따라가기 정보를 표시하지 않는다.)
------------------- End of File -----------------------------------

(옮긴이: 위의 따라가기 프로그램을 아래처럼 우리말에 더 가깝게 고칠 수 있다.

무른값 따라가기
: 따라가기? 따라가기 @ ;
: 켜 1 맞바꿔 ! ;
: 꺼 0 맞바꿔 ! ;
: 따라가며.보여 ." 지금의 더미 내용:" .더미 ;
번역기용어 : ; 따라가기? 면 번역 따라가며.보여 라 되돌이> 버려 \ ; ;
포스용어

;를 다시 정의하고 아래처럼 보이며.버려와 안.보이며.버려를 정의하고 실행시켜
보라.

따라가기 켜 : 보이며.버려 버려 ;
따라가기 꺼 : 안.보이며.버려 버려 ;
11 22 33 44 55 66 보이기.버려 안.보이기.버려
보이기.버려 안.보이기.버려
보이기.버려 안.보이기.버려 )

포스를 벽 없는 방이라고 부르는 것은 옳다.


참고 문헌
---------

내가 본 책 중에는 아래 책이 포스를 배우기에 가장 낫다.

FORTH: A Text and Reference
by Mahlon G. Kelly and Nicholas Spies
Published by Prentice-Hall in 1986

내 생각에는 위 책만 못하지만 아래 책도 포스를 배우는데 널리 쓰인다.

Starting FORTH
by Leo Brodie
Published by Prentice-Hall in 1981
같은 사람이 쓴 2판이 나와 있고 이것은 1판보다 나을 것이다.

위에 소개한 책와 당신의 컴퓨터에서 쓸 수 있는 공개 포스 시스템을 당신이
하나씩 구하기를 진심으로 바란다. 공개 포스 시스템은 부족한 구석이 있겠지만
정의어를 비롯하여 모든 것을 더하고 빼고 바꿀 수 있는 포스의 특색은 모두
가지고 있으므로 불가능해 보이는 것을 가능하게 하는 것을 포스의 능력은
충분히 맛볼 수 있을 것이다.

(옮긴이: 옮긴이는 위 책을 모두 가지고 있고 포항공대 도서관에 1987년에
출간된 Starting Forth 2판이 있다. HITEL에서 IBM PC에서 쓸 수 있는 피그미
포스를 찾을 수 있다.)

이 긴 글을 읽어 주어 고맙다. 포스로 프로그램 짜는 것을 당신이 심각하게
고려하도록 이 글이 자극이 되었으면 좋겠다. 포스가 널리 쓰이면 우리 모두가
얻는 것이 정말로 많을 것이라고 생각하기 때문에 시간을 들여 이 글을 썼다.
포스는 벽없는 방이다. 속임수가 아니고 과장이 아니다. 정말로 포스는 가장
강력하고, 말랑말랑하고, 확장하기 쉽고, 일이 잘 되고, 만족스러운, 따라서
가장 바람직한 언어이고 환경이다. 그리고 지금까지 만들어진 거의 모든
컴퓨터에서 포스를 쓸 수 있다. 오늘은 찾아다녀야 포스가 쓰이는 것을 볼 수
있겠지만 조만간 가는 곳 어디서나 포스를 볼 수 있게 되기를 바란다.

재벌 2세가 재벌이 될 확률과
금메달리스트 2세가 금메달을 딸 확률이 비슷해지도록
자유오픈소스 대안화폐를 씁시다.

아이디의 아이디어 무한도전
http://blog.aaidee.com

귀태닷컴
http://www.gwitae.com

cleansugar의 이미지

아래 글은 "제 2 차 프로그램 언어의 역사 학회"(Second History of
Programming Languages Conference)를 위해 준비한 Philip J. Koopman Jr.의
"What is Forth?"를 번역한 것이다.
포스를 접해본 사람은 그렇게 많지 않을 것이다. 한국과학기술원의 변종홍님
에 의해 애플 II 컴퓨터에 이식된 우리말 포스 "늘품"에 관한 기사가 잡지에
몇 번 소개되었고 교학사에서 1988년에 "FORTH 입문"이라는 책이 출판된 것 외
에는 포스가 우리나라에 소개된 것은 거의 없는 것 같다.* 포스는 우리말에 가
장 어울리는 컴퓨터 언어이다. 베이식 언어에서 지정어를 한글로 바꾼다고 프
로그램이 바로 우리말이 되지는 않는다. 포스는 나중붙임 (postfix) 표기법을
쓰기 때문에 목적어가 동사 앞에 오는 우리말에 가깝다. 하지만 그보다 더 중
요한 것은 포스를 쓰면 사용자가 문법을 만들 수 있다는 것이다. 프로그래머에
게 모든 것이 허용되어 있기 때문에 __우리말에 맞추어 포스를 고쳐 쓰면 된다
__. 옮긴이는 포스가 C나 C++의 자리를 차지하리라고는 믿지 않지만 우리말 컴
퓨터 언어를 만드는데는 가장 좋은 출발점이라고 생각한다. 옮긴이의 바람은
어린이들이 우리의 생각틀로 프로그램 만드는 법을 배울 수 있게 되는 것이다.
관심있는 분들의 연락을 바란다.

1993.10.7
고원용
대전시 유성구 장동 100 한국화학연구소 무기소재부 340-343
wykoh (HITEL)
F7WYK@CHEM.KRICT.RE.KR

* 박진묵;변종홍, "늘품" 마이크로소프트웨어 1987년 9월 178-189.
변종홍, "컴퓨터가 우리말을 알아듣는다" 과학동아 1988년 2월 157-161.
변종홍, "우리말 무른연모도 만들자" 과학동아 1988년 3월 156-161.
이태욱, "FORTH 입문" 교학사, 1988. -- 이 책만 가지고 포스를 배우기에는
내용이 충분치 못하지만 우리말로 출판된 유일한 책이다. 현재 시중에서
2쇄를 구할 수 있다.

IBM PC에서 쓸 수 있는 포스인 Pygmy V1.14와 "왜 포스가 그렇게 대단한가?"라
는 글을 이 글과 함께 Hitel에 올린다.

피그미에서 다음을 입력하면 우리말로 쓴 예들을 실행시킬 수 있다. 한글 DOS
를 사용하고 있지 않다면 피그미를 실행시키기 전에 "다른안시한글"과 같은 에
뮬레이터를 먼저 올려야 한글을 쓸 수 있다.

: 베껴 DUP ;
: 맞바꿔 SWAP ;

==========================================================================

포스(Forth)란?

--------------------------------------------------------------
Philip J. Koopman Jr.
United Technologies Research Center, East Hartford, CT

copyright 1993 by Association for Computing Machinery(ACM)
이 글은 매사추세츠주 보스톤시에서 열린 Second History of
Programming Languages Conference (HOPL-II)를 위해 마련되었다.
복사 배포로 돈을 벌려는 것이 아니고 제목과 ACM에 저작권이 있음
과 ACM의 허락을 얻어 배포함을 명시하면 이 글의 일부 또는 전부를
무료로 복사할 수 있다. 다른 방법으로 복사하거나 재출판하려면 따로
ACM의 허락을 얻어야 한다.
--------------------------------------------------------------

포스의 간단한 소개
------------------

포스는 확장할 수 있는 언어이고 대화식의 프로그램 개발법이다. 원래 내장
제어용의 미니 컴퓨터나 마이크로컴퓨터에 쓰려고 개발되었고 지금까지 생산된
거의 모든 프로세서에 이식되었다. 포스는 스프레드쉬트, 전문가 시스템, 여럿
이 쓰는 데이타베이스 등의 다양한 응용프로그램을 만드는데 사용되었다.

스택이 두 개인 추상 기계

겉으로 보기에 포스는 스택에 바탕한 추상 기계에서 바로 실행할 수 있는 언
어이다. 이 추상 기계를 이루는 최소한의 굳은모는 프로그램 카운터, 주기억장
치, ALU, 자료 처리용 누름 스택, 서브루틴 되돌이 주소 누름 스택이다.

포스는 나중붙임(postfix)라고도 불리는 거꾸로된 폴란드식 표기법(reverse
polish notation, RPN)을 써서 자료스택에 있는 자료를 처리한다. 예를 들어
다음을 자판에서 친다면

3 4 + 5 * . __35 ok__

이것은 3을 스택에 올리고 4를 3 위에 올리고 3과 4을 없애고 합으로 얻은 7에
5를 곱한다. "." 연산은 스택에 하나 남은 결과 35를 보인다. (컴퓨터의 출력
은 밑줄로 표시하였다.) (옮긴이: 이는 우리말의 순서와 같다. "__3__에 __4__
를 __더__하고 __5__를 __곱__하고 __보__여라.") "ok"는 포스의 명령 프롬프
트이다. SWAP이나 DUP(duplicate)와 같은 연산은 스택의 맨 위에 있는 값들의
순서를 바꾸거나 베낀 값을 포갠다.

공약수 찾기

속을 들여다 보면 포스 프로그램은 RPN을 계산에만 쓰는 것이 아니라 문법을
간단하게 하고 모듈화하기 위한 수단으로 이용한다. "공약수 찾기(factoring)"
라고 알려진 프로그램방법을 쓰면 공통의 코드를 재사용하여 복잡한 일을 하는
프로그램을 작고 간단하게 만들 수 있다.

서브루틴을 부르고 되돌아가는 것은 포스 프로그램과 공약수 찾기에서 매우
중요한 부분이다. 예를 들어 스택의 맨 위에 있는 두 정수의 제곱의 합을 구하
는 함수(포스에서는 낱말(word)이라고 부른다)를 생각해 보자.

: SUM-OF-SQUARES ( a b -- c ) DUP * SWAP DUP * + ;
: 제곱합 ( a b -- c ) 베껴 * 맞바꿔 베껴 * + ;

실행할 때 자료스택에 있는 두 정수 a와 b가 이 낱말에 입력되어 한 정수 c가
자료스택으로 출력된다. ":"는 SUM-OF-SQUARES라는 이름으로 함수의 정의를 시
작하고 ";"는 정의를 끝낸다. 괄호 안에 있는 것은 덧붙임말이다. 포스에서는
보통 위에서처럼 스택 효과를 괄호 안에 표시한다. 그 뜻은 둘째 값 a와 맨 위
값 b가 없어지고 새로운 값 c가 스택에 오른다는 것이다.

위 프로그램에서 값을 베껴서 곱하는 부분은 공통이므로 SQUARED라고 불리는
새 정의(공약수)를 사용해서 고쳐 쓸 수 있다. 포스 추상 기계는 되돌이 스택
과 자료스택을 따로 가지고 있기 때문에 서브루틴을 부르고 또 부르고 하더라
도 실행할 때 더 하는 일이 없다. 고쳐 쓴 프로그램에서 자료스택에 있는 값들
은 SUM-OF-SQUARES에서 SQUARED로 저절로 넘겨진다.

: SQUARED ( n -- n**2 ) DUP * ;
: 제곱 ( n -- n**2 ) 베껴 * ;
: SUM-OF-SQUARES ( a b -- c ) SQUARED SWAP SQUARED + ;
: 제곱합 ( a b -- c ) 제곱 맞바꿔 제곱 + ;

좋은 포스 프로그래머들은 낱말의 이름을 잘 짓고 낱말을 짧게 (될 수 있는
대로 1 줄 이내로) 정의하고 공약수로 뽑아낸 부분을 다시 쓰려고 애쓴다. 낱
말에 꼭맞는 이름을 고르는 능력은 부러워 할만한 재능이다. 공약수찾기는 아
주 중요해서 대부분의 포스 프로그램은 스택 연산하는 것보다 더 자주 서브루
틴을 부른다. 공약수를 찾으면 자주 쓰이는 공약수를 어셈블리어로 고쳐 써서
속도 최적화를 하기도 쉽다. 위의 예에서 스택 효과를 바꾸지 않고 SQUARED를
어셈블리어로 고쳐 쓸 수 있다.

포스 프로그램을 쓰는 것은 어떤 응용에 필요한 모든 기능을 포함하도록 이
언어를 확장하는 것이다. 그러므로, 포스로 프로그램을 쓰는 것은 어떤 응용에
특화된 언어를 만드는 것이라고 생각할 수 있다. 이러한 방법론은 매우 빠른
편집/번역/시험 순환과정과 함께 눈에 띄게 생산성을 높이는 것 같다. 만들어
진 포스 낱말은 바로 시험해서 프로그래머가 그 결과를 볼 수 있다. 예를 들면
위에서 정의된 낱말들은 아래에 보인 것처럼 시험할 수 있다.

3 SQUARED . __9 ok__
3 4 SUM-OF-SQUARES . __25 ok__

통역(interpretation)과 번역(compilation)과 실행(execution)

포스 시스템은 텍스트 통역기와 주소 통역기로 두 수준에서 통역을 한다. 텍
스트 통역기는 자판이나 파일 입력으로부터 빈칸으로 나뉘어진 문자열을 찾아
낸다. 통역상태에서 텍스트 통역기는 그 문자열에 해당하는 낱말을 찾아 실행
시키려 한다 (수를 나타내는 문자열은 예외로 취급되어 수로 바뀐다). ":"도
다른 것처럼 하나의 낱말이다. ":"은 사전에 새 낱말이 들어갈 자리를 만들고
텍스트 통역기를 번역상태로 바꾼다. 번역 상태에서는 입력 흐름에서 온 대부
분의 낱말들이 실행되는 대신 사전에 있는 그 낱말의 정의를 가리키는 포인터
로 번역된다.

번역된 포스 프로그램은 낱말들의 모임이고 각 낱말 속에는 다른 낱말을 가
리키는 포인터들이 있다. 포인터들은 마침내 기계어로 쓰인 기본 낱말들을 가
리킨다. 물론 이 기본 낱말 가운데 몇 개는 사용자가 지은 것일 수도 있다. 포
스 주소 통역기는 번역된 낱말들을 실행시키는데 쓰인다. 이때 쓰이는 전통적
방법은 꿰어진 코드법(threaded code technique)이다. 번역된 프로그램을 실행
시키는데는 포스 텍스트 통역기가 필요없지만 많은 응용프로그램이 이를 바탕
으로 명령행(command-line) 사용자 인터페이스를 만든다.

포스 시스템은 한번에 번역을 한다 (one-pass compilation). 포스는 겉에
드러난 문장 분석기(parser)가 없다. (그리고 사실상 따라야 할 문법도 없다.)
(옮긴이: 우리말 문법에 맞는 컴퓨터 언어를 만들 수 있는 가능성이 여기에 있
다. (우리말을 어떤 컴퓨터 언어에 맞추는 것이 아니라) __포스를 우리말에 맞
추면 된다__.) 프로그램의 흐름을 바꾸는 낱말들은 특별한 "바로 속성"을 가지
고 있어 텍스트 통역기가 번역상태에 있더라도 바로 실행된다. "바로말"
(immediate word)은 실행되면 특별한 구조의 번역을 시작한다. 예를 들어 IF는
실행할 때 자료스택의 맨 위 값에 따라 가지를 치는 조건문(branch
conditional)의 번역을 시작한다. 그리고 그와 짝인 (다른 언어에서 endif에
해당하는) THEN이 가지치기의 목표 주소를 결정하여 그 값을 IF가 마련해 둔
자리에 써 넣는다. 사용자도 바로말을 만들 수 있으므로 흐름을 바꾸는 새로운
구조나 다른 특성을 더해 번역기를 확장할 수 있다.

포스에서 자료 구조는 "짓는말"(defining word)이라 불리는 특별한 낱말들에
의해 만들어진다. 짓는말은 두 부분으로 이루어진다. CREATE 부분은 사전에 자
료구조의 예(instance)가 들어갈 자리를 만들고 DOES> 부분이 그 짓는말에 의
해 정의되는 모든 낱말이 공유할 기능을 정의한다. 예를 들면 배열을 만드는낱
말은 CREATE 부분에서 사전에 이름붙인 배열을 등록하고 자리를 마련한 후
DOES> 부분에서 (첨자가 가리키는) 주소를 계산한다. 짓는말을 써서 자료 구조
를 만든 구체적인 방법을 숨기고 닮은 낱말들을 만들 수 있다.

포스 프로그래머들은 전통적으로 자신들이 사용하는 기계와 프로그램 개발환
경을 완전히 이해하고 장악하는 것을 중요하게 생각한다. 따라서 포스의 한 특
징이 포스 번역기가 하지 않는 일에서 드러낸다. 자료형을 확인하고 마크로를
번역 전에 처리하고 생략할 수 있는 연산을 없애는 등 다른 언어의 전통적인
번역기가 제공하는 기능들이 기본적인 포스 컴파일러에는 없다. (물론 만들어
넣을 수 있다.) 이렇게 간단하기 때문에 포스 개발환경은 8비트 마이크로프로
세서의 내부(on-chip) ROM에 들어갈 수 있을 정도로 작다. 하지만 포스를 확장
할 수 있으므로 100K 바이트를 넘게 차지하고 다중 창을 사용하는 완전히 갖춰
진 개발환경을 꾸밀 수도 있다. 또한 프로그래머는 포스 번역기와 실행 시스템
을 완전히 이해할 수 있다. 포스를 쓰면 프로그래머가 언어와 굳은모를 완전히
장악하고도 매우 유연하고 생산성이 높은 개발환경에서 일할 수 있다.

Philip J. Koopman Jr.
United Technologies Research Center, East Hartford, CT

This description is copyright 1993 by ACM, and was developed
for the Second History of Programming Languages Conference
(HOPL-II), Boston MA.

Permission to copy without fee all or part of this material
is granted, provided that the copies are not made or
distributed for direct commercial advantage, the ACM
copyright notice and the title of the publication and its
data appear, and notice is given that copying is by
permission of the Association for Computing Machinery. To
copy otherwise, or to republish, requires a fee and/or
specific permission.

재벌 2세가 재벌이 될 확률과
금메달리스트 2세가 금메달을 딸 확률이 비슷해지도록
자유오픈소스 대안화폐를 씁시다.

아이디의 아이디어 무한도전
http://blog.aaidee.com

귀태닷컴
http://www.gwitae.com

imyaman의 이미지

하이텔이라는 단어가 나와서 또 한번 놀랐네요

익명 사용자의 이미지

커피 한잔으로 여유를~

익명 사용자의 이미지

예..예전에 고박사님의 글을 읽고, 포스를 조금 만져보았습니다....최근에는 고용원박사의 글 인쇄한것을 책꽃이 에서 발견해서 3개월전에 다시 읽어보기도 했지요...지금도 forth도 나름대로 선전하고 발전하고 있습나다. atmega요 amforth, pic용으로 FlashForth도 소스포지에 있지요...pc bios에 forth언어로 새롭게 작성하는 프로제트도 있고...

지금 forth200x로 여러가지 논의가 진행되고 있죠...http://www.forth200x.org에서 포스에 대한 논의가 진행되고 있기도 하고,

postfix, stack oriented....오랜만에 보는 것이라..지금도 간단한 계산문제는 forth를 실행시켜서 계산하는 포스 맨으로서 올리신분께 감사드립니다.

khj의 이미지

개인적으로 소장하고 싶어 복사 해 갑니다.

세계에 컴퓨터 언어가 C, JAVA, 같은 유명한 것만 있는건 아니었군요.

이런 언어가 80년대에 있었다니 놀랍네요.

cleansugar의 이미지

남산도서관에 예전에 출간된 Forth 책 한권 아직 남아 있고 대출 가능합니다.

재벌 2세가 재벌이 될 확률과
금메달리스트 2세가 금메달을 딸 확률이 비슷해지도록
자유오픈소스 대안화폐를 씁시다.

아이디의 아이디어 무한도전
http://blog.aaidee.com

귀태닷컴
http://www.gwitae.com

khj의 이미지

몰랐네요 놀랐습니다.

어떤 의도로 예명을 만드신 것인지 몰라 그냥 설탕으로 썻는데 괜찬으실지 모르겠네요

대단히 세심하시네요 그런 정보를 어떻게 아시고 계신건지 기억까지 하고 계시니 더 대단하신 것 같습니다.

유용한 정보 감사하고 또한 댓글 달아 주셔서 감사합니다.

즐거운 하루 되십시오.

cleansugar의 이미지

여기 책 제목을 썼습니다. http://kldp.org/node/112703

댓글을 달았는데 플로팅이 안되네요.

정책이 바뀐건 지 버그인지 모르겠습니다.

재벌 2세가 재벌이 될 확률과
금메달리스트 2세가 금메달을 딸 확률이 비슷해지도록
자유오픈소스 대안화폐를 씁시다.

아이디의 아이디어 무한도전
http://blog.aaidee.com

귀태닷컴
http://www.gwitae.com

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.