모두 합치면 


static const char *pointer;

static int x, y, k;

 

static int factor2();

static int factor();

 

static int var()

{

    int result = factor2();

    while((*pointer == '+') || (*pointer == '-'))

        if(*pointer == '+') 

        {

            pointer++;

            result += factor2();

        }

        else if(*pointer == '-')

        {

            pointer++;

            result -= factor2(); 

        }

    return result;

}

 

static int factor2()

{

    int result = factor();

    while(*pointer == '*' || *pointer == '/')

        switch(*pointer)

        {

        case '*':

            pointer++;

            result *= factor();

            break;

        case '/':

            pointer++;

            result /= factor();

            break;

        }

    return result;

}

 

static int factor()

{

    int result = 0;

    if (*pointer == '(')

    {

        pointer++;

        result = var();

        if (*pointer == ')')

        {

            pointer++;

            return result;

        }

    }

    else if(('0' <= *pointer) && (*pointer<= '9')) // 부호가 없어야됨

    {

        while(true)

            if('0' <= *pointer&& *pointer<= '9') 

            {

                result *= 10;

                result += *pointer - '0';

                pointer++;

            }

            else

                break;

        return result;

    }

    else if(*pointer== 'x') 

    {

        pointer++;

        return x;

    }

    else if(*pointer== 'y') 

    {

        pointer++;

        return y;

    }

    else if(*pointer== 'k') 

    {

        pointer++;

        return k;

    }

}

 

int main()

{

    int result;

    const char *sic = "((x+y)-(x*2))+(k*(x-y))";

    x = 0, y = 0, k = 0;

    pointer = sic;

    result = var();

    printf("%d", result);

}


이 됩니다. (수식의 공백을 처리하는 함수는 추가하지 않았으니 수식에 공백이 포함되어있으면 연산이 제대로 이루어 지지 않습니다.) 


-----------------------------------------------


곱하기 기호가 생략된 경우에도 각각 처리할 수 있는 방법이 있다.

factor함수를 약간 바꾸어 주면 된다.


static int factor2()

{

    int result = factor();

    while(*pointer == '*' || *pointer == '/')

        switch(*pointer)

        {

        case '*':

            pointer++;

INSIDE:

            result *= factor();

            break;

        case '/':

            pointer++;

            result /= factor();

            break;

        }

    if (isalpha(*pointer) || *pointer == L'(')

        goto INSIDE;

    return result;

}

문자나 괄호를 만나게 될 경우 이는 <operand> <operator> <operand>꼴이 아니므로 곱하기가 생략되었다고 취급할 수 있다.


그럼 제곱연산은 어떻게 처리해야될까?


연산자 순위가 +- < */ < ^로 처리된다면

factor2에서 제곱을 확인하는 함수를 추가하고, factor를 호출하는 로직을 만들어야한다.


double carrot()

{

    double result = factor();

    if(*ptr == L'^')

    {

        ptr++;

        result = pow(result, factor());

    }

    return result;

}


static int factor2()

{

    int result = factor();

    while(*pointer == '*' || *pointer == '/')

        switch(*pointer)

        {

        case '*':

            pointer++;

INSIDE:

            result *= carrot();

            break;

        case '/':

            pointer++;

            result /= carrot();

            break;

        }

    if (isdigit(*pointer) || *pointer == L'(')

        goto INSIDE;

    return result;

}


와 같이 만들 수 있다.


또한 절댓값도 같이 계산시키고 싶다면 어찌해야될까?

생각해보면 절댓값 기호는 괄호의 한 종류로 볼 수 있다. 즉, 괄호를 처리하는 부분과 동일하게 절댓값을 연산하면 되는 것이다.


factor함수에 연산을 추가한다.


    if (*pointer == '(')

    {

        pointer++;

        result = var();

        if (*pointer == ')')

        {

            pointer++;

            return result;

        }

    }

   else if (*pointer == '|')

    {

        pointer++;

        result = var();

        if (*pointer == '|')

        {

            pointer++;

            return abs(result);

        }

    }


함수는 어떻게 처리해야될까? sin sqrt tan같은 것을 말하는 것이다.

먼저 factor에서 실수를 받을 수 있도록 변형하자. (모든 형식을 소숫점 연산을 위해 float나 double로 변경해야한다.)

} else if(('0' <= *pointer ) && (*pointer <= '9') || *pointer == '-') {

    double ret = 1.0f, minus = 1;

    unsigned int left = 0;

    unsigned long long right = 0;

 

    if (*pointer== '-') {

        minus = -1;

        pointer++;

    }

    else if (*pointer== '+') {

        pointer++;

    }

 

    while (iswdigit(*pointer)) {

        left = left * 10 + *pointer- '0';

        pointer++;

    }

 

    if (*pointer== '.')

    {

        pointer++;

        while (isdigit(*pointer)) {

            ret /= 10;

            right = right * 10 + *pointer - '0';

            pointer++;

        }

    }

 

    ret = (double)left + right * ret;

    result = ret * minus;

    return result;

}


이제 함수를 스캔할 수 있게 첫 자리가 문자인 경우를 탐색해야한다.


else if(*pointer== 'x') 

    {

        pointer++;

        return x;

    }





구문 위에 다음과 같이 쓰면 글자를 검색할 수 있다.

한 글자가 아닌 경우만 검색하면 되는 것이다.


