C++中缀表达式建立表达式树

//算符优先级
typedef struct _Priority
{
    char op;
    int isp;
    int icp;
}Priority;

const int symbols = 8;
static Priority pri_table[symbols] =
{
    {'#', 0, 0},
    {'+', 3, 2},
    {'-', 3, 2},
    {'*', 5, 4},
    {'/', 5, 4},
    {'^', 6, 7},
    {'(', 1, 8},
    {')', 8, 1}
};
inline bool isDigit(char ch)
{
    return ch >= '0' && ch <= '9';
}
inline bool opNumber(char ch)
{
    return (( ch >= '0' && ch <= '9' || ch == '.')  ||
            ( ch == '@' || ch == '#' || ch == '$' || ch == '%' || ch == '&' ) || (ch == 'R' || ch == 'P'));
}
inline bool isLetterUnderline(char ch)
{
    return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
}
inline bool FloatEqualZero(float f)
{
    return (f >= -FLT_EPSILON && f <= FLT_EPSILON);
}
bool isDigitStr(const char * str , float &val)
{
    bool bRet = false;
    val = 0.00f;
    if (str == NULL)
    {
        return bRet;
    }
    size_t len = strnlen(str,MAX_EXP);
    if (len >= MAX_EXP)
    {
        return bRet;
    }
    float hasDot = false;
    float w = 1;
    for (int i=0; i<(int)len; ++i)
    {
        if (isDigit(str[i]) || str[i] == '.')
        {
            if(str[i] == '.')
            {
                if(hasDot)
                {
                    bRet =false;
                    break;
                }
                hasDot = true;
            }
            else
            {
                if(hasDot)
                {
                    w *= 0.1f;
                    val += (str[i] - '0') * w;
                }
                else
                {
                    val = val * 10 + str[i] - '0';
                }
            }
        }
        else
        {
            bRet = false;
            break;
        }
    }
    return bRet;
}
typedef enum _NodeType
{
    NODE_TYPE_OP,
    NODE_TYPE_NUM,
    NODE_TYPE_VAR,
    NODE_TYPE_EXPAND_VAR,
    NODE_TYPE_PARAM,
    NODE_TYPE_RANDOM
}NodeType;


//中缀表达式建树
bool ExpTree::CreateExpTree(const char * str)
{
    bool b = scanNode(str);
    if (!b)
    {
        return false;
    }
    std::stack<ExpNode*> node_stack;
    std::stack<ExpNode*> op_stack;
    ExpNode temp_node;
    temp_node.type = NODE_TYPE_OP;
    temp_node.op = '#';
    op_stack.push(&temp_node);
    for (int i = 0; i < count; i++)
    {
        if (nodes[i].type == NODE_TYPE_NUM || nodes[i].type == NODE_TYPE_VAR ||
            nodes[i].type == NODE_TYPE_PARAM || nodes[i].type == NODE_TYPE_RANDOM)
        {
            nodes[i].left = NULL;
            nodes[i].right = NULL;
            node_stack.push(&nodes[i]);
        }
        else if (nodes[i].type == NODE_TYPE_OP)
        {
            switch (nodes[i].op)
            {
            case '(':
                {
                    op_stack.push(&nodes[i]);
                }
                break;
            case ')':
                {
                    while (op_stack.top()->op != '(')
                    {
                        ExpNode *op = op_stack.top();
                        op_stack.pop();
                        ExpNode *right = node_stack.top();
                        node_stack.pop();
                        ExpNode *left = node_stack.top();
                        node_stack.pop();
                        op->left = left;
                        op->right = right;
                        node_stack.push(op);
                    }
                    if (op_stack.empty())
                    {
                        return false;
                    }
                    op_stack.pop(); //弹出栈顶左括号
                }
                break;
            case '+':
            case '-':
            case '*':
            case '/':
            case '^':
                {
                    while (cmpSymbolPri(op_stack.top()->op, nodes[i].op) >= 0)
                    {
                        ExpNode *op = op_stack.top();
                        op_stack.pop();
                        ExpNode *right = node_stack.top();
                        node_stack.pop();
                        ExpNode *left = node_stack.top();
                        node_stack.pop();
                        op->left = left;
                        op->right = right;
                        node_stack.push(op);
                    }
                    op_stack.push(&nodes[i]);
                }
                break;
            default:
                return false;
                break;
            }
        }
        else
        {
            return false;
        }
    }
    while (op_stack.top()->op != '#')
    {
        ExpNode *op = op_stack.top();
        op_stack.pop();
        ExpNode *right = node_stack.top();
        node_stack.pop();
        ExpNode *left = node_stack.top();
        node_stack.pop();
        op->left = left;
        op->right = right;
        node_stack.push(op);
    }
    op_stack.pop();
    if(node_stack.size() != 1)
    {
        return false;
    }
    root = node_stack.top();
    node_stack.pop();
    return true;

}
float ExpTree::Value()
{
    return valNode(root);
}

