我有一个基于二叉树的数学表达式解析器,它非常适用于“普通”数学,例如:(3.5 * 2) ^ 1 / (1 << 6)
. 但是,我想稍微扩展它以添加一个三元选择运算符,镜像来自 C: 的那个{expr} ? {true-expr} : {false-expr}
。我还想添加功能,例如sin(x)
or ave(...)
。
然而,我不知道如何处理这个问题(由于评估的工作方式),我也无法在网上找到任何涵盖这个的东西,至少以非基于语法的方式(我想避免语法分析器生成器为此,如果可能的话)。
我的解析器当前通过评估中缀表达式并立即将其转换为树来工作,然后可以从那里评估树,即:它是标准表达式树。
目前我的评估员看起来像这样:
struct Node
{
int nType;
union
{
unsigned long dwOperator;
BOOL bValue;
int nValue; //for indices, args & functions
number_t fValue;
char* szValue; //for string literals to pass to functions
};
Node* pLeft;
Node* pRight;
};
number_t EvaluateTree(Node* pNode)
{
if(pNode == NULL)
return 0.0f;
int nType = pNode->nType;
if(nType == TOKEN_OPERATOR)
{
number_t fLeft = EvaluateTree(pNode->pLeft);
number_t fRight = EvaluateTree(pNode->pRight);
switch(pNode->dwOperator)
{
case '+': return fLeft + fRight;
case '-': return fLeft - fRight;
case '*': return fLeft * fRight;
case '/': return fLeft / fRight;
case '^': return pow(fLeft,fRight);
case '_': return pow(fLeft,1.0f/fRight);
case '%': return fmod(fLeft,fRight);
//case '?': return bSelect = ?;
//case ':': return (bSelect) ? fLeft : fRight;
//case '>': return fLeft > fRight;
//case '<': return fLeft < fRight;
//case '>=': return fLeft >= fRight;
//case '<=': return fLeft <= fRight;
//case '==': return fLeft == fRight;
//case '!=': return fLeft != fRight;
//case '||': return fLeft || fRight;
//case '&&': return fLeft && fRight;
case '&': return static_cast<number_t>(static_cast<unsigned long>(fLeft) & static_cast<unsigned long>(fRight));
case '|': return static_cast<number_t>(static_cast<unsigned long>(fLeft) | static_cast<unsigned long>(fRight));
case '~': return static_cast<number_t>(~static_cast<unsigned long>(fRight));
case '>>': return static_cast<number_t>(static_cast<unsigned long>(fLeft) >> static_cast<unsigned long>(fRight));
case '<<': return static_cast<number_t>(static_cast<unsigned long>(fLeft) << static_cast<unsigned long>(fRight));
default:
{
printf("ERROR: Invalid Operator Found\n");
return 0.0f;
}
}
}
else if(nType == TOKEN_NUMBER)
return pNode->fValue;
else if(nType == TOKEN_CALL)
return CreateCall(pNode); //not implemented
else if(nType == TOKEN_GLOBAL)
return GetGlobal(pNode);
else if(nType == TOKEN_ARGUMENT)
return GetArgument(pNode);
else if(nType == TOKEN_STRING)
return 0.0f;
return 0.0f;
}
关于如何实现这一点的任何提示/指针/建议或有用的链接?
一小部分示例(根据要求):
我已经有的工作
输入:2 * (3 ^ 1.5) - 4 / (1 << 3)
输出:In-Order: 2.0 * 3.0 ^ 1.5 - 4.0 / 1.0 << 3.0
Pre-Order: - * 2.0 ^ 3.0 1.5 / 4.0 << 1.0 3.0
Post-Order: 2.0 3.0 1.5 ^ * 4.0 1.0 3.0 << / -
Result: 9.892304
我要添加的内容
输入:(GetDay() == 31) ? -15.5 : 8.4
输出:8.4
31日输出:-15.5
输入:(max([0],20)
其中 [0] 表示参数 0,并且 [0] = 35)
输出:20
输入:((GetField('employees','years_of_service',[0]) >= 10) ? 0.15 : 0.07
其中 [0] 是参数 0,并且 [0] 设置为有效索引)
输出(如果员工的 years_of_service 小于 10:0.15
否则输出:0.07
它基本上是数学,带有一些受 C 启发的添加,除了参数不是按名称传递,而是按索引传递,并且字符串由单引号转义而不是双引号。
当我完成最后一点时,我希望要么编译字节码,要么 JIT 它,因为我计划将它用于游戏或依赖数学的程序,其中输入集数据是恒定的,但输入集可以改变,但它被频繁使用,所以它需要“快速”,并且需要非程序员可以使用。