如何定義並檢出 `var_decl` (變數宣告) 的合法性(1)。 - benchen2001/matiec GitHub Wiki

好的,我們來分析 iec_bison.yy (或類似的 Bison 語法檔案,用於解析 IEC 61131-3 語言) 如何定義並檢出 var_decl (變數宣告) 的合法性。

核心概念:

Bison (或 Yacc) 的主要工作是語法分析 (Syntax Analysis)。它根據你在 .yy 檔案中定義的語法規則 (Grammar Rules) 來判斷輸入的 token 序列是否符合語言的語法結構。

對於 var_decl,"合法" 在 Bison 的層面上主要是指語法結構上的正確性。也就是說,變數宣告的各個部分 (名稱、冒號、類型、可選的地址、可選的初始值、分號) 是否按照預期的順序和格式出現。

尋找相關程式碼:

你需要在 iec_bison.yy 檔案中找到定義 var_decl 這個非終端符 (non-terminal symbol) 的語法規則。它通常看起來像這樣 (具體名稱和結構可能因不同的實作而略有差異):

%{
// C/C++ 宣告和 include 檔案
#include "iec_common.h" // 假設有共用定義
#include "symbol_table.h" // 假設有符號表處理
// ... 其他 include
%}

// Bison 宣告部分 (%token, %type, %start 等)
%token T_VAR T_END_VAR T_COLON T_SEMICOLON T_ASSIGN T_AT
%token T_IDENTIFIER // 由 Lexer 返回的標識符 token
%token T_BOOL T_INT T_REAL // ... 其他基本類型 token
// ... 其他 token 定義

%type <symbol> identifier // 假設 identifier 返回一個符號對象
%type <type_info> type_spec // 假設 type_spec 返回類型資訊
%type <expr_node> simple_spec_init // 假設返回表達式節點
// ... 其他 %type 定義

%% /* 語法規則開始 */

/* ... 其他規則 ... */

var_declarations_list:
      var_declaration
    | var_declarations_list var_declaration
    ;

var_declaration:
      identifier_list T_COLON type_spec location_spec simple_spec_init T_SEMICOLON
      {
          // 動作代碼 (Action Code): 當此規則成功匹配時執行
          // 這裡可以進行語義檢查、建立符號表條目、建構 AST 節點等
          printf("Parsed a variable declaration.\n");
          // 例如: process_variable_declaration($1, $3, $4, $5);
          // $1: identifier_list 的值
          // $3: type_spec 的值
          // $4: location_spec 的值 (可能是 NULL)
          // $5: simple_spec_init 的值 (可能是 NULL)
      }
    ;

identifier_list:
      identifier
      { $$ = create_identifier_list($1); } // 建立只包含一個標識符的列表
    | identifier_list T_COMMA identifier
      { $$ = add_to_identifier_list($1, $3); } // 將標識符添加到現有列表
    ;

// 類型說明符 (可能很複雜,包含基本類型、陣列、結構體、FB 等)
type_spec:
      simple_type_name
      { $$ = process_simple_type($1); }
    | array_spec
      { $$ = process_array_type($1); }
    /* | structured_type_spec */
    /* | function_block_type_name */
    /* ... 其他類型規則 ... */
    ;

// 可選的位置說明符
location_spec:
      /* empty */
      { $$ = NULL; } // 沒有 AT 子句
    | T_AT direct_variable
      { $$ = process_location($2); }
    ;

// 可選的初始化
simple_spec_init:
      /* empty */
      { $$ = NULL; } // 沒有初始化
    | T_ASSIGN constant_expression // 或更通用的 expression
      { $$ = process_initialization($2); }
    ;

/* ... 其他規則,例如 simple_type_name, array_spec, direct_variable, constant_expression 等 ... */

%% /* 語法規則結束 */

// C/C++ 輔助函數
// ... process_variable_declaration, create_identifier_list, 等函數的實作 ...

說明:

  1. var_declaration 規則: 這是核心。它定義了一個合法的變數宣告必須包含:

    • identifier_list: 一個或多個用逗號分隔的變數名稱 (標識符)。identifier_list 本身是另一個非終端符,它遞迴地定義了如何處理逗號分隔的列表。
    • T_COLON: 一個冒號 token。
    • type_spec: 變數的類型說明。這本身可能是一個複雜的非終端符,涵蓋基本類型、陣列、結構體、功能塊等。Bison 會遞迴地去匹配 type_spec 的規則。
    • location_spec: 可選的 AT 位置說明符。這個規則可以匹配空 (epsilon,表示沒有 AT 子句) 或者 T_AT 後面跟著一個 direct_variable (表示具體的地址,如 %IX0.0)。
    • simple_spec_init: 可選的初始化部分。這個規則可以匹配空 (表示沒有初始化) 或者 T_ASSIGN (即 :=) 後面跟著一個 constant_expression (或更一般的表達式)。
    • T_SEMICOLON: 一個分號 token,標示宣告結束。
  2. Token: 大寫的 T_ 開頭的通常是終端符 (terminal symbols)token。這些是由詞法分析器 (Lexer, 通常是 Flex) 從原始碼中識別並傳遞給 Bison 的最小單元。例如 T_VAR, T_COLON, T_IDENTIFIER, T_INT 等。

  3. 非終端符: 小寫的名稱 (如 var_declaration, identifier_list, type_spec) 是非終端符 (non-terminal symbols)。它們代表了語法結構中的一個概念,由一個或多個終端符或其他非終端符組成。

  4. 匹配過程: 當 Bison 讀取由 Lexer 提供的 token 流時,它會嘗試將這些 token 與語法規則進行匹配。

    • 如果輸入的 token 序列能夠符合 var_declaration 規則所定義的順序和結構 (例如,看到一個標識符,接著是冒號,接著是合法的類型,然後是可選的 AT,可選的初始化,最後是分號),Bison 就認為這是一個語法上合法var_declaration
    • 如果 token 序列不符合任何定義的規則 (例如,缺少冒號、類型名稱拼錯導致 Lexer 無法識別、分號遺漏等),Bison 就會報告語法錯誤 (Syntax Error)
  5. 動作代碼 (Action Code {...}): 規則後面花括號 {...} 中的 C/C++ 代碼是動作代碼。當 Bison 成功匹配整個規則後,會執行這些代碼。這些代碼通常用於:

    • 建立抽象語法樹 (AST) 節點。
    • 填充符號表 (Symbol Table),記錄變數名稱、類型、地址等資訊。
    • 執行初步的語義檢查 (雖然複雜的語義檢查通常在 AST 建立後進行),例如檢查類型名稱是否存在。
    • 計算或傳遞值 (使用 $1, $2, $$ 等特殊變數)。

總結:

iec_bison.yy 中,var_decl 的 "合法性" 主要是通過其語法規則來定義和檢出的。Bison 檢查輸入的 token 是否嚴格按照 identifier_list T_COLON type_spec location_spec simple_spec_init T_SEMICOLON 這個模式 (以及其子規則定義的模式) 排列。如果匹配成功,則語法上合法;否則,報告語法錯誤。更深層次的語義合法性 (如類型相容性、名稱衝突等) 通常在規則匹配成功後執行的動作代碼中處理,或者在後續的語義分析階段處理。

⚠️ **GitHub.com Fallback** ⚠️