這是一個非常重要的問題,它涉及到編譯器不同階段的職責劃分。 - 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_cAST 節點。 lhs_node是指向代表左側variable的 AST 子樹的指標。rhs_node是指向代表右側expression的 AST 子樹的指標。
- 呼叫
- 不關心型別:在這個階段,Bison 完全不關心
lhs_node所代表的變數是什麼型別,也不關心rhs_node所代表的表達式計算結果會是什麼型別。只要語法結構正確(例如,RUN := 5.0 ;在語法上是完全正確的,因為RUN是一個variable,:=是ASSIGN,5.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節點時,會執行以下檢查:- 確定 LHS 型別:
- 遞迴訪問
assignment_statement_c節點的左子節點 (lhs_node)。 - 分析
lhs_node(可能是symbolic_variable_c,structured_variable_c等)。 - 查詢符號表 (Symbol Table)(也是在 Stage 3 中建立或填充的)以獲取該變數在宣告時的資料型別。例如,查到
RUN的型別是BOOL。
- 遞迴訪問
- 確定 RHS 型別:
- 遞迴訪問
assignment_statement_c節點的右子節點 (rhs_node)。 - 分析
rhs_node(可能是常數、變數、運算表達式、函式呼叫等)。 - 根據表達式的構成和運算符的規則,推導出該表達式計算結果的資料型別。例如,
5.0的型別是REAL;SUM / N的型別根據SUM(REAL) 和N(INT) 的運算規則,結果可能是REAL。
- 遞迴訪問
- 比較與驗證:
- 根據 IEC 61131-3 標準中定義的型別相容性規則和隱式轉換規則,比較 LHS 的型別和 RHS 的型別。
- 檢查是否允許賦值:
- 完全匹配:例如
INT := INT。 - 允許的隱式轉換:例如
REAL := INT(通常允許,整數會被轉換為實數)。 - 不允許的轉換:例如
BOOL := REAL(通常不允許)。
- 完全匹配:例如
- 錯誤報告:
- 如果比較結果顯示型別不相容且不允許隱式轉換,則 Stage 3 會產生一個型別錯誤訊息。
- 這個錯誤訊息會利用儲存在
assignment_statement_c及其子節點中的位置資訊(這些資訊最初來自iec_flex.ll的yylloc並由iec_bison.yy傳遞到 AST 節點中),指出錯誤發生的具體位置(檔案、行號、列號)。
- 確定 LHS 型別:
3. 範例說明 (RUN := 5.0 ;)
假設在 average_st.txt 的程式碼中(錯誤地)寫入了 RUN := 5.0 ;:
iec_flex.ll: 掃描到RUN,:=,5.0,;,產生IDENTIFIER,ASSIGN,REAL_CONSTANT,;標記序列。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在此階段不報錯。
- 匹配
- 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 節點獲取的位置資訊)。
- Visitor 訪問到這個
4. 總結
iec_bison.yy負責語法:它確保程式碼的書寫格式符合語言規則,並構建 AST。它不理解型別。- Stage 3 負責語意和型別檢查:它遍歷
iec_bison.yy產生的 AST,查詢符號表,推導表達式型別,並根據語言的型別規則驗證賦值等操作的合法性。 ASSIGN在iec_bison.yy中僅作為一個語法分隔符和結構標識符,觸發assignment_statement規則的匹配和 AST 節點的創建。型別是否匹配的判斷是在後續階段利用這個 AST 結構完成的。