. 기본 분석기

기본 분석기(Default Parser)란 아무것도 하지 않는 디폴트 분석기이다. C HTML, 자바 문서들은 엄격한 문법을 가지지만 매뉴얼이나 소설, 메모 같은 텍스트들은 특별히 적용할 문법이 없으므로 모든 텍스트는 일반 문자열로 출력되어야 한다. 예를 들어 Readme.txt 같은 일반 텍스트 파일은 구문 분석을 할만한 규칙이 없으므로 분석할 필요도 없이 흰바탕에 검정색으로 문자열을 출력하면 된다.

그러나 ApiEdit에 문법강조 기능이 들어가게 되면 모든 출력코드들이 이 기능을 지원하기 위해 전면적으로 수정되어야 하는데 일반 텍스트를 위해서 문법강조를 하지 않는 코드까지 유지하려면 무척 번거로워질 것이다. 문법강조가 필요할 때와 그렇지 않을 때를 구분하자면 코드는 다음과 같아질 것이다.

 

if (문법이 있는 문서) {

     구문 분석을 한 후 출력

} else {

     일반 문자열로 출력

}

 

출력 코드뿐만 아니라 분석기 생성, 관리, 파괴, 편집 등 모든 코드들이 문법 유무에 따라 두벌의 코드를 가져야 하는데 이렇게 하자면 코드를 유지, 관리하기가 어려워진다. 이럴 때는 약간의 발상 전환으로 두 벌의 코드를 하나로 통합할 필요가 있다.

문법이 없다는 말은 모든 문자열의 스타일이 일반 문자열이라는 뜻과 같다. 즉 일반 텍스트도 구문 분석을 하기는 하되 분석결과를 획일적으로 같게 만드는 것이다. 문법이 적용되지 않는 문서도 문법을 가지게 만듦으로써 ApiEdit의 분석 관련 코드를 일반화시킬 수 있다. 이때 사용되는 분석기가 바로 기본 분석기이다. 기본 분석기는 분석결과는 단순하지만 C++ 분석기, 자바 분석기 등과 동일한 자격을 가지며 ApiEdit의 구문 분석 요청을 매끄럽게 처리하는 일종의 플레이스 홀더(Place Holder) 역할을 한다.

기본 분석기는 pInfo 배열에 분석결과를 작성하기는 하지만 실제로 문서를 분석하지는 않기 때문에 코드도 아주 간단하다. Parse.h에 다음과 같이 CParseNull 클래스를 선언하도록 하자.

 

class CParseNull : public CParse

{

public:

     CParseNull();

     ~CParseNull() {};

     TCHAR *GetInfo(int iIndex);

private:

     void ParseLine(CApiEdit &ae,int nLine);

};

 

원칙적으로 클래스당 하나의 헤더 파일을 따로 만드는 것이 좋지만 모듈이 많아지면 실습해보기 어려우므로 분석기 관련 코드는 계속 Parse.h, Parse.cpp에 작성하기로 하자. 기본 분석기 클래스 CParseNull CParse로부터 상속을 받으므로 pInfo, ParseSize 등의 멤버변수와 MakeParseInfo, DeleteParseInfo, ParseLines 등의 멤버함수를 그대로 상속받는다. 생성자와 CParse가 구현하지 않는 순수 가상함수 두 개는 정의해야 한다. 구현 코드는 다음과 같으며 CParse.cpp에 작성한다.

 

CParseNull::CParseNull()

{

     lstrcpy(arStyle[0].name,"보통");

     arStyle[0].fore=(DWORD)-1;

     arStyle[0].back=(DWORD)-1;

}

 

TCHAR *CParseNull::GetInfo(int iIndex)

{

     switch (iIndex) {

     case 0:

          return (TCHAR *)0;

     case 1:

          return TEXT(" \t\r\n\"\’\\.,<>:;/()[]{}~!@#%^&*-+=?|$");

     default:

          return TEXT("");

     }

     return 0;

}

 

void CParseNull::ParseLine(CApiEdit &ae,int nLine)

{

     int nUnit=0;

     MakeParseInfo(nLine,nUnit,ae.pLine[nLine].Start,0);

}

 

하는 일이 없기 때문에 코드는 정말 지극히 간단하다. 생성자는 스타일에 따른 색상을 정의한다. 기본 분석기는 0번의 보통 스타일밖에 가지지 않으며 이 스타일의 색상은 모두 -1이다. ApiEdit의 디폴트 색상을 그냥 쓴다는 뜻이다. 따라서 모든 문자열은 일반 문자열로 해석되며 ApiEdit가 정의한 색상대로 출력된다.

GetInfo 함수는 분석기의 고유 정보를 조사한다. iIndex로 알고 싶은 정보의 번호를 전달하면 다음과 같은 값을 리턴한다.

 

번호

설명

0

분석기의 고유 번호인 ID이다. 값은 호스트가 현재 선택된 분석기를 조사할 사용된다. 정수형을 리턴하므로 호출측에서는 int 캐스팅해야 한다. 분석기가 추가될 때마다 1 증가하는 고유 ID 붙여 주면 된다.

1

구분자 문자열이다. 문법에 따라 인정하는 구분자 목록은 달라진다.

2

주석 문자열이다. C 경우 //

3

블록 주석의 시작 문자열이다. C 경우 /*

4

블록 주석의 문자열이다. C 경우 */

5

들여쓰기를 문자열이다. C {, 파스칼은 begin

6

내어쓰기를 문자열이다. C }, 파스칼은 end

 

CParseNull::GetInfo 함수는 ID 0을 리턴하며 구분자는 웬만한 기호들을 다 포함하고 있다. 주석과 들여쓰기는 지원하지 않으므로 2번 이후의 문자열은 모두 빈 문자열이다.

ParseLine 함수는 인수로 전달된 nLine을 분석하는데 기본 분석기는 문서 내용과 상관없이 모든 줄을 0번 스타일로 상수 분석한다. MakeParseInfo 함수를 호출하여 모든 줄의 0번 유닛 style 0으로 작성하고 있다. ParseLines 함수는 nLine 줄까지 이 함수를 반복적으로 호출하며 그 결과 pInfo 배열은 다음과 같이 작성된다.

줄의 중간에서 스타일이 바뀌는 경우가 없기 때문에 모든 줄의 유닛도 단 하나만 필요하다. 기본 분석기는 실제로 문서 내용을 분석하지 않기 때문에 이 코드로는 분석기의 동작과 구조를 살펴볼 수 없다. 다음에 이어지는 C++ 분석기의 코드를 보면 분석기가 어떤 식으로 문서를 분석해내는지 볼 수 있을 것이다.