一个真正有用的下一步是构建一个解析树:

您可以通过编写中缀解析器来实现其中之一。您可以通过编写一个简单的递归下降解析器来做到这一点,或者引入大炮并使用解析器生成器。无论哪种情况,它都有助于构建一个正式的语法:
expression: additive
additive: multiplicative ([+-] multiplicative)*
multiplicative: primary ('*' primary)*
primary: variable
| number
| '(' expression ')'
请注意,此语法不处理2x
语法,但应该很容易添加。
注意语法规则中递归的巧妙使用。 primary
仅捕获变量、数字和带括号的表达式,并在遇到运算符时停止。 multiplicative
解析一个或多个primary
由符号分隔的表达式*
,但在遇到+
or-
符号时停止。 additive
解析一个或多个由andmultiplicative
分隔的表达式,但在遇到 a 时停止。因此,递归方案决定了运算符的优先级。+
-
)
正如我在下面所做的那样,手动实现预测解析器并不太难(参见 ideone.com 上的完整示例):
function parse()
{
global $tokens;
reset($tokens);
$ret = parseExpression();
if (current($tokens) !== FALSE)
die("Stray token at end of expression\n");
return $ret;
}
function popToken()
{
global $tokens;
$ret = current($tokens);
if ($ret !== FALSE)
next($tokens);
return $ret;
}
function parseExpression()
{
return parseAdditive();
}
function parseAdditive()
{
global $tokens;
$expr = parseMultiplicative();
for (;;) {
$next = current($tokens);
if ($next !== FALSE && $next->type == "operator" &&
($next->op == "+" || $next->op == "-"))
{
next($tokens);
$left = $expr;
$right = parseMultiplicative();
$expr = mkOperatorExpr($next->op, $left, $right);
} else {
return $expr;
}
}
}
function parseMultiplicative()
{
global $tokens;
$expr = parsePrimary();
for (;;) {
$next = current($tokens);
if ($next !== FALSE && $next->type == "operator" &&
$next->op == "*")
{
next($tokens);
$left = $expr;
$right = parsePrimary();
$expr = mkOperatorExpr($next->op, $left, $right);
} else {
return $expr;
}
}
}
function parsePrimary()
{
$tok = popToken();
if ($tok === FALSE)
die("Unexpected end of token list\n");
if ($tok->type == "variable")
return mkVariableExpr($tok->name);
if ($tok->type == "number")
return mkNumberExpr($tok->value);
if ($tok->type == "operator" && $tok->op == "(") {
$ret = parseExpression();
$tok = popToken();
if ($tok->type == "operator" && $tok->op == ")")
return $ret;
else
die("Missing end parenthesis\n");
}
die("Unexpected $tok->type token\n");
}
好的,现在你有了这个可爱的解析树,甚至还有一张漂亮的图片。怎么办?您的目标(目前)可能是简单地组合术语以获得形式的结果:
n1*a + n2*b + n3*c + n4*d + ...
我会把那部分留给你。拥有解析树应该使事情变得更加简单。