我正在嘗試解析我的空閒時間,並且我想實現一個非常簡單的語法的shift-reduce解析器。我讀過很多在線文章,但我仍然對如何創建分析樹感到困惑。下面是我想要做的一個例子:使用shift-reduce解析構建解析樹
語法:
Expr -> Expr TKN_Op Expr
Expr -> TKN_Num
以下範例輸入:
1 + 1 + 1 + 1
也就是說,符號化後,就變成了:
TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
我明白:
- 移裝置推堆棧上的第一輸入令牌和從輸入
- 減少裝置替換堆棧上的一個或多個元素與語法元素 除去它
所以,基本上,這應該發生:
Step 1:
Stack:
Input: TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
What: Stack is empty. Shift.
Step 2:
Stack: TKN_Num
Input: TKN_Op TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
What: TKN_Num can be reduced to Expr. Reduce.
Step 3:
Stack: Expr
Input: TKN_Op TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
What: Cannot reduce. Shift.
Step 4:
Stack: Expr TKN_Op
Input: TKN_Num TKN_Op TKN_Num TKN_Op TKN_Num
What: Cannot reduce. Shift.
Step 5:
Stack: Expr TKN_Op TKN_Num
Input: TKN_Op TKN_Num TKN_Op TKN_Num
What: TKN_Num can be reduced to Expr. Reduce.
// What should I check for reduction?
// Should I try to reduce incrementally using
// only the top of the stack first,
// then adding more stack elements if I couldn't
// reduce the top alone?
Step 6:
Stack: Expr TKN_Op Expr
Input: TKN_Op TKN_Num TKN_Op TKN_Num
What: Expr TKN_Op Expr can be reduced to Expr. Reduce.
Step 7:
Stack: Expr
Input: TKN_Op TKN_Num TKN_Op TKN_Num
What: ...
// And so on...
除了「要減少什麼?」懷疑,我不知道如何正確地構建一個分析樹。樹應該看起來像這樣:
1 + o
|
1 + o
|
1 + 1
我應該創建一個新的節點嗎?
什麼時候我應該添加孩子到新創建的節點/何時應該創建一個新的根節點?
感謝您的詳細解答。還有一件事:我應該儘可能減少堆疊或儘可能減少? (當有兩個可能的減少,優先級是什麼? –
「儘量減少堆棧」?如果您的解析操作不提供選擇,則您無法選擇堆棧大小。如果沒有衝突,則不必做出選擇 - }如果您有選擇,可以爲優先級問題定義不同的答案,並獲得不同的shift-reduce分析器。如果你有衝突,你的語法不是LALR(1);通過選擇一個,你已經隱含地定義了你指定的BNF的一個有趣的變體是合法的。這個問題的正確答案是「閱讀一本關於解析的書」,因爲細節變得非常技術化。 –