프로그램과 소프트웨어
컴퓨터와 인간지능 : Donald G. Fink 저, 이기호 역, 이화여대 출판부, 1986, Page 145~164
교훈에 교훈을 더하며 교훈에 교훈을 더하고 ; 경계에 경계를 더하며 경계에 경계를 더하고 ; 여기서 조금, 저기서 조금 ; …이제 가서 서판에 기록하고 책에 써서… - 이사야서 28 장 13 절, 30 장 8 절
현 단계에서 컴퓨터로 문제를 풀 때 인간과 기계 사이의 복잡한 협력을 필요로 하는 것은 매우 당연하다. 컴퓨터는 인간이 지시하는 대로 한다. 즉 인간은 컴퓨터 언어의 형태로 씌여진 프로그램을 가지고 제어한다. 이 장에서는 컴퓨터 프로그램이 어떻게 계획되어 어떻게 씌여지며 그리고 어떻게 자연 언어에서 기계 코드로 바뀌는지에 관해 좀더 자세히 논하고자 한다. 이미 앞서 π 의 계산을 통해 전문가가 실제적인 컴퓨터 (G.E. 모델 225) 에 이 문제를 어떻게 프로그램했는지를 알 수 있었다. 그렇다면 프로그래머가 프로그램의 세세한 단계를 조립하고 컴파일링 하는데 컴퓨터가 어떻게 도움이 되는지 알 게 될 것이다.
컴퓨터 프로그램을 작성하는 데는 네 가지 주요한 단계를 거쳐야 한다. 첫째, 프로그래머는 문제를 정의한다. 즉 프로그래머는 문제를 기계 계산을 위한 적당한 말로 재정의한다. 둘째, 프로그래머는 문제를 푸는데 사용된 장치를 구체화하는데 시스템 순서도 (systems flow chart) 를 순서대로 그린다. 셋째로, 논리 순서도 (logic flow chart) 라는 또 다른 표를 그리는데, 이것은 컴퓨터가 대답을 얻기 위한 지시단계를 상세히 나타낸다. 넷째로, 논리도 (logic chart) 를 가지고, 컴퓨터가 해독할 수 있도록 고안된 영숫자 약어 (mnemonic abbreviations) 를 사용하여 지시표 (table of instructions) 를 작성한다. 프로그래머는 이것을 손으로 하거나 (manual coding) 또는 기계를 사용하기도 한다 (machine-assisted coding). 이것은 프로그램을 통해 컴퓨터로 옮겨져 조금씩 수행되는 지시들이다. 추리과정을 앞으로 참고하기 위해 능숙한 프로그래머는 이사야의 명령 "책에 써라" 에 따른다.
4 장에서는 계산을 위해 π 문제를 정의하였다. 컴퓨터를 위해서 정확하고 일반적인 형태로 π 급수에서의 각 항을 정의해야 한다. 즉 각 항에 대한 수학적 표현을 찾아야 한다. 보통 사용해 온 급수에서, 각 항은 분자 4 를 갖고 분모는 홀수이며 항의 부호는 + 와 - 가 교대로 나타난다. 만약 N 을 그 항의 수라고 한다면 (첫 번째 항에 대해서 N = 1, 두 번째 항에 대해서 N = 2 등등), "N 번째" 항의 크기 (magnitude) 가 다음과 같다는 것을 발견한다.
N 항의크기 = 
우리는 N = 1, 2, 3 등으로 치환해서 그 급수에 대응하는 항의 크기와 그 값을 비교함으로써 이 식을 검토할 수 있다 (제 1 장).
N 항의 부호는 -1 의 멱으로서 표시될 수 있다.
N 항의 부호 =
N = 1, 2, 3, …
그리고 N 항의 부호가 붙은 값은 다음과 같다.
N 항 = 
100 개의 항을 계산하는 과정은 상당히 명백하다. 우리는 컴퓨터가 먼저 N = 1 을 사용해서 크기를 계산하고, 그 다음 N = 1 에 대한 부호를 계산해서 그 결과를 곱하도록 지시한다. 이 연산은 첫 번째 항의 부호가 붙은 크기를 만들어내는데, 그것은 항들을 위해서 예약된 첫째 기억장소에 저장된다 (문제에서 기억장소는 0101 에서 0200 까지이다). 그러면 N 을 1 에서 2 로 바꾸고 둘째 항을 만들어 이를 위하여 그 과정을 반복한다. 그 과정은 N = 100 일 때까지 계속되며 100 항이 계산되고 저장된다.
다음 단계는 "98 항의 합" 을 만들기 위해 처음에 98 이란 기억장소에 저장된 항들을 더해서 그것을 특정한 기억장소 (문제에서는 1098) 에 저장한다. 그러면 99 번째 항이 "99 항의 합" 을 만들어내기 위해 그 결과에 더해지는 것은 1099 에 저장된다. 마지막으로 100 번째 항은 100 항의 합을 만들어내기 위해서 최후의 결과에 더해지고, 그것은 1100 에 저장된다.
다음 지시는 98, 99, 100 항의 합의 값을 조사하는데 그것은 각기 주어진 π 값보다 작고, 크고, 그리고 작아야 한다. 만약 이들 값이 정확하다면 프로그램은 다음 단계로 계속된다. 그렇지 않다면 컴퓨터는 "합의 오류" 라는 인쇄 지시를 받는다. 그러면 프로그래머는 출력을 조사하며 논리도에서 무엇이 틀렸는지를 조사한다.
다음 지시는 98 항과 99 항 합의 평균에 대한 계산을 요구하는데 그것은 우리 문제에서 기억장소 1108 에 저장되어 있다. 그 다음 99 항과 100 항의 합에 대한 평균이 주어지며 그것은 기억장소 1109 에 저장된다. 이 두 평균의 평균이 계산되어 1110 에 저장된다. 이 마지막 결과는 π = 3.141592 의 주어진 근사치와 비교된다 (π = 3.141592 라는 값은 이미 기억장소 1111 에 저장되어 있다). 모든 숫자가 일치되면 프로그램은 컴퓨터에게 "해결된 문제" 라고 인쇄를 지시한다. 만약 그렇지 않다면, "해결되지 않은 문제" 가 인쇄된다. 마지막 지시는 풀이가 끝났다는 컴퓨터에 대한 통보이다. 다음 문제를 위해 새 데이터가 들어올 때까지는 데이터를 기억장치에 저장한 채 끝난다.
간단한 예를 앞의 네 단락에서 설명했다. 그러나 대부분 컴퓨터의 많은 연습문제는 그렇게 쉽지 않다. 그래서 프로그래머가 프로그램 계획을 앞에서 언급했던 논리 순서도로 작성하는 것이 보통이다. π 문제에 대한 논리 순서도는 <그림 1> 에서 보여준다.

