
//[2009.01.11.일][생성!!!]{-------------------------------------------------
//*.asm 문서를 번역하여 *.ob1 문서를 만들어 준다.
//이 문서는 *.obj 로 만들기 위한 전단계의 모든 [지역라벨] 이 해당 [asm기호]
//로 치환되어 있는 상태로, 그대로 code 로 번역하면 바로 *.obj 가 된다.
//즉, *.obj 를 보다 간단하게 번역하기 위하여 임시로 만드는 문서가 된다.
//}-------------------------------------------------------------------------


#include <vcl.h>
#pragma hdrstop


//[사용 header file]
//{
    #include  "c_define.h"
    #include  "vmos_def.h"

    #include  "ide_library.h"
    #include  "library.h"
    #include  "file.h"
    #include  "database.h"
    #include  "parser.h"
    #include  "asmencoder.h"
    #include  "object1st.h"

    #include  "ide_msgbox.h"
    #include  "msg_msg.h"

    //[2011.04.29.금][추가!!!]
    #include  "buildStatus.h"

//}

//ide_msgbox_Form->_MsgBox(d_MSGBOX_error, debugStr);

bool __fastcall Object1st(char  *pTempFileName)
{
  //[2009.01.11.일][생성!!!]{-----------------------------------------------------------------
  //<*.asm> 를 읽어서 <*.ob1> 을 만들어 준다.
  //
  //<1단계>
  //
  // - [지역라벨] 의 모든 [추가주소] 를 확정하고 수집하는 단계.
  //
  // - 모든 [지역라벨] 의 _FUNC_:BASE 로 한 [추가주소] 를 얻는다.
  //
  // - _STR_ (FD.X.STR.{: 위치) 의 _FUNC_:BASE 위치를 얻는다.
  //
  //<2단계>
  //
  // - <*.ob1> 문서를 만든다.
  //
  // - 수집한 [지역라벨] 정보를 바탕으로 [지역라벨] 이 사용된 [피연산자] 를
  //   해당 [ASM 기호] 로 교체한다.
  //
  // - 구해진 _STR_ 을 참고로 [문자열] 의 [추가주소] 를 다시 계산하고 참조 [SEGMENT] 를
  //   _FUNC_ 로 수정한 기호로 수정해 준다.
  //
  // - 처리하면서 동시에 <*.ob1> 문서를 만들어 준다.
  //   이미 용도를 다한 [지역라벨] 은 버린다.
  //   [함수라벨] 등 [전역라벨] 은 그대로 복사한다.
  //   즉, [지역라벨] 과 [문자열] 만 처리 대상이 되고 나머지는 버리거나 그대로 복사하면 된다.
  //
  // - [행번호] 는 일단 전용 저장소에 _FUNC_:BASE 로한 [추가 주소] 와 함께 정리해 놓는다.
  //   따라서, [함수영역:단위] 로 주소가 정의 된다.
  //   <*.obj> 가 저장될때 이 [행번호] 도 <*.$> 문서로 같이 저장되어야 한다.
  //
  //<중요방법>
  //
  // - 모든 [지역라벨] 은 [함수영역] 안에서만 유효하므로 위의 [1:2단계] 처리는 전부 해당 함수
  //   영역단위로 처리 되어야 한다.
  //
  //<함수영역>
  //
  // - 시작 : [함수이름라벨]
  //          유일한 [전역라벨] 로 앞에 ":" 이 붙어 있으므로 바로 알수 있다.
  //
  // - 끝   : "FD.X.STR.}:"
  //          해당 함수안에서 사용된 [문자열] 기술 영역 끝 까지가 된다.
  //
  //}-----------------------------------------------------------------------------------------

  //[VAR]
  //{
      class  DATABASE  *database;
      int    result = 0;

      //처리에 필요한 정보 구조체는 한개만 생성하면 된다.
      struct OBJECT1STINFO  object1stInfo;

      //[1단계] 처리 시작시 현재 정보를 [대피] 한다.
      //이 정보는 [2단계] 처리시 다시 원래 처리한 시작 지점으로 돌아갈때 사용된다.
      struct OBJECT1STINFO  object1stInfo_BackUp;

      //부가 정보를 관리한다.
      //수집 라벨 등 수많은 정보를 관리 하므로 용량이 크므로 별도로 관리 되어야 한다.
      struct OBJECT1STINFOETC  object1stInfoEtc;

      //[2009.02.08.일][추가!!!]
      //{
          //지정 문서의 [라벨] 총 수를 가진다.
          int    labelTotalCount;

      //}

      //[2009.03.29.일][추가!!!]
      //[문자열영역] 이 시작되면 true 로 설정하고 끝나면 false 로 설정한다.
      bool  strAreaStart = false;

  //}

  //[DATABASE 위치 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[*.asm 문서 열기]
  //{
      //[!]{-----------------------------------------------------------
      //<*.asm> 문서를 열어준다.
      //{DATABASE} 안의 [문서정보구조체] 에 문서 크기 만큼 생성해준다.
      //}--------------------------------------------------------------

      if(FILE_Open2(pTempFileName,
                    (unsigned char **)(&(database->fileinfo.buf)),
                    &(database->fileinfo.size),
                    &(database->fileinfo.handle)) != true)
      {
        //<*.asm> 문서열기 오류로 더이상 진행하지 않고 바로 종료한다.
        return(false);

      }

  //}

  //[tempfile][*.ob1 file buffer 생성]
  //{
      //[tempfile 저장소 생성]
      //{
          //*.ob1 문서는 *.asm 문서의 2 배 정도면 충분하다.
          TEMPFILE_Create(database->fileinfo.size * OPT_Ob1File_SizeFactor);

      //}

      //[<*.ob1> 문서 이름 만들기]
      //{
          //<*.ob1> 문서 이름을 미리 만들어 놓는다.
          //*.c 파일 이름을 그대로 사용하고 확장자만 바꾼다.
          TEMPFILE_MakeFileName(pTempFileName, "gob1");

      //}

  //}

  //[정보 초기화]
  //{
      //*.asm 문서가 저장되 있는 위치를 얻는다.
      object1stInfo.asmBuf  = database->fileinfo.buf;

      //*.ob1 문서가 저장중인 위치를 얻는다.
      object1stInfo.ob1Buf  = database->tempfile.buf;

      //총 행수를 얻는다.
      object1stInfo.lineTotalCount = STR_Get_LineCount(object1stInfo.asmBuf);

      object1stInfo.lineStartIndex = 0;

      object1stInfo.line           = 0;

      object1stInfo.word[0]        = '\0';

      object1stInfo.wordStartIndex = 0;

      //[부가정보] 의 위치를 얻는다.
      //용량이 크므로 [주소] 로 관리한다.
      object1stInfo.infoEtc        = &object1stInfoEtc;

      //[부가 정보 초기화]
      //{
          object1stInfoEtc.ofsAdr   = 0;
          object1stInfoEtc.strBase  = 0;

          //[행라벨 정보 초기화]
          //{
              //[2009.01.22.목][추가!!!]
              STRBUF_New(&(object1stInfoEtc.lineLabel),
                         //[기호길이] + [공백(1)] + [최고 16 Digit 16진수 표기(16)] + 공백(1) + CRLF(2)
                         //             |<---------------------- 20 Byte ---------------------------->|
                         //[총 크기] = (([기호길이] + 20) * [*.ob1 문서 행수] ) / 2
                         //정도면 크기는 충분하다(행번호가 전체 문서의 절반을 넘을수 없으므로).
                         ((OPT_1st_symbol_length + 20) * object1stInfo.lineTotalCount) / OPT_Ob1LineLabel_SizeFactor);

          //}

      //}

      //[라벨관리 정보 초기화]
      //{
          //[2009.01.14.수][추가!!!]{---------------------------------------------------------------
          //[1단계] 처리시 [지역라벨] 을 수집하고 [2단계] 처리시 [지역라벨] 이 사용된 [피연산자] 의
          //주소를 확정하는데 사용된다.
          //이 정보는 [함수영역] 단위로 사용된다.
          //}---------------------------------------------------------------------------------------

          //[라벨 총 개수 얻기]
          //{
              //[2009.02.08.일][추가!!!]{------------------------------------------
              //<*.asm> 의 [라벨] 총 수를 구한다.
              //이는 라벨을 저장할 저장소를 꼭 필요한 만큼만 생성하기 위한 것이다.
              //}------------------------------------------------------------------

              StrBuf_GetLabelCount(object1stInfo.asmBuf, object1stInfo.lineTotalCount, &labelTotalCount);

          //}

          //지정 문서안의 [라벨] 수 만큼만 생성한다.
          //object1stInfo.infoEtc->labelItems = new struct OBJECT1STLABELITEM[labelTotalCount];
          //[동적생성단위적용][2021.01.24.일][수정]
          object1stInfo.infoEtc->labelItems = new struct OBJECT1STLABELITEM[UnitX(1024, labelTotalCount)];

          //처음에는 아무것도 저장 된 것이 없다.
          object1stInfo.infoEtc->labelItemCount = 0;

      //}

      //[<*.gasm2> 저장소 초기화]
      //{
          //[2009.03.29.일][추가!!!]{---------------------------------------------------------------
          //<*.gasm2> 를 저장할 [저장소] 를 생성한다.
          //전부 [8 Byte(16 byte 문자열)] 크기의 정보 + CRLF 만 저장하므로 행수에 맞게 만들면 된다.
          //<*.gasm> 전체 행과 1 : 1 로 대응해야 한다.
          //}---------------------------------------------------------------------------------------

          STRBUF_New(&(object1stInfoEtc.gasm2),
                       //행과 1:1 로 대응----------------------------v
                       (OPT_1st_symbol_length * object1stInfo.lineTotalCount));

      //}

      //[검증처리]
      //{
          //[2009.01.16.금][추가!!!]
          //Object1st_Debug_LabelView_Clear(&object1stInfo);

      //}

      //[2009.03.29.일][추가!!!]{------
      //처음에는 [배열영역] 이 아니다.
      strAreaStart = false;
      //}------------------------------

  //}

  
  //[빈문서 인가?]
  //{
      //[2011.11.09.수][중요추가!!!][------------------------------------
      //[설계묶음] 안의 <*.c> 에 실제 [번역] 되는 내용이 없는 경우
      //생성되는 <*.gasm> 문서는 완전히 비워진 문서가 되는데
      //이 경우 문서 끝을 알수 없어 [무한반복] 에 빠지게 된다.
      //이를 방지하기 위하여 아예 처리시작부에서 <*.gasm> 에 내용이 없는
      //경우는 아예 처리하지 않는것으로 수정한다.
      //
      //다른 [번역] 부분에는 정확하게 문서량으로 처리되나, 이 처리부는
      //여러번 단계적으로 처리하므로 아예 여기서 [한번] 으로 마무리한다.
      //
      //[맷돌C] 로 AVR-ISP GUI 를 제작하면서 발견하고 수정한다.
      //}----------------------------------------------------------------

      //처리할 <*.gasm> 에 아무 내용이 없는 경우는 바로 저장부로 가서 마무리한다.
      if(object1stInfo.asmBuf[0] == '\0')  goto OB1_FILE_SAVE;

  //}


  //[가상기계 제작 진행창]
  //{
      //[2011.04.29.금][추가!!!]{--------------------------------------
      //현재 처리중인 [문서정보] 를 [가상기계 제작 진행창] 에 보여주고
      //관련설정을 수행한다.
      //}--------------------------------------------------------------

      //[!]{-------------------------------------------------------------------------
      //문서를 읽어들일때 [행수] 를 얻지 않으므로, 여기서 직접 얻어서 전달해야 한다.
      //단, <STR_Get_LineCount()> 함수는 처리 시간이 많이 걸리는데 주의한다.
      //}-----------------------------------------------------------------------------

      buildStatus_Form->_fileLineCount = object1stInfo.lineTotalCount;
      buildStatus_Form->_FileInfo(pTempFileName, buildStatus_Form->_fileLineCount);

  //}


  //[Object 1st 처리]
  //{
      //[1단계 처리]
      //{
          OBJ1_1ST:

          //[Win7 <응답이 없는 상태> 해결]
          //{
              //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
              //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
              //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
              //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
              //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
              //이런 형상이 발생하지 않도록 수정한다.
              //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
              //이 문장을 넣어 준다.
              //}-------------------------------------------------------------------------------------------

              Application->ProcessMessages();

          //}

          //[가상기계 제작 진행창]
           //{
              //[2011.04.29.금][추가!!!]{--------------------------------------------
              //[중지] 요청이 있는 경우는 더이상 처리하지 않고 종료해야 한다.
              //일단, [오류] 로 처리하고, [오류 문자열] 에 [중지요청] 임을 알려준다.
              //}--------------------------------------------------------------------

              if(buildStatus_Form->Visible == false)
              {
                //[!]{-------------------------------------------------------
                //이 경우는 [즁지] 요청으로 간주하고 여기서 처리를 종료한다.
                //}----------------------------------------------------------

                msg_msg_Form->_PrintAddLine
                (d_msg_msg,
                 "\r\n"
                 "[ 가상기계 제작 취소! ]\r\n"
                 "사용자 요청으로 가상기계 제작이 [취소] 되었습니다.");

                goto lbError;

              }

          //}

          //여기서부터 또 하나의 행이 시작되는 것이다.

          //[현재 행에 내용이 있는가?]
          //{
              //현재 행에 처리할 것이 없다면 다음 행으로 넘어가야 한다.
              Object1st_GetWord(&object1stInfo, 0);

              //첫 단어가 아무것도 없는 경우는 이 행에는 처리할게 없는 것이므로 다음 행으로 넘긴다.
              if(STR_Match(object1stInfo.word, "") == true) { goto OBJ1_1ST_LINE_END; }

          //}

          //[1단계 시작 정보 처리]
          //{
              //[2단계] 에서 [함수영역] 처음부터 다시 시작해야 하므로 현재 위치의 [정보 구조체] 를 저장한다.
              object1stInfo_BackUp = object1stInfo;

              //[지역라벨] 을 관리 하는 정보 구조체 개수를 다시 초기화 한다.
              //해로운 [함수영역] 이 시작되므로.
              object1stInfo.infoEtc->labelItemCount = 0;

          //}

          //[함수라벨]
          //{
              result = Tree_Object1st_1st_FuncLabel(&object1stInfo);

              switch(result)
              {
                case yes   :  goto OBJ1_1ST_LINE_END;
                case no    :  break;

              }

          //}

          OBJ1_1ST_LOOP:

          //[행번호]
          //{
              //[문자열 영역 검사]
              //{
                  //[2009.03.29.일][추가!!!]{-----------------
                  //현재 [문자열영역] 이라면 처리하지 않는다.
                  //}-----------------------------------------

                  if(strAreaStart != true)
                  {
                    result = Tree_Object1st_1st_LineNumber(&object1stInfo);

                    switch(result)
                    {
                      case yes   :  goto OBJ1_1ST_LINE_END;
                      case no    :  break;

                    }

                  }

              //}

          //}

          //[문자열 영역 시작 라벨]
          //{
              //[문자열 영역 검사]
              //{
                  //[2009.03.29.일][추가!!!]{-----------------
                  //현재 [문자열영역] 이라면 처리하지 않는다.
                  //}-----------------------------------------
                  
                  if(strAreaStart != true)
                  {
                    result = Tree_Object1st_1st_StrAreaStart(&object1stInfo);

                    switch(result)
                    {
                      case yes   :  //[1단계] 는 전부 처리 되었으므로 [2단계] 처리도 넘어간다.
                                    //[문자열영역시작] 부터는 [문자열 code] 만 있으므로 굳이
                                    //이단계에서 처리할 필요는 없다.
                                    //이미 _STR_ 은 얻었으므로.
                                    //goto OBJ1_2ST;

                                    //[2009.03.29.일][추가!!!]{-------
                                    //[문자열 영역] 의 시작을 알린다.
                                    strAreaStart = true;
                                    //}-------------------------------

                                    goto OBJ1_1ST_LINE_END;

                      case no    :  break;

                    }

                  }

              //}

          //}

          //[문자열 영역 끝 라벨]
          //{
              result = Tree_Object1st_1st_StrAreaEnd(&object1stInfo);

              switch(result)
              {
                case yes   :  //[1단계] 는 전부 처리 되었으므로 [2단계] 처리도 넘어간다.

                              //[2009.03.29.일][추가!!!]{-------
                              //[문자열 영역] 의 시작을 알린다.
                              strAreaStart = false;
                              //}-------------------------------

                              goto OBJ1_2ST;

                case no    :  break;

              }

          //}

          //[지역라벨]
          //{
              //[문자열 영역 검사]
              //{
                  //[2009.03.29.일][추가!!!]{-----------------
                  //현재 [문자열영역] 이라면 처리하지 않는다.
                  //}-----------------------------------------

                  if(strAreaStart != true)
                  {
                    result = Tree_Object1st_1st_Label(&object1stInfo);

                    switch(result)
                    {
                      case yes   :  goto OBJ1_1ST_LINE_END;
                      case no    :  break;

                    }

                  }

              //}

          //}

          //[명령행]
          //{
              //[문자열 영역 검사]
              //{
                  //[2009.03.29.일][추가!!!]{-----------------
                  //현재 [문자열영역] 이라면 처리하지 않는다.
                  //}-----------------------------------------

                  if(strAreaStart != true)
                  {
                    result = Tree_Object1st_1st_OpcodeLine(&object1stInfo);

                    switch(result)
                    {
                      case yes   :  goto OBJ1_1ST_LINE_END;
                      case no    :  break;

                    }

                  }

              //}

          //}

          //[해당없는 행]
          //{
              //[!]{-----------------------------------------------------------
              //실제 [문자열영역] 안의 [문자열] 만 해당한다.
              //실제 별도 함수로 처리 되지 않고 있으므로 여기서 직접 추가한다.
              //}--------------------------------------------------------------

              //[<*.gasm2> 문서 만들기]
              //{
                  //[2009.03.29.일][추가!!!]
                  Object1st_Gasm2_AddOfsAdr(&object1stInfo, false, 0);

              //}

          //}


          OBJ1_1ST_LINE_END:

          //[가상기계 제작 진행창]
          //{
              //[2011.04.29.금][추가!!!]{-------------------------------------------
              //현재 처리중인 [현재 행] 과 [총 처리 행수] 를 처리한다.
              //여기서 처리하는 이유는 [듬성 듬성] 처리하여 정보는 보여주되
              //처리 시간 증가에 영향을 주지않기 위함이다.
              //
              //이 문서는 전부 1 행 단위로 처리 되므로 [문서량/10] 단위로 처리한다.
              //}-------------------------------------------------------------------

              if((buildStatus_Form->_fileLineCount/10) > 0)
              {
                if(object1stInfo.line%(buildStatus_Form->_fileLineCount/10) == 0)
                {
                  //[현재행] 보여주기.
                  buildStatus_Form->_LineNum(object1stInfo.line);

                  //[전체 처리 행수] 보여주기.
                  buildStatus_Form->_TotalLineNum();

                }

              }
              else
              {
                //[현재행] 보여주기.
                buildStatus_Form->_LineNum(object1stInfo.line);

                //[전체 처리 행수] 보여주기.
                buildStatus_Form->_TotalLineNum();

              }

          //}

          //[행단위 후처리]
          //{
              //[다음행 지정]
              //{
                  //다음 행의 시작 index 를 구한다.
                  STR_Get_NextLineStartIndex(object1stInfo.asmBuf,
                                             object1stInfo.lineStartIndex,
                                             &(object1stInfo.lineStartIndex));

              //}

              //[행 순번 증가]
              //{
                  //한개의 행을 처리한 것으로 보아서 행 번호를 증가시킨다.
                  object1stInfo.line++;

                  //[가상기계 제작 진행창]
                  //{
                      //[2011.04.29.금][추가!!!]{----------------------------------------
                      //[가상기계 제작 상태 창] 에 [총 처리 행수] 정보를 표시하기 위하여
                      //이 창에서 관리하는 [총 처리 행수] 환경변수를 수정해 준다.
                      //}----------------------------------------------------------------

                      //행이 증가할때 마다 같이 증가시켜 준다.
                      buildStatus_Form->_totalLineNum++;

                  //}

              //}

              //아직 문서의 끝이 아니므로 다음 행을 처리하도록 한다.
              goto OBJ1_1ST_LOOP;

          //}

      //}


      //[2단계 처리]
      //{
          //[2단계] 처리를 수행한다.

          OBJ1_2ST:

          //[Win7 <응답이 없는 상태> 해결]
          //{
              //[2010.09.26.일][중요추가!!!]{---------------------------------------------------------------
              //WinXP 에서는 아무 문제가 없었는데, Win7 에서는 [무한반복] 이 계속되는 경우
              //일정 시간이 지나면 [응답이 없는 상태] 로 지정되어 [맷돌] 과 통신시에 [시간제한] 에
              //계속 걸리는 문제가 발생하고, [하얗게] 되는 문제가 발생한다.
              //보기에도 좋지 않고, 통신에도 문제가 방생하므로 [무한반복] 부분에 [외부 알림문 확인] 을 넣어
              //이런 형상이 발생하지 않도록 수정한다.
              //이는 [링크] 등 다른 부분도 마찬가지이므로 대규모 [무한반복] 을 처리하는 부분에는 전부
              //이 문장을 넣어 준다.
              //}-------------------------------------------------------------------------------------------

              Application->ProcessMessages();

          //}

          //[가상기계 제작 진행창]
          //{
              //[2011.04.29.금][추가!!!]{--------------------------------------------
              //[중지] 요청이 있는 경우는 더이상 처리하지 않고 종료해야 한다.
              //일단, [오류] 로 처리하고, [오류 문자열] 에 [중지요청] 임을 알려준다.
              //}--------------------------------------------------------------------

              if(buildStatus_Form->Visible == false)
              {
                //[!]{-------------------------------------------------------
                //이 경우는 [즁지] 요청으로 간주하고 여기서 처리를 종료한다.
                //}----------------------------------------------------------

                msg_msg_Form->_PrintAddLine
                (d_msg_msg,
                 "\r\n"
                 "[ 가상기계 제작 취소! ]\r\n"
                 "사용자 요청으로 가상기계 제작이 [취소] 되었습니다.");

                goto lbError;

              }

          //}

          //[검증처리]
          //{
              //[2009.01.16.금][추가!!!]
              //Object1st_Debug_LabelView(&object1stInfo);

          //}


          //[함수영역 시작으로 이동]
          //{
              //다시 [2단계] 처리를 수행하기 위하여 [1단계] 처리를 수행한 함수 영역의 시작으로 이동한다.
              //이는 이미 [1단계] 시작시 [대피] 시켜 놓은 [정보구조체] 를 다시 설정하면 된다.
              object1stInfo = object1stInfo_BackUp;

          //}

          //여기서부터 또 하나의 행이 시작되는 것이다.

          //[현재 행에 내용이 있는가?]
          //{
              //현재 행에 처리할 것이 없다면 다음 행으로 넘어가야 한다.
              Object1st_GetWord(&object1stInfo, 0);

              //첫 단어가 아무것도 없는 경우는 이 행에는 처리할게 없는 것이므로 다음 행으로 넘긴다.
              if(STR_Match(object1stInfo.word, "") == true) { goto OBJ1_2ST_LINE_END; }

          //}

          //[함수라벨]
          //{
              result = Tree_Object1st_2st_FuncLabel(&object1stInfo);

              switch(result)
              {
                case yes   :  goto OBJ1_2ST_LINE_END;
                case no    :  break;

              }

          //}

          OBJ1_2ST_LOOP:

          //[행번호]
          //{
              result = Tree_Object1st_2st_LineNumber(&object1stInfo);

              switch(result)
              {
                case yes   :  goto OBJ1_2ST_LINE_END;
                case no    :  break;

              }

          //}

          //[문자열 영역 끝 라벨]
          //{
              result = Tree_Object1st_2st_StrAreaStart(&object1stInfo);

              switch(result)
              {
                case yes   :  //[2단계] 는 전부 처리 되었으므로 다음 처리부로 이동한다.
                              goto OB1_2ST_END;
                case no    :  break;

              }

          //}

          //[지역라벨]
          //{
              result = Tree_Object1st_2st_Label(&object1stInfo);

              switch(result)
              {
                case yes   :  goto OBJ1_2ST_LINE_END;
                case no    :  break;

              }

          //}

          //[명령행]
          //{
              result = Tree_Object1st_2st_OpcodeLine(&object1stInfo);

              switch(result)
              {
                case yes   :  goto OBJ1_2ST_LINE_END;
                case no    :  break;

              }

          //}

          OBJ1_2ST_LINE_END:


          //[가상기계 제작 진행창]
          //{
              //[2011.04.29.금][추가!!!]{-------------------------------------------
              //현재 처리중인 [현재 행] 과 [총 처리 행수] 를 처리한다.
              //여기서 처리하는 이유는 [듬성 듬성] 처리하여 정보는 보여주되
              //처리 시간 증가에 영향을 주지않기 위함이다.
              //
              //이 문서는 전부 1 행 단위로 처리 되므로 [문서량/10] 단위로 처리한다.
              //}-------------------------------------------------------------------

              if((buildStatus_Form->_fileLineCount/10) > 0)
              {
                if(object1stInfo.line%(buildStatus_Form->_fileLineCount/10) == 0)
                {
                  //[현재행] 보여주기.
                  buildStatus_Form->_LineNum(object1stInfo.line);

                  //[전체 처리 행수] 보여주기.
                  buildStatus_Form->_TotalLineNum();

                }

              }
              else
              {
                //[현재행] 보여주기.
                buildStatus_Form->_LineNum(object1stInfo.line);

                //[전체 처리 행수] 보여주기.
                buildStatus_Form->_TotalLineNum();

              }

          //}


          //[행단위 후처리]
          //{
              //[다음행 지정]
              //{
                  //다음 행의 시작 index 를 구한다.
                  STR_Get_NextLineStartIndex(object1stInfo.asmBuf,
                                             object1stInfo.lineStartIndex,
                                             &(object1stInfo.lineStartIndex));

              //}

              //[행 순번 증가]
              //{
                  //한개의 행을 처리한 것으로 보아서 행 번호를 증가시킨다.
                  object1stInfo.line++;

                  //[가상기계 제작 진행창]
                  //{
                      //[2011.04.29.금][추가!!!]{----------------------------------------
                      //[가상기계 제작 상태 창] 에 [총 처리 행수] 정보를 표시하기 위하여
                      //이 창에서 관리하는 [총 처리 행수] 환경변수를 수정해 준다.
                      //}----------------------------------------------------------------

                      //행이 증가할때 마다 같이 증가시켜 준다.
                      buildStatus_Form->_totalLineNum++;

                  //}

              //}

              //아직 문서의 끝이 아니므로 다음 행을 처리하도록 한다.
              goto OBJ1_2ST_LOOP;

          //}

          OB1_2ST_END:

          //각각의 행을 처리한 다음에 다음 행을 지정하거나 문서의 끝에 도달한 경우 등의 처리를 수행한다.

          //[문서의 끝인가?]
          //{
              //현재 [행번호 + 2] 이 총 행수와 같다면 모든 행을 다 처리한 것이다.
              //이는 <*.asm> 문서에 빈행은 없으나 맨 마지막 문서행은 내용이 없는 CRLF 만 있기 때문이다.

              if((object1stInfo.line + 2) >= object1stInfo.lineTotalCount)
              {
                //모든 행을 다 처리 하였으므로 문서를 저장하는 곳으로 이동한다.
                goto OB1_FILE_SAVE;

              }
              else
              {
                //[다음행 지정]
                //{
                    //[2009.01.14.수][추가!!!]{-----------------------------------------------
                    //현재 행이 [문자열 영역 끝 라벨] 행 위치 이므로, 다시 [함수라벨] 이 있는
                    //다음행을 지정해 주고 넘어 가야 한다.
                    //}-----------------------------------------------------------------------

                    //다음 행의 시작 index 를 구한다.
                    STR_Get_NextLineStartIndex(object1stInfo.asmBuf,
                                               object1stInfo.lineStartIndex,
                                               &(object1stInfo.lineStartIndex));

                    //행 순번 증가.
                    object1stInfo.line++;

                //}

                //다시 다음 [함수] 의 [1단계] 처리로 들어 간다.
                goto OBJ1_1ST;

              }

          //}

      //}

  //}


  OB1_FILE_SAVE:


  //[tempfile][*.ob1 file 저장]
  //{
      //[!]{---------------------------------------------------
      //tempfile [저장소] 의 내용을 <*.ob1> 문서로 저장한다.
      //저장할 파일의 이름은 이미 사전에 만들어진 상태이다.
      //해당 buffer 의 삭제는 아래 함수에서 자동으로 처리된다.
      //}------------------------------------------------------

      TEMPFILE_Save();

  //}

  //[행번호 문서 저장]
  //{
      //[2009.01.22.목][추가!!!]{-----------------
      //[행번호] 를 최종적으로 <*.$> 로 저장한다.
      //}-----------------------------------------

      Object1st_LineNumberFileSave(&object1stInfo, pTempFileName);

  //}

  //[<*.gasm2> 문서 저장]
  //{
      //[2009.03.29.일][추가!!!]
      Object1st_Gasm2FileSave(&object1stInfo, pTempFileName);

  //}

  //[함수 후처리]
  //{
      //동적 생성한 것을 삭제한다.
      if(object1stInfo.infoEtc->labelItems != NULL) { delete [] object1stInfo.infoEtc->labelItems; object1stInfo.infoEtc->labelItems = NULL; }

      //[2009.01.22.목][추가!!!]
      STRBUF_Delete(&(object1stInfo.infoEtc->lineLabel));

      //[2009.03.29.일][추가!!!]
      STRBUF_Delete(&(object1stInfo.infoEtc->gasm2));

      //[2012.04.28.토][추가!!!]
      database->FILEINFO_Delete(&(database->fileinfo));

  //}

  return(true);

  lbError:
  //{
      //[2011.04.29.금][추가!!!]{------------------------------
      //[가상기계 제작 진행 중지] 를 처리하기 위하여 추가한다.
      //}------------------------------------------------------

      //[함수 후처리]
      //{
          //동적 생성한 것을 삭제한다.
          if(object1stInfo.infoEtc->labelItems != NULL) { delete [] object1stInfo.infoEtc->labelItems; object1stInfo.infoEtc->labelItems = NULL; }

          //[2009.01.22.목][추가!!!]
          STRBUF_Delete(&(object1stInfo.infoEtc->lineLabel));

          //[2009.03.29.일][추가!!!]
          STRBUF_Delete(&(object1stInfo.infoEtc->gasm2));

      //}

      //[2011.05.02.월][추가!!!]{------------------------------------------------------
      //이미 생성된 저장소가 있으므로 반드시 [삭제] 해야 한다.
      //원래는 <TEMPFILE_Save()> 에서 저장시 자동 [삭제] 되지만 중간에 종료하는 경우는
      //이 과정을 거치지 않기 때문에 별도로 [삭제] 해 주어야 한다.
      //}------------------------------------------------------------------------------

      TEMPFILE_Delete();

      //[2012.04.28.토][추가!!!]
      database->FILEINFO_Delete(&(database->fileinfo));

      return(false);

  //}

}

