B (프로그래밍 언어)
1. 개요
B는 켄 톰슨이 개발한 프로그래밍 언어이다. 유닉스 운영체제 개발을 위해 BCPL을 기반으로 만들어졌으며, 초기에는 PDP-7과 PDP-11에서 사용되었다. B 언어는 자료형이 없는 특징을 가졌으며, C 언어로 발전하는 과정에서 중요한 역할을 했다. C 언어는 유닉스 운영체제 개발에 사용되었고, 한국의 IT 산업에도 간접적으로 영향을 미쳤다.
-
절차적 프로그래밍 언어 -
C (프로그래밍 언어)
C는 하드웨어 제어와 이식성이 뛰어난 고급 절차적 프로그래밍 언어로서, 다양한 분야에서 사용되며 후속 언어에 영향을 주었고, 성능과 효율성이 높지만 안전성 문제 개선이 필요한 언어이다. -
절차적 프로그래밍 언어 -
펄
펄은 래리 월이 개발한 텍스트 조작에 강점을 가진 다목적 프로그래밍 언어이며, 1987년 펄 1.0이 처음 공개된 이후 여러 버전 업데이트를 거쳐 객체 지향 프로그래밍과 유니코드 지원 기능을 추가했고, 현재 펄 5가 널리 사용되며 CPAN을 통해 방대한 모듈 생태계를 제공한다.
2. 역사
B는 사실상 C의 조상 언어로 볼 수 있다. B 언어로 만든 프로그램은 컴파일러에 의해 중간 코드로 변환되어 실행하는 인터프리터를 필요로 했다. 실행 시에는 인터프리터 번역 순서대로 처리되기 때문에 실행 속도가 매우 느렸다. 단, PDP-7 버전은 기계어로 처리할 수 있도록 개선되었다.
초기에는 유닉스를 사용한 DEC의 PDP-7 및 PDP-11과 GCOS OS가 동작하는 허니웰의 36비트 메인프레임에서 사용되었다. 최초의 PDP-7용에서는 스레드 코드로 컴파일되었고, 데니스 리치가 기계어로 출력하는 컴파일러를 만들었다. 1970년에 PDP-11이 도입되었지만, 이식에는 스레드 코드가 사용되었다. 이때 최초의 yacc가 PDP-11용으로 개발되었다. 데니스 리치는 이 시기에 유지보수를 담당했다.
B 언어는 BCPL의 영향을 그대로 받았기 때문에 B라는 명칭 또한 BCPL의 머리글자를 따왔을 가능성이 높다. 하지만 켄 톰슨은 멀틱스에서 사용하기 위해 전혀 다른 방식의 언어인 Bon을 고안했는데, 이것이 이름의 유래일 가능성도 있다.
2.1. 개발 배경
켄 톰슨은 DEC의 컴퓨터 PDP-7로 유닉스를 개발하고 있었지만, 당시 유닉스는 어셈블리 언어로만 프로그램 개발이 가능했다. 그래서 켄 톰슨은 유닉스에서 동작하는 고급 언어 개발을 시작했다. 그는 유닉스 개발 이전에 멀틱스 개발에 참여하고 있었는데, 멀틱스의 BCPL을 바탕으로 B 언어를 개발했다.
B 언어는 켄 톰슨이 당시의 미니컴의 메모리 용량에서 작동할 수 있게 하려고 불필요한 구성 요소(컴포넌트)를 제거한 일종의 BCPL 시스템이었다. BCPL이나 Forth와 같이 B 언어는 워드 형태의 1개의 데이터형만 가지고 있었다. 많은 연산자(사칙 연산 등)는 이 데이터를 정수로 취급하였고, 그 이외에는 모두 포인터로 다루었다. 그 외의 부분은 C 언어의 초기 버전과 비슷하며, C 언어의 표준 입출력 라이브러리에 비견되는 라이브러리를 가지고 있었다.
B 언어는 BCPL의 영향을 그대로 받았기 때문에 B라는 명칭 또한 BCPL의 머리글자를 따왔을 가능성이 높다. 하지만 켄 톰슨은 멀틱스에서 사용하기 위해 전혀 다른 방식의 언어인 Bon을 고안했는데, 이것이 이름의 유래일 가능성도 있다. 켄 톰슨은 다음과 같이 회고했다.
2.2. 초기 개발 (1969년)
켄 톰슨은 멀틱스 프로젝트에서 사용했던 BCPL 언어를 기반으로 B 언어를 설계했다. B 언어는 기본적으로 톰슨이 당시 미니컴퓨터의 메모리 용량에 맞추기 위해 불필요하다고 생각한 구성 요소를 제거한 BCPL 시스템이었다. BCPL에서 B 언어로 전환하는 과정에는 톰슨의 선호에 따른 변경 사항도 포함되었는데, 주로 프로그램에서 공백이 아닌 문자의 수를 줄이는 방향이었다.
BCPL의 ALGOL과 유사한 구문은 이 과정에서 상당 부분 변경되었다. 예를 들어, 대입 연산자 `:='`는 루터샤우저의 Superplan에서 사용된 `=`로 변경되었고, 동등 연산자 `=`는 `==`로 대체되었다.
톰슨은 `x =+ y` 구문(C에서는 `+=` 연산자)을 사용하여 x에 y를 더하는 "두 주소 할당 연산자"를 추가했다. 이 구문은 더글러스 맥클로이가 TMG를 구현하면서 비롯되었으며, B의 컴파일러가 처음 구현되었고, ALGOL 68의 `x +:= y` 구문에서 TMG로 전달되었다. 톰슨은 여기서 더 나아가 증가 및 감소 연산자(`++` 및 `--`)를 만들었는데, 접두사 또는 접미사 위치에 따라 값을 변경하기 전 또는 후에 가져올지 결정했다. 그러나 이 기능은 B의 초기 버전에는 없었다. 데니스 리치에 따르면, DEC PDP-11의 자동 증가 및 자동 감소 주소 모드를 위해 만들어졌다고 추측되기도 하지만, B가 처음 개발되었을 때는 해당 기계가 존재하지 않았기 때문에 이는 사실이 아니다.
for 루프의 세미콜론 버전은 켄 톰슨이 스티븐 존슨의 연구에서 가져온 것이다.
2.3. 발전과 C 언어로의 진화
B 언어는 켄 톰슨, 데니스 리치, 브라이언 커니핸에 의해 개량되어 NewB(NB)를 거쳐 C 언어로 발전했다.
B 언어는 자료형이 없는 설계로 허니웰이나 PDP-7과 같은 낡은 컴퓨터에서는 쓸모있었지만, PDP-11이나 현대적인 컴퓨터가 지원하는 문자 자료형을 적절히 처리할 수 없었기 때문에 문제가 되었다. 1971년 데니스 리치는 컴파일러가 기계어 코드를 생성할 수 있도록 하는 한편 자료형 변수를 추가하는 등 전면적인 변경을 시도했다. 1971년부터 1972년까지 B 언어는 NewB 언어로 진화했고, 앨런 슈나이더(Alan Snyder)의 강력한 요구로 전처리기가 더해져 1972년부터 1973년 초까지 C 언어로 진화했다. 1973년 여름, PDP-11용 유닉스가 C 언어로 다시 작성되어 이러한 노력은 완전한 결실을 맺게 되었다.
1973년에는 허니웰 635 시스템에서 IBM 360/370 시스템으로 이식할 필요성이 제기되었는데, 이 과정에서 마이크 레스크(Mike Lesk)는 훗날 C 언어 표준 입출력 라이브러리(stdio)가 되는 《범용 I/O 패키지》를 작성했다.
2.4. 유산과 영향
B 언어는 C 언어로 대체되어 현재는 거의 사용되지 않는다. 그러나 GCOS 메인프레임()과 특정 임베디드 시스템()에서 소규모 시스템의 제한된 하드웨어, 광범위한 라이브러리, 도구, 라이선스 비용 문제, 그리고 단순히 작업에 충분하다는 등의 여러 가지 이유로 계속 사용되었다. 매우 영향력 있는 AberMUD는 원래 B로 작성되었다.
B 언어는 C 언어를 거쳐 현대의 프로그래밍 언어에 많은 영향을 주었다. 특히 C 언어는 한국의 IT 산업 발전에도 큰 영향을 주었기에, B 언어는 한국 IT 발전에도 간접적으로 기여했다고 볼 수 있다.
3. 특징
B는 실질적인 C의 조상 언어로, 컴파일러에 의해 중간 코드로 변환되어 인터프리터를 통해 실행되는 방식이었다. 이 때문에 실행 속도가 매우 느렸지만, PDP-7 버전은 기계어로 처리할 수 있도록 개선되었다.
켄 톰슨은 BCPL을 바탕으로 B 언어를 개발했으며, 이후 데니스 리치, 브라이언 커니핸과 함께 NewB(NB)를 거쳐 C 언어로 발전시켰다.
B 언어는 초기에 자료형이 없는 설계였으나, 1971년 데니스 리치가 컴파일러가 기계어 코드를 생성하고 자료형 변수를 추가하는 등 전면적인 변경을 가했다. 1972년에는 앨런 슈나이더(Alan Snyder)의 요구로 전처리기가 추가되면서 초기 C 언어로 진화했다.
B 언어는 1990년대까지 허니웰 메인프레임에서 사용되었고, 일부 임베디드 시스템이나 다중 사용자 온라인 게임 AberMUD 등에도 활용되었다.
B 언어의 명칭은 BCPL의 머리글자를 따왔을 가능성이 있지만, 켄 톰슨이 고안한 Bon 언어에서 유래했을 수도 있다.
3.1. 기술적 측면
B 언어는 BCPL이나 Forth와 같이 워드 형태의 1개의 데이터형만 가지고 있었다. 많은 연산자(사칙 연산 등)는 이 데이터를 정수로 취급하였고, 그 이외에는 모두 포인터로 다루었다. 그 이외의 부분은 C 언어의 초기 버전과 비슷하다. C 언어의 표준 입출력 라이브러리에 비견되는 라이브러리를 가지고 있었다.
초기에는 유닉스를 사용한 DEC의 PDP-7용과 PDP-11에서 사용되었고, GCOS라고 하는 OS가 동작하는 허니웰의 36비트 메인프레임에도 사용되었다. 최초의 PDP-7용에서는 스레드 코드로 컴파일하였고, 데니스 리치가 기계어로 출력하는 컴파일러를 만들었다. 1970년에 PDP-11에 도입되었지만 역시 이식에는 스레드 코드가 사용되었다. 이때 최초의 yacc가 PDP-11용으로 개발되었다. 데니스 리치는 이 시기에 유지보수를 담당했다.
B 언어는 자료형이 없는 설계로 허니웰이나 PDP-7과 같은 낡은 컴퓨터에서는 쓸모있었지만, PDP-11이나 현대적인 컴퓨터가 지원하는 문자 자료형을 적절히 처리할 수 없었기 때문에 문제가 되었다.
3.2. 설계 철학
B 언어는 재귀 호출을 지원하고, 비수치형 데이터를 다룰 수 있으며, 특정 기종에 의존하지 않는 범용적인 언어였다. 운영체제나 다른 언어 개발을 목표로 설계되었다. 켄 톰슨은 B 언어를 설계하면서 간결성과 효율성을 중시했는데, 이는 훗날 C 언어의 설계에도 큰 영향을 미쳤다. B 언어는 제한된 메모리 용량을 가진 미니 컴퓨터와 같은 하드웨어 자원을 가진 시스템에서도 동작할 수 있도록 설계되었다.
B 언어는 데이터 형식이 없는 대신, 하드웨어의 CPU 레지스터에 대응하는 워드형 1종에 의존하는 방식을 채택했다. 이는 어떤 비트 길이의 CPU에도 대응할 수 있도록 하기 위함이었다. 워드는 문맥에 따라 정수 또는 메모리 주소로 취급되었다. 그러나 ASCII 코드가 일반화되고, 벨 연구소에 PDP-11이 도입되면서 문자 데이터형의 지원이 중요해졌다. B 언어와 같이 형식이 없는 언어의 사양은 단점으로 여겨지게 되었고, 켄 톰슨과 데니스 리치는 언어를 확장하여 내부 형식과 사용자 정의 형식을 지원하도록 개선하였다. 이것이 C 언어의 시초가 되었다.
B 언어로 작성된 프로그램은 컴파일러에 의해 중간 코드로 변환되었고, 실행하기 위해서는 인터프리터가 필요했다. 실행 시에는 인터프리터가 번역 순서대로 처리했기 때문에 실행 속도가 매우 느렸다. 다만, PDP-7 버전은 기계어를 출력할 수 있도록 개선되었다.
4. 문법 (Syntax)
B 언어는 문법이 매우 간결하다. 다음은 B 언어의 주요 문법 요소이다.
* 주석: `/*` 와 `*/` 사이에 작성한다.
* 변수 선언: 모든 변수는 `auto` 키워드를 사용하여 선언한다.
* 함수 정의: 함수는 다음과 같은 형태로 정의한다.
```
name(parameters) {
statements
}
```
* 제어문: `if`, `while`, `switch`, `goto` 문을 사용할 수 있다.
* 표현식: B 언어는 다양한 연산자를 지원하는 표현식을 사용할 수 있다.
5. 코드 예제
c
/* 다음 함수는 음수가 아닌 정수 n을 b진수 형태로 출력한다 (단, 2<=b<=10).
이 루틴은 ASCII 문자 코드 값이 0에서 9까지 연속하고 있음을 이용하고 있다. */
printn(n,b) {
extrn putchar;
auto a;
if(a=n/b) /* 대입문. 등차 비교가 아님 */
printn(a, b); /* 재귀 호출 */
putchar(n%b + '0');
}
```
```c
/* 다음 프로그램은 네이피어 상수 e-2를 약 4000개의 소수 자릿수까지 계산하여 5자 그룹으로 각 줄에 50개의 문자로 인쇄한다. 방법은 단순한 출력 변환으로, 다음과 같은 전개식이다.
1/2! + 1/3! + ... = .111...
여기서 숫자의 기수는 2, 3, 4, ...이다. */
main() {
extrn putchar, n, v;
auto i, c, col, a;
i = col = 0;
while(i
while(col<2*n) {
a = n+1;
c = i = 0;
while(i
v[i++] = c%a;
c =/ a--;
}
putchar(c+'0');
if(!(++col%5))
putchar(col%50?' ':'*n');
}
putchar('*n*n');
}
v[2000];
n 2000;
```
켄 톰슨(Ken Thompson)의 B 사용자 참조(Users' Reference to B)에는 B 언어의 특징을 보여주는 두 가지 예제 코드가 수록되어 있다. 첫 번째 예제는 `printn` 함수로, 주어진 숫자를 특정 진법으로 출력하는 기능을 재귀 호출을 통해 구현한다. 두 번째 예제는 네이피어 상수(e)에서 2를 뺀 값을 소수점 이하 4000자리까지 계산하여 출력하는 프로그램이다. 각 예제에 대한 자세한 설명은 하위 섹션을 참고하면 된다.
5.1. 예제 1: printn 함수
켄 톰슨이 쓴 Users' Reference to B에서 발췌된 `printn` 함수는 다음과 같다.
```c
/* 다음 함수는 음수가 아닌 정수 n을 b진수 형태로 출력한다 (단, 2<=b<=10).
이 루틴은 ASCII 문자 코드 값이 0에서 9까지 연속하고 있음을 이용하고 있다. */
printn(n,b) {
extrn putchar;
auto a;
if(a=n/b) /* 대입문. 등차 비교가 아님 */
printn(a, b); /* 재귀 호출 */
putchar(n%b + '0');
}
```
이 함수는 음수가 아닌 정수 `n`을 `b`진수로 출력한다. (단, 2 ≤ `b` ≤ 10) 함수의 작동 방식은 다음과 같다.
* `extrn putchar;`: 외부 변수 `putchar`를 선언한다. `putchar`는 한 문자를 출력하는 함수이다.
* `auto a;`: 자동 변수 `a`를 선언한다. `auto` 키워드는 함수 범위의 수명을 가진 변수를 선언한다.
* `if(a=n/b)`: `n`을 `b`로 나눈 몫을 `a`에 할당한다. 이때 `=`는 대입 연산자이며, 동등 비교 연산자(`==`)가 아니다. 만약 `a`가 0이 아니라면 (즉, `n`이 `b`보다 크다면) 참이 되어 if문 안의 내용을 실행한다.
* `printn(a, b);`: `printn` 함수를 재귀 호출한다. `n`을 `b`로 나눈 몫을 다시 `printn` 함수의 인자로 넣어 호출함으로써, `n`이 `b`보다 작아질 때까지 반복한다.
* `putchar(n%b + '0');`: `n`을 `b`로 나눈 나머지를 문자 형태로 출력한다. `n%b`는 0에서 9 사이의 값이 되는데, 여기에 문자 '0'의 ASCII 코드 값을 더함으로써 해당 숫자에 해당하는 ASCII 문자 코드를 얻고, `putchar` 함수를 통해 출력한다.
결과적으로, 이 함수는 재귀 호출을 사용하여 큰 자리수부터 작은 자리수 순서로 숫자를 출력한다.
5.2. 예제 2: 네이피어 상수(e) 계산
c
/* 다음 프로그램은 네이피어 상수 e를 소수점 이하 4000자리까지 계산하여,
한 행에 5개씩 그룹으로 나누어 50개 문자를 출력한다.
이 방법은 다음 식을 단순하게 확장한 것이다.
1/2! + 1/3! + ... = .111....
이는 각각 2진법, 3진법, 4진법... 에 대응한다. */
main() {
extrn putchar, n, v;
auto i, c, col, a;
i = col = 0;
while (i < n)
v[i++] = 1;
while (col < 2 * n) {
a = n + 1;
c = i = 0;
while (i < n) {
c =+ v[i] * 10;
v[i++] = c % a;
c =/ a--;
}
putchar(c + '0');
if (!(++col % 5))
putchar(col % 50 ? ' ' : '*n');
}
putchar('*n*n');
}
v[2000];
n 2000;
```
이 프로그램은 네이피어 상수(e)를 소수점 이하 4000자리까지 계산한다. 5개의 숫자마다 공백을 추가하고, 50개의 숫자(10개의 그룹)마다 줄 바꿈을 하여 결과를 출력한다.
프로그램 작동 원리는 다음과 같다.
* `v[2000]` 배열은 각 자릿수를 저장하는 데 사용되며, 초기에는 모든 요소가 1로 설정된다.
* `n`은 계산할 자릿수를 나타내며 2000으로 설정되어 있다.
* 바깥쪽 `while` 루프는 출력할 총문자 수가 `2*n` (4000)이 될 때까지 반복한다.
* 안쪽 `while` 루프는 각 자릿수를 계산한다.
* `c`는 올림을 처리하는 변수이다.
* `v[i]`에 10을 곱하고 `c`를 더한다.
* `v[i]`를 `a`로 나눈 나머지를 `v[i]`에 저장한다.
* `c`를 `a`로 나눈 몫을 `c`에 저장한다.
* `a`를 1 감소시킨다.
* `putchar(c+'0')`는 계산된 자릿수 `c`를 문자로 변환하여 출력한다.
* 5개의 숫자를 출력할 때마다 공백을, 50개의 숫자를 출력할 때마다 줄 바꿈을 출력한다.
6. B 언어와 한국의 IT 산업 (추가)
B 언어는 한국의 IT 산업에 직접적으로 사용된 사례는 드물다. 그러나 B 언어는 C 언어로 발전하였고, C 언어는 한국 IT 산업 발전에 큰 영향을 미쳤다. 따라서 B 언어는 C 언어를 통해 간접적으로 한국 IT 산업에 영향을 미쳤다고 볼 수 있다.