스캐너 만들기 #2




지난 시간에 스캐너를 만들기 위해서 문법 정의를 하였습니다.

그런데 빼먹은 부분이 있습니다.


바로 문자열을 표현할때 쓰는 따옴표(double-quotes), 문자를 표현할때 쓰는 홑따옴표(single-quotes) 부분입니다.

그리고 여러줄 주석을 사용할때 쓰는 '/*', '*/' 도 정의하지 않았네요.


이 부분은 지난시간에 정의한 것과는 조금 레벨이 다릅니다.




형식이 있는 단어 스캔


C언어에서 문자열의 경우 따옴표("") 로 감싸게 됩니다.

즉, '따옴표로 시작해서 따옴표로 끝남' 이라는 형석이 있는것이죠.


이걸 단순히 스캔한다면,

TOKEN : {

<STRING : "\"" (~[])* "\"">

}



이렇게 될 것입니다.

소스코드에 아래와 같은 부분이 있다고 가정해 봅시다.


int main() {
string name = "hong gil-dong";
string address = "seoul";

return 0;
}



이런 경우에, 위 정규표현식에 매칭되는 부분은 어디일가요?

"hong gil-dong" , "seoul" 이렇게 2개가 아닙니다.


"hong gil-dong";

string address ="seoul"



여기까지 통째로 매핑되어 버립니다.

왜냐면 정규표현식에서는 "최대 길이 일치의 원칙(longest match principle)" 이라는게 존재하기 때문입니다.



/* */ 로 표현하는 주석도 한번 살펴 볼까요?


int main() {
/*
string name = "hong gil-dong";
string address = "seoul";
*/

int age = 10;
/*
int count = 20;
*/


return 0;
}





이 경우에 아래와 같이 토큰 정의를 했다고 가정해 봅시다.

SKIP: { <"/*" (~[])* "*/"> }



과연 위 정규표현식에 의해서 처리되는 문자열은 어디까지 일까요?

네, 앞서 말씀드린 "최대 길이 일치의 원칙" 에 의해서 아래처럼 되어버립니다.




/*
string name = "hong gil-dong";
string address = "seoul";
*/

int age = 10;
/*
int count = 20;
*/





이런 문제 해결을 위해서 JavaCC 에서는 '상태(state)' 라는 것을 제공해 줍니다.

MORE : { <"/*"> : IN_BLOCK_COMMENT }

<IN_BLOCK_COMMENT> MORE: { <~[]> }

<IN_BLOCK_COMMENT> SKIP: { <"*/"> : DEFAULT }


MORE : { <"\""> : IN_DB_QUOTES }

<IN_DB_QUOTES> MORE : { <(~["\""])+>

| <"\\" ~[]> }

<IN_DB_QUOTES> TOKEN : { <STRING : "\""> : DEFAULT }




먼저 앞에 있는 <IN_BLOCK_COMMENT> 는 

"현재 스캔 상태가 'IN_BLOCK_COMMENT' 일 경우에만, 다음 어휘해석 규칙을 사용하겠다" 라는 의미입니다.


그리고 MORE 는 '현재 어떤 문자열을 찾기 위해서 스캔중이다' 라는걸 의미합니다.

즉, MORE 로 문자열(소스코드)의 파싱이 종료된다면, 오류가 발생하게 되죠.


소스코드가 아래처럼 되면 오류가 발생되어야 하기 때문에 MORE 를 사용하는 것입니다.



int main() {
/*
string name = "hong gil-dong";
string address = "seoul";

return 0;
}




만약 MORE 가 없다면, 정상적으로 스캔되고 끝나버리겠지요.


JavaCC 의 표현방식을 보다보면 조금 헷갈리실 것 같아서 정리하고 넘어가겠습니다.


가장 앞에 붙을 수 있는 명령들은 TOEKN, SKIP, MORE, SPECIAL_TOKEN 등이 있습니다.

그리고 이런 명령들 뒤에는 세미콜론(:) 이 붙게 됩니다.

그 뒤에 모든 내용을 대괄호({}) 로 감싸게 되죠.


이 안에는 스캔할 문법이 들어갑니다.

<토큰명: 정규표현식> : 변경될 상태


이런 형태로 들어갑니다.

그런데 여기서 '토큰명', '변경될 상태'는 생략이 가능합니다.



이번에 마지막으로 문자를 스캔할 규칙을 작성해 보겠습니다.

MORE : { <"'"> : IN_SNG_QUOTE }

<IN_SNG_QUOTE> MORE : {

<~["\'", "\\", "\n", "\r"]> : QUOTE_TERM

| <"\\" ~[]> : QUOTE_TERM

}

<QUOTE_TERM> TOKEN: { <CHARACTER: "'"> : DEFAULT }




조금 복잡하긴 합니다만, 차근차근 하나씩 따라가시면 크게 어렵진 않으실거라 믿습니다.



이렇게 어휘분석(lexical analyzing)이 끝이 났습니다.

다음에는 구문분석(syntax analyzing)을 해 보도록 하겠습니다.






'개발관련 > 컴파일러' 카테고리의 다른 글

컴파일러 만들기 6부  (17) 2014.05.31
컴파일러 만들기 4부  (0) 2012.07.12
컴파일러 만들기 3부  (1) 2012.07.12
컴파일러 만들기 2부  (8) 2012.07.11
컴파일러 만들기 1부  (4) 2012.07.10