//计算
float ExpTree::cacul(float a, char op, float b)
{
    float ret = 0.00f;
    switch (op)
    {
    case '+':
        ret = a + b;
        break;
    case '-':
        ret = a - b;
        break;
    case '*':
        ret = a * b;
        break;
    case '/':
        {
            if(!FloatEqualZero(b))
            {
                ret = a / b;
            }
        }
        break;
    case '^':
        ret = pow(a, b);
        break;
    default:
        break;
    }
    return ret;
}
//求值函数
float ExpTree::valNode(ExpNode* cur)
{
    float res = 0.0f;
    if (cur->type == NODE_TYPE_OP)
    {
        res = cacul(valNode(cur->left), cur->op, valNode(cur->right));

        //计算随机上下限
        if (cur->left->chValue[0] == 'R')
        {
            min_value = cacul(min_value,cur->op,valNode(cur->right));
            max_value = cacul(max_value,cur->op,valNode(cur->right));
        }
        else if (cur->right->chValue[0] == 'R')
        {
            min_value = (valNode(cur->left),cur->op,min_value);
            max_value = (valNode(cur->left),cur->op,max_value);
        }
    }
    else
    {
        if (cur->type == NODE_TYPE_NUM)
        {
            res = cur->fValue * cur->sign;
        }
        else if (cur->type == NODE_TYPE_VAR || cur->type == NODE_TYPE_EXPAND_VAR || cur->type == NODE_TYPE_PARAM || cur->type == NODE_TYPE_RANDOM)
        {
            res = GetParamValue(cur->chValue) * cur->sign;
        }
    }

    return res;
}
int ExpTree::cmpSymbolPri(const char &ispop, const char &icpop)
{
    int pri_isp = -1;
    int pri_icp = -1;
    for (int i=0,j=0; i< symbols;i++)
    {
        if (pri_table[i].op == ispop)
        {
            pri_isp = pri_table[i].isp;
            ++j;
            if (j == 2)
            {
                break;
            }
        }
        if(pri_table[i].op == icpop)
        {
            pri_icp = pri_table[i].icp;
            ++j;
            if (j == 2)
            {
                break;
            }
        }
    }
    return pri_isp - pri_icp;
}

