脚本语言的特点,咱们不再赘述了。自定义的脚本引擎还有许多亟待优化的地方,不过不碍我们讲解如何实现自定义脚本引擎。
本人呢,代码水平很菜,肯定会出现很多的错误,大家发现了呢,可以随手在自己实现的过程中改了,顺带给我提个醒儿,这儿先谢谢您呐!同时呢,这个是优化前的代码,自己可以用更高效的方法改写,提高效率。
下面会把自己当时写的验证demo,贴出来,那是我的起步。代码质量有点差,大家凑合看吧。
此处呢,先从简单的说起。咱们先抛开字符串和浮点数。先看看整数吧。
老师说过,计算一个表达式的值,可以用逆波兰表达式(想不起来的同学,可以搜索下,瞅一眼)。咱们就用这个试试,先把表达式转成逆波兰表达式的形式,然后按照逆波兰表达式的步骤进行计算。
第2步呢,想想你要支持的运算符,设置一下他们的优先级。然后就可以求解了。
//calcstrvalue.cpp
#include "stdafx.h"
#include "calcstrvalue.h"
#include "automicopt.h"
#include
int GetOperatorPriorityA(LPCSTR lpszOp, int& nOpCount)
{
if(strcmp(lpszOp, "+") == 0 || strcmp(lpszOp, "-") == 0)
{
nOpCount = 2; //操作数个数
return 10; //优先级
}
else if(strcmp(lpszOp, "*") == 0 || strcmp(lpszOp, "/") == 0)
{
nOpCount = 2;
return 11;
}
else if(strcmp(lpszOp, ">") == 0 || strcmp(lpszOp, "<") == 0 || strcmp(lpszOp, "==") == 0 || strcmp(lpszOp, "!=") == 0
|| strcmp(lpszOp, ">=") == 0 || strcmp(lpszOp, "<=") == 0)
{
nOpCount = 2;
return 8;
}
else if(strcmp(lpszOp, "&&") == 0)
{
nOpCount = 2;
return 3;
}
else if(strcmp(lpszOp, "||") == 0)
{
nOpCount = 2;
return 2;
}
else if(strcmp(lpszOp, "(") == 0 || strcmp(lpszOp, ")") == 0)
{
nOpCount = -1; //操作数以实际为准
return 100;
}
else if(strcmp(lpszOp, "!") == 0)
{
nOpCount = 1;
return 22;
}
else if(strcmp(lpszOp, "&") == 0)
{
nOpCount = 2;
return 7;
}
else if(strcmp(lpszOp, "^") == 0)
{
nOpCount = 2;
return 6;
}
else if(strcmp(lpszOp, "|") == 0)
{
nOpCount = 2;
return 5;
}
//不认识的操作符
ATLASSERT(FALSE);
nOpCount = 0;
return 0;
}
int CompareOperatorPriorityA(LPCSTR op1, LPCSTR op2, int& nOpCount)
{
int op1c = 0, op2c = 0;
int op1p = GetOperatorPriorityA(op1, op1c);
int op2p = GetOperatorPriorityA(op2, op2c);
if(op1p == op2p)
{
nOpCount = op1c;
return 0;
}
else if(op1p > op2p)
{
nOpCount = op1c;
return 1;
}
else
{
nOpCount = op2c;
return -1;
}
}
void push_op(LPCSTR lpszOp, std::deque<CStringA>& qOp, std::deque<CStringA>& qOpCalcstra)
{
printf("op:%s\n", lpszOp);
if(qOp.empty())
{
qOp.push_back(lpszOp);
return;
}
if(strcmp(lpszOp, "(") == 0)
{
qOp.push_back(lpszOp);
return;
}
if(strcmp(lpszOp, ")") == 0)
{
while(qOp.size() && qOp.back() != "(")
{
qOpCalcstra.push_back(qOp.back());
qOp.pop_back();
}
qOp.pop_back(); //弹出'('
}
else
{
if(qOp.back() == "(")
{
qOp.push_back(lpszOp);
return;
}
//比较优先级
int nOpsum = 0;
//如果比栈顶的优先级大,直接入栈
if(CompareOperatorPriorityA(lpszOp, qOp.back(), nOpsum) > 0)
{
qOp.push_back(lpszOp);
}
else
{
//把小于等于lpszOp优先级的操作符统统弹出,入栈qOpCalcstra
do
{
qOpCalcstra.push_back(qOp.back());
qOp.pop_back();
//比较下一个操作符
} while (qOp.size() && qOp.back() != '(' && CompareOperatorPriorityA(lpszOp, qOp.back(), nOpsum) <= 0);
qOp.push_back(lpszOp);
}
}
}
__int64 CalcCalcstraA(std::deque<CStringA>& qOpCalcstra)
{
std::deque<__int64> qOpValue;
while(qOpCalcstra.size())
{
char c = *qOpCalcstra.front();
if(c >= '0' && c <= '9')
{
//是数字
qOpValue.push_back(_atoi64(qOpCalcstra.front()));
}
else
{
//是运算符的时候,获取运算符的个数
int nOpsum = 0;
GetOperatorPriorityA(qOpCalcstra.front(), nOpsum);
ATLASSERT(nOpsum > 0);
switch(nOpsum)
{
case 2:
{
ATLASSERT(qOpValue.size() >= 2);
if(qOpValue.size() >= 2)
{
__int64 right = qOpValue.back();
qOpValue.pop_back();
__int64 left = qOpValue.back();
qOpValue.pop_back();
qOpValue.push_back(automic_operator<__int64, __int64>(qOpCalcstra.front(), left, right));
}
}
break;
case 1:
{
ATLASSERT(qOpValue.size() >= 1);
if(qOpValue.size() >= 1)
{
__int64 value = qOpValue.back();
qOpValue.pop_back();
qOpValue.push_back(automic_operator<__int64, __int64>(qOpCalcstra.front(), value));
}
}
break;
}
}
qOpCalcstra.pop_front();
}
ATLASSERT(qOpValue.size() == 1);
return qOpValue.back();
}
__int64 CalcValueA(LPCSTR lpszEquation)
{
if(strchr(lpszEquation, ' '))
{
//不能含有空格(为了方便解析)
ATLASSERT(FALSE);
return 0;
}
//预处理是把+-正负号统一转化为加减操作,方便下面的解析
//先预处理把类似2*-3,2*+2的处理成2*(0 -3),2*(0 +2),方便解析,否则,区分减号或负号很麻烦
CStringA strEquation;
//需要做预处理
BOOL bProcess = FALSE;
const char* test = lpszEquation;
while (*test)
{
if(*test == '-' || *test == '+')
{
if(test == lpszEquation)
{
bProcess = TRUE;
strEquation.Append("(0");
//查找数字结尾
const char* num_end = test + 1;
while (*num_end)
{
if(*num_end >= '0' && *num_end <= '9')
num_end++;
else
{
//数字到末尾了
strEquation.Append(test, num_end - test);
strEquation.AppendChar(')');
test = num_end;
break;
}
}
if(*num_end == '\0')
{
//上面没有找到,文字到末尾了
strEquation.Append(test);
strEquation.AppendChar(')');
break; //break while (*test)
}
}
else if(test - 1 >= lpszEquation)
{
//'+'‘-’前面跟的不是数字,而是其他运算符
if((*(test - 1) < '0' || *(test - 1) > '9') && (*(test - 1) != ')'))
{
if(strEquation.IsEmpty())
{
bProcess = TRUE;
strEquation.Append(lpszEquation, test - lpszEquation);
}
strEquation.Append("(0");
//查找数字结尾
const char* num_end = test + 1;
while (*num_end)
{
if(*num_end >= '0' && *num_end <= '9')
num_end++;
else
{
//数字到末尾了
strEquation.Append(test, num_end - test);
strEquation.AppendChar(')');
test = num_end;
break;
}
}
if(*num_end == '\0')
{
//上面没有找到,文字到末尾了
strEquation.Append(test);
strEquation.AppendChar(')');
break; //break while (*test)
}
}
}
}
if(bProcess)
{
strEquation.AppendChar(*test);
}
test++;
}
if(bProcess)
lpszEquation = strEquation.GetString();
std::deque<CStringA> qOp;
std::deque<CStringA> qOpCalcstra;
//拆分操作数(数字)与运算符(非数字)
const char* cursor = lpszEquation;
const char* first = cursor;
while (*cursor)
{
if(*cursor == '(' || *cursor == ')' || (*cursor == '!' && *(cursor + 1) != '='))
{
if(first < cursor)
{
if(*first >= '0' && *first <= '9')
{
CStringA strOpValue;
strOpValue.Append(first, cursor - first);
qOpCalcstra.push_back(strOpValue);
printf("opValue:%s\n", strOpValue);
}
else
{
//操作符解析完毕
CStringA strOp;
strOp.Append(first, cursor - first);
push_op(strOp, qOp, qOpCalcstra);
}
}
CStringA strOp;
strOp.Append(cursor, 1);
push_op(strOp, qOp, qOpCalcstra);
cursor++;
first = cursor;
continue;
}
//当前是数字
if(*cursor >= '0' && *cursor <= '9')
{
if(*first < '0' || *first > '9')
{
//操作符解析完毕
CStringA strOp;
strOp.Append(first, cursor - first);
push_op(strOp, qOp, qOpCalcstra);
first = cursor;
}
}
else //当前是非数字
{
//first记录的是数字,表面操作数解析完毕
if(*first >= '0' && *first <= '9')
{
CStringA strOpValue;
strOpValue.Append(first, cursor - first);
qOpCalcstra.push_back(strOpValue);
first = cursor;
printf("opValue:%s\n", strOpValue);
}
}
cursor++;
}
if(*first >= '0' && *first <= '9')
{
CStringA strOpValue;
strOpValue.Append(first, cursor - first);
qOpCalcstra.push_back(strOpValue);
printf("opValue:%s\n", strOpValue);
}
else if(*first)
{
//操作符解析完毕
CStringA strOp;
strOp.Append(first, cursor - first);
push_op(strOp, qOp, qOpCalcstra);
}
while(qOp.size())
{
qOpCalcstra.push_back(qOp.back());
qOp.pop_back();
}
//此时qOpCalcstra保存的是逆波兰表达式,根据表达式计算结果
return CalcCalcstraA(qOpCalcstra);
}
//calcstrvalue.h
#pragma once
#include
extern __int64 CalcValueA(LPCSTR lpszEquation);
template <class T_VALUE, class T_RESULT>
class automic_operator
{
public:
operator T_RESULT()
{
return m_Result;
}
automic_operator(LPCSTR lpszOp, const T_VALUE& Left, const T_VALUE& Right)
{
ZeroMemory(&m_Result, sizeof(m_Result));
if(strcmp(lpszOp, "+") == 0)
{
m_Result = Left + Right;
}
else if(strcmp(lpszOp, "-") == 0)
{
m_Result = Left - Right;
}
else if(strcmp(lpszOp, "*") == 0)
{
m_Result = Left * Right;
}
else if(strcmp(lpszOp, "/") == 0)
{
if(Right != 0)
{
m_Result = Left / Right;
}
}
else if(strcmp(lpszOp, ">") == 0)
{
m_Result = Left > Right;
}
else if(strcmp(lpszOp, "<") == 0)
{
m_Result = Left < Right;
}
else if(strcmp(lpszOp, "==") == 0)
{
m_Result = Left == Right;
}
else if(strcmp(lpszOp, "!=") == 0)
{
m_Result = Left != Right;
}
else if(strcmp(lpszOp, ">=") == 0)
{
m_Result = Left >= Right;
}
else if(strcmp(lpszOp, "<=") == 0)
{
m_Result = Left <= Right;
}
else if(strcmp(lpszOp, "&&") == 0)
{
m_Result = Left && Right;
}
else if(strcmp(lpszOp, "||") == 0)
{
m_Result = Left || Right;
}
else if(strcmp(lpszOp, "&") == 0)
{
m_Result = Left & Right;
}
else if(strcmp(lpszOp, "^") == 0)
{
m_Result = Left ^ Right;
}
else if(strcmp(lpszOp, "|") == 0)
{
m_Result = Left | Right;
}
}
automic_operator(LPCSTR lpszOp, const T_VALUE& Value)
{
ZeroMemory(&m_Result, sizeof(m_Result));
if(strcmp(lpszOp, "!") == 0)
{
m_Result = !Value;
}
}
~automic_operator()
{
}
protected:
T_RESULT m_Result;
};
测试
printf("%d\n", 2&1 || 2 | 3 && 1 ^ 3);
以上实现的是整数的数值运算和逻辑运算。以后咱们讲解通过改写上面的代码,支持浮点数和字符串。
谢谢!