欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

OpenPLC 源代码分析

最编程 2024-06-08 15:40:40
...

一、matiec中的bison ST语法定义规则

matiec:IEC 61131-3中定义的程序设计语言的编译器

示例程序:

FUNCTION 函数名称 : 返回值类型
  VAR_INPUT
    输入变量名称 : 变量类型;
  END_VAR
  VAR
    本地变量名称 : 变量类型 := 变量值;
  END_VAR

  返回值变量名称 := 某种运算; //示例:返回值变量 := INT_TO_REAL(输入变量1+输入变量2)/本地变量;
END_FUNCTION

FUNCTION_BLOCK 功能块名称
  VAR_INPUT
    输入变量名称 : 变量类型;
  END_VAR
  VAR
    本地变量名称 : 变量类型;
  END_VAR
  VAR_OUTPUT
    输出变量名称 : 变量类型;
  END_VAR
  VAR_EXTERNAL CONSTANT
    外部常量名称 : 常量类型;
  END_VAR

  IF Reset THEN
    本地变量 := 外部常量;
  ELSE
    本地变量 := 本地变量 + 1;
  END_IF;

  输出变量 := 本地变量;
END_FUNCTION_BLOCK

PROGRAM 程序名称
  VAR_OUTPUT
    输出变量名称 : 变量类型;
  END_VAR
  VAR_INPUT
    输入变量名称 : 变量类型;
  END_VAR
  VAR
    本地变量名称 : 变量类型
  END_VAR

  INITIAL_STEP 初始步名称:
      动作1名称(限定符);
  END_STEP
  
  ACTION 动作1名称:
      动作1行为;
  END_ACTION

  TRANSITION FROM 初始步名称 TO 第1步名称
    := 转移条件;
  END_TRANSITION

  STEP 第1步名称:
      动作2名称(限定符);
  END_STEP
  
  ACTION 动作2名称:
      动作2行为;
  END_ACTION

END_PROGRAM


