# 在 `iec_bison.yy` 中 ASSIGN 賦值的型別檢查機制 - benchen2001/matiec GitHub Wiki
在 iec_bison.yy 中 ASSIGN 賦值的型別檢查機制
一、類型相容性檢查的基本原理
首先,需要明確一個關鍵概念:在 matiec 編譯器中,iec_bison.yy 本身不直接處理型別檢查。這是編譯器設計中的基本原則 - 職責分離:
iec_bison.yy(Stage 1-2):負責語法分析,確保程式碼結構符合 IEC 61131-3 語法規則- 語義分析階段(Stage 3):負責型別檢查和其他語義規則驗證
對於賦值語句 (variable := expression),型別不匹配的檢測是在 Stage 3 進行的,而不是在 iec_bison.yy 中。以下是完整的檢測流程:
二、具體檢測流程
1. 階段一和二:語法分析(iec_bison.yy)
在這個階段,iec_bison.yy 只關注語法結構,不關心型別:
assignment_statement
: variable ASSIGN expression ';'
{
$$ = new_assignment_statement($1, $3);
/* 設置位置資訊 */
}
;
這裡產生了 assignment_statement_c 類型的 AST 節點,包含左值(LHS)和右值(RHS)兩個子節點。重要的是:此時沒有任何型別檢查!
2. 階段三:語義分析
型別檢查在 Stage 3 中執行,通過以下關鍵文件實現:
stage3/datatype_assignment_check.cc:負責檢查賦值操作的型別相容性stage3/type_symbol_table.cc:維護變數和表達式的型別資訊stage3/fill_candidate_datatypes.cc:推導表達式的可能型別
檢查流程如下:
2.1 遞迴收集型別資訊
首先,系統會通過遞迴遍歷 AST 節點來收集和填充型別資訊:
// 偽代碼 - 實際實現在 fill_candidate_datatypes.cc
visit(assignment_statement_c *node) {
// 遞迴訪問左側,確定其型別
visit(node->l_exp);
// 遞迴訪問右側,確定其型別
visit(node->r_exp);
// 型別資訊被存儲在每個節點的 candidate_datatypes 中
}
2.2 型別相容性檢查
然後,執行賦值語句的型別相容性檢查:
// 偽代碼 - 實際實現在 datatype_assignment_check.cc
visit(assignment_statement_c *node) {
// 獲取左側的型別
datatype_t lhs_type = get_type_id(node->l_exp->datatype);
// 獲取右側的型別
datatype_t rhs_type = get_type_id(node->r_exp->datatype);
// 檢查型別相容性
if (!is_type_compatible(lhs_type, rhs_type)) {
// 報告型別錯誤
report_type_error(node, lhs_type, rhs_type);
}
}
2.3 實際範例(以 average_st.txt 為例)
如果我們修改 average_st.txt 中的賦值語句:
SUM := RUN; // 錯誤:嘗試將 BOOL 型別賦值給 REAL 型別
檢測過程將是:
- 語法分析:
iec_bison.yy接受這行語句,因為它符合variable ASSIGN expression;的語法形式 - 型別識別: Stage 3 確定
SUM的型別是REAL,RUN的型別是BOOL - 相容性檢查: 系統檢查
BOOL是否可以賦值給REAL - 錯誤報告: 型別不相容,產生錯誤訊息:
Error: Type mismatch in assignment - cannot convert 'BOOL' to 'REAL'
三、型別相容性規則
IEC 61131-3 標準定義了嚴格的型別相容性規則。主要規則包括:
- 相同型別: 總是允許(如
REAL := REAL) - 數值型別轉換:
INT→REAL: 允許(擴展轉換)REAL→INT: 不允許(截斷轉換,需顯式轉換函數)
- 布林型別:
BOOL不能直接賦值給任何非布林型別- 非布林型別不能直接賦值給
BOOL
- 陣列和結構:
- 必須型別完全相同,包括維度和成員
- 字串型別:
- STRING 和 WSTRING 不可互換
- 字串長度可以不同(較長的會被截斷)
四、示例:average_st.txt 中的型別檢查
分析示例檔案中的賦值語句:
SUM := SUM - FIFO.XOUT; // 有效:REAL := REAL - REAL
FIFO (RUN := RUN, ...); // 有效:BOOL := BOOL
SUM := SUM + FIFO.XOUT; // 有效:REAL := REAL + REAL
XOUT := SUM/N; // 有效:REAL := REAL/INT(結果是 REAL)
SUM := N*XIN; // 有效:REAL := INT*REAL(結果是 REAL)
XOUT := XIN; // 有效:REAL := REAL
所有這些賦值語句在型別檢查上都是合法的,因為:
SUM和XOUT是REAL型別RUN是BOOL型別N是INT型別FIFO.XOUT是REAL型別(根據DELAY功能塊定義)
五、總結
-
分工原則:
iec_bison.yy(Stage 1-2) 只處理語法結構- Stage 3 負責型別檢查和語義驗證
-
檢測機制:
- 通過建立符號表收集型別資訊
- 透過遞迴遍歷 AST 計算表達式型別
- 根據 IEC 61131-3 標準的型別規則檢查相容性
-
實際應用:
- 這種設計使編譯器有更清晰的結構和責任分離
- 更容易擴展和維護(型別系統可以獨立演化)
- 支援 IEC 61131-3 標準的嚴格型別檢查要求
這種分層設計是工業級編譯器的標準做法,確保了高品質的錯誤檢測和更好的用戶體驗。