//[1단계 처리 함수]-------------------------------------------------------------

int __fastcall Tree_Object1st_1st_FuncLabel(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{------------------------------------------
  //[함수라벨] 은 [1단계] 에서는 처리할 것이 없으므로 확인만 한다.
  //
  //[2009.03.20.금][중요수정!!!]
  //반드시 여기서 함수 단위 [추가주소] 를 0 으로 초기화해 주어야 한다.
  //함수 안의 [추가주소는] @FUNC:BASE 이므로 여기서 0 이 되어야 한다.
  //}------------------------------------------------------------------

  //[처리내용]
  //{
      // ":함수이름:" 의 전역 라벨인지만 확인한다.
      //또한, [행번호] 만 저장하는 <*.$> 에도 그대로 추가해 주어야 한다.

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[함수라벨 인가?]
  //{
      //[함수라벨] 은 유일한 [전역라벨] 로 단어의 시작이 ":" 문자로 시작한다.
      if(prObject1stInfo->word[0] != ':')
      {
        //[함수라벨] 이 아니므로 이 함수에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[추가 주소 초기화]
  //{
      //[2009.03.20.금][중요수정!!!]{------------------------------------------
      //[추가주소] 는 [함수] 가 새로 시작되었으므로 0 으로 초기화 되어야 한다.
      //}----------------------------------------------------------------------

      prObject1stInfo->infoEtc->ofsAdr = 0;

  //}

  //[관련 정보 처리]
  //{
      //[2009.01.22.목][추가!!!]

      //[<*.$> 에 저장]
      //{
          //[행번호] 저장 문서에 추가해 준다.
          STRBUF_Add(&(prObject1stInfo->infoEtc->lineLabel), prObject1stInfo->word);
          STRBUF_Add(&(prObject1stInfo->infoEtc->lineLabel), " \r\n");

      //}

  //}

  //[<*.gasm2> 문서 만들기]
  //{
      //[2009.03.29.일][추가!!!]
      //Object1st_Gasm2_AddOfsAdr(prObject1stInfo, false, 0);
      //[함수라벨] 은 후에 [함수 주소] 를 기록해주어야 하므로 [함수라벨] 을 그대로 추가해야 한다. 
      STRBUF_Add(&(prObject1stInfo->infoEtc->gasm2), prObject1stInfo->word);
      STRBUF_Add(&(prObject1stInfo->infoEtc->gasm2), " \r\n");

  //}

  return(yes);

}

int __fastcall Tree_Object1st_1st_LineNumber(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{--------------------------------------
  //[행번호] 는 [1단계] 에서는 처리할 것이 없으므로 확인만 한다.
  //[2009.01.22.목][수정!!!]
  //[행번호] 에 해당한다면 그대로 [전용 저장소] 에 추가하면 된다.
  //
  //[2009.03.30.월][수정!!!]---------------------------------------
  //단, 바로 이전 [행번호] 와 중복 되는 경우는 [추가] 하지 않는다.
  //}--------------------------------------------------------------

  //[처리내용]
  //{
      // "$행번호" 라면 [전용 저장소] 에 정해진 형식으로 추가해 주어야 한다.
      //<*.ob1> 에는 추가하지 않는다.

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

      //[2009.01.22.목][추가!!!]
      char   tempStr[OPT_wordStrSize];

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[행번호 인가?]
  //{
      //[행번호] 는 첫 문자가 "$" 인지만 확인하면 된다.
      if(prObject1stInfo->word[0] != '$')
      {
        //[행번호] 가 아니므로 이 함수에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[중복검사]
  //{
      //[2009.03.30.뤌][추가!!!]{-------------------------
      //[행번호] 가 중복되는 경우는 처리하지 않아야 한다.
      //}-------------------------------------------------

      if(Object1st_LineNumberExistCheck(prObject1stInfo, prObject1stInfo->word) == true) return(yes);

  //}

  //[<*.$> 에 저장]
  //{
      //[2009.01.22.목][추가!!!]{-------------
      // [행번호] [추가주소(16진수 최소표기)]
      //
      // 의 형식으로 행단위로 추가한다.
      //}-------------------------------------

      //[추가주소 구하기]
      //{
          //값을 16 진수 최소표기로 바꿔 준다.

          CONV_LongVal_To_Hex2(prObject1stInfo->infoEtc->ofsAdr, tempStr);

      //}

      STRBUF_Add(&(prObject1stInfo->infoEtc->lineLabel), prObject1stInfo->word);
      STRBUF_Add(&(prObject1stInfo->infoEtc->lineLabel), " ");
      STRBUF_Add(&(prObject1stInfo->infoEtc->lineLabel), tempStr);
      STRBUF_Add(&(prObject1stInfo->infoEtc->lineLabel), " \r\n");

  //}

  //[<*.gasm2> 문서 만들기]
  //{
      //[2009.03.29.일][추가!!!]
      Object1st_Gasm2_AddOfsAdr(prObject1stInfo, false, 0);

  //}

  return(yes);

}

int __fastcall Tree_Object1st_1st_StrAreaStart(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{--------------------------------------
  //[문자열 영역 시작] 은 "FD.X.STR.{:" [지역라벨] 을 찾으면 된다.
  //[문자열] 영역의 시작 위치 _STR_ 도 구해서 저장한다.
  //}--------------------------------------------------------------

  //[처리내용]
  //{
      // "FD.X.STR.{:" 인지 확인하고 이 위치가 _STR_ 이 되므로 이 _STR_ 의
      //_FUNC_:BASE 로한 [추가주소] 를 해당 [정보 구조체] 에 기록해 놓는다.

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

      char   tempWord[3][OPT_wordStrSize];

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[문자열 영역 시작 인가?]
  //{
      //[문자열 영역 시작] 은 "FD.X.STR.{:" 라벨인지만 확인하면 된다.
      //"." 를 [구분자] 로 0, 2, 3 의 [단어] 만 확인하면 간단하게 알수 있다.

      STR_GetWord(prObject1stInfo->word, '.', 0, tempWord[0]);
      STR_GetWord(prObject1stInfo->word, '.', 2, tempWord[1]);
      STR_GetWord(prObject1stInfo->word, '.', 3, tempWord[2]);

      if(!((STR_Match(tempWord[0], "FD")  == true) &&
           (STR_Match(tempWord[1], "STR") == true) &&
           (STR_Match(tempWord[2], "{:")  == true)))
      {
        //[문자열 영역 시작] 에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[_STR_ [추가주소] 기록]
  //{
      //지금 시점의 ofsAdr 이 _FUNC_:BASE 로한 _STR_ 의 [추가주소] 가 되므로 이것을 기록해 놓는다.
      prObject1stInfo->infoEtc->strBase = prObject1stInfo->infoEtc->ofsAdr;

  //}

  //[<*.gasm2> 문서 만들기]
  //{
      //[2009.03.29.일][추가!!!]
      Object1st_Gasm2_AddOfsAdr(prObject1stInfo, false, 0);

  //}

  return(yes);

}

int __fastcall Tree_Object1st_1st_StrAreaEnd(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{------------------------------------
  //[문자열 영역 끝] 은 "FD.X.STR.}:" [지역라벨] 을 찾으면 된다.
  //이제 [1단계] 처리가 끝난 것이다.
  //}------------------------------------------------------------

  //[처리내용]
  //{
      // "FD.X.STR.}:" 인지 확인하면 된다.

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

      char   tempWord[3][OPT_wordStrSize];

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[문자열 영역 끝 인가?]
  //{
      //[설명!!!]{-----------------------------------------------------------
      //[문자열 영역 끝] 은 "FD.X.STR.}:" 라벨인지만 확인하면 된다.
      //"." 를 [구분자] 로 0, 2, 3 의 [단어] 만 확인하면 간단하게 알수 있다.
      //}--------------------------------------------------------------------

      STR_GetWord(prObject1stInfo->word, '.', 0, tempWord[0]);
      STR_GetWord(prObject1stInfo->word, '.', 2, tempWord[1]);
      STR_GetWord(prObject1stInfo->word, '.', 3, tempWord[2]);

      if(!((STR_Match(tempWord[0], "FD")  == true) &&
           (STR_Match(tempWord[1], "STR") == true) &&
           (STR_Match(tempWord[2], "}:")  == true)))
      {
        //[문자열 영역 끝] 에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[<*.gasm2> 문서 만들기]
  //{
      //[2009.03.29.일][추가!!!]
      Object1st_Gasm2_AddOfsAdr(prObject1stInfo, false, 0);

  //}

  return(yes);

}

int __fastcall Tree_Object1st_1st_Label(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{---------------------------------------------------------------
  //[지역라벨] 인지 확인하고 맞다면, [지역라벨] 을 수집하고 _FUNC_:BASE 로한
  //[추가주소] 를 얻어서 전용 저장소에 기록해 준다.
  //이 정보는 [2단계] 처리시 [지역라벨] 이 사용된 [피연산자] 를 기호로 확정하는데 사용된다.
  //}---------------------------------------------------------------------------------------

  //[처리내용]
  //{
      // "라벨이름:" 인지 확인하면 된다.
      //[지역라벨] 은 맨 뒤에 ":" 이 붙어 있는지만 확인하면 된다.

      //[라벨이름], 해당 라벨의 [ofsdr] 은 계속 전용 저장소에 정리해 주어야 한다.

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[지역라벨 인가?]
  //{
      //[지역라벨] 은 맨뒤에 ":" 이 있는 것만 확인하면 된다.

      if(STR_WordLastChar(prObject1stInfo->word) != ':')
      {
        //[지역라벨] 에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[지역라벨 정보 수집]
  //{
      //[라벨이름]
      //{
          //현재 단어가 [지역라벨] 이름 자체가 된다.
          STR_Assign(prObject1stInfo->infoEtc->labelItems[prObject1stInfo->infoEtc->labelItemCount].name,
                     prObject1stInfo->word);

      //[라벨주소]
      //{
          //현재 ofsAdr 의 값이 이 [지역라벨] 의 _FUNC_:BASE 로한 [추가주소] 가 된다.
          prObject1stInfo->infoEtc->labelItems[prObject1stInfo->infoEtc->labelItemCount].ofsAdr = prObject1stInfo->infoEtc->ofsAdr;

      //}

      //[지역라벨] 정보가 하나 저장되었다.
      prObject1stInfo->infoEtc->labelItemCount++;

  //}

  //[<*.gasm2> 문서 만들기]
  //{
      //[2009.03.29.일][추가!!!]
      Object1st_Gasm2_AddOfsAdr(prObject1stInfo, false, 0);

  //}

  return(yes);

}

int __fastcall Tree_Object1st_1st_OpcodeLine(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{------------------------------------------------------
  //이 함수는 최종적으로 호출되므로, 이 함수가 호출된 시범의 행은 무조건
  //[명령행] 일수밖에는 없다.
  //따라서, 무조건 [명령행] 으로 보고 정확한 [명령 전체 길이(Byte 단위)] 를 구한뒤
  // ofsAdr += [명령 전체 길이];
  //로 관리 변수를 수정해 주어야 한다.
  //이는 [지역라벨] 의 정확한 [추가주소] 를 계산하기 위한 것이다.
  //
  //이 함수가 유일하게 ofsAdr 이 계산되는 함수다.
  //}------------------------------------------------------------------------------

  //[처리내용]
  //{
      // OPCODE OPND0 OPND1 ...
      //
      //의 [명령행] 을 처리하면서 전체 명령행의 크기(Byte 단위) 얻어 ofsAdr 값을 수정한다.
      //ofsAdr += [명령행 전체 크기]

      //[명령] 은 현재 무조건 Opt_VMOS_OpcodeSize Byte 크기를 갖으며,
      //[피연산자] 는 [ASM 기호] 자체에 정확한 크기가 기록되 있으므로 간단하게 알수 있다.
      //또한, [피연산자] 는 앞에 2 Byte 크기의 [피연산자정보] 가 붙는것에 주의한다.

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

      //명령행 전체 길이를 갖는다.
      int    opcodeTotalSize = 0;

      //[피연산자] 1 개의 크기 정보를 가진다.
      int    opndSize = 0;

      int    i;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[<*.gasm2> 문서 만들기]
  //{
      //[2009.03.29.일][추가!!!]{--------------------------------------------------------------
      //<prObject1stInfo->infoEtc->ofsAdr> 이 수정 되기 전의 값이 이 [명령행] 의 [시작주소] 가
      //되므로 여기서 처리한다.
      //}--------------------------------------------------------------------------------------

      Object1st_Gasm2_AddOfsAdr(prObject1stInfo, true, prObject1stInfo->infoEtc->ofsAdr);

  //}

  //[!]{------------------------------------------------------------------------------------------
  //이 함수는 무조건 [명령행] 인 경우만 사용되므로 일일히 [명령행] 인지 따질 필요는 없다.
  //바로 이 [명령행의 총 크기(Byte 단위)] 만 구하면 된다.
  //
  //1) [명령행] 의 첫번째 단어는 무조건 [명령] 이 된다.
  //2) 두번째 단어부터 [피연산자] 가 되며, [피연산자] 는 각각 항상 2Byte 크기의 [정보] 를 갖는다.
  //3) [피연산자] 가 가지고 있는 [정보] 를 참조하면 바로 [피연산자] 자체 크기를 알수 있다.
  //4) 1) - 3) 까지의 정보를 가지면, 명령행의 정확한 Byte 단위 크기를 알수 있다.
  //}---------------------------------------------------------------------------------------------

  //[명령 행 크기 구하기]
  //{
      //[명령 크기]
      //{
          //명령은 무조건 첫 단어 위치가 되고 현재 무조건 해당 고정 크기를 갖는다.
          //별도로 단어를 추출할 필요는 없으므로 크기만 기록해 놓는다.
          opcodeTotalSize += d_VMOS_OpcodeSize;

      //}

      //[피연산자 전체 크기 구하기]
      //{
          //피연산자는 구조가 복잡 하므로 전용 함수를 사용하여 구한다.

          for(//0st 단어는 이미 처리한 [명령] 이므로 실제 [피연산자] 는 1st 부터 시작된다.
              i = 1;
              ;
              i++)
          {
            //[단어 추출]
            //{
                //현재 지정 순번의 단어를 추출한다.
                Object1st_GetWord(prObject1stInfo, i);

                //추출한 단어가 "" 인 경우는 더이상 이 행에 처리할 단어가 없는 것이다.
                if(prObject1stInfo->word[0] == '\0') break;

            //}

            //[피연산자 크기 얻기]
            //{
                opndSize = Object1st_Get_OpndSize(prObject1stInfo->word);

            //}

            //[명령행 크기 수정]
            //{
                opcodeTotalSize += opndSize;

            //}

          }

      //}

  //}

  //[현재 전체 주소 수정]
  //{
      prObject1stInfo->infoEtc->ofsAdr += opcodeTotalSize;

  //}

  return(yes);

}

//[2단계 처리 함수]-------------------------------------------------------------

int __fastcall Tree_Object1st_2st_FuncLabel(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{------------------
  //[함수라벨] 의 경우는 그대로 복사하면 된다.
  //}------------------------------------------

  //[처리내용]
  //{
      // ":함수이름:" 의 [전역라벨] 이라면 그대로 <*.ob1> 에 추가한다.

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[함수라벨 인가?]
  //{
      //[함수라벨] 은 유일한 [전역라벨] 로 단어의 시작이 ":" 문자로 시작한다.
      if(prObject1stInfo->word[0] != ':')
      {
        //[함수라벨] 이 아니므로 이 함수에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //[*.ob1 에 추가]
  //{
      TEMPFILE_Add(prObject1stInfo->word); TEMPFILE_Add(" \r\n");

  //}

  return(yes);

}

int __fastcall Tree_Object1st_2st_LineNumber(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{---------------------------------------
  //[2009.01.22.목][수정!!!]
  //[행번호] 에 해당하는지만 확인하고 <*.ob1> 에는 추가하지 않는다.
  //}---------------------------------------------------------------

  //[처리내용]
  //{
      // "$행번호" 라면 그대로 <*.ob1> 문서에 추가한다.

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[행번호 인가?]
  //{
      //[행번호] 는 첫 문자가 "$" 인지만 확인하면 된다.
      if(prObject1stInfo->word[0] != '$')
      {
        //[행번호] 가 아니므로 이 함수에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  return(yes);

}

int __fastcall Tree_Object1st_2st_StrAreaStart(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{--------------------------------------
  //[문자열 영역 시작] 은 "FD.X.STR.{:" [지역라벨] 을 찾으면 된다.
  //
  // FD.X.STR.{:
  // 문자열 code ...
  // ...
  //
  // FD.X.STR.}:
  //
  //사이의 [문자열 code] 만 그대로 <*.ob1> 에 추가하면 된다.
  //[문자열 영역 라벨] 은 추가하지 않는다.
  //}--------------------------------------------------------------

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

      char   tempWord[3][OPT_wordStrSize];

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[문자열 영역 시작 인가?]
  //{
      //[문자열 영역 시작] 은 "FD.X.STR.{:" 라벨인지만 확인하면 된다.
      //"." 를 [구분자] 로 0, 2, 3 의 [단어] 만 확인하면 간단하게 알수 있다.

      STR_GetWord(prObject1stInfo->word, '.', 0, tempWord[0]);
      STR_GetWord(prObject1stInfo->word, '.', 2, tempWord[1]);
      STR_GetWord(prObject1stInfo->word, '.', 3, tempWord[2]);

      if(!((STR_Match(tempWord[0], "FD")  == true) &&
           (STR_Match(tempWord[1], "STR") == true) &&
           (STR_Match(tempWord[2], "{:")  == true)))
      {
        //[문자열 영역 시작] 에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  NEXT_LINE:

  //[다음행 지정]
  //{
      //다음 행의 시작 index 를 구한다.
      STR_Get_NextLineStartIndex(prObject1stInfo->asmBuf,
                                 prObject1stInfo->lineStartIndex,
                                 &(prObject1stInfo->lineStartIndex));

      //행 순번 증가.
      prObject1stInfo->line++;

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[문자열 영역 끝 인가?]
  //{
      //[문자열 영역 시작] 은 "FD.X.STR.}:" 라벨인지만 확인하면 된다.
      //"." 를 [구분자] 로 0, 2, 3 의 [단어] 만 확인하면 간단하게 알수 있다.

      STR_GetWord(prObject1stInfo->word, '.', 0, tempWord[0]);
      STR_GetWord(prObject1stInfo->word, '.', 2, tempWord[1]);
      STR_GetWord(prObject1stInfo->word, '.', 3, tempWord[2]);

      if((STR_Match(tempWord[0], "FD")  == true) &&
         (STR_Match(tempWord[1], "STR") == true) &&
         (STR_Match(tempWord[2], "}:")  == true))
      {
        //[문자열 영역 끝] 에 해당한다면 더이상 처리할 것이 없으므로 이 함수를 종료한다.

        // 아무 처리도 하지 않는다.

      }
      else
      {
        //[!]{------------------------------------------------------------------------------------------
        //[문자열 영역 끝] 에 해당하지 않는 경우는 [문자열 code] 이므로 읽어 들인 행을 그대로 복사한다.
        //지금 추출한 [단어] 가 곧 [문자열 code] 전체가 되므로 그대로 <*.ob1> 에 추가하면 된다.
        //}---------------------------------------------------------------------------------------------

        //[*.ob1 에 추가]
        //{
            TEMPFILE_Add(prObject1stInfo->word); TEMPFILE_Add(" \r\n");

        //}

        //다시 다음 행으로 이동한다.
        goto NEXT_LINE;

      }

  //}

  return(yes);

}

int __fastcall Tree_Object1st_2st_Label(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{----------------------------------------------------------------
  //[지역라벨] 인지 확인하고, [지역라벨] 은 [2단계] 에서는 아무 의미가 없으므로 그냥 버린다.
  //}----------------------------------------------------------------------------------------

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[첫 단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      Object1st_GetWord(prObject1stInfo, 0);

  //}

  //[지역라벨 인가?]
  //{
      //[지역라벨] 은 맨뒤에 ":" 이 있는 것만 확인하면 된다.

      if(STR_WordLastChar(prObject1stInfo->word) != ':')
      {
        //[지역라벨] 에 해당하지 않는다.

        //[정보복구]
        //{
            (*prObject1stInfo) = object1stInfo_Backup;

        //}

        //해당하지 않으므로 여기서 종료한다.
        return(no);

      }

  //}

  //아무 처리도 하지 않는다.

  return(yes);

}

int __fastcall Tree_Object1st_2st_OpcodeLine(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.13.화][생성!!!]{--------------------------------------------
  //이 함수는 최종적으로 호출되므로, 이 함수가 호출된 시범의 행은 무조건
  //[명령행] 일수밖에는 없다.
  //}--------------------------------------------------------------------

  //[방법]
  //{
      // [명령] [피연산자0] [피연산자1] ...
      //
      // [명령]
      //
      //  - 그대로 복사한다.
      //
      // [피연산자]
      //
      //  - [일반 피연산자] 와 [지역라벨] 과 [문자열기호] 3가지 경우가 존재한다.
      //
      //  1) [일반 피연산자]
      //     => 가장 첫번째 오는 단어는 무조건 해당된다.
      //     => 그대로 <*.ob1> 에 추가한다.
      //
      //  2) [지역라벨]
      //     => 단어 뒤에 ":" 이 붙어 있는지만 확인하면 된다.
      //     => 해당 라벨의 [ASM 기호] 로 변환하여 <*.ob1> 에 추가한다.
      //     => "i.u.8.c.F.8:ofsAdr" 기호로 변환한다.
      //
      //  3) [문자열기호]
      //     => "i.u.8.c.S.8:(1차주소)" -> "i.u.8.c.F.8:(_STR_ + 1차주소)" 로 변환한다.
      //     => [문자열기호] 는 "." 를 [구분자] 로 4st 단어가 "S" 로 [임시 문자열 세그먼트] 이므로 쉽게 구분할수 있다.
      //

  //}

  //[VAR]
  //{
      struct OBJECT1STINFO  object1stInfo_Backup;

      char   tempWord[OPT_wordStrSize];

      int    i;

  //}

  //[정보대피]
  //{
      //이 함수에 해당하지 않는 경우를 대비하여 정보를 대피시킨다.
      object1stInfo_Backup = (*prObject1stInfo);

  //}

  //[명령행 구분처리]
  //{
      //[2009.01.17.토][수정!!!]{--
      //[명령행] 을 구분 처리한다.
      //}--------------------------

      //[명령어 처리]
      //{
          //[명령행] 이므로 무조건 [명령어] 는 존재한다.
          //[명령어] 는 첫단어에 있으므로 무조건 그대로 <*.ob1> 에 추가한다.

          //현재 지정 순번의 단어를 추출한다.
          Object1st_GetWord(prObject1stInfo, 0);

          //[*.ob1 에 추가]
          //{
              TEMPFILE_Add(prObject1stInfo->word); TEMPFILE_Add(" ");

          //}

      //}

      //[피연산자 구분 처리]
      //{
          for(//[피연산자] 는 1st 부터 시작한다.
              i = 1;
              ;
              i++)
          {
            //[단어 추출]
            //{
                //현재 지정 순번의 단어를 추출한다.
                Object1st_GetWord(prObject1stInfo, i);

                //추출한 단어가 "" 인 경우는 더이상 이 행에 처리할 단어가 없는 것이다.
                if(prObject1stInfo->word[0] == '\0') break;

            //}

            //[단어 구분]
            //{
                //[지역라벨 인가?]
                //{
                    //[전역라벨] 도 [피연산자] 위치에 사용될 수 있으나 [전역라벨] 은
                    //맨 앞에 ":" 이 붙어 있으므로 쉽게 구별가능하다.
                    //[전역랍ㄹ은]

                    if(//[전역라벨] 은 해당되지 않아야 한다.
                       (prObject1stInfo->word[0] != ':') &&
                       (STR_WordLastChar(prObject1stInfo->word) == ':'))
                    {
                      //[지역라벨][2009.01.19.월]{-------------
                      //해당 [ASM 기호] 로 바꿔준다.
                      // "i.u.8.c.F.8:ofsAdr" 기호로 변환한다.
                      //전용 함수로 처리한다.
                      //}--------------------------------------

                      //해당 [지역라벨] 의 [ASM 기호] 를 얻는다.
                      Object1st_Get_AsmSymbol_LocalLabel(prObject1stInfo,
                                                         prObject1stInfo->word,
                                                         tempWord);

                      //[*.ob1 에 추가]
                      //{
                          TEMPFILE_Add(tempWord); TEMPFILE_Add(" ");

                      //}

                      //다음 [피연산자] 처리로 넘어 간다.
                      continue;

                    }            

                //}

                //[문자열 기호 인가?]
                //{
                    //"." 를 [구분자] 로 4st 단어인 [세그먼트] 가 "S" 인지 확인하면 된다.
                    STR_GetWord(prObject1stInfo->word, '.', 4, tempWord);

                    if(tempWord[0] == 'S')
                    {
                      //[문자열 기호][2009.01.19.월]{--------------------------------------------
                      // "i.u.8.c.S.8:(1차주소)" -> "i.u.8.c.F.8:(_STR_ + 1차주소)" 로 변환한다.
                      //}------------------------------------------------------------------------

                      //해당 [지역라벨] 의 [ASM 기호] 를 얻는다.
                      Object1st_Get_AsmSymbol_String(prObject1stInfo,
                                                     prObject1stInfo->word,
                                                     tempWord);

                      //[*.ob1 에 추가]
                      //{
                          TEMPFILE_Add(tempWord); TEMPFILE_Add(" ");

                      //}

                      //다음 [피연산자] 처리로 넘어 간다.
                      continue;

                    }

                //}

                //[일반적인 경우]
                //{
                    // 그대로 추가한다.

                    //[*.ob1 에 추가]
                    //{
                        TEMPFILE_Add(prObject1stInfo->word); TEMPFILE_Add(" ");

                    //}

                //}

            //}

          }

          TEMPFILE_Add("\r\n");

      //}

  //}

  return(yes);

}

//[기본 처리 함수]--------------------------------------------------------------

void __fastcall Object1st_GetWord(//정보구조체.
                                  struct OBJECT1STINFO  *prObject1stInfo,
                                  //지정 단어 순번(BASE : 0).
                                  int    pWordXst)
{
  //[2009.01.12.월][생성!!!]{--------------------------------------------------------------
  //[정보구조체] 를 전달 받아서 현재 정보를 참고하여 해당 순번의 단어를 추출하여 반환한다.
  //현재 행의 시작 index 값등 기본 정보는 전부 [정보구조체] 에 들어 있다.
  //}--------------------------------------------------------------------------------------

  //[단어 추출]
  //{
      //현재 행의 첫 단어를 추출한다.
      STR_GetLineWordBuf(prObject1stInfo->asmBuf,
                         prObject1stInfo->lineStartIndex,
                         pWordXst,
                         &(prObject1stInfo->wordStartIndex),
                         prObject1stInfo->word);

  //}

  return;

}

int __fastcall Object1st_Get_OpndSize(char  *pOpndAsmSymbol)
{
  //[2009.01.14.수][생성!!!]{------------------------------------------------------------------
  //[피연산자] 에 사용된 기호의 종류에 따라 [피연산자] 의 실제 크기를 추출하여 반환한다.
  //현재 Object1st() 단계에서는 [피연산자] 에 jump 등에 사용된 [지역라벨] 과 완벽한
  //[ASM 기호] 로 되 있는 순수 [피연산자] 2 종류가 있다.
  //이를 구분하여 처리한다.
  //
  //1) [지역라벨]
  //
  //   - [정보(2 Byte)] + [라벨주소(8  Byte)] = 10 Byte 가 된다.
  //   - [지역라벨] 은 결국 일종의 [상수] 가 되며 모든 [기호체계] 에서는 반드시
  //     해당 [피연산자] 에 대한 2 Byte 정보가 앞에 붙는다.
  //
  //2) [피연산자]
  //
  //   - [정보(2 Byte)] + [OPND 크기] 가 된다.
  //   - "0.1.2.3.4.5:value" 의 형식이다.
  //     예) i.u.8.c.F.8:ofsAdr
  //     따라서, "." 를 [구분자] 로 5 번째 단어를 읽으면 이 값이 이 [피연산자] 의 크기가 딘다.
  //
  //}------------------------------------------------------------------------------------------

  //[VAR]
  //{
      char  tempStr[OPT_wordStrSize];
      char  opndSizeStr[OPT_wordStrSize];
      char  hexStr[OPT_wordStrSize];

      int   size = 0;

  //}

  if(STR_WordLastChar(pOpndAsmSymbol) == ':')
  {
    //단어의 끝이 ":" 로 끝난다면 [피연산자] 에 사용된 [지역라벨] 에 해당한다.

    size = 2 + 8;

  }
  else
  {
    //"." 를 [구분자] 로 5st 의 단어가 [피연산자] 자체 크기가 된다.
    STR_GetWord(pOpndAsmSymbol, '.', 5, tempStr);

    //현재 "x:value" 단어 상태이므로 ":" 를 기준으로 다시 0st 단어를 추출한다.
    STR_GetWord(tempStr, ':', 0, opndSizeStr);

    //[값으로 변환]
    //{
        //16진수 문자열로 합성한다.
        STR_Assign(hexStr, "0x"); STR_Add(hexStr, opndSizeStr);

        //값으로 변환한다.
        CONV_HexStr_To_IntVal(hexStr, &size);

    //}

    //[피연산자 정보] 2 Byte 를 더해준다.
    size += 2;

  }

  return(size);

}

void __fastcall Object1st_Get_AsmSymbol_LocalLabel(struct OBJECT1STINFO  *pObject1stInfo,
                                                   char                  *pWord,
                                                   char                   rAsmSymbol[])
{
  //[2009.01.19.월][생성!!!]{---------------------------------------------------
  //[피연산자] 에 사용된 [지역라벨] 의 _FUNC_:BASE 로한 [추가주소] 를 먼저 찾고
  //이에 해당하는 [ASM 기호] 를 만들어 준다.
  //
  // "i.u.8.c.F.8:ofsAdr"
  //
  //로 기호를 합성한다.
  //이 과정은 [함수 영역 단위] 로 시행된다.
  //}---------------------------------------------------------------------------

  //[VAR]
  //{
      int  i;

  //}

  //[해당 라벨 찾기]
  //{
      for(i = 0; i < pObject1stInfo->infoEtc->labelItemCount; i++)
      {
        if(STR_Match(pObject1stInfo->infoEtc->labelItems[i].name , pWord) == true)
        {
          //같은 것을 찾았으므로 해당 [추가주소] 로 해당 [ASM 기호] 를 만들어 준다.

          SYMBOL_Ob1_Asm_LocalLabel(pObject1stInfo->infoEtc->labelItems[i].ofsAdr, rAsmSymbol);

          //찾았으므로 종료한다.
          return;

        }

      }

  //}

  //여기에 절대 도달할 수 없다.

  return;

}

void __fastcall Object1st_Get_AsmSymbol_String(struct OBJECT1STINFO  *pObject1stInfo,
                                               char                  *pWord,
                                               char                   rAsmSymbol[])
{
  //[2009.01.19.월][생성!!!]{---------------------------------------------------
  //[피연산자] 에 사용된 [지역라벨] 의 _FUNC_:BASE 로한 [추가주소] 를 먼저 찾고
  //이에 해당하는 [ASM 기호] 를 만들어 준다.
  //
  // "i.u.8.c.S.8:(1차주소)" -> "i.u.8.c.F.8:(_STR_ + 1차주소)" 로 변환한다.
  //
  //로 기호를 합성한다.
  //이 과정은 [함수 영역 단위] 로 시행된다.
  //
  //[추가주소] 만 다시 계산하고 [ASM 기호] 는 전용 함수를 사용한다.
  //}---------------------------------------------------------------------------

  //[VAR]
  //{
      char                tempStr[OPT_wordStrSize];
      char                hexStr[OPT_wordStrSize];

      unsigned long long  ofsAdr = 0;

  //}

  //[주소 계산]
  //{
      //[현재 기호] 의 [1차추가주소] 를 얻는다.
      //":" 를 [구분자] 로 1st 단어가 [1차주소] 가 된다.
      STR_GetWord(pWord, ':', 1, tempStr);

      //[16진수] 문자열로 만든다.
      STR_Assign(hexStr, "0x"); STR_Add(hexStr, tempStr);

      //값으로 바꾼다.
      CONV_HexStr_To_LongVal(hexStr, (long long *)(&ofsAdr));

      //[추가 주소 계산]
      //{
          //문자열의 _FUNC_:BASE 로한 실제 [추가주소] 를 확정한다.
          ofsAdr = pObject1stInfo->infoEtc->strBase + ofsAdr;

      //}

  //}

  //[ASM 기호 만들기]
  //{
      SYMBOL_Ob1_Asm_String(ofsAdr, rAsmSymbol);

  //}

  return;

}

void __fastcall Object1st_LineNumberFileSave(struct OBJECT1STINFO  *pObject1stInfo,
                                             //일단 기본이 되는 *.obj 문서 이름으로 전달 받는다.
                                             char                  *pOb1FileName)
{
  //[2009.01.22.목][생성!!!]{------------------------------------------------------------------
  //수집한 [행번호 라벨] 을 <*.$> 문서로 저장해 준다.
  //<*.obj> 문서 이름을 전달 받아서 저장할 <*.$> 이름을 만들어 주어 이 문서 이름으로 저장한다.
  //이는 문서이름은 같고 확장자만 다르기 때문이다.
  //}------------------------------------------------------------------------------------------


  //[VAR]
  //{
      class DATABASE  *database;

      char  fileFullName[OPT_filepath_length] = {""};
      char  fileName[OPT_file_name_length]    = {""};
      char  newName[OPT_file_name_length]     = {""};

  //}

  //[DATABASE 위치 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[문서 이름 만들기]
  //{
      //먼저 순수 [문서이름(경로제외)] 만 추출한다. ("name.ext" 형식...)
      STR_GetFileNameOnly(pOb1FileName, fileName);

      //확장자를 <*.$> 로 바꾸어 준다.
      STR_ChangeFileExt(fileName, "$", newName);

      //새로운 경로를 만들어 준다.
      STR_Assign(fileFullName, database->buildpath);
      STR_Add(fileFullName, newName);

  //}

  //[저장]
  //{
      STRBUF_File_Save(&(pObject1stInfo->infoEtc->lineLabel), fileFullName);

  //}

  return;

}

bool __fastcall Object1st_LineNumberExistCheck(struct OBJECT1STINFO  *pObject1stInfo,
                                               //일단 기본이 되는 *.obj 문서 이름으로 전달 받는다.
                                               char                  *pLineNumberSym)
{
  //[2009.03.30.월][생성!!!]{------------------------------------------------
  //[행번호] 가 [목록] 에 이미 존재하는지 확인한다.
  //[행번호] 가 겹치는 경우는 전부 연속되므로 간단하게 확인 가능하다.
  //
  //즉, 가장 마지막 추가된 것만 확인하면 지금 추가할 것이 겹치는지 확인된다.
  //return(true) : 이미 존재하는 것이다.
  //}------------------------------------------------------------------------

  //[VAR]
  //{
      char   lineStr[OPT_lineStrSize];
      char   word[OPT_lineStrSize];

      int    lineStartIndex;

  //}

  //가장 마지막에 추가된 행의 시작 위치를 구한다.
  //"$행 [주소] \r\n"
  //상태로 count 를 index 로한 위치는 CRLF 바로 뒤 '\0' 위치가 된다.
  STR_Get_BeforeLineStartIndex(pObject1stInfo->infoEtc->lineLabel.buf,
                               pObject1stInfo->infoEtc->lineLabel.count,
                               &lineStartIndex);

  //이 행의 첫단어를 추출한다.
  STR_GetLineWordBuf(pObject1stInfo->infoEtc->lineLabel.buf,
                     lineStartIndex,
                     0,
                     NULL,
                     word);

  //비교 결과를 바로 반환한다.
  return(STR_Match(pLineNumberSym, word));

}

//[<*.gasm2> 문서 관련]---------------------------------------------------------

void __fastcall Object1st_Gasm2_AddOfsAdr(struct OBJECT1STINFO  *pObject1stInfo,
                                          //[주소:true] 이고 [공백:false] 가된다.
                                          bool                   pTadrFspace,
                                          //<pTadrFspace:false> 인 경우는 의미 없는 값이다.
                                          unsigned long long     pOfsAdr)
{
  //[2009.03.29.일][생성!!!]{-----------------------------------------------------------------------
  //<*.gasm2> 문서 저장소에 전달받은 [추가주소] 의 값을 [16진수 16자리수] 문자열로 바꾸어 추가한다.
  //<pTadrFspace:false> 인 경우는 16자리의 [공백] 으로 대신 채워 주어야 한다.
  //이 함수는 모든 행의 처리에서 무조건 다 수행되어야 한다(행과 1:1 로 대응해야 하므로).
  //
  // "XXXXXXXXXXXXXXXX \r\n"
  //
  //의 형식이 된다.
  //}-----------------------------------------------------------------------------------------------

  //[VAR]
  //{
      char  hexStr[OPT_wordStrSize];

  //}

  //[[추가주소] 16진수 문자열로 변환]
  //{
      if(pTadrFspace == true) { CONV_LongVal_To_Hex(pOfsAdr, 16, hexStr);  }
      //[추가주소] 가 아닌 경우는 16자리수의 공백으로 채워준다.
      else                    { STR_Assign(hexStr, "----------------");    }

  //}

  //[추가]
  //{
      STRBUF_Add(&(pObject1stInfo->infoEtc->gasm2), hexStr);
      STRBUF_Add(&(pObject1stInfo->infoEtc->gasm2), " \r\n");
  //}

  return;


}

void __fastcall Object1st_Gasm2FileSave(struct OBJECT1STINFO  *pObject1stInfo,
                                        //일단 기본이 되는 *.obj 문서 이름으로 전달 받는다.
                                        char                  *pOb1FileName)
{
  //[2009.03.29.일][생성!!!]{-------------------------------
  //<*.gasm2> 저장소의 내용을 <*.gasm2> 문서로 저장해 준다.
  //}-------------------------------------------------------

  //[VAR]
  //{
      class DATABASE  *database;

      char  fileFullName[OPT_filepath_length] = {""};
      char  fileName[OPT_file_name_length]    = {""};
      char  newName[OPT_file_name_length]     = {""};

  //}

  //[DATABASE 위치 얻기]
  //{
      DATABASE_GetPtr(&database);

  //}

  //[문서 이름 만들기]
  //{
      //먼저 순수 [문서이름(경로제외)] 만 추출한다. ("name.ext" 형식...)
      STR_GetFileNameOnly(pOb1FileName, fileName);

      //확장자를 <*.gasm2> 로 바꾸어 준다.
      STR_ChangeFileExt(fileName, "gasm2", newName);

      //새로운 경로를 만들어 준다.
      STR_Assign(fileFullName, database->buildpath);
      STR_Add(fileFullName, newName);

  //}

  //[저장]
  //{
      STRBUF_File_Save(&(pObject1stInfo->infoEtc->gasm2), fileFullName);

  //}

  return;

}
























//[검증용 함수]-----------------------------------------------------------------

void __fastcall Object1st_Debug_LabelView(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.16.금][생성!!!]{-------------------------------------
  //행마다 수집한 [라벨정보] 를 IDE 의 아래 [알림창] 에 보여준다.
  //}-------------------------------------------------------------

  //[VAR]
  //{
      char  labelInfoStr[1024*100] = {""};
      char  hexStr[256] = {""};
      int   i;

  //}

  for(i = 0; i < prObject1stInfo->infoEtc->labelItemCount; i++)
  {
    //"[8 byte 주소] [라벨이름]" 이 한 개의 행이 되도록 정리한다.

    CONV_LongVal_To_Hex(prObject1stInfo->infoEtc->labelItems[i].ofsAdr, 16, hexStr);

    STR_Add(labelInfoStr, hexStr);
    STR_Add(labelInfoStr, " ");
    STR_Add(labelInfoStr, prObject1stInfo->infoEtc->labelItems[i].name);
    STR_Add(labelInfoStr, " \r\n");

  }

  //[_STR_ 정보 추가]
  //{
      CONV_LongVal_To_Hex(prObject1stInfo->infoEtc->strBase, 16, hexStr);

      STR_Add(labelInfoStr, hexStr);
      STR_Add(labelInfoStr, " ");
      STR_Add(labelInfoStr, "_STR_");
      STR_Add(labelInfoStr, " \r\n");

  //}

  msg_msg_Form->_PrintAddLine(1, labelInfoStr);

  return;

}

void __fastcall Object1st_Debug_LabelView_Clear(struct OBJECT1STINFO  *prObject1stInfo)
{
  //[2009.01.16.금][생성!!!]

  //디버그 창을 비운다.
  msg_msg_Form->_Print(1, "");

  return;

}














