C 프로그래밍 (K&R, Exercise 1-23)

Copyright (c) 2015-, All Rights Reserved by Kwanghoon Choi
(아래 강의 노트를 자유롭게 이용하되 다른 웹 사이트 등을 통한 배포를 금합니다.)

The C Programming Language 2nd Ed. by Kerninghan & Ritchie ( Exercise 1-23)

C 프로그램의 텍스트를 입력받아 모든 주석을 제거하고 남은 부분을 출력하는 프로그램을 작성하시오.

  • 주석은 /* */ 형태이고
  • 주석 안에 주석은 없다고 가정한다.
  • 문자열 " /* */ "는 주석이 아니고,
  • 문자열 안에 \" 문자를 사용할 수 있음을 고려하시오. 문자열 " \"abc\" "에 큰 따옴표 2개가 포함되어 있다.

프로그램을 작성해 실행해서

#include <stdio.h>

/* The main function */
int main() {
   /* print */
   printf("   \" Hello World \"   \n");
   printf("   /* This is not a comment */  \n");
   return 0;
}

를 입력하면

#include <stdio.h>

int main() {
   printf("   \" Hello World \"   \n");
   printf("   /* This is not a comment */  \n");
   return 0;
}

를 출력해야 한다.

이 프로그램을 작성해보자. 먼저 프로그램이 꽤 복잡할 듯 하니 간단한 경우를 생각해보자.

1) 처음에는 입력 받은 문자를 그대로 출력한다.

2) 주석 시작 기호 /* 이후에는 */가 나올때 까지 입력을 절대 출력하면 안된다.

우선 이 두 가지 경우를 잘 구분할 수 있어야 겠다. 1)과 같은 상태를 NORMAL이라고 부르자. 이 상태에서 '/'를 입력 받으면 주석 시작 기호가 나올 가능성이 있다. NORMAL 상태에서 '/'를 입력 받은 상태를 SLASH라고 부르고, 아래와 같이 표시하도록 약속하자.

NORMAL ==  '/'  ==> SLASH

 

[SLASH 상태]

SLASH 상태에서 '*'를 입력 받으면 주석이 시작된다. 이 상태를 COMMENT_BEGIN이라고 하자.

SLASH == '*' ==> COMMENT_BEGIN

SLASH 상태에서 다시 '/'를 입력 받으면 이전 '/'를 출력하고 다시 SLASH 상태가 된다.

SLASH == '/' ==> SLASH (직전에 입력 받았던 '/'를 출력)

'*'나 '/'가 아닌 다른 문자를 입력 받으면 주석 상태가 아니므로 '/'과 방금 입력 받은 문자 ('*'가 아닌 그 문자)를 출력하고, NORMAL 상태로 돌아간다.

SLASH == c ==> NORMAL  (c는 '*'나 '/'가 아님)   '/'와 c를 출력

 

[COMMENT_BEGIN 상태]

COMMENT_BEGIN 상태에서 '*'를 입력 받으면 주석 끝에 도달할 가능성이 있다. 이 상태를 STAR라 부르자.

COMMENT_BEGIN == '*' ==> STAR

만일 COMMENT_BEGIN 상태에서 '*'가 아닌 다른 문자를 입력 받으면 출력을 하면 안된다. 왜냐하면 이 상태는 주석의 내부에 있는 상태이기 때문이다.

COMMENT_BEGIN == c ==> COMMENT_BEGIN  (c는 '*'가 아님)   c는 출력하지 않음

 

[STAR 상태에서]

STAR 상태에서 '/'를 입력 받으면 주석이 끝나고 이제부터는 입력 받은 것을 출력할 수 있는 상태로 바뀌어야 한다.

STAR == '/' ==> NORMAL

STAR 상태에서 다시 '*'를 입력 받으면 STRT 상태에 남아 있는다.

STAR == '*' ==> STAR

STAR 상태에서 '*'나 '/'가 아닌 문자를 입력 받으면 여전히 주석이 끝나지 않았다.

STAR == c ==> COMMENT_BEGIN  (c는 '/'나 '*'가 아님)

여기까지 논의한 내용을 정리해보면 다음과 같다.

 

[Table 1]

NORMAL ==  '/'  ==> SLASH

