수학식 구문해석(Mathematical Expressions Parser)

수학식 구문해석이란 예를 들어 쉽게 말해, “cos(0)+45″와 같은 수학식을 문자열 그대로 입력하면 컴퓨터가 이 구문을 해석하여 계산하고 계산결과를 반환하는 것이다.

필요에 의해 쓸만한 수학구문해석 소스를 검색해 본결과 다음 사이트에서 제공하는 Fast mathematical expressions parser 클래스가 가장 쓸만했다.

http://www.codeproject.com/cpp/FastMathParser.asp

예제를 분석해 보면 그 사용법을 금방 알 수 있겠지만, 나름대로 필요한 내용만을 빼내어 쉽게 정리하고자 한다. 혹, 다른 이에 급하게 수학식을 해석해야하는 기능을 구현하고자 할때, 이 글이 손쉬운 길잡이 되었으면 하는 바램이다.

먼저 위의 링크를 통해서 소스코드를 다운로드 받고 ParserLib 폴더의 muParser.sln 솔루션을 열어 컴파일 한다. 라이브러리를 Static이 아닌 DLL로 사용하고 싶다면 ParserDLL 폴더의 muParserDLL.sln를 열어 컴파일 하면 되겠지만, 여기서는 Static을 이용하였다. 별 어려움 없이 쉽게 컴파일 할 수 있을 것이다.

이제 컴파일된 라이브러리를 사용하기 위해 새로운 프로젝트(콘솔이든, MFC 든 상관없으며, 여기서는 콘솔로 하였다) 시작하고 추가 포함 디렉토리와 추가 라이브러리 디렉토리로 바로 전에 컴파일 했단 ParserLib 폴더를 잡아주고 추가종속성에 muParserDbg.lib를 입력한다. 이 경우는 Debug의 경우이고 Release의 경우는 muParser.lib를 입력한다.

여기서 정리할 내용은 간단히 주어진 수학식을 계산하여 계산 결과를 얻어 내는 것이다.

#include "muParser.h"
#include 

using namespace std;

int main() {
    char line[100];
    mu::Parser  parser;

    cin >> line;

    try {
        parser.SetExpr(line);
        cout << "결과: " << parser.Eval() << endl;
    } catch(mu::Parser::exception_type &e) {
        cout << "Msg: " << e.GetMsg() << endl;
    }
}

핵심이 되는 클래스는 mu 네임스페이스에 있는 Parser이고 수학식을 Parser의 SetExpr 맴버함수를 통해 전달해 주고, Eval 맴버함수를 통해 결과를 얻는다. Eval 맴버 함수는 옳바르지 않은 수학식일 경우 exception_type 예외를 발생하므로, 이 예외를 잡아 처리해 주면 된다.

사용할 수 있는 수식은 아래 두 표를 참고하기 바란다. 거의 대부분의 수학식과 이진연산식을 사용할 수 있으며, 개발자가 원하는 식을 직접 구현해 넣을 수 있다.

간단히 쓸만한 수학식 구문해석 클래스에 대해서 살펴보았고, 더 자세한 것에 대해서는 직접 다운로드 받은 예제를 통해 분석해보시길 바랍니다... 분명히 Fast mathematical expressions parser 라이브러리는 많은 사람들의 좋은 평가만큼이나 쓸만한 라이브러리가 틀림없습니다.

작업표시줄의 “시작” 버튼 위치 이동시키기

옛날 델파이(Delphi) 할적에 Window 컨트롤에 대해 이런 저런 장난을 많이도 쳤었는데, VC++로 전향한 이후에는 그런 장난을 하지 못했습니다. 오늘 한번 VC++를 가지고 컨트롤 장난질을 해봅니다. 이미 식상한 내용이긴 합니다만…. 모처럼 코딩(한달넘게 못해뜸)을 하면서 머리에 기름칠(ㅡㅡ;)도 좀 할겸해서… ㅋ

전역 변수입니다. (굳이 전역을 빼지 않아두 될 것도 있습니만..)

HWND starthandle;
CWnd StartButton;
CRect rect;
int nWidth, nHeight;

“시작” 버튼을 이동시키는 코드입니다. 버튼 컨트롤에 대한 클릭 이벤트에 넣으면 적당하겠군요.

starthandle = ::FindWindowEx(0, 0, "Shell_TrayWnd", NULL);
starthandle = ::FindWindowEx(starthandle, 0, "Button", NULL);

StartButton.m_hWnd=starthandle;
StartButton.EnableWindow(TRUE);
StartButton.GetWindowRect(&rect);
nWidth = rect.Width();
nHeight = rect.Height();

StartButton.MoveWindow(nMove,0,nWidth, nHeight ,TRUE);
nMove+=10;

“시작” 버튼을 가지고 장난을 쳤으면 이제 다시 원상복귀를 시켜놔야겠죠? 🙂

starthandle = ::FindWindowEx(0, 0, "Shell_TrayWnd", NULL);
starthandle = ::FindWindowEx(starthandle, 0, "Button", NULL);
StartButton.m_hWnd=starthandle;
StartButton.MoveWindow(0,0,nWidth,nHeight,TRUE);

음.. 별 쓰잘때기 없는 거죠? ㅋ 하지만 위의 내용에 제법 요긴한게 있긴 합니다. 윈도우 클래스를 이용해서 윈도우 핸들 구하는 방법도 나와 있구요.. 윈도우 핸들가지고 객체화(OOP –;)해서 나중에 요긴하게 두루 두루 써먹는 기법도 나와있네요..

개인적으로는 이제 제발 좀 코딩을 즐겁게 해보자는 취지에서리…. 올려봅니다.

소켓을 우아하게 종료하기

서버나 클라이언트를 종료하고 netstat로 종료시에 소켓이 어떤 상태인지 살펴보면 ‘TIME_WAIT’으로 표시되어있는것을 볼수있습니다. 그리고 그것들은 잠시(몇분)후에 사라졌습니다. 소켓을 종료할때 이러한 ‘TIME_WAIT’ 과정을 거치지 않고 우아하게 바로 종료하는 방법은 아래와 같습니다.

code = ::shutdown( m_hSocket, SD_BOTH ); // Send a FIN here 

// Wait for socket to fail (ie closed by other end) 
if( code != SOCKET_ERROR ) 
{   
    fd_set readfds; 
    fd_set errorfds; 
    timeval timeout; 
    FD_ZERO( &readfds ); 
    FD_ZERO( &errorfds ); 
    FD_SET( m_hSocket, &readfds ); 
    FD_SET( m_hSocket, &errorfds ); 

    timeout.tv_sec  = MAX_LINGER_SECONDS; 
    timeout.tv_usec = 0; 
    ::select( 1, &readfds, NULL, &errorfds, &timeout ); 
} 

code = ::closesocket( m_hSocket ); 
m_hSocket = INVALID_SOCKET; 

이것이 ACK과 FIN을 기다는 방법입니다. 이렇게 하지 않았을때는 소켓은 오랜시간동안 TIME_WAIT의 대기과정을 거쳐야합니다.

[출처] 델마당(www.delmadang.com) 정승유님의 글

오렌지맵 예전의 2차배포자료

1) 공간격자(Spatial Grid) 적용
2) 수치지도의 도형 및 속성 편집 및 Undo, Redo 기능
3) Legend 컨트롤(레이어 관리 컨트롤) 추가
4) 좌표, 거리, 면적측정 기능
5) ESRI의 Shape의 가져오기
6) 그림 파일 및 높은 품질의 EMF 내보내기 기능
7) 개발자 지원 강화

다운로드