03_dcl_main.cpp |
void dirdcl(StringBuffer &bin) { // 직접 선언자를 분석하고 결과 출력 char ch = bin.peekc(); if (is_fnamch(ch)) { // direct-declarator: 이름 (2) std::string identifier = ""; while (bin.is_empty() == false) { ch = bin.getc(); if (is_namch(ch) == false) { bin.ungetc(); break; } identifier += ch; } if (identifier.empty()) // 식별자에 추가된 문자가 없다면 예외 throw Exception("올바른 식별자 이름이 아닙니다."); std::cout << identifier.c_str() << ": "; } else if (ch == '(') { // direct-declarator: (declarator) (3) bin.getc(); // ( 문자를 해석해서 진입했으므로 다음으로 넘긴다 dcl(bin); if (bin.peekc() != ')') // 닫는 괄호가 없으면 예외 throw Exception("닫는 괄호가 없습니다."); bin.getc(); // ) 괄호 검사를 진행했으므로 다음으로 넘긴다 } // direct-declarator: direct-declarator() (4) // direct-declarator: direct-declarator[] (5) while (bin.is_empty() == false) { ch = bin.peekc(); if (ch == '(') { // 함수 기호 획득 bin.getc(); // ( 괄호를 해석해서 진입했으므로 넘긴다 if (bin.peekc() != ')') // 닫는 괄호가 없으면 예외 throw Exception("잘못된 함수 기호입니다."); bin.getc(); // ) 괄호를 해석했으므로 다음으로 넘긴다 std::cout << "function returning "; } else if (ch == '[') { // 배열 기호 획득 bin.getc(); // [ 괄호를 해석해서 진입했으므로 넘긴다 if (bin.peekc() != ']') // 닫는 괄호가 없으면 예외 throw Exception("잘못된 배열 기호입니다."); bin.getc(); // ] 괄호를 해석했으므로 다음으로 넘긴다 std::cout << "array of "; } else { // 이외의 경우 반복문을 탈출한다 break; } } } |
이 함수는 크게 direct-declarator의 4, 5번 정의를 기준으로 구분할 수 있다. 위는 이름과 괄호, 아래는 함수 기호와 배열 기호에 관한 구문이다. 이제 dcl 프로그램의 모든 구현을 보았으니 다른 선언의 해석이 어떻게 진행되는지를 관찰할 수 있다. arrptr을 예제로 고르자. 편의를 위해 ap라고 하겠다.
코드 |
버퍼 상태 |
출력 |
dcl1 호출 |
(*ap)[]; |
|
while (ch == '*') ... |
(*ap)[]; |
|
dirdcl1 호출 |
(*ap)[]; |
|
if (ch == '(') 진입 |
(*ap)[]; |
|
bin.getc() |
*ap)[]; |
|
dcl2 호출 |
*ap)[]; |
|
while (ch == '*') ... |
ap)[]; |
|
dirdcl2 호출 |
ap)[]; |
|
if (is_fnamch(ch)) 진입 |
ap)[]; |
|
while (is_namch(ch)) ... |
)[]; |
ap: |
dirdcl2 종료 |
)[]; |
ap: |
dcl2) while (pc > 0) ... |
)[]; |
ap: pointer to |
dcl2 종료 |
)[]; |
ap: pointer to |
if (ch != ')') ... |
)[]; |
ap: pointer to |
bin.getc() |
[]; |
ap: pointer to |
while ("()" || "[]") ... |
; |
ap: pointer to array of |
dirdcl1 종료 |
; |
ap: pointer to array of |
dcl1) while (pc > 0) ... |
; |
ap: pointer to array of |
dcl1 종료 |
; |
ap: pointer to array of |
코드가 재귀적으로 호출되기 때문에 혼란스러울 수 있으니 주의 깊게 보기 바란다. 다른 모든 예제도 이 방법을 이용하여 출력을 예상할 수 있다. 그러나 원서에도 나와 있지만, 이 프로그램은 완전하지 않다. const와 같은 키워드를 처리할 수 없고, 공백을 잘못 입력했을 때 오작동할 수도 있으며, 함수의 인자에 대해 어떤 것도 하지 않았다.재귀적인 사고에 약한 사람이라면 이 예제를 분석하고 개선하면서 재귀적인 능력이 비약적으로 상승할 것이다. 또 후에 기회가 된다면 K&R의 dcl 구현을 반드시 살펴보라. 이 코드보다 아주 간단명료해서, 이해하는 데 도움이 많이 될 것이다.
이와 같이 C의 선언을 분석하는 프로그램을 만들고 테스트해볼 수 있었다.