SLASH == '*' ==> COMMENT_BEGIN
SLASH == '/' ==> SLASH (직전에 입력 받았던 '/'를 출력)
SLASH == c ==> NORMAL  (c는 '*'나 '/'가 아님)   '/'와 c를 출력

COMMENT_BEGIN == '*' ==> STAR
COMMENT_BEGIN == c ==> COMMENT_BEGIN  (c는 '*'가 아님)   c는 출력하지 않음

STAR == '/' ==> NORMAL
STAR == '*' ==> STAR
STAR == c ==> COMMENT_BEGIN   (c는 '/'나 '*'가 아님) 

이제까지 NORMAL 상태에서 주석으로 들어갔다 나오는 과정에 해야할 일을 정리해보았다. 이제는 NORMAL 상태에서 입력 받고 그대로 출력하는 과정을 살펴본다.

NORMAL 상태를 가정하고, '/' 입력이 아닌 문자가 들어오는 경우이다. 만일 '\"' 따옴표가 입력되면 문자열 안으로 들어가게 된다. 문자열 안에서 /* */가 나타나도 주석이 아님을 다시 상기하자.

NORMAL == '\"' ==> STRING_BEGIN  ( '\"'를 출력)

문자열이 시작되었고 다시 '\"' 문자가 나올때까지 반복해서 출력한다. 단 문자열 안에서 '\\'과 '\"'이 연속으로 나오면 이때의 따옴표는 백슬래시와 함께 문자열 안에 포함된 따옴표임을 뜻하므로 둘 다 출력해주어야 한다.

STRING_BEGIN == '\\' ==> BACKSLASH   ('\\' 출력)

BACKSLASH == c ==> STRING_BEGIN (c 출력)

STRING_BEGIN 상태에서 다시 따옴표가 나오면 문자열을 벗어나게 되고, 다시 NORMAL 상태가 된다.

STRING_BEGIN == '\"' ==> NORMAL ('\"' 출력)

STRING_BEGIN 상태에서 '\\'과 '\"'이 아닌 문자가 들어오면 문자열 내의 문자로 무조건 출력한다.

STRING_BEGIN == c ==> STRING_BEGIN (c가 '\\'나 '\"'가 아닌 문자. c를 출력)

NORMAL 상태에서 문자열에 들어갔다 다시 나오는 경우를 요약해보면 다음과 같다.

[Table 2]

NORMAL == '\"' ==> STRING_BEGIN  ( '\"'를 출력)

STRING_BEGIN == '\\' ==> BACKSLASH   ('\\' 출력)
BACKSLASH == c ==> STRING_BEGIN (c 출력)
STRING_BEGIN == '\"' ==> NORMAL ('\"' 출력)
STRING_BEGIN == c ==> STRING_BEGIN (c가 '\\'나 '\"'가 아닌 문자. c를 출력)

지금까지  NORMAL 상태에서 '/'나 '\"'이 들어오는 경우에 대해 정리했다. 이제 이 두 문자가 아닌 다른 문자가 입력되면 주석도 아니고 문자열도 아니므로 그대로 출력하면 된다.

NORMAL == c ==> NORMAL  (c는 '/'나 '\"'가 아님, c를 출력)

테이블로 정리하면 다음과 같다.

[Table 3]

NORMAL == c ==> NORMAL  (c는 '/'나 '\"'가 아님, c를 출력)

지금까지 정리한 Table 1, 2, 3을 모두 모으면 Exercise 1-23에서 요구하는 프로그램의 동작 방식이 된다. 프로그램을 시작하면 NORMAL 상태에서 시작하고, 입력된 문자에 따라 Table 1, 2, 3의 규칙을 따라 상태 이동을 하면서 출력을 제어한다.

 

Table 1, 2, 3을 참고해서 작성한 프로그램의 골격은 아래와 같다.

#define NORMAL 1
#define SLASH 2
#define STRING_BEGIN 3
...

int state;

state = NORMAL;   
while ( (c = getchar()) != EOF ) {
   if ( state == NORMAL ) {
      if ( c == '/' ) state = SLASH;  
      else if (c == '\"' ) {
           putchar( c );
           state = STRING_BEGIN;   
      }
      else putchar( c ); 
   }
   else if ( state == SLASH ) {
      ...
   }
   else if ( state == STRING_BEGIN ) {
      ...
   }
   ...
}

Leave a Reply

Your email address will not be published. Required fields are marked *