모두 합치면
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++로 작성한 것이다. 다시 작성하기는 싫었기 때문에...
포함된 wstring 관련 파일은 https://github.com/rollrat/wstring-master/tree/master/wstring-master 여기서 구할 수 있다.
List.h는 http://blog.naver.com/rollrat/220525418663여기에 있다.
goto문은 가급적이면 쓰지말고 되도록 다른걸로 대체하는게 좋을거야..