bool ExpTree::scanNumber(const char * str, int len, float &val, int &bytes)
{
    if (len < 0)
        return false;
    val = 0.00f;
    bool hasDot = false;
    float w = 1;
    int i=0;
    for(;i<len; i++)
    {
        if (isDigit(str[i]) || str[i] == '.')
        {
            if(str[i] == '.')
            {
                if(hasDot)
                {
                    return false;;
                }
                hasDot = true;
            }
            else
            {
                if(hasDot)
                {
                    w *= 0.1f;
                    val += (str[i] - '0') * w;
                }
                else
                {
                    val = val * 10 + str[i] - '0';
                }
            }
        }
        else
        {
            break;
        }
    }
    bytes = i-1;
    return true;
}
bool ExpTree::scanSymbol(const char * str, int len, char * buf, int &bytes)
{

    
    //最少两个字符'@' '#' '$' '%' 与一个字母的组合
    if (len< 2)
    {
        return false;
    }
    int i=0;
    buf[i] = str[i];
    i++;
    //首字符必须是字母或者数字或下划线
    if (isLetterUnderline(str[i]))
    {
        
        buf[i] = str[i];
        i++;
         for (; i<len; i++)
        {
            //后序字符
            if(isLetterUnderline(str[i]) || isDigit(str[i]))
            {
                buf[i] = str[i];
            }
            else
            {
                break;
            }
        }
    }
    else
    {
        return false;
    }
    buf[i] = '\0';
    bytes = i-1;
    return true;
}
bool ExpTree::scanExpandSymbol(const char * str, int len, char * buf, int &bytes)
{
    //最少三个字符'&' 数字 与一个字母的组合
    if (len< 3)
    {
        return false;
    }
    int i=0;
    //'&'符号
    buf[i] = str[i];
    i++;
    //首字符必须是字母或者数字或下划线
    if (isLetterUnderline(str[i]))
    {
        
        buf[i] = str[i];
        i++;
         for (; i<len; i++)
        {
            //后序字符
            if(isLetterUnderline(str[i]) || isDigit(str[i]))
            {
                buf[i] = str[i];
            }
            else
            {
                break;
            }
        }
    }
    else
    {
        return false;
    }
    buf[i] = '\0';
    bytes = i-1;
    return true;
}
bool ExpTree::scanRandom(const char * str, int len, char * buf, int &bytes)
{
    
    //R[M,N] or R[M]
    if (len < 6)
    {
        return false;
    }
    int i=0;
    //R
    buf[i] = str[i];
    i++;
    //[
    if (str[i] != '[')
    {
        return false;
    }
    buf[i] = str[i];
    i++;
    bool find = false;
    for (; i<len; i++)
    {
        buf[i] = str[i];
        if(buf[i] == ']')
        {
            find = true;
            break;
        }
    }
    if (!find)
    {
        return false;
    }
    buf[i] = str[i];
    i++;
    buf[i] = '\0';
    bytes = i-1;
    return true;

}
bool ExpTree::scanParam(const char * str, int len, char * buf, int &bytes)
{
    if (len < 2)
    {
        return false;
    }
    int i=0;
    buf[i]=str[i];
    i++;
    buf[i]=str[i];
    i++;
    buf[i]='\0';
    bytes = i-1;
    return true;
}
float ExpTree::query_prop_value(char chr, const char* prop_name)
{
    PERSISTID obj = PERSISTID();
    float ret = 0.00f;
    if (chr == '@') //自己
    {
        IGameClient* pGameClient = (IGameClient*)CHelper::GetGameClient();
        obj = pGameClient->GetPlayer();
    }
    //else if (chr == '#')
    //{
    //    obj = m_skill;
    //}
    //else if (chr == '$')
    //{
    //    obj = m_target;
    //}
    //else if (chr == '%')
    //{
    //    obj = m_target_skill;
    //}

    if (obj != PERSISTID())
    {
        ret = QueryPropValue(obj,prop_name);
    }
    return ret;
}
float ExpTree::query_expand_prop_value(const char* prop_name, char from)
{
    float ret = 0.0f;
    //ret = QueryPropValueBySource(pGameObject, m_self, prop_name, (RefreshPropSourceType)from);
    ret = QueryPropValueBySource(prop_name,int(from));

    return ret;
}
float ExpTree::GetParamValue(const char *szFormula)
{
    float res = 0.0f;
    int len = static_cast<int>(strnlen(szFormula, MAX_NODE_EXP-1));
    if (len == 0 || len >= MAX_NODE_EXP-1)
    {
        return res;
    }
    if (isDigit(szFormula[0]) || szFormula[0] == '.')
    {
        bool hasDot = false;
        float w = 1;
        for(int i=0;i<len; i++)
        {
            if (isDigit(szFormula[i]) || szFormula[i] == '.')
            {
                if(szFormula[i] == '.')
                {
                    if(hasDot)
                    {
                        res = 0.00f;
                        break;
                    }
                    hasDot = true;
                }
                else
                {
                    if(hasDot)
                    {
                        w *= 0.1f;
                        res += (szFormula[i] - '0') * w;
                    }
                    else
                    {
                        res = res * 10 + szFormula[i] - '0';
                    }
                }
            }
            else
            {
                res = 0.00f;
                break;
            }
        }
    }
    else if(szFormula[0] == '@' || szFormula[0] == '#' || szFormula[0] == '$' || szFormula[0] == '%')
    {
        char var[MAX_NODE_EXP];
        int i = 0;
        //去掉头@ # $ %
        while(i<len-1)
        {
            var[i]=szFormula[i+1];
            i++;
        }
        var[i]=0;
        res = query_prop_value(szFormula[0],var);
    }
    else if (szFormula[0] == '&')
    {
        char var[MAX_NODE_EXP];
        //去掉 &
        int i=0;
        //获取参数
        while(i<len-1)
        {
            var[i]=szFormula[i+1];
            i++;
        }
        var[i]=0;
        res = query_expand_prop_value(var, 3);
    }
    //判断是否是属性相关的变量
    else if (szFormula[0] == 'P')
    {   
        int index = szFormula[1] - '1';

        if (index < MAX_PARAM)
        {
            res= param[index];
        }
    }

    //判断是否是随机数相关的变量,格式R[P1,P2]或R[P1]
    else if (szFormula[0] == 'R')
    {
        //查找是否有逗号
        const char *cfind = strchr(szFormula, ',');
        if (cfind == NULL)
        {
            //没有逗号,取一个变量的随机数
            char var[MAX_NODE_EXP];
            int i=0;
            while(i<len-3)
            {
                var[i]=szFormula[2+i];
                i++;
            }
            var[i]=0;
            float max = GetParamValue(var);
            res = (float)util_random_float(max);

            //保存随机范围
            min_value = 0.0f;
            max_value = max;
        }
        else
        {
            //有逗号,取两个变量间的随机数
            char var[MAX_NODE_EXP];
            int split = (int)(cfind - szFormula);
            int i=0;
            while(i<split-2)
            {
                var[i]=szFormula[2+i];
                i++;
            }
            var[i]=0;
            float min = GetParamValue(var);
            i=0;
            while(i<len-split-2)
            {
                var[i]=szFormula[split+1+i];
                i++;
            }
            var[i]=0;
            float max = GetParamValue(var);
            if (max < min)
            {
                //转化为合法的范围
                float temp = min;
                min = max;
                max = temp;
            }
            res = min + (float)util_random_float((float)(max - min));

            //保存随机范围
            min_value = min;
            max_value = max;
        }
    }
    return res;
}
bool ExpTree::scanNode(const char * str)
{
    int len = (int)strnlen(str,MAX_EXP-1);
    if (len == MAX_EXP-1 || len == 0)
    {
        return false;
    }
    int i, sign;
    //inNum标记当前是否可以输入操作数
    bool inNum;
    for(i = 0, sign = 1, inNum = true; i<len; i++)
    {
        if(opNumber(str[i]))
        {
            if(inNum)
            {
                int bytes = 0;
                bool b = false;
                if (isDigit(str[i]) || str[i] == '.')
                {
                    nodes[count].type = NODE_TYPE_NUM;
                    b = scanNumber(&str[i],len-i,nodes[count].fValue, bytes);
                }
                else if (str[i] == '@' || str[i] == '#' || str[i] == '$' || str[i] == '%')
                {
                    nodes[count].type = NODE_TYPE_VAR;
                    b = scanSymbol(&str[i],len-i, nodes[count].chValue, bytes);
                }
                else if (str[i] == '&')
                {
                    nodes[count].type = NODE_TYPE_EXPAND_VAR;
                    b = scanExpandSymbol(&str[i],len-i, nodes[count].chValue, bytes);
                }
                else if (str[i] == 'R')
                {
                    nodes[count].type = NODE_TYPE_RANDOM;
                    b = scanRandom(&str[i],len-i,nodes[count].chValue, bytes);
                }
                else if (str[i] == 'P')
                {
                    nodes[count].type = NODE_TYPE_PARAM;
                    b = scanParam(&str[i],len-i,nodes[count].chValue, bytes);
                }
                else
                {
                    return false;
                }
                if(!b)
                {
                    return false;
                }
                i += bytes;
                nodes[count].sign = sign;
                count ++;
                if (count > MAX_NODE)
                {
                    return false;
                }
                sign = 1;
                inNum = false;
            }
            else
            {
                return false;
            }
        }
        else
        {
            switch(str[i])
            {
            case '(':
            case ')':
                {
                    nodes[count].type = NODE_TYPE_OP;
                    nodes[count].op = str[i];
                    count ++;
                    if (count > MAX_NODE)
                    {
                        return false;
                    }
                }
                break;
            case '+':
            case '-':
            case '*':
            case '/':
            case '^':
                {
                    if(inNum)
                    {
                        if(str[i] != '+' && str[i] != '-') throw true;
                        while(str[i] == '+' || str[i] == '-')
                        {
                            if(str[i] == '-')
                                sign *= -1;
                            i++;
                        }
                        i--;
                    }
                    else
                    {
                        nodes[count].type = NODE_TYPE_OP;
                        nodes[count].op = str[i];
                        count ++;
                        if (count > MAX_NODE)
                        {
                            return false;
                        }
                        inNum = true;
                    }
                }
                break;
            default:
                return false;
                break;
            }
        }
    }
    return count > 0;
}