CONFIGURATION config
  VAR_GLOBAL CONSTANT
    外部常量 : 常量类型 := 常量值;
  END_VAR

  RESOURCE Res0 ON PLC
    TASK plc_task(INTERVAL := T#100ms,PRIORITY := 1);
    PROGRAM plc_task_instance WITH plc_task : 程序名;
  END_RESOURCE
END_CONFIGURATION
 *        TYPE
 *           d_s: STRUCT d1: int; d2: int;
 *           d_a: ARRAY [1..3] OF d_s;  
 *           c_s: STRUCT c1: d_a; c2: d_a;
 *           b_s: STRUCT b1: c_s; b2: c_s;
 *           b_a: ARRAY [1..3] OF b_s;  
 *           a_s: STRUCT a1: b_a; a2: b_a;
 *        END_TYPE 
 *        VAR
 *          structvar: a_s;
 *        END_VAR

二、matiec源码分析

1. stage1

2. stage2

3. stage3

4. stage4

程序结构的说明:

  • stage4函数调用new_code_generator函数
  • new_code_generator函数的返回值为类generate_c_c的实例化对象
  • 类generate_c_c派生于类iterator_visitor_c
  • 类iterator_visitor_c派生于类visitor_c
  • 类visitor_c引入absyntax.def和析构虚函数

类的说明:

1.主程序结构中的类

image.png

2.其他类

  • 类print_function_parameter_data_types_c image.png

  • 类analyse_variable_c image.png

  • 类calculate_common_ticktime_c image.png

  • 类generate_c_SFC_IL_ST_c image.png

  • 类generate_c_pous_c image.png

  • 类generate_c_config_c image.png

  • 类generate_c_resources_c image.png

其他:

visitor_c *generate_code = new_code_generator(&s4o, builddir);:生成POUS.c、POUS.h、LOCATED_VARIABLES.h和VARIABLES.csv,但是文件内容为空
tree_root->accept(*generate_code);:生成Config0.c、Config0.h和Res0.c,但是文件内容不为空 delete_code_generator(generate_code);:生成POUS.c、POUS.h、LOCATED_VARIABLES.h和VARIABLES.csv的内容

SYM_LIST(library_c, enumvalue_symtable_t enumvalue_symtable;)
宏替换的程序:
class library_c:	public list_c {						
  public:									
    __VA_ARGS__									
  public:									
    class_name_c(								
                 int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0,
                 int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0);
    class_name_c(symbol_c *elem, 						
                 int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0,
                 int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0);
    virtual void *accept(visitor_c &visitor);					
    /* WARNING: only use this method for debugging purposes!! */		
    virtual const char *absyntax_cname(void) {return #class_name_c;};		
};

SYM_REF4(function_declaration_c, derived_function_name, type_name, var_declarations_list, function_body, enumvalue_symtable_t enumvalue_symtable;)
宏替换的程序:
class function_declaration_c: public symbol_c {					
  public:									
    symbol_c *ref1;								
    symbol_c *ref2;								
    symbol_c *ref3;								
    symbol_c *ref4;								
    __VA_ARGS__									
  public:									
    function_declaration_c(symbol_c *ref1,
		 symbol_c *ref2,						
		 symbol_c *ref3,						
		 symbol_c *ref4 = NULL,						
                 int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0,
                 int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0);
    virtual void *accept(visitor_c &visitor);					
    /* WARNING: only use this method for debugging purposes!! */		
    virtual const char *absyntax_cname(void) {return #function_declaration_c;};	
};
//configure.c

symbol->accept(generate_c_config); //起始代码

/* (A.2) Global variables */
vardecl = new generate_c_vardecl_c(&s4o,
                                 generate_c_vardecl_c::local_vf,
                                 generate_c_vardecl_c::global_vt,
                                 symbol->configuration_name);
vardecl->print(symbol);
delete vardecl;
s4o.print("\n");

/* (B.3) Global variables initializations... */
s4o.print(s4o.indent_spaces);
vardecl = new generate_c_vardecl_c(&s4o,
                                 generate_c_vardecl_c::constructorinit_vf,
                                 generate_c_vardecl_c::global_vt,
                                 symbol->configuration_name);
vardecl->print(symbol);
delete vardecl;
s4o.print("\n");
//POUS.c
/* (B.2) Member initializations... */
s4o.print(s4o.indent_spaces);
vardecl = new generate_c_vardecl_c(&s4o,
                                   generate_c_vardecl_c::constructorinit_vf,
                                   generate_c_vardecl_c::input_vt    |
                                   generate_c_vardecl_c::output_vt   |
                                   generate_c_vardecl_c::inoutput_vt |
                                   generate_c_vardecl_c::private_vt  |
                                   generate_c_vardecl_c::located_vt  |
                                   generate_c_vardecl_c::external_vt);
vardecl->print(symbol->var_declarations, NULL,  FB_FUNCTION_PARAM"->");
delete vardecl;
s4o.print("\n");

/* (C.4) Initialize TEMP variables */
/* function body */
s4o.print(s4o.indent_spaces + "// Initialise TEMP variables\n");
vardecl = new generate_c_vardecl_c(&s4o,
                                   generate_c_vardecl_c::init_vf,
                                   generate_c_vardecl_c::temp_vt);
vardecl->print(symbol->var_declarations, NULL,  FB_FUNCTION_PARAM"->");
delete vardecl;
s4o.print("\n");

POUS.h的变量声明 image.png

POUS.c的变量初始化 image.png

Config0.c的变量初始化 image.png

三、matiec生成C代码的规则

原始ST代码

1.handle_program函数:

PROGRAM PLC_PRG
  VAR_INPUT
    local1 : INT := 11;
    local2 : INT := 21;
  END_VAR
  VAR_OUTPUT
    local3 : INT;
  END_VAR

  local3 := local1 + local2;

END_PROGRAM

matiec编译后的C语言代码:

void PLC_PRG_init__(PLC_PRG *data__, BOOL retain) {
  __INIT_VAR(data__->LOCAL1,11,retain)
  __INIT_VAR(data__->LOCAL2,21,retain)
  __INIT_VAR(data__->LOCAL3,0,retain)
}

// Code part
void PLC_PRG_body__(PLC_PRG *data__) {
  // Initialise TEMP variables

  __SET_VAR(data__->,LOCAL3,,(__GET_VAR(data__->LOCAL1,) + __GET_VAR(data__->LOCAL2,)));

  goto __end;

__end:
  return;
} // PLC_PRG_body__() 

总结规则

void 程序名_init__(程序名 *data__, BOOL retain) {
  __变量类型_VAR(data__->变量名,变量值,retain)
}

//Code part
void 程序名_body__(程序名 *data__) {
  // Initialise TEMP variables
  
  __SET_VAR(data__->,变量3,,(__GET_VAR(data__->变量1,) 运算符 __GET_VAR(data__->变量2,)));
  goto __end;
  
__end:
  return;
} //程序名_body__()

matiec handle_program核心代码

if (wanted_varformat == constructorinit_vf) {
    for(int i = 0; i < list->n; i++) {
        if (is_fb) {
            s4o.print(nv->get());
            this->current_var_type_symbol->accept(*this);
            s4o.print(FB_INIT_SUFFIX);
            s4o.print("(&");
            this->print_variable_prefix();
            list->elements[i]->accept(*this);
            print_retain();
            s4o.print(");");
        }
        else if (this->current_var_init_symbol != NULL) {
            s4o.print(nv->get());
            s4o.print(INIT_VAR);
            s4o.print("(");
            this->print_variable_prefix();
            list->elements[i]->accept(*this);
            s4o.print(",");
            this->current_var_init_symbol->accept(*this);
            print_retain();
            s4o.print(")");
        }
    }
}
else if (wanted_varformat == init_vf) {
    s4o.print(SET_VAR);
    s4o.print("(");
    print_variable_prefix();
    s4o.print(",");
}
list->elements[i]->accept(*this);

else if (wanted_varformat == init_vf) {
    s4o.print(",,");
    this->current_var_init_symbol->accept(*this);
    s4o.print(");\n");
void print(symbol_c *symbol, symbol_c *scope = NULL, const char *variable_prefix = NULL) {
  this->set_variable_prefix(variable_prefix);
  if (globalinit_vf == wanted_varformat)
    globalnamespace = scope;

  finterface_var_count = 0;

  switch (wanted_varformat) {
    case constructorinit_vf: nv = new next_var_c("", "\n"+s4o.indent_spaces); break;
    case finterface_vf:      /* fall through... */
    case localinit_vf:       /* fall through... */
    case local_vf:           nv = new next_var_c("", ", "); break;
    default:                 nv = NULL;
  } /* switch() */

  symbol->accept(*this);

  delete nv;
  nv = NULL;
  globalnamespace = NULL;
}

2.handle_function函数:

原始ST代码

FUNCTION AverageVal : REAL
  VAR_INPUT
    Cnt1 : INT;
    Cnt2 : INT;
  END_VAR
  VAR
    InputsNumber : REAL := 2.0;
  END_VAR

  AverageVal := INT_TO_REAL(Cnt1+Cnt2)/InputsNumber;
END_FUNCTION

matiec编译后的C语言代码:

// FUNCTION
REAL AVERAGEVAL(
  BOOL EN, 
  BOOL *__ENO, 
  INT CNT1, 
  INT CNT2)
{
  BOOL ENO = __BOOL_LITERAL(TRUE);
  REAL INPUTSNUMBER = 2.0;
  REAL AVERAGEVAL = 0;

  // Control execution
  if (!EN) {
    if (__ENO != NULL) {
      *__ENO = __BOOL_LITERAL(FALSE);
    }
    return AVERAGEVAL;
  }
  AVERAGEVAL = (INT_TO_REAL(
    (BOOL)__BOOL_LITERAL(TRUE),
    NULL,
    (INT)(CNT1 + CNT2)) / INPUTSNUMBER);

  goto __end;

__end:
  if (__ENO != NULL) {
    *__ENO = ENO;
  }
  return AVERAGEVAL;
}

3.handle_function_block

原始ST代码

FUNCTION_BLOCK CounterST
  VAR_INPUT
    Reset : BOOL;
  END_VAR
  VAR
    Cnt : INT;
  END_VAR
  VAR_OUTPUT
    OUT : INT;
  END_VAR
  VAR_EXTERNAL CONSTANT
    ResetCounterValue : INT;
  END_VAR

  IF Reset THEN
    Cnt := ResetCounterValue;
  ELSE
    Cnt := Cnt + 1;
  END_IF;

  Out := Cnt;
END_FUNCTION_BLOCK

matiec编译后的C语言代码:

void COUNTERST_init__(COUNTERST *data__, BOOL retain) {
  __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__->RESET,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__->CNT,0,retain)
  __INIT_VAR(data__->OUT,0,retain)
  __INIT_EXTERNAL(INT,RESETCOUNTERVALUE,data__->RESETCOUNTERVALUE,retain)
}

// Code part
void COUNTERST_body__(COUNTERST *data__) {
  // Control execution
  if (!__GET_VAR(data__->EN)) {
    __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE));
    return;
  }
  else {
    __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE));
  }
  // Initialise TEMP variables

  if (__GET_VAR(data__->RESET,)) {
    __SET_VAR(data__->,CNT,,__GET_EXTERNAL(data__->RESETCOUNTERVALUE,));
  } else {
    __SET_VAR(data__->,CNT,,(__GET_VAR(data__->CNT,) + 1));
  };
  __SET_VAR(data__->,OUT,,__GET_VAR(data__->CNT,));

  goto __end;

