Program Language/C & C++

[C++] 계산기 만들기 (3) low-level input

야곰야곰+책벌레 2022. 1. 6. 10:40
728x90
반응형

Low-level input

지금까지 정의된 대로 계산기를 사용하면 몇 가지 불편한 점이 드러난다. 값을 출력하기 위해 표현식 뒤에 세미콜론을 추가하는 것은 지루한 면이 있고 이름이 공백만으로 끝나는 것은 골치 아픈 일이다. 예를 들어, x=7은 식별자 x 뒤에 연산자 = 와 숫자 7이 오는 것이 아니라 식별자 - 다. 원하는 것을 얻으려면 x =7 뒤에 공백을 추가해야 한다. 두 문제 모두 get()의 type-oriented default input을 읽는 코드로 교체하여 해결할 수 있다.

Token Token_stream::get()
{
	char ch;
	do { // skip whitespace except ’\n’
		if (!ip−>get(ch)) return ct={Kind::end};
	} while (ch!='\n' && isspace(ch));
    
	switch (ch) {
	case ';':
	case '\n':
		return ct={Kind::print};

여기서는 do-while문을 사용한다. ip->get(ch) 호출은 입력 스트림 *ip에서 ch로 단일 문자를 읽는다. 기본적으로 get()은 >>처럼 공백을 건너뛰지 않는다. cin에서 읽을 수 있는 문자가 없으면 테스트 if(! ip->get(ch))가 성공한다. 이 경우 계산기 세션을 종료하기 위해 Kind::end가 반환된다. operator !(not)은 get()이 성공하면 true를 반환하기 때문에 사용된다.

표준 라이브러리 함수 isspace()는 공백에 대한 표준 테스트를 제공한다. isspace(c)는 c가 공백 문자이면 0이 아닌 값을 반환하고 그렇지 않으면 0을 반환한다. 테스트는 테이블 조회로 구현되므로 isspace()를 사용하는 것이 개별 공백 문자를 테스트하는 것보다 훨씬 빠르다. 유사한 함수는 문자가 숫자(isdigit()), 문자(isalpah()) 또는 숫자나 문자(isalnum())인지 테스트한다.

공백을 건너뛴 후 다음 문자는 다음에 올 문자 토큰의 종류를 결정하는 데 사용된다.

공백이 발생할 대가지 문자열을 읽어서 발생하는 >> 연산자의 문제는 문자나 숫자가 아닌 문자가 별견될 때까지 한 번에 한 문자씩 읽어 해결한다.

default: // NAME, NAME=, or error
	if (isalpha(ch)) {
		string_value = ch;
		while (ip−>get(ch) && isalnum(ch))
			string_value += ch; // append ch to end of string_value
		ip−>putback(ch);
		return ct={Kind::name};
}

다행히도 이 두 가지 개선 사항은 코드의 단일 로컬 섹션을 수정하여 모두 구현할 수 있다. 개선 사항이 로컬 수정을 통해서만 구현될 수 있도록 프로그램을 구성하는 것은 중요한 설계 목표다.

문자열 끝에 문자를 하나씩 추가하는 것이 비효율적이라고 걱정할 수 있다. 매우 긴 문자열을 위한 것이지만 최신 문자열 구현은 '작은 문자열 최적화'를 제공한다. 이것은 계산기에서 이름으로 사용할 수 있는 종류의 문자열을 처리하는 데 비효율적인 작업이 포함되지 않는다는 것을 의미한다. 특히 짧은 문자열을 사용하면 free store를 사용할 필요가 없다. 짧은 문자열의 최대 문자열 수는 구현에 따라 다르지만 14개 정도가 적당할 것이다.

728x90
반응형