float ExpTree::calculate_param(const PERSISTID& skill,const char * szFormula, const float (&arg)[MAX_PARAM])
{
    if (szFormula == NULL)
    {
        return 0.00f;
    }
    size_t len = strnlen(szFormula,MAX_EXP-1);
    if (len == 0 || len == MAX_EXP-1)
    {
        return 0.00f;
    }
    memset(param,0,sizeof(param));
    memcpy(param,arg,sizeof(float) * MAX_PARAM);
    bool b = CreateExpTree(szFormula);
    if (!b)
    {
        return 0.00f;
    }

    m_skill = skill;
    min_value = 0.0f;
    max_value = 0.0f;

    return (float)Value();
}

void ExpTree::GetRandomLimits( float& min_value,float& max_value )
{
    min_value = this->min_value;
    max_value = this->max_value;
}

float QueryPropValue( const PERSISTID& obj, const char* prop_name )
{
    float ret = 0.0f;
    if (obj.IsNull() || strcmp(prop_name,"") == 0)
    {
        return ret;
    }

    IGameObject* pGameObject = (IGameObject*)CHelper::GetEntity(obj);
    if (!pGameObject)
    {
        return ret;
    }

    if (pGameObject->FindProp(prop_name))
    {
        int prop_type = pGameObject->GetPropType(prop_name);
        if (prop_type == VTYPE_INT)
        {
            ret = (float)pGameObject->QueryPropInt(prop_name);
        }
        else if(prop_type == VTYPE_FLOAT)
        {
            ret = (float)pGameObject->QueryPropFloat(prop_name);
        }
        else if  (prop_type == VTYPE_DOUBLE)
        {
            ret = (float)pGameObject->QueryPropDouble(prop_name);
        }
    }


    float add_value = 0.0f;
    std::string add_prop = std::string(prop_name) + "Add";
    if (pGameObject->FindProp(add_prop.c_str()))
    {
        int prop_type = pGameObject->GetPropType(add_prop.c_str());
        if (prop_type == VTYPE_INT)
        {
            add_value = (float)pGameObject->QueryPropInt(add_prop.c_str());
        }
        else if(prop_type == VTYPE_FLOAT)
        {
            add_value = (float)pGameObject->QueryPropFloat(add_prop.c_str());
        }
        else if  (prop_type == VTYPE_DOUBLE)
        {
            add_value = pGameObject->QueryPropDouble(add_prop.c_str());
        }
    }

    return ret + add_value;
}

float QueryPropValueBySource( const char* prop_name, int source )
{
    float res = 0.0f;

    IGameClient* pGameClient = (IGameClient*)CHelper::GetGameClient();
    PERSISTID obj = pGameClient->GetPlayer();
    IGameObject* pGameObject = (IGameObject*)CHelper::GetEntity(obj);
    if (pGameObject && prop_name && pGameObject->FindRecord("RefreshPropCompute"))
    {
        CVarList result;
        pGameObject->FindRecordRow(CVarList() <<"RefreshPropCompute" << 0 << prop_name, result);
        int row = result.IntVal(0);
        if (row < 0)
        {
            return res;
        }

        int prop_type = pGameObject->GetRecordColType("RefreshPropCompute",source);
        if (prop_type == VTYPE_INT)
        {
            res = (float)pGameObject->QueryRecordInt("RefreshPropCompute", row, source);
        }
        else if (prop_type == VTYPE_FLOAT)
        {
            res = (float)pGameObject->QueryRecordFloat("RefreshPropCompute", row, source);
        }
        else if (prop_type == VTYPE_DOUBLE)
        {
            res = (float)pGameObject->QueryRecordDouble("RefreshPropCompute", row, source);
        }
    }

    return res;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

!chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值