함수의 이름 끝에 괄호가 있는지 확인하고 사이의 문자열로 검색하면 된다.



} else if (isalpha(*pointer) && isalpha(pointer[1]) {

    const char* tmp = pointer;

    for ( ; isalpha(*tmp); tmp++ ; // 괄호를 찾기 위해


    if (*tmp == '(') {// 괄호가 나왔으면


        char func_name[6];

        int length = 0;


        for ( ; *pointer != '('; pointer++)

             func_name[length++] = *pointer;


        func_name[length] = 0;

 

        if (!strcmp(func_name, "sin"))

            result = sin(var() * 0.01745329251994329576923690768489);

        else if (!strcmp(func_name, "exp"))

            result = exp(var());

        else if (!strcmp(func_name, "sqrt"))

            result = sqrt(var());

        ... <생략>

        if (*pointer == ')')

        {

              pointer++;

              return result;

        }

}


마지막으로 C++로 작성한 것이다. 다시 작성하기는 싫었기 때문에...


#define _USE_MATH_DEFINES
#include <math.h>
 
#include "WString.h"
#include "WStringBuilder.h"
#include "List.h"
 
#define radian 0.01745329251994329576923690768489 // 57.295779513082320876798154814105
 
namespace Utility {
    
    class Eval // Arithmetic
    {
        const wchar_t *ptr;
        List<char> variable;
        List<double> values;
 
        char *variable_release;
        double *values_release;
 
    public:
 
        void add_variable(char variable, double dou)
        {
            this->variable.Append(variable);
            this->values.Append(dou);
        }
 
        double get_value(const wchar_t *ptr)
        {
            this->ptr = ptr;
            variable_release = variable.ToArray();
            values_release = values.ToArray();
            return plus_minus();
        }
 
        double get_value(const WString& refer)
        {
            return get_value(refer.Reference());
        }
 
    private:
        
        double plus_minus()
        {
            double result = multiple_divide();
            while(*ptr == L'+' || *ptr == L'-')
                if(*ptr == L'+') {
                    ptr++;
                    result += multiple_divide();
                } else if(*ptr == L'-') {
                    ptr++;
                    result -= multiple_divide();
                }
            return result;
        }
        
        double multiple_divide()
        {
            double result = carrot();
            while(*ptr == L'*' || *ptr == L'/')
                if(*ptr == L'*') {
                    ptr++;
                INSIDE:
                    result *= carrot();
                } else if(*ptr == L'/') {
                    ptr++;
                    result /= carrot();
                }
            if (iswalpha(*ptr) || *ptr == L'(')
                goto INSIDE;
            return result;
        }
        
        double carrot()
        {
            double result = factor();
            if(*ptr == L'^')
            {
                ptr++;
                result = pow(result, factor());
            }
            return result;
        }
        
        double factor()
        {
            double result = 0;
            if (*ptr == L'(') {
                ptr++;
                result = plus_minus();
                if (*ptr == L')') {
                    ptr++;
                    return result;
                }
            } else if (*ptr == L'|') {
                ptr++;
                result = plus_minus();
                if (*ptr == L'|') {
                    ptr++;
                    return abs(result);
                }
            } else if((L'0' <= *ptr) && (*ptr<= L'9') || *ptr == L'-') {
                double ret = 1.0f, minus = 1;
                unsigned int left = 0;
                unsigned long long right = 0;
 
                if (*ptr == L'-') {
                    minus = -1;
                    ptr++;
                }
                else if (*ptr == L'+') {
                    ptr++;
                }
 
                while (iswdigit(*ptr)) {
                    left = left * 10 + *ptr - L'0';
                    ptr++;
                }
 
                if (*ptr == L'.')
                {
                    ptr++;
                    while (iswdigit(*ptr)) {
                        ret /= 10;
                        right = right * 10 + *ptr - L'0';
                        ptr++;
                    }
                }
 
                ret = (double)left + right * ret;
                result = ret * minus;
                return result;
            } else if (iswalpha(*ptr)) { // 변수는 한 자리로 취급
                const wchar_t *tmp = ptr;            
                for (; iswalpha(*tmp); tmp++)
                    ;
                if (*tmp == L'(') {
                    WStringBuilder wsb(6);
                    
                    for (; iswalpha(*ptr); ptr++)
                        wsb.Append( *ptr);
                    
                    WString sst_str;
                    sst_str.Clone(wsb.ToString());
                    if (*ptr == L'(') {
                        ptr++;
                        if (sst_str == L"sin") {
                            result = sin(plus_minus() * radian);
                        } else if (sst_str == L"cos") {
                            result = cos(plus_minus() * radian);
                        } else if (sst_str == L"tan") {
                            result = tan(plus_minus() * radian);
                        } else if (sst_str == L"exp") {
                            result = exp(plus_minus());
                        } else if (sst_str == L"cot") {
                            result = 1 / tan(plus_minus() * radian);
                        } else if (sst_str == L"csc") {
                            result = 1 / sin(plus_minus() * radian);
                        } else if (sst_str == L"sec") {
                            result = 1 / cos(plus_minus() * radian);
                        } else if (sst_str == L"ln" || sst_str == L"log") {
                            result = log(plus_minus());
                        } else if (sst_str == L"log10") {
                            result = log10(plus_minus());
                        }
                        
                        if(*ptr == L')') {
                            ptr++;
                            return result;
                        }
                    }
                }
                size_t count = 0;
                for (; count < variable.Size(); count++)
                    if (variable_release[count] == *ptr) {
                        ptr++;
                        return values_release[count];
                    }
            }
        }
    
    };
 
}


포함된 wstring 관련 파일은 https://github.com/rollrat/wstring-master/tree/master/wstring-master 여기서 구할 수 있다.

List.h는 http://blog.naver.com/rollrat/220525418663여기에 있다.