一個簡單的解析器
編寫解析器的最簡單方法是使用遞迴下降技術。這將建立一個自上而下的解析器(可能正式描述為 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;