그림 1 6 자리 10 진수로 π 를 계산하고 검사하는 시스템 순서도
만약 우리가 상자와 화살표를 앞에서 설명한 프로그램 요약과 비교해보면, 그것들은 똑같은 정보를 갖고 있음을 발견하게 된다. 그러므로 도표가 따라가기에 훨씬 용이하다. 그것은 일목요연하게 계획을 파악할 수 있으며, 처음부터 끝까지 프로그램의 지시사항을 이해할 수 있다. 직사각형의 상자들은 비교하지 않는 지시들을 넣는 데 사용된다. 비교를 요구할 때 상자 끝을 둥그렇게 하는데 사용된다. 비교를 요구할 때 상자 끝을 둥그렇게 하는데 하나의 화살표가 들어와서 2 개 이상의 화살표가 밖으로 나가게 된다. 그렇게 생긴 화살표에는 비교의 결과가 붙여진다 ("예 [yes]" 또는 "아니오 [no]" ; "=" 또는 "≠").
일반항으로 프로그램을 전개하여 나갈 때, 논리도 (그림 1) 를 세밀하게 조사해야 하는데, 그것은 컴퓨터가 따라가야 하는 논리의 개별적인 단계와 통로를 표시한다. 이것은 지금까지 다루어지지 않았지만 중요한 과정이어서 이 그림을 조심스럽게 뒤따라 가보아야 한다. <그림 1-A> 의 맨 위에서 (1) 이란 숫자가 붙은 둥근 상자로 된 프로그램의 시작을 발견할 것이다. 상자 (2) 에 있는 지시를 받는 다음 단계는 N = 1 이라는 처음 값을 준다. 그러면 상자 (3) 은 컴퓨터가 N = 1 에 대한 항의 부호가 붙은 값을 계산해서 결과를 저장하도록 지시한다. 상자 (4) 에서 첨자 N 은 1 이 증가된다. 상자 (5) 는 N 의 값이 101 에 도착했는지를 알기 위해 테스트한다. 즉 이 단계에서 테스트에 대한 반응은 "아니오" 이다. "아니오" 에 대한 화살표는 상자 (3) 으로 되돌아가게 하는데, 그것은 컴퓨터로 하여금 그 항 다음의 값을 계산해서 저장하도록 지시한다.
계산하고 저장해서, 첨자를 증가시켜 테스트를 하기 위한 상자들은 "순환 (loop)" 을 형성한다. 컴퓨터 용어에서 "순환" 은 되풀이되는 지시들을 포함한다. 이것은 필요할 때마다 일일이 지시를 쓰는 번거로움을 덜어 준다. 상자 (3, 4 와 5) 의 순환은 계산과, 저장, 첨자의 증가, 그리고 그것의 값을 테스트한다. 순환은 100 개의 항에 대해 다른 값을 계산하여 저장하면 계산을 끝낸다.
첫째 항은 기억장소 0100 + N 즉 0101 에 저장된다. 두 번째 항은 기억장소 0102 에 저장되고, 이렇게 계속해서 100 번째 항은 기억장소 0200 에 저장된다. 100 번째 항이 계산 저장될 때, N 의 값은 101 이 되며 상자 (5) 에 대한 반응이 "예" 로 되면 순환을 끝내고 "예" 에 대한 화살표는 항의 합을 구하기 위해 N 의 값을 다시 1 로 정하는 상자 (6) 으로 논리회로를 옮긴다.
항의 합은 상자 (7) 에서 구한다. 첫째 항은 0100 + N (= 0101 왜냐하면 N = 1 이기 때문) 의 내용인데, 그것은 기억장소 1098 의 내용 (처음 값 0) 에 더해지며 그 결과는 같은 기억장소 (1098) 에 저장된다. 기억장소는 더하고 저장하는 연산이 계속되기 때문에 두 가지 연산에 사용될 수 있다. 즉 1098 의 내용은 그 항의 다음 덧셈이 그 자리에 저장될 때까지는 없어지지 않는다.
상자 (8) 은 컴퓨터로 하여금 그 항의 현재 값을 인쇄하도록 한다. 이 문자는 프로그램에서 제거될 수 있다. 왜냐하면 지금까지 살펴본 대로 값을 인쇄하는 것이 문제의 핵심은 아니기 때문이다. 그 문장은 잘못된 프로그램을 고치는데 (debugging) 사용될 수 있다.
상자 (9) 는 N 의 값을 1 씩 증가한다 (지금 N 은 2 이다). 상자 (10) 은 N 의 값을 99 와 비교한다. N 이 아직 이 값에 도달되지 않았을 때도 "아니오" 라는 화살표가 상자 (7) 로 되돌아가는데, 그것은 둘째와 첫째 항의 합을 만들어낸다.
상자 (7), (8), (9) 그리고 (10) 은 98 항까지의 합을 구하는 순환을 만든다. 순환을 98 번 회전하는 동안 그 테스트에 대한 반응은 "아니오" 일 것이다. 98 번째 항이 합해진 다음, N 의 값은 99 가 되고, 테스트에 대한 반응은 "예" 이다. "예" 의 화살표는 상자 (1) 로 인도되는데, 그곳에서 99 번째 항이 98 항까지의 합 (기억장소 1098) 에 더해져서 그 결과가 기억 장소 1099 에 저장된다. 다음으로, 상자 (12) 는 100 번째 항을 검색하는데 그 이유는 N 은 아직 99 이며 기억장소는 0100 + N + 1 = 0200 이고, 기억장소 1099 에 99 항까지의 합을 더하기 때문이다. 그 결과는 기억장소 1100 에 저장된다. 이 단계에서 컴퓨터는 기억장소 0101 에서 0200 까지 저장되는 100 개의 항을 계산하고 1098, 1099 그리고 1100 에 저장되는 세 개의 합을 계산한다.
다음은 4 장의 "인간 프로그램" 을 따라서 98, 99, 100 항까지의 합들을 3.14,592 인지 테스트한다. 이들 테스트는 결정 상자 (13), (14), 그리고 (15) 의 순서로 수행된다. 이 상자들이 "아니오" 화살표들은 합의 크기가 오류라는 메시지 (ERROR IN MAGNITUDE OF SUM) 를 인쇄되도록 한다. "예" 화살표는 다음 상자로 가며 결국은 (관계된 값들 모두가 정확한 것이 발견되면) 다음 지시로 간다. 이 상자 (16) 은 98, 99 항까지의 합의 평균을 계산하고 그 결과를 기억장소 1108 에 놓는다. 다음 상자 (17) 은 99 와 100 항까지의 합의 평균을 구해서 기억장소 1109 에 그 결과를 둔다. 상자 (18) 은 두 평균값의 평균을 구해서 그 결과를 기억장소 1110 에 둔다.
결정 상자 (19) 는 마지막 평균값이 주어진 π 의 값 (3.141592) 과 같은지를 묻는다. 만약 그 대답이 같다면 상자 (20) 에 의해서 프린터는 "해결된 문제 (PROBLEM SOLVED) 를 인쇄하도록 명령받는다 ; 그렇지 않을 경우엔 상자 (21) 에 의해서 "해결되지 않은 문제 (PROBLEM UNSOLVED)" 를 인쇄하도록 명령받는다. 어떤 메시지가 있은 후 마지막 지시는 "컴퓨터를 멈추게 하라 (stop the computer)" 이다 (상자 (22)).
이 도형을 관찰하면서 두 가지 중요한 사항을 기억해야 한다. 첫째, 한 항에서 다음으로 옮겨지는 첨자 N 의 사용이다. 이것은 N 의 각 값에 대한 새로운 결과를 만들면서 계속하여 될 수 있게 하는 하나의 계산이다. 둘째, 명시된 N 의 값에 도달하면 순환을 끝내기 위해 결정 상자를 사용하는 것이다.
상세한 논리도를 조사한 다음에는 넷째 단계로 진행하는데 이 단계는 지시를 컴퓨터가 알아 들을 수 있는 언어를 사용한다). <그림 1> 의 많은 상자들은 여러 개의 기계어의 지시를 요구한다. 예를 들면 상자 (3) 은 2N 을 만들어 2N 에서 1 을 빼고, 2N - 1 을 저장하며 한 레지스터 내에 숫자 4 를 놓고 2N - 1 을 검색하여, 레지스터의 내용을 이것으로 나누고 피승수로서 나중의 검색을 위해 기억장소에 몫을 자리잡게 하는 지시들을 요구한다. 또한 상자 (3) 은 레지스터 내에 N 을 두고 그것에 1 을 더함으로써 N + 1 을 계산한다. 그 결과는 임시로 저장된다. 그때 -1 은 레지스터 내에 자리잡고 저절로 N + 1 번 곱해진다. 곱은 레지스터 내에서 나타나고, 이것은 이미 저장된 피승수에 의해 곱해진다. 이 코딩은 100 번 수행되어야 하므로 지시를 반복해서 쓴다는 것은 매우 지리할 것이다. 오히려 상자 (3) 의 계산을 위해 한 세트의 지시가 기계어로 씌여져 기억장치 내에 저장되는 편이 낫다. 지시들은 필요할 때마다 N 의 합당한 값과 함께 매번 검색된다.
프로그래머 자신은 이 모든 일을 기계어로 수행하지만 몇 가지 이유로 이것을 기피하려고 한다. 먼저 0101 을 의미할 때 기억장소를 0101 으로 쓰는 것처럼 지시를 쓰는 초기 단계에서 설사 아주 가벼운 오류를 하더라도 프로그램의 다음 단계는 틀리게 될 것이고, 프로그래머는 그것을 다시 해야 한다. 다음에 다른 오류가 일어나고 그 오류의 영향은 프로그래머의 초기 궤양이 만성이 될 때까지 진행될지도 모른다. 오랜 훈련이 프로그래머가 오류를 없애는 합리적인 방법이라고 하더라도 일의 무료함은 더 좋은 방법을 찾기 위한 영감 같은 것처럼 행동한다. 더 나은 방법을 찾기 위한 영감 같은 것처럼 행동한다. 더 나은 방법은 기계에 의해 도움을 받는 코딩 ("조립장치 [assemblers]" 혹은 "컴파일러 [compilers]" 라고 불리우는 프로그램을 사용한다) 인데, 그 내부에서 기억장소를 할당하고 순환을 정하고 각 항을 계산해서, 그것들을 더하고, 나누기, 평균, 저장, 그리고 검색을 위한 절차의 상세한 것들은 컴퓨터 자체가 담당한다. 제 4 장에서 우리는 "소프트웨어" 라고 알려진 프로그래밍 조력자가 평범한 영어가, 적어도 영어의 양식에 맞춰지거나 생략된 형태의 영어가, 프로그램을 쓰는 데 사용된다고 하였다. 이 절차는 컴퓨터에게 코딩의 상세한 부분을 맡긴다. 기계는 초인적인 정확성을 갖고 있기 때문에 기계 때문에 일어나는 오류는 거의 없다.
많은 형태의 기계에 도움을 받는 코딩이 있다. 그것들은 상대적인 어드레싱, 상징적인 어드레싱, 해석적인 코딩, 조립, 부호 번역과 같은 것들로 진행된다. 여기서는 FORTRAN (FORmular TRANslation) 으로 알려진 컴파일러 언어 (compiler language) 라는 특별한 경우를 택한다. 이것은 프로그래밍 공학과 과학적인 프로그램을 작성하는데 널리 사용되며 π 의 문제에 적당하다. 다른 컴파일러 언어, 특히 COBOL (CommonBusiness-Oriented Language) 은 비즈니스에의 적용을 위한 프로그램 작성에 도움을 주기 위해 개발되었다. (미국정부는 COBOL 의 사용이 적합하지 않다면 어떤 컴퓨터도 팔거나 빌려주지 않을 것이라는 통지를 했다). 오늘날, 일반적으로 사용되는 모든 컴퓨터는 거의 COBOL 과 FORTRAN 편집을 위해 설정되며 특정한 목적을 위한 것으로는 여러 가지 변형이 있다 (웨스트포인트에 있는 미육사관학교에서는 CADETRAN 으로 알려진 FORTRAN 변형을 가르친다).
아마 FORTRAN 을 소개하기에 가장 좋은 방법은 π 문제를 웨스트포인트에 있는 G.E. 모델 225 컴퓨터에 수행시킬 때 일어나는 반응에 대한 다음과 같은 설명이라고 하겠다. 앞에서 프로그래머 (주석 : 제너럴 일렉트릭 (General Electric) 컴퓨터의 포스터 (Mr. Jerry Foster) 에게 우리는 많은 신세를 졌다. 사용된 컴퓨터는 웨스트 포인트 사관학교의 지시이다. 그 컴퓨터는 롬바르트 (Major H.W. Lombard) 관리하에 있다. 이 책을 쓰는 데 그에게서도 역시 많은 도움을 받았다.) 는 논리도 (그림 46) 를 그리는 데 한 시간 가량을 소비했다. 프로그래머는 이 도표를 가지고 31 개의 문장을 코딩용지 위에 각각 FORTRAN 으로 지시를 썼다. 이들 문장에 대해서는 이 책의 부록에 자세히 설명되었다. 작성에는 약 15 분이 소요된다. 그러면 프로그래머는 FORTRAN 의 각 문항에 한 장씩 31 개의 카드를 키펀치한다. 펀치에는 약 5 분 소요된다. 카드 덱 즉, 소스 덱 (source deck) 은 프로그래머에 의해 "소스에서" 라고 공식화되는 것처럼, 즉 논리도 내에서 발표된 것처럼 문제를 갖는다.
다음 프로그래머는 컴퓨터 표준 프로그램 수집소 (library) 에서 약 2 인치 두께의 FORTRAN 컴파일러라는 라벨이 붙은 천공카드를 꺼내온다. 이 카드들은, 실제로 그 자체로는 복잡한 프로그램인데, 그것들은 이미 컴퓨터 제조업자에 의해 천공되어 있다. 이것은 FORTRAN 부호와 단어들 그리고 언어 구문론상의 모든 규칙, 종종 나타나는 오류의 목록, FORTRAN 문장을 인지하여 그것들을 모델 225 기계어로 바꾸는 일을 포함하여 많은 양의 데이터를 갖는다. 이 컴파일러 덱은 프로그램 전문가팀 (애리조나 페닉스) 의 수개월에 걸친 노력의 결과였다. 그들의 작업은 모델 225 컴퓨터에 FORTRAN 지시를 받아들이도록 적용시키는 것이었다.
프로그래머는 컴퓨터 기억장치의 모든 내용을 없애고 카드 입력기의 호퍼 (hopper) 에 컴파일러 덱 (compiler deck) 을 놓는다. 이 덱의 꼭대기에 소스 덱 31 장의 카드를 둔다. 그리고 프로그래머는 시작 단추를 누른다. 컴퓨터가 기억장치 안에 FORTRAN 일을 저장하는 동안 카드를 읽으면서 입력기는 달각달각 소리를 낸다. 컴퓨터의 기억장치는 비어 있는 저장소에 표준이 되는 FORTRAN 절차들의 카드 덱이 도착하면, 컴퓨터는 각 문장을 분석하고 문제 해결을 위한 절차를 기억장치에서 선택하면서 카드를 읽는다. 그리하여 각 문장에서 요구되는 기계어를 만들어낸다. 컴퓨터는 그 자체를 지시할 수 있는 정확한 순서로 소스 덱에서 명시된 단계를 수행하기 위해 자체의 언어로 이들 절차를 조립하고 번역한다. 그러면 컴퓨터의 자동 펀치는 기계코드로 번역된 프로그램을 나타내는 카드 (목적 덱, object deck) 를 천공한다.
그 다음, 프로그래머는 FORTRAN 접두사와 FORTRAN 접미사 (주석 : PREFIX 는 목적 덱 기계 언어 문장들과 접미사의 필요한 과정들의 정확한 위치에 있는 기억장소에 위치한 "적하기 (loader)" 이다. SUFFIX 는 "선택이 없는" 과 "선택과 있는" 과정들로 나누어 진다. 전자는 모든 프로그램에 필요하고, 후자는 단지 어떤 이름들과 상징어들을 통해 프로그래머에 의해 요구될 때만 적하된다.) 로 라벨이 붙은 다른 두 개의 카드 세트를 표준 프로그램의 수집소에서 취한다. 이들 두 집합 사이에 기계 내에서의 특정한 문제를 접어두는 카드 덱 하나를 만들기 위한 목적 덱 카드를 삽입한다. 프로그래머는 이렇게 묶여진 덱을 카드입력기에 옮기고, 다시 시작 단추를 누른다. 입력기가 다시 소리를 내며 문제가 옮겨지는데 45 초가 걸린다. 지금 컴퓨터 기억장치는 목적 덱의 내용과 문제에 관련된 FORTRAN 절차를 포함한다.
다 옮겨지면 컴퓨터는 자동적으로 π 값의 계산을 "시작하며" 주어진 값과 그것을 비교한다. 1 ~ 2 초의 간격 후 (실제로 컴퓨터는 그동안 초 당 몇 백만 비트라는 속도로 데이터를 진행한다) 출력 인쇄기가 작동한다. 지시는 인쇄될 각 항의 값을 요구한다. 결국 32 초 안에 101 개의 줄이 인쇄되는데, 그중 200 개는 각 항의 값이고, 마지막은 "문제가 해결된" 값이다. 각 항의 값을 인쇄하는데 대부분의 시간이 걸린다. 컴퓨터 계산에 걸리는 시간을 더욱 합리적으로 조절하려면 프로그래머가 FORTRAN 문장 8 (부록 참조) 이 들어 있는 카드를 없앰으로써 그 항의 값을 프린트하는 과정을 생략하도록 절차를 변경할 수 있는데 이것은 가치있는 일이다. 컴퓨터가 이 일을 완료하는 데 걸리는 시간은 단지 3 초에 불과하다. 손으로 문제를 계산하느라고 시간을 소비하는 독자는 컴퓨터의 백만배 속도의 이점을 실감하게 된다.
요약하면 숙달된 프로그래머가 문제를 이해해서 논리도를 그리고 FORTRAN 문장을 써서 소스 덱을 천공하는 데 약 80 분이 걸린다. 그리고 목적 덱을 번역해서 그것을 옮기고 계산하는 데 걸리는 시간은 기계로 대략 160 초가 걸린다.
FORTRAN 과 같은 컴파일러 언어에 관한 모든 것을 배운다는 것은 사람들에게 고역스러운 노릇이지만 그러나 그 골자는 그렇게 어려운 것이 아니다. 기계 코드로 지시가 천공된 컴파일러 덱에 있는 카드들은 컴퓨터로 하여금 주요한 일들을 수행하게 한다.
(1) 기호 (수, 문자 그리고 단어) 를 인지함으로써 모든 FORTRAN 문을 분석하여 그것들을 기계어 지시로 바꾼다.
(2) 프로그래머에 의해 사용된 각 변수의 이름을 나중의 참고를 위해 표로 만든다.
(3) 각 변수에 기억장소를 할당하여 산술적인 지시와 연결 시킨다.
(4) 문제를 해결하도록 기계어 지시들을 적당한 순서로 배열한다 (컴퓨터는 실제로 <그림 1> 의 논리를 따른다).
(5) 프로그래머가 한 오류를 명시해 주는 메시지뿐 아니라 프로그래머가 관찰할 수 있도록 소스 덱 문장을 인쇄해낸다.
(6) 기계 지시들은 카드 (목적 덱) 에 천공한다.
물론 이것들은 만약 프로그래머가 손으로 프로그램을 컴파일한다면 그가 사용하게 되는 단계들과 매우 흡사한 것이다. 이들 작업이 기계에 할당될 수 있다는 사실은 금세기 기술면에서의 커다란 성과 가운데 하나이다.
컴퓨터 연산의 예와 같이 산술적인 기호들을 인식해서 분석해 보자. FORTRAN 은 계산을 위해 다음과 같은 기호를 사용한다.
|
부호 |
의 미 |
|
+ - * / ** |
앞에 있는 값과 다음의 값을 더하라. 앞의 값에서 다음의 값을 빼라. 앞과 뒤의 값을 곱하라. 앞의 값을 다음 값으로 나누어라. 앞의 값의 지수로 다음에 오는 값을 올려라. |
우리는 π 급수에서 N 번째 항의 부호가 있는 값을 표시함으로써 이들 부호의 사용을 제시할 수 있다.
평범한 표현 ; 
FORTRAN 표현 ; (-1**(N + 1))* (4./(2.*N - 1.))
(주석 : FORTRAN 표현의 크기 부분에 있는 10 진 자리수는 중요하다. 그것들은 컴퓨터에게 그 합의 크기가 유동소수점 형태에서 계산된다는 것을 의미한다. 즉, 10 진 소수점 아랫수가 10 의 멱에 의해 곱해진다. 부호 부분에서 10 진 소수점이 없는 것은 이러한 연산이 고정된 소수점 형태에 있다는 것을 의미한다. 즉, 단지 정수. 이 장의 나머지와 부록에서 단지 FORTRAN 주석이 사용될 것이다. 혼합된 즉 고정소수점과 유동소수점 표현들이 가능하다는 것도 역시 가정되었다. 그 결과는 결과 변수의 모드 (mode) 에 의해 이루어진다.)
카드 입력기가 이 FORTRAN 표현식을 만나면 무슨 일이 일어나는가? 먼저 그것은 최초의 괄호를 만난다. 이것은 컴파일러로 하여금 닫는 괄호가 이 문 내에서 뒤따라야 한다는 것에 주목하게 한다. 컴파일러가 계속해 나가면, 그것은 최초의 괄호가 닫혀지기 전에 먼저 닫혀져야 하는 또 다른 괄호를 발견한다. 그 뒤에 단 하나의 asterisk(*) 가 있다. 그 asterisk 는 앞에 있는 것이 모두 승수라는 것을 의미한다. 마지막 닫히는 괄호가 발견될 때까지 다음 것을 읽는다.
컴파일러는 이 계산을 하기 위해서 코딩을 해야 한다. 괄호에 의해 주어진 실마리와 부호의 순서대로 그렇게 한다. 그것을 괄호 내에서 밖으로, 그리고 왼쪽에서 오른쪽으로 작업해 나가며 상세한 다음 지시를 고안한다.
기억장소 N 을 보고 그 내용을 축적 레지스터 (주석 : 축적지는 가산수 또는 승수 등의 데이터를 가지고, 다른 수들 (피가산수 또는 피승수) 등과 결합하는 특별한 레지스터이다. 그런 후에 그 결과 (합 또는 제곱) 를 받아들이기도 한다.) 에 두라. 레지스터의 내용에 1 을 더하고 그 결과를 덧셈을 하기 위한 기억장소에 저장하라. 축적 레지스터에 -1 을 두라. 이것에 -1 을 곱하고 -1 이 N + 1 번 곱해질 때까지 계속하라. 그 결과 (-1**(N + 1)) 을 이 곱셈의 위치에 저장하라. 기억장소 N 의 내용을 다시 축적 레지스터에 두라. 레지스터의 내용을 유동소수점수로 바꾸라. 축적 레지스터의 내용에 유동소수점수 2 를 곱하고 그 유동소수점수 2.*N 은 축적 레지스터에 두라. 2.*N 에서 유동소수점수 1. 을 빼고 그 차 2.*N - 1. 을 축적 레지스터에 두라. 이 기억장소의 내용으로 유동소수점 4 를 나누라. 그 유동소수점 답을 축적 레지스터에 두라. 뒤로 돌아가서 (-1**(N + 1)) 이 저장된 기억장소의 내용을 검색하라. 이 수를 유동소수점으로 바꾸라. 축적 레지스터의 내용 (4./(2.*N - 1)) 에 (-1**(N + 1)) 을 곱하라. 그 곱을 저장하라. 이것은 (-1**(N + 1))*(4./(2.*N - 1.)) 의 계산이다.
이 코딩은 N 번째 항의 부호와 크기를 계산하기 위해 제공된다. 앞의 소스 문장 (DIMENSION) 은 컴파일러에게 계산에 대한 답이 100 개 있다는 것을 가르쳐 주며, 그리하여 필요한 기억장소들이 주어진다. 첫 번째 항에 대한 해답은 주어진 기억장소의 첫 번째 위치에 놓여진다. 그러면 소스 문장으로부터의 지시는 N 의 값을 1 만큼 증가시킨다. 또한 다음 지시는 계산이 다시 수행되도록 하여, 그것은 두 번째 항의 부호가 붙은 크기를 만들어서 두 번째 주어진 기억장소에 그 값을 저장한다. 그리고 100 개의 모든 기억장소가 각 항의 계산값으로 채워질 때까지 계속한다.
프로그래머의 도움 없이 그와 같이 코딩을 컴퓨터가 만드는 것은 많은 사고가 컴파일러 프로그램에 들어가 있기 때문에 가능하다. 산술 부호의 평범한 조합, 괄호의 배열, 그리고 연산의 수열 모든 것이 미리 처리되고, 컴파일러 덱에서 구체화된 한 부분의 논리적인 설계로 만든다. 당면 문제를 유지하기 위해 문자 부호, 그리고 수열의 어떤 사용은 규정에 따라 제외되어야 하며 이런 제한들은 FORTRAN 규칙을 야기시키는데 그 FORTRAN 규칙을 소스 덱을 만드는 프로그래머에 의해 배우고 엄격히 준수되어야 한다. 그러나 만약 그 규칙들이 준수된다면, FORTRAN 을 위해 장치된 컴퓨터는 문장을 읽고 그것을 분석해서 기계어의 지시를 만들 것이다. 더우기, 그것은 모든 프로그래머의 이름, 부호, 그리고 그것들이 저장되는 기억장소의 목록을 만든다. 따라서 부호와 이름은 일단 만들어지면, 재조정 없이 다른 문장 내에서도 사용될 수 있다.
이 특정한 기계 지시들의 생산은 매우 어마어마하며 컴퓨터는 더 야심적인 일을 수행해야 한다. 그것은 프로그램의 처음부터 끝까지 순조롭게 진행할 수 있도록 모든 지시들을 분류하고 배열함으로써 전반적인 과정 (목적 덱) 을 만들어야 한다. 전자계산학의 아주 세심한 일 가운데 어떤 것은 컴파일러 언어의 향상에 기초가 된다.
기억장소를 명시하는 부호 혹은 이름들을 컴파일러가 사용할 때 주의하여야 한다. 이 장의 서두에서 π 의 문제가 주어질 때 기억장소로 숫자를 사용했었다 (즉 100 개의 항의 저장을 위해 기억장소 0101 에서 0200 까지 사용했다). 물론 실제로 컴퓨터는 비트 (bit) 로 표현된 숫자를 언급함으로써 기억장소를 발견한다. 그러나 프로그래머는 컴파일러를 가지고 숫자보다는 훨씬 기억하기 쉬운 부호나 이름만을 기억해야 한다.
DIMENSION TERM (100) 이란 FORTRAN 문장을 통해 컴퓨터로 하여금 100 개의 자리를 따로 놓게 지시한다고 가정하자. 컴파일러 100 개의 기억장소를 TERM 에 할당할 것이다. 그러나 프로그래머는 100 개의 기억장소가 어떻게 사용되는지 알 필요도 주의할 필요도 없다. 이 방법으로 프로그래머는 TERM 또는 TERM (N) 을 배열의 일반적인 기억장소로서 사용할 수 있으며, 배열 내의 위치로 N 을 사용할 수 있다. 배열의 위치는 N 을 1 에서 100 까지의 값과 같게 놓음으로써 발견되며 특정한 기억장소를 TERM 과 관련된 기억장소의 N 값에 더함으로써 발견한다.
이것은 프로그램을 영어 이름과 부호로 쓰는데 가장 중요한 절차이다. 그것은 프로그래머로 하여금 특별한 양을 갖는 단어를 선택하게 허용한다. 컴파일러는 이 단어와 기억장소의 기록을 만들어 나중에도 같은 기억장소를 가진 같은 단어를 명시한다.
등호는 FORTRAN 부호 중에서 가장 유력한 것 중의 하나이다. FORTRAN 프로그램에서 (부록의 문장 1, 2, 3 을 보라), 초항의 부호가 붙은 크기는 다음과 같이 쓰여진다.
DIMENSION TERM (100)
N = 1
TERM (N) = (-1**(N
+ 1))*(4./2.*(N - 1.))
프로그래머에게 이것은 그가 TERM 이란 이름으로 100 개의 기억장소를 예약했고, 그리고 100 개의 기억장소 중 첫째 기억에 첨자를 정했다. 그러면 TERM(N) 은 처음 위치이고 그것은 다른 의미를 갖는다. 다시 말하면, 등호 왼쪽의 값을 답의 기억장소와 일치하고 오른쪽 값을 계산된 값과 일치한다.
부호 컴파일러 프로그래머의 이름과 부호로부터 목록을 작성하기 위해 바꾸어지고, 만들어진 목적 지시는 더 많은 기억장소를 필요로 하므로 컴퓨터는 편집이 완료되기 전에 기억장소에서 벗어나서 크고 복잡한 프로그램을 수행한다. 부호 번역은 기억장치가 가득차면 오류 메시지로 프로그래머에게 경고한다. 경고를 받으면 프로그래머는 문장을 독립해서 컴파일 될 수 있는 그룹으로 나누어야 하며, 컴퓨터가 다음 것을 컴파일하기 전에 자기 테이프와 같은 보조 기억장치에 완전한 것을 저장할 수 있도록 한다. 이런 형태의 문제가 수행될 때 현재의 것이 수행되면서 두 번째 부분 (그리고 세 번째 등등) 은 외부의 저장장치로부터 안으로 읽혀진다. 이런 일을 겹치기 (overlaying) 라고 부른다. 프로그램의 모든 부분에서 사용되어야 하는 기억장소에 다음 부분을 부과하지 않도록 프로그래머는 조심하여야 한다.
최근 기계에 준하는 프로그래밍의 확장은 놀라울 정도이다. 가장 놀라운 "소프트웨어" 항목 중의 하나는 "보고서 (report writer)" 이다. 이런 프로그램은 컴퓨터로 하여금 요구된 데이터를 위한 자기 테이프 파일을 찾게 하여 논리적이고 산술적인 연산을 하도록 하여 결론에 도달하여 전자계산학을 모르는 사람이라도 이해할 수 있는 보고서를 인쇄할 수 있도록 한다.
예를 들면, 어떤 식료품의 지배인이 프로그래머 의장에게 다음과 같은 보고서를 만들어 달라고 요구할지도 모른다 : "지난 석 달 동안 총판매량이 1 만 달러를 초과한 모든 소매 판로의 목록과 그 기간 동안의 순수입을 얘기해 주시오." 평범한 언어로 된 몇 개의 문장을 조금 개조하여 특별한 매개변수를 몇 개 더한 보고서 프로그램을 컴퓨터에 집어 넣을 수 있다. 더 이상 수고하지 않고도 필요로 하는 목록은 언제든지 컴퓨터에서 자동적으로 준비가 된다. 그리고 컴퓨터는 판매기록 파일을 찾아서 지시된 대로 수입을 계산한다.
스포큰 (spoken) 컴퓨터 지시에 (not typewritten) 관한 실험은 몇 년 동안 진행되어 왔으며 많은 컴퓨터 전문가들은 인간과 컴퓨터 사이에 마이크와 확성기로 직접 의사소통하는 것이 10 년 또는 20 년 내에 이루어질 것이며, 경제적으로도 실행 가능할 것으로 기대한다.
우리가 묘사할 수 있는 컴퓨터 소프트웨어의 모습은 시작에 불과하다. 그러나 우리는 이 책에서 컴퓨터가 매일 하고 있는 것에 대한 몇 가지 중요한 의문점을 제기한다. 만약 존재한다면 인공 지능이란 무엇인가? 말할 필요도 없이 이것은 넌센스에서 센스로 옮기는 것이 유리한 논쟁의 주제이다. 질문에 대한 합리적인 접근으로서 인간 지능의 구조를 다음 장에서 다루어야 할 것으로 여겨진다.