`ASSIGN` (`:=`) 在 `iec_bison.yy` 中的處理 - benchen2001/matiec GitHub Wiki

好的,我們來針對 iec_bison.yyASSIGN (:=) 符號的處理進行完整深入的探討與說明,並結合 average_st.txt 範例。


ASSIGN (:=) 在 iec_bison.yy 中的處理

ASSIGNiec_bison.yy 中扮演著關鍵的語法角色,它標識了賦值語句的操作。以下是其處理過程的詳細說明:

1. 詞法定義 (%token)

  • 宣告:在 iec_bison.yy 的 Bison 宣告區,ASSIGN 必須被定義為一個終端符號(token)。這通常看起來像這樣:
    %token ASSIGN /* Represents the ':=' operator */
    
  • 來源:這個 ASSIGN 標記是由詞法分析器(iec_flex.ll)在掃描到原始碼中的 := 符號時產生的。iec_flex.ll 會返回 ASSIGN 這個整數代碼給 Bison。

2. 語法規則 (Grammar Rules)

  • 核心用途ASSIGN 主要出現在定義賦值語句 (Assignment Statement) 的語法規則中。這是 ST 語言最基本的語句之一。
  • 典型規則:一個典型的賦值語句規則如下所示:
    assignment_statement: variable ASSIGN expression ';'
                          {
                            $$ = new_assignment_statement($1, $3); // Create AST node
                            combine_locations($$, $1, $4);       // Set location info
                          }
                        ;
    
  • 規則解析
    • assignment_statement: 這是定義的非終端符號,代表一個完整的賦值語句。
    • variable: 這是一個非終端符號,代表賦值操作的左側 (LHS)。它必須能夠解析為一個可以被賦值的目標(l-value),例如:
      • 簡單變數 (symbolic_variable_c),如 SUM
      • 陣列元素 (array_variable_c),如 arr[i]
      • 結構成員 (structured_variable_c),如 FIFO.XOUT
      • 直接地址變數 (direct_variable_c),如 %QX0.0。 (具體 variable 如何解析由其他規則定義)。
    • ASSIGN: 這是關鍵的終端符號,即詞法分析器返回的 := 標記。它在語法上分隔了左側的目標變數和右側的表達式。
    • expression: 這是一個非終端符號,代表賦值操作的右側 (RHS)。它可以是任何計算結果的有效表達式,例如:
      • 常數 (constant_c)。
      • 變數 (symbolic_variable_c, structured_variable_c 等)。
      • 算術/邏輯/比較運算 (add_expression_c, and_expression_c, gt_expression_c 等)。
      • 函式呼叫 (function_invocation_c)。
    • ';': 分號終端符號,標記 ST 語句的結束。

3. 語法分析過程 (Shift/Reduce)

當 Bison 解析器遇到 ASSIGN 標記時:

  1. 移入 (Shift):通常,在解析了左側的 variable 之後,如果下一個標記是 ASSIGN,Bison 會將 ASSIGN 標記移入 (shift) 到其內部堆疊中,並轉換到下一個狀態,期望接下來能匹配一個 expression
  2. 歸約觸發 (Reduce Trigger):當 Bison 的堆疊頂部形成了 variable ASSIGN expression ; (或類似的匹配序列) 時,它就識別出這符合 assignment_statement 規則的右側。ASSIGN 的存在是觸發這個歸約動作的關鍵條件之一。

4. 動作執行 (Action) 與 AST 構建

  • 核心動作:在 assignment_statement 規則的 {...} 動作塊中,主要工作是創建代表該賦值語句的 AST 節點。
  • 創建節點:動作程式碼會呼叫 ast_build.cc 中的輔助函數,通常是 new_assignment_statement()
    $$ = new_assignment_statement($1, $3);
    
    • $1: 代表規則右側第一個符號 (variable) 的語義值,即指向 LHS 變數對應 AST 節點的指標 (symbol_c*)。
    • $3: 代表規則右側第三個符號 (expression) 的語義值,即指向 RHS 表達式對應 AST 節點的指標 (symbol_c*)。
    • $$: 代表規則左側非終端符號 (assignment_statement) 的語義值,它被設置為新創建的 assignment_statement_c 節點的指標。
  • ASSIGN 的角色:請注意,ASSIGN (:=) 標記本身通常不會在 AST 中創建一個獨立的節點。它的語義(賦值操作)被隱含地表示在 assignment_statement_c 這個 AST 節點的結構中——該節點將 LHS 和 RHS 子節點關聯起來。ASSIGN 在語法分析階段的主要作用是識別和驗證賦值語句的結構。
  • 位置資訊:動作通常還會計算新創建節點的源代碼位置,結合 LHS ($1) 的起始位置和分號 ($4) 的結束位置。

5. 範例 (average_st.txt)

讓我們看看 SUM := SUM - FIFO.XOUT ; 這行程式碼的解析過程:

  1. yylex() 返回 IDENTIFIER ("SUM") -> 歸約為 variable ($1 指向 symbolic_variable_c("SUM"))。
  2. yylex() 返回 ASSIGN ($2)。Bison 將其移入堆疊。
  3. yylex() 返回 IDENTIFIER ("SUM"), SUB, IDENTIFIER ("FIFO"), ., IDENTIFIER ("XOUT") -> 經過一系列移入和歸約,最終形成 expression ($3 指向 sub_expression_c,其子節點分別是 symbolic_variable_c("SUM")structured_variable_c("FIFO.XOUT"))。
  4. yylex() 返回 ; ($4)。Bison 將其移入堆疊。
  5. 歸約:此時堆疊頂部匹配 variable ASSIGN expression ;
  6. 執行動作
    • 呼叫 new_assignment_statement($1, $3),其中 $1 是 LHS 的 SUM 節點,$3 是 RHS 的 SUM - FIFO.XOUT 表達式樹。
    • 返回一個新的 assignment_statement_c 節點。
    • $$ 設置為這個新節點的指標。
    • 設置新節點的位置資訊。
  7. 壓棧:將代表 assignment_statement 的狀態和其語義值 ($$) 壓回堆疊。

對於 average_st.txt 中的其他賦值語句,如 XOUT := SUM/N ;SUM := N*XIN ;,處理流程完全相同,只是 $1$3 指向的具體 AST 子樹不同。

六、總結

ASSIGN (:=) 在 iec_bison.yy 中:

  • 是一個由 %token 定義的終端符號
  • 是構成賦值語句語法規則的關鍵部分,用於分隔左側變數和右側表達式。
  • 在語法分析過程中,它的出現是觸發 assignment_statement 規則歸約的重要條件。
  • 在 AST 構建時,其語義被 assignment_statement_c 節點結構所體現,而 ASSIGN 標記本身通常不產生獨立的 AST 節點

因此,ASSIGN 對於正確解析 ST 程式碼中的賦值操作至關重要,確保了程式碼的結構符合預期,並指導了相應 AST 節點的創建。