스캐너 작성



지난 시간에 말씀드린대로, 사용할 스캐너(scanner)겸 파서(parser) 제너레이터(generator)는 JavaCC 입니다.


홈페이지 주소는 아래와 같습니다.

http://javacc.java.net/


우리가 정의한 VVSL 에 어울리는 홈페이지 입니다. 매우 심플하네요. 하하하.

그래도 나름 버젼은 5.0 입니다. :)


다운받아서 doc 폴더의 index.html 을 열어보니 아래와 같은 문구가 눈에 띕니다.

We recommend the following step-by-step process to learning JavaCC:


그러나!!

JavaCC 가 lex 나 yacc 정도의 유명한 제너레이터가 아니기 때문에!!

저는 그냥 대충보고 넘어가려고 합니다. 후후.


물론 관심있는 분들은 문서에 나와 있는데로, 차근히 하나씩 공부해 보시는 것도 좋을 거라 생각됩니다.

참고로...

모든 스캐너와 파서는 제너레이터마다 사용방법과 문법이 다릅니다.

심지어 아시다시피 언어마다 정규표현식을 나타내는 방식도 다르답니다.





스캐너 만들기 #1




스캐너를 만들기 이전에, JavaCC 의 문법 규칙파일인 "*.jj" 의 형식에 대해서 설명 드리겠습니다.


options {

JavaCC 옵션

}


PARSER_BEGIN(파서 클래스명)

package 패키지명;

import 라이브러리명;


public class 파서클래스명 {

java 코드

}

PARSER_END(파서클래스명)


스캐너 작성


파서 작성



대략 이런 구조입니다.


왜 스캐너 부분뿐 아니라 다른 부분이 섞여 있는지는 눈치 채셨죠?

JavaCC 는 렉서 제너레이터(lexer generator)이면서, 파서 제너레이터(parser generator)이기 때문입니다.

두가지 기능이 있는 툴이기 때문에 파서 내용도 포함되어 있습니다.


이제 위 구조에서 '스캐너 작성' 부분을 먼저 구현하려고 합니다.

작성을 하려면, 정규표현식에 대한 지식은 반드시 필요합니다.

잘 모르시는 분들은 찾아보시기 바랍니다.

특히 자바의 정규표현식이 헷갈리시는 분들은 인터넷을 참고하세요.




스캐너 작성


JavaCC 에서 토큰은 아래처럼 표현합니다.

TOKEN: {

   < 토큰명 1 : 정규표현식 1>

| < 토큰명 2 : 정규표현식 2> 

| < 토큰명 3 : 정규표현식 3>

| < 토큰명 4 : 정규표현식 4>

| < 토큰명 5 : 정규표현식 5>

}




식별자와 예약어 스캔




TOKEN : {
<VOID : "void">
| <INT : "int">
| <STRING : "string">
| <RETURN : "return">
}

TOKEN : {
<IDENTIFIER : ["a"-"z", "A-Z", "_"](["a"-"z", "A-Z", "_", "0"-"9"])*>
}

TOKEN : {
<INTEGER : (["0"-"9"])+>
}




정의한 언어 자체가 워낙 간단하니, 예약어도 매우 간단합니다.


문자열(소스코드)에서 "void" 를 찾으면, VOID.

문자열(소스코드)에서 "int" 를 찾으면, INT.

이런식입니다.



그리고 IDENTIFIER 토큰인 식별자는 뒤에 나와있는 정규표현식 대로입니다.

처음은 알파벳이나 '_' 로 시작하고, 뒤에는 알파벳, '_' 혹은 숫자가 들어간 문자열인 셈이죠.

이건 식별자 토큰으로 간주한다는 것입니다.


그런데 "void" 뿐만 아니라, 대부분 IDENTIFIER 의 정규표현식에도 일치하고, 다른 정규표현식에도 일치합니다.

이 경우, 제너레이터마다 방식은 다르겠지만 JavaCC 에서는 아래와 같은 순서로 처리합니다.


1. 정규표현식 중 가장 많은 문자가 일치하는 토큰을 따른다.

 - 즉, "voidTest" 인 경우 VOID 토큰의 정규표현식에는 4문자 일치. IDENTIFIER 토큰에는 8문자가 일치.

 - 그러므로 일치된 문자수가 가장 많은 IDENTIFIER 로 간주.


2. 일치하는 문자의 수가 동일한 경우, 먼저 정의된 토큰을 따른다.

 - "void" 의 경우 VOID 토큰의 정규표현식에도 4 문자 일치. IDENTIFIER 토큰 정규표현식에도 4 문자가 일치.

 - 그러나 VOID 토큰이 먼저 정의되었으므로, VOID 토큰으로 간주.



가장 마지막에 나온 INTEGER 는 너무나 쉽습니다.

그냥 숫자면 됩니다. VVSL 에서는 16진수나 8진수 숫자 같은건 없고 무조건 10진수이기 때문에 더욱 간단합니다.




토큰을 생성하지 않는 단어 스캔


소스코드에 작성되는 모든 문자들이 의미있는 값은 아닙니다.

예를들어 공백이나 주석같은 부분들은 무시되어야 할 문자들입니다.

이런 것들은 SKIP 을 사용해서 나타냅니다.




SKIP : {
<SPACES : ([" ", "\t", "\n", "\r", "\f"])+> }
<COMMENT : "//" (~["\r", "\n"])*("\n"|"\r\n"|"\r")?>
}




COMMENT 부분을 보면, 개행문자가 ? 로 되어 있습니다.

상식적으로 항상 있어야 할 것 같지 않나요? 이유는 소스코드 가장 마지막 줄에 코멘트가 올 경우, 개행문자가 없기 때문입니다.

토큰의 정규표현식을 생성하면서, 이 부분을 함상 염두에 두어야 합니다.

"소스코드의 가장 마지막 줄"










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

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