一个简单的解析器
编写解析器的最简单方法是使用递归下降技术。这将创建一个自上而下的解析器(可能正式描述为 LL(1)
)。为了开始这个例子,我们首先要为我们的语言建立语法规则。在这个例子中,我们将对只能使用 plus 运算符的表达式使用简单的算术表达式赋值:
Assignment --> Identifier := Expression
Expression --> Expression + Term | Term
Term --> Identifier | (Expression)
Identifier --> x | y | z
对于语法的每个规则,我们可以编写一个过程来识别规则的传入令牌。出于本示例的目的,我们可以假设一个名为 NextToken
的例程,它调用一个词法分析器来提供令牌,以及一个名为 error
的例程,它用于输出错误信息。使用的语言基于 Pascal。
var token:char; (* Updated by NextToken *)
procedure identifier;
begin
if token in ['x','y','z']
then
NextToken
else
error('Identifier expected')
end;
你可以看到此代码实现了识别 Identifier
的规则。然后我们可以类似地实现 Term
的规则:
procedure expression forward;
procedure term;
begin
if token = '('
then
begin
nextToken;
expression;
if token <> ')'
then
error(') expected')
else NextToken
end
else
identifier
end;
当我们来实施 Expression
的规则时,我们遇到了问题; Expression
规则的第一个元素本身就是一个 Expression
。这将导致我们写下以下内容:
procedure expression;
begin
expression;
...
end;
这是直接自我递归的,因此会永远循环。由于这个原因,由自上而下算法解析的语法不能是左递归的。解决此问题的一个简单方法是以下列方式将递归重新设置为迭代:
Expression --> Term { + Term}*
我们现在可以将语法规则编码为:
procedure expression;
begin
term;
while token = '+'
do
begin
NextTerm;
term
end
end;
我们现在可以使用剩余的赋值规则来完成解析器:
procedure assignment;
begin
identifier;
if token <> '='
then
error('= expected')
else
begin
NextToken;
expression;
end
end;