這是一個非常重要的問題,它涉及到編譯器不同階段的職責劃分。 - benchen2001/matiec GitHub Wiki

好的,這是一個非常重要的問題,它涉及到編譯器不同階段的職責劃分。

核心答案:iec_bison.yy 本身 不會 檢測賦值語句中左側 (LHS) 型別與右側 (RHS) 值/型別不匹配的錯誤。

iec_bison.yy 的主要職責是語法分析 (Syntax Analysis),而不是語意分析 (Semantic Analysis) 或型別檢查 (Type Checking)。

以下是完整深入的探討與說明:


1. iec_bison.yy 的職責:語法結構驗證與 AST 構建

  • 語法規則匹配iec_bison.yy 的核心工作是根據定義的語法規則(BNF 範式)來驗證從詞法分析器 (iec_flex.ll) 傳來的標記流在結構上是否合法。對於賦值語句,它只關心是否看到了類似 variable ASSIGN expression ';' 的模式。
  • AST 節點創建:當語法規則成功匹配時,iec_bison.yy 中的動作程式碼(Action)會被執行。對於賦值語句,這通常意味著:
    • 呼叫 new_assignment_statement(lhs_node, rhs_node) 來創建一個 assignment_statement_c AST 節點。
    • lhs_node 是指向代表左側 variable 的 AST 子樹的指標。
    • rhs_node 是指向代表右側 expression 的 AST 子樹的指標。
  • 不關心型別:在這個階段,Bison 完全不關心 lhs_node 所代表的變數是什麼型別,也不關心 rhs_node 所代表的表達式計算結果會是什麼型別。只要語法結構正確(例如,RUN := 5.0 ; 在語法上是完全正確的,因為 RUN 是一個 variable:=ASSIGN5.0 是一個 expression; 是語句結束符),Bison 就會成功解析並構建對應的 AST 節點。

2. 型別不匹配檢測的發生階段:Stage 3 (語意分析與型別檢查)

型別檢查是語意分析的一部分,它發生在語法分析成功並生成了完整的 AST 之後,通常在 matiec 的 Stage 3 中進行。

  • 輸入:Stage 3 的輸入是 stage1_2 (Bison) 產生的抽象語法樹 (AST)。
  • 處理方式:Stage 3 通常使用 Visitor 設計模式來遍歷 AST。當 Visitor 訪問到一個 assignment_statement_c 節點時,會執行以下檢查:
    1. 確定 LHS 型別
      • 遞迴訪問 assignment_statement_c 節點的左子節點 (lhs_node)。
      • 分析 lhs_node(可能是 symbolic_variable_c, structured_variable_c 等)。
      • 查詢符號表 (Symbol Table)(也是在 Stage 3 中建立或填充的)以獲取該變數在宣告時的資料型別。例如,查到 RUN 的型別是 BOOL
    2. 確定 RHS 型別
      • 遞迴訪問 assignment_statement_c 節點的右子節點 (rhs_node)。
      • 分析 rhs_node(可能是常數、變數、運算表達式、函式呼叫等)。
      • 根據表達式的構成和運算符的規則,推導出該表達式計算結果的資料型別。例如,5.0 的型別是 REALSUM / N 的型別根據 SUM (REAL) 和 N (INT) 的運算規則,結果可能是 REAL
    3. 比較與驗證
      • 根據 IEC 61131-3 標準中定義的型別相容性規則隱式轉換規則,比較 LHS 的型別和 RHS 的型別。
      • 檢查是否允許賦值
        • 完全匹配:例如 INT := INT
        • 允許的隱式轉換:例如 REAL := INT (通常允許,整數會被轉換為實數)。
        • 不允許的轉換:例如 BOOL := REAL (通常不允許)。
    4. 錯誤報告
      • 如果比較結果顯示型別不相容且不允許隱式轉換,則 Stage 3 會產生一個型別錯誤訊息
      • 這個錯誤訊息會利用儲存在 assignment_statement_c 及其子節點中的位置資訊(這些資訊最初來自 iec_flex.llyylloc 並由 iec_bison.yy 傳遞到 AST 節點中),指出錯誤發生的具體位置(檔案、行號、列號)。

3. 範例說明 (RUN := 5.0 ;)

假設在 average_st.txt 的程式碼中(錯誤地)寫入了 RUN := 5.0 ;

  1. iec_flex.ll: 掃描到 RUN, :=, 5.0, ;,產生 IDENTIFIER, ASSIGN, REAL_CONSTANT, ; 標記序列。
  2. iec_bison.yy:
    • 匹配 variable 規則得到 symbolic_variable_c("RUN") 節點 ($1)。
    • 匹配 expression 規則得到 real_c("5.0") 節點 ($3)。
    • 匹配 assignment_statement: variable ASSIGN expression ';' 規則。
    • 成功匹配! 因為語法結構正確。
    • 執行動作:$$ = new_assignment_statement($1, $3),創建一個 assignment_statement_c 節點,其左子節點是 symbolic_variable_c("RUN"),右子節點是 real_c("5.0")
    • iec_bison.yy 在此階段不報錯。
  3. Stage 3 (語意分析/型別檢查):
    • Visitor 訪問到這個 assignment_statement_c 節點。
    • 訪問 LHS (symbolic_variable_c("RUN")),查詢符號表,得知 RUN 的型別是 BOOL
    • 訪問 RHS (real_c("5.0")),得知其型別是 REAL
    • 比較 LHS 型別 (BOOL) 和 RHS 型別 (REAL)。
    • 根據 IEC 61131-3 規則,REAL 不能隱式轉換或賦值給 BOOL
    • 檢測到型別不匹配!
    • Stage 3 產生錯誤訊息,類似於:average_st.txt:XX:YY: error: Type mismatch: cannot assign REAL to BOOL (其中 XX, YY 是從 AST 節點獲取的位置資訊)。

4. 總結

  • iec_bison.yy 負責語法:它確保程式碼的書寫格式符合語言規則,並構建 AST。它不理解型別。
  • Stage 3 負責語意型別檢查:它遍歷 iec_bison.yy 產生的 AST,查詢符號表,推導表達式型別,並根據語言的型別規則驗證賦值等操作的合法性。
  • ASSIGNiec_bison.yy 中僅作為一個語法分隔符和結構標識符,觸發 assignment_statement 規則的匹配和 AST 節點的創建。型別是否匹配的判斷是在後續階段利用這個 AST 結構完成的。