__end:
  return;
} // COUNTERST_body__() 

其他

#define SYM_REF3(class_name_c, ref1, ref2, ref3, ...)									\
class class_name_c: public symbol_c {											\
  public:														\
    symbol_c *ref1;													\
    symbol_c *ref2;													\
    symbol_c *ref3;													\
    __VA_ARGS__														\
  public:														\
    class_name_c(symbol_c *ref1,											\
		 symbol_c *ref2,											\
		 symbol_c *ref3,											\
                 int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0,			\
                 int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0);			\
    virtual void *accept(visitor_c &visitor);										\
    /* WARNING: only use this method for debugging purposes!! */							\
    virtual const char *absyntax_cname(void) {return #class_name_c;};							\
};
SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body, enumvalue_symtable_t enumvalue_symtable;)

目前支持的数据类型

/* B 1.3.1 - Elementary Data Types */
/***********************************/
void *visit(time_type_name_c        *symbol) {return (void *)"TIME";        };
void *visit(bool_type_name_c        *symbol) {return (void *)"BOOL";        };
void *visit(sint_type_name_c        *symbol) {return (void *)"SINT";        };
void *visit(int_type_name_c         *symbol) {return (void *)"INT";         };
void *visit(dint_type_name_c        *symbol) {return (void *)"DINT";        };
void *visit(lint_type_name_c        *symbol) {return (void *)"LINT";        };
void *visit(usint_type_name_c       *symbol) {return (void *)"USINT";       };
void *visit(uint_type_name_c        *symbol) {return (void *)"UINT";        };
void *visit(udint_type_name_c       *symbol) {return (void *)"UDINT";       };
void *visit(ulint_type_name_c       *symbol) {return (void *)"ULINT";       };
void *visit(real_type_name_c        *symbol) {return (void *)"REAL";        };
void *visit(lreal_type_name_c       *symbol) {return (void *)"LREAL";       };
void *visit(date_type_name_c        *symbol) {return (void *)"DATE";        };
void *visit(tod_type_name_c         *symbol) {return (void *)"TOD";         };
void *visit(dt_type_name_c          *symbol) {return (void *)"DT";          };
void *visit(byte_type_name_c        *symbol) {return (void *)"BYTE";        };
void *visit(word_type_name_c        *symbol) {return (void *)"WORD";        };
void *visit(lword_type_name_c       *symbol) {return (void *)"LWORD";       };
void *visit(dword_type_name_c       *symbol) {return (void *)"DWORD";       };
void *visit(string_type_name_c      *symbol) {return (void *)"STRING";      };
void *visit(wstring_type_name_c     *symbol) {return (void *)"WSTRING";     };

