정말 유용한 다음 단계는 파스 트리를 구성하는 것입니다 : 당신은 중위 파서를 작성하여 다음 중 하나를 만들 것
. 간단한 재귀 파서를 작성하거나 큰 총과 using a parser generator을 가져 와서이 작업을 수행 할 수 있습니다. 두 경우 모두, 그것은 형식적인 문법을 구성하는 데 도움이 문법은 2x
구문을 처리하지 않는
expression: additive
additive: multiplicative ([+-] multiplicative)*
multiplicative: primary ('*' primary)*
primary: variable
| number
| '(' expression ')'
참고하지만, 쉽게 추가 할 수 있어야합니다.
문법 규칙에서 재귀를 영리하게 사용합니다. primary
은 변수, 숫자 및 괄호로 묶은 표현식 만 캡처하고 연산자로 실행되면 중지합니다. multiplicative
은 *
기호로 구분 된 하나 이상의 primary
표현식을 구문 분석하지만 +
또는 -
기호로 실행되면 중지합니다. additive
은 +
및 -
으로 구분 된 하나 이상의 multiplicative
수식을 구문 분석하지만 )
으로 실행되면 중지합니다. 따라서 재귀 체계는 연산자 우선 순위를 결정합니다. 심지어 꽤 당신이 아름다운 파스 트리가 그래서 지금,
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");
}
이 좋아, 그리고 : 나는 (see full example at ideone.com) 아래에했던 것처럼
이는 predictive parser 손으로 구현하기 너무 몹시 어려운 일이 아니다 그것으로가는 그림. 이제 뭐?귀하의 목표는 (지금은) 간단히 용어를 결합하여 양식의 결과를 얻을 수 있습니다.
n1*a + n2*b + n3*c + n4*d + ...
나는 그 부분을 남겨 둘 것입니다. 구문 분석 트리를 사용하면 훨씬 간단하게 작업을 수행 할 수 있습니다.
귀하의 VAR 토큰은 관련 문자열이 있습니다. NUMBER 토큰에 연결된 숫자가없는 이유는 무엇입니까? –
제약 조건에 따라 [OOP 해석기] (http://sourcemaking.com/design_patterns/interpreter)를 구성 해보십시오. 토큰을 다루는 것보다 쉬워야하며 나무가 그 자체를 표현해야합니다. – ircmaxell
@David Heffernan : 표현식과 프로그래밍 언어를 다루는 PHP의 장점 중 하나는 sigil 변수입니다. 프로그래밍 언어의 키워드와의 충돌에 대해 걱정할 필요없이 변수'$ operator'와'$ var'의 이름을 지정할 수 있습니다. –