私が構築したバイナリツリーベースの数式パーサーがあります。これは、次のような「通常の」数学に最適です(3.5 * 2) ^ 1 / (1 << 6)
。ただし、 C: のものをミラーリングして、三項選択演算子を追加するために少し拡張したいと思います{expr} ? {true-expr} : {false-expr}
。sin(x)
やなどの機能も追加したいと思いave(...)
ます。
ただし、これをどのように処理するかについての手がかりはありません(評価の仕組みのため)、少なくともグラマーベースではない方法でこれをカバーするものをWeb上で見つけることはできません(グラマーパーサージェネレーターを避けたいです)このため、可能であれば)。
私のパーサーは現在、中置式を評価し、すぐにツリーに変換することで機能します。その後、そこからツリーを評価できます。つまり、標準式ツリーをボグします。
現在、私の評価者は次のようになっています。
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] は有効なインデックスに設定されます)
出力 (emplyee の years_of_service が 10 未満の場合:0.15
そうでなければ出力:0.07
引数が名前ではなくインデックスで渡され、文字列が double の代わりに一重引用符でエスケープされることを除いて、基本的には C にインスパイアされたいくつかの追加を伴う数学です。
最後のビットが完成したら、入力セットデータが一定であるが入力セットが変更できますが、頻繁に使用されるため、「高速」である必要があり、プログラマー以外でも使用できる必要があります。