目前支持的不同数据类型之间可以进行运算的操作符

void *print_datatypes_error_c::visit(    or_expression_c *symbol) {return print_binary_expression_errors( "OR", symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(   xor_expression_c *symbol) {return print_binary_expression_errors("XOR", symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(   and_expression_c *symbol) {return print_binary_expression_errors("AND", symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(   equ_expression_c *symbol) {return print_binary_expression_errors( "=" , symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(notequ_expression_c *symbol) {return print_binary_expression_errors( "<>", symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(    lt_expression_c *symbol) {return print_binary_expression_errors( "<" , symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(    gt_expression_c *symbol) {return print_binary_expression_errors( ">" , symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(    le_expression_c *symbol) {return print_binary_expression_errors( "<=", symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(    ge_expression_c *symbol) {return print_binary_expression_errors( ">=", symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit(   add_expression_c *symbol) {return print_binary_expression_errors( "+" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);}
void *print_datatypes_error_c::visit(   sub_expression_c *symbol) {return print_binary_expression_errors( "-" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);}
void *print_datatypes_error_c::visit(   mul_expression_c *symbol) {return print_binary_expression_errors( "*" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);}
void *print_datatypes_error_c::visit(   div_expression_c *symbol) {return print_binary_expression_errors( "/" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);}
void *print_datatypes_error_c::visit(   mod_expression_c *symbol) {return print_binary_expression_errors("MOD", symbol, symbol->l_exp, symbol->r_exp);}
void *print_datatypes_error_c::visit( power_expression_c *symbol) {return print_binary_expression_errors( "**", symbol, symbol->l_exp, symbol->r_exp);}
bool remove_from_candidate_datatype_list(symbol_c *datatype, std::vector <symbol_c *> &candidate_datatypes) {
	int pos = search_in_candidate_datatype_list(datatype, candidate_datatypes);
	if (pos < 0)
		return false;
	
	candidate_datatypes.erase(candidate_datatypes.begin() + pos);
	return true;
}
void *fill_candidate_datatypes_c::handle_binary_operator(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr) {
	if (NULL == l_expr) return NULL; /* if no prev_il_instruction */
	if (NULL == r_expr) return NULL; /* if no IL operand!! */

	for(unsigned int i = 0; i < l_expr->candidate_datatypes.size(); i++)
		for(unsigned int j = 0; j < r_expr->candidate_datatypes.size(); j++)
			/* NOTE: add_datatype_to_candidate_list() will only really add the datatype if it is != NULL !!! */
			add_datatype_to_candidate_list(symbol, widening_conversion(l_expr->candidate_datatypes[i], r_expr->candidate_datatypes[j], widen_table));
	remove_incompatible_datatypes(symbol);
	if (debug) std::cout <<  "[" << l_expr->candidate_datatypes.size() << "," << r_expr->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}

bool fill_candidate_datatypes_c::add_datatype_to_candidate_list(symbol_c *symbol, symbol_c *datatype) {
  /* If it is an invalid data type, do not insert!
   * NOTE: it reduces overall code size to do this test here, instead of doing every time before calling the add_datatype_to_candidate_list() function. 
   */
  if (!get_datatype_info_c::is_type_valid(datatype)) /* checks for NULL and invalid_type_name_c */
    return false;

  if (search_in_candidate_datatype_list(datatype, symbol->candidate_datatypes) >= 0) 
    /* already in the list, Just return! */
    return false;
  
  /* not yet in the candidate data type list, so we insert it now! */
  symbol->candidate_datatypes.push_back(datatype);
  return true;
}

void fill_candidate_datatypes_c::remove_incompatible_datatypes(symbol_c *symbol) {
  #ifdef __REMOVE__
    #error __REMOVE__ macro already exists. Choose another name!
  #endif
  #define __REMOVE__(datatype)\
      remove_from_candidate_datatype_list(&get_datatype_info_c::datatype,       symbol->candidate_datatypes);\
      remove_from_candidate_datatype_list(&get_datatype_info_c::safe##datatype, symbol->candidate_datatypes);
  
  {/* Remove unsigned data types */
    uint64_t value = 0;
    if (VALID_CVALUE( uint64, symbol)) value = GET_CVALUE(uint64, symbol);
    if (IS_OVERFLOW ( uint64, symbol)) value = (uint64_t)UINT32_MAX + (uint64_t)1;
    
    if (value > 1          )          {__REMOVE__(bool_type_name);}
    if (value > UINT8_MAX  )          {__REMOVE__(usint_type_name);  __REMOVE__( byte_type_name);}
    if (value > UINT16_MAX )          {__REMOVE__( uint_type_name);  __REMOVE__( word_type_name);}
    if (value > UINT32_MAX )          {__REMOVE__(udint_type_name);  __REMOVE__(dword_type_name);}
    if (IS_OVERFLOW( uint64, symbol)) {__REMOVE__(ulint_type_name);  __REMOVE__(lword_type_name);}
  }

  {/* Remove signed data types */
    int64_t value = 0;
    if (VALID_CVALUE(  int64, symbol)) value = GET_CVALUE(int64, symbol);
    if (IS_OVERFLOW (  int64, symbol)) value = (int64_t)INT32_MAX + (int64_t)1;
    
    if ((value <  INT8_MIN) || (value >  INT8_MAX)) {__REMOVE__(sint_type_name);}
    if ((value < INT16_MIN) || (value > INT16_MAX)) {__REMOVE__( int_type_name);}
    if ((value < INT32_MIN) || (value > INT32_MAX)) {__REMOVE__(dint_type_name);}
    if (IS_OVERFLOW( int64, symbol))                {__REMOVE__(lint_type_name);}
  }
    
  {/* Remove floating point data types */
    real64_t value = 0;
    if (VALID_CVALUE( real64, symbol)) value = GET_CVALUE(real64, symbol);
    if (IS_OVERFLOW ( real64, symbol)) value = (real64_t)REAL32_MAX + (real64_t)1;
    if (value >  REAL32_MAX )         {__REMOVE__( real_type_name);}
    if (value < -REAL32_MAX )         {__REMOVE__( real_type_name);}
    if (IS_OVERFLOW( real64, symbol)) {__REMOVE__(lreal_type_name);}
  }
  #undef __REMOVE__
}

void *print_datatypes_error_c::visit( ADD_operator_c *symbol) {return print_binary_operator_errors("ADD" , symbol, symbol->deprecated_operation);}

int search_in_candidate_datatype_list(symbol_c *datatype, const std::vector <symbol_c *> &candidate_datatypes) {
	if (NULL == datatype) 
		return -1;

	for(unsigned int i = 0; i < candidate_datatypes.size(); i++)
		if (get_datatype_info_c::is_type_equal(datatype, candidate_datatypes[i]))
			return i;
	/* Not found ! */
	return -1;
}

目前支持的变量类型

/* the types of variables that need to be processed... */
static const unsigned int none_vt	  = 0x0000;
static const unsigned int input_vt	  = 0x0001;  // VAR_INPUT
static const unsigned int output_vt	  = 0x0002;  // VAR_OUTPUT
static const unsigned int inoutput_vt = 0x0004;  // VAR_IN_OUT
static const unsigned int private_vt  = 0x0008;  // VAR
static const unsigned int temp_vt	  = 0x0010;  // VAR_TEMP
static const unsigned int external_vt = 0x0020;  // VAR_EXTERNAL
static const unsigned int global_vt   = 0x0040;  // VAR_GLOBAL
                                                 //    Globals declared inside a resource will not be declared
                                                 //    unless global_vt is acompanied by resource_vt
static const unsigned int located_vt  = 0x0080;  // VAR <var_name> AT <location>
static const unsigned int program_vt  = 0x0100;  // PROGRAM (inside a configuration!)
                                                 //    Programs declared inside a resource will not be declared
                                                 //    unless program_vt is acompanied by resource_vt
static const unsigned int en_vt       = 0x0200;  // EN  declaration
static const unsigned int eno_vt      = 0x0400;  // ENO declaration
static const unsigned int resource_vt = 0x8000;  // RESOURCE (inside a configuration!)
                                                 //    This, just of itself, will not print out any declarations!!
                                                 //    It must be acompanied by either program_vt and/or global_vt

/* the qualifier of variables that need to be processed... */
static const unsigned int none_vq        = 0x0000;
static const unsigned int constant_vq    = 0x0001;  // CONSTANT
static const unsigned int retain_vq      = 0x0002;  // RETAIN
static const unsigned int non_retain_vq  = 0x0004;  // NON_RETAIN

目前支持的变量格式

typedef enum {finterface_vf,
              foutputassign_vf,
              local_vf,
              localinit_vf,
              init_vf,
              constructorinit_vf,
              globalinit_vf,
              globalprototype_vf
             } varformat_t;

IEC 61131-3数据类型结构

image.pngimage.png

image.png