Jierは、IEC 61131-3テキストをそのままインタプリタ実行できるツールです。PLCへ書き込まずに手元のPCでIEC 61131-3プログラムの動作を確認できます。
Jieccの--runオプション(jiecc --run)として呼び出します。
Windows 7以降、およびLinux(WSL) Ubuntu 22.04.5 LTS以降の64bit OSにて動作するコマンドライン版があります。
Jieccのダウンロードページからjiecc.zip(Windows)またはjiecc.tgz(Linux)をダウンロードすると、jiecc.exe(またはjiecc)が含まれています。--runオプションでJierを呼び出せます。
IEC 61131-3テキストファイルを実行するには、次の形式でコマンドを入力します。
$ jiecc.exe --run <入力IEC 61131-3テキストファイルパス>
例えば、次のIEC 61131-3テキストファイルを実行すると:
program __main__
var
str : string;
end_var
{st}
str := 'Hello, world!';
{end}
end_program
$ jiecc.exe --run .\hello.txt --verbose
cycle 0: {en: True, eno: True, str: 'Hello, world!'}
--- Interpreter stopped after 1 cycles ---
デフォルトでは変数状態の出力は行われません。--verboseオプションを指定すると、スキャンサイクルごとに cycle N: {変数名: 値, ...} の形式で変数の状態が出力されます。
program __main__ はデフォルトで 1 スキャンサイクルのみ実行して終了します(詳細は後述)。
jiecc.exe --versionで、バージョンを確認できます。
Jierには、IEC 61131-3プログラムの書き方に応じて2つの実行モードがあります。
configurationブロックを書かず、program __main__という名前のプログラムPOUを定義すると、1スキャンサイクルだけ実行して終了します。手軽に動作を確認したい場合に使用します。
// counter.txt
program __main__
var
count : dint := 0;
end_var
{st}
count := count + 1;
{end}
end_program
$ jiecc.exe --run .\counter.txt --verbose
cycle 0: {en: True, eno: True, count: 1}
--- Interpreter stopped after 1 cycles ---
出力に含まれる en(enable 入力)・eno(enable 出力)は、IEC 61131-3規格のPOUが持つ標準変数です。--verboseを省略した場合、変数状態は出力されません。
configurationブロックでリソース・タスク・プログラムインスタンスを定義すると、タスクのintervalで指定した周期でスキャンサイクルが繰り返し実行されます。Ctrl+Cで停止します。
var_globalを使うと、複数のプログラム間でデータを共有できます。
// scan_counter.txt
program Counter
var_external
g_count : dint;
end_var
{st}
g_count := g_count + 1;
{end}
end_program
configuration MainConfig
resource MainRes on plc
var_global
g_count : dint;
end_var
task tsk(interval := t#100ms, priority := 1);
program counter_prog with tsk: Counter();
end_resource
end_configuration
$ jiecc.exe --run .\scan_counter.txt --verbose
cycle 0: {g_count: 1, en: True, eno: True}
cycle 1: {g_count: 2, en: True, eno: True}
cycle 2: {g_count: 3, en: True, eno: True}
...
^C
--- Interpreter stopped after 3 cycles ---
--verbose使用時のスキャンサイクル出力には、var_globalで宣言したグローバル変数と、最後に登録されたプログラムインスタンスのローカル変数が含まれます。
以下に、2つのプログラムがグローバル変数を共有する例を示します。
// producer_consumer.txt
program Producer
var_external
shared : dint;
end_var
{st}
shared := shared + 10;
{end}
end_program
program Consumer
var
observed : dint;
end_var
var_external
shared : dint;
end_var
{st}
observed := shared;
{end}
end_program
configuration MainConfig
resource MainRes on plc
var_global
shared : dint;
end_var
task tsk(interval := t#100ms, priority := 1);
program producer_prog with tsk: Producer();
program consumer_prog with tsk: Consumer();
end_resource
end_configuration
$ jiecc.exe --run .\producer_consumer.txt --verbose
cycle 0: {shared: 10, en: True, eno: True, observed: 10}
cycle 1: {shared: 20, en: True, eno: True, observed: 20}
cycle 2: {shared: 30, en: True, eno: True, observed: 30}
...
^C
--- Interpreter stopped after 3 cycles ---
shared を Consumer が読み取る(--verbose 指定時)--verboseを指定すると、スキャンサイクルごとに変数の状態(cycle N: {...})と実行サマリー(--- Interpreter stopped after N cycles ---)を標準出力(stdout)に出力します。デフォルトはoffです。
$ jiecc.exe --run .\counter.txt --verbose
cycle 0: {en: True, eno: True, count: 1}
--- Interpreter stopped after 1 cycles ---
出力形式は cycle N: {変数名: 値, ...} です。STRING型変数はIEC 61131-3の$エスケープ形式でシングルクォートで表示されます(例: 'Hello$NWorld')。
--traceオプションは引数なしまたはPOU名を指定して使用します。
jiecc --run hello.txt --trace # 全PROGRAMをトレース jiecc --run hello.txt --trace main # 'main' POU のみトレース
フィルタの一致対象: POU名のみ(大文字小文字を区別しない)。フィルタに一致するPROGRAMの各トップレベルステートメントが実行されるたびに、ステートメントの種類と結果をstderrに出力します。同一POUを複数インスタンス化した場合、全インスタンスがまとめてトレースされます(TRACE注入はPOU定義体レベルで行われるため)。フィルタが存在するPOUに一致しない場合はエラー終了します(終了コード 1)。
次のプログラムを例に説明します。
// trace_demo.txt
program __main__
var
count : dint;
end_var
{st}
count := count + 1;
count;
puts(dint_to_string(count));
{end}
end_program
$ jiecc.exe --run .\trace_demo.txt --trace
標準出力(stdout):
1
トレースログ(stderr):
[TRACE cy=0 prog=__main__] ASSIGN -> NIL [TRACE cy=0 prog=__main__] PLACE -> 1 [TRACE cy=0 prog=__main__] POUCALL -> True
ステートメント種別と結果値の読み方:
ASSIGN -> NIL: 代入文(:=)は IEC 61131-3 の「文」であり値を生成しません。結果は常に NIL になります。PLACE -> 1: 変数名だけの文(count;)は変数の現在値を返します。デバッグ用途で変数の値をトレースに記録したいときに便利です。POUCALL -> True: FUNCTION 呼び出しを文として使った場合、その戻り値が -> の右に表示されます。puts は BOOL 型(常に TRUE)を返すため True が表示されます。IF / FOR / WHILE などの制御フロー文も値を持たないため NIL になります。トレース行の形式は次の通りです。
[TRACE cy=<サイクル番号> prog=<プログラム名>] <ステートメント種別> -> <結果値>
--watchオプションに監視するVAR_GLOBAL変数名をカンマ区切りで指定すると、その変数への書き込みが発生したサイクルをstderrに出力します。*を指定するとリソース内の全VAR_GLOBALを一括監視します。
jiecc --run hello.txt --watch g_count # 特定の変数を監視 jiecc --run hello.txt --watch g_count,g_status # 複数の変数をカンマ区切りで指定 jiecc --run hello.txt --watch * # 全VAR_GLOBALを監視
スキャンサイクル出力(stdout)の例(--verbose併用時):
cycle 0: {g_count: 1, en: True, eno: True}
cycle 1: {g_count: 2, en: True, eno: True}
cycle 2: {g_count: 3, en: True, eno: True}
--- Interpreter stopped after 3 cycles ---
watchログ(stderr)の例(--watch g_count 指定時):
[WATCH cy=0 global] g_count: 0 -> 1 [WATCH cy=1 global] g_count: 1 -> 2 [WATCH cy=2 global] g_count: 2 -> 3
watch行の形式は次の通りです。
[WATCH cy=<サイクル番号> global] <変数名>: <変更前の値> -> <変更後の値>
--watchで監視できるのはVAR_GLOBAL(CONFIGURATIONのvar_global)のスカラ変数のみです。プログラムローカル変数・配列要素・構造体フィールドへの書き込みは監視対象外です。なお、発火条件は値の変化ではなく書き込み発生時です(同値再代入でも出力されます)。
putsはIEC 61131-3プログラム内からデバッグ出力を行う組み込み関数です。stdpouに自動的に含まれているため、宣言なしで使用できます。
program __main__
var
counter : dint := 0;
end_var
{st}
counter := counter + 1;
puts(dint_to_string(counter));
puts('loop done');
{end}
end_program
$ jiecc.exe --run .\example.txt 1 loop done
出力先は標準出力(stdout)です。サイクル出力(cycle N: {...})より先に書き出されます。戻り値はbool型(常にTRUE)。
{foreign})Jierは{foreign 'モジュール.クラス名'}プラグマを使って、Pythonで実装したクラスをPOUとして使用できます。これにより、テスト用モック・アルゴリズムの段階的実装・既存Pythonライブラリの活用が可能です。
Pythonで実装するクラスのインタフェースは次の通りです。
# my_pou.py
class Multiply:
"""FUNCTION の Python 実装例(無状態)"""
def execute(self, a, b):
return a * b
class Accumulator:
"""FUNCTION_BLOCK の Python 実装例(有状態)"""
def __init__(self):
self._total = 0
def execute(self, add_val, reset):
if reset:
self._total = 0
self._total += add_val
return {'total': self._total}
// IEC 側の宣言
function {foreign 'my_pou.Multiply'} Multiply : dint
var_input
a : dint;
b : dint;
end_var
end_function
function_block {foreign 'my_pou.Accumulator'} Accumulator
var_input
add_val : dint;
reset : bool;
end_var
var_output
total : dint;
end_var
end_function_block
FUNCTIONの場合はexecute()がスカラ値を返し、FUNCTION_BLOCKの場合は出力変数名をキーとするdictを返します。インスタンスの状態(インスタンス変数)は自動的に保持されるため、FBのスキャンサイクル間でデータを維持できます。
セキュリティ上の注意: {foreign}は任意のPythonモジュールを読み込んで実行します。信頼できるソースのSTプログラムのみを実行してください。
Jierはjiecc --runとして呼び出します。--runに加えて、プリプロセス関連オプション(-D、-I、-E等)やその他のオプションが使用できます。オプションの詳細はJieccのオプション一覧を参照してください。
| オプション | 説明 |
|---|---|
--max-cycles N |
最大スキャンサイクル数を指定します。program __main__使用時のデフォルトは1、CONFIGURATIONあり時のデフォルトはCtrl+Cで停止するまで無制限です。 |
--trace [FILTER] |
PROGRAMのステートメントが実行されるたびに [TRACE] 行をstderrに出力します。FILTERを省略すると全PROGRAMが対象。FILTERにはPOU名(同一POUの全インスタンスがまとめてトレースされます)を指定できます。一致するPOUが存在しない場合はエラー終了します。 |
--watch VAR,... |
監視するVAR_GLOBAL変数名をカンマ区切りで指定します。変数への書き込み時に [WATCH] 行としてstderrに出力します。* を指定するとリソース内の全VAR_GLOBALを一括監視します。 |
--ir-audit warn|fail |
IRコントラクト検査モードを指定します。warn(デフォルト): 違反をstderrに警告して実行継続。fail: 違反で例外を発生させます。 |
--strict-ir |
--ir-audit=failのエイリアスです。 |
--verbose |
各スキャンサイクルの変数状態ダンプ(cycle N: {...})と実行サマリーを標準出力に表示します。デフォルトはoffです。 |
Jier 7.1.0のオプション一覧は以下の通りです。
usage: jier.py [-h] [--version] [--output OUTPUT] [--define-macro DEFINE_MACRO] [--syspath SYSPATH] [--target TARGET] [--line-separator LINE_SEPARATOR]
[--retro_caps] [--max-include-depth MAX_INCLUDE_DEPTH] [--max-expansion-depth MAX_EXPANSION_DEPTH] [--max-if-nesting MAX_IF_NESTING]
[--recursion-limit RECURSION_LIMIT] [--preprocess-only] [--max-cycles MAX_CYCLES] [--trace [FILTER]] [--watch WATCH] [--ir-audit {warn,fail}]
[--strict-ir] [--verbose] [--pp-output-pragma-style PP_OUTPUT_PRAGMA_STYLE] [--remove-comments] [-dM] [-dD] [--silent]
[--undefine-macro UNDEFINE_MACRO] [-include FORCE_INCLUDE] [-w] [-Werror] [-P] [-M] [-MM] [-MD] [-MMD] [-MF MF] [-MT MT] [--set SET]
[filepath ...]
Jier is an IEC 61131-3 interpreter.
It interprets and executes IEC 61131-3 programs in scan cycle mode.
Typical usage:
jier <IEC 61131-3 text filepath>
For additional details, visit:
https://www.graviness.com/iec_61131_3/jier.html
positional arguments:
filepath the IEC 61131-3 text file path.
options:
-h, --help show this help message and exit
--version show program's version number and exit
--output, -o OUTPUT the output file path for preprocessed output (used with -E). Default: STDOUT (outputs to standard output.)
--define-macro, -D DEFINE_MACRO
define a macro. -D <macro> to set <macro> to 1 or -D<macro>=<value> to assign a specific value. e.g. -D DEBUG, -D V=10.
--syspath, -I SYSPATH
add the directory SYSPATH to the list of directories to be searched for (s)include files.
--target, -t TARGET conversion target. e.g. OMRON, KEYENCE, MITSUBISHI, CODESYS. Default: STD.
--line-separator, -N LINE_SEPARATOR
newline code for the output. e.g. LF, CRLF, CR. Default: LF.
--retro_caps output IEC 61131-3 keywords in uppercase.
--max-include-depth MAX_INCLUDE_DEPTH
the maximum depth of the nested #include. The default is 100.
--max-expansion-depth MAX_EXPANSION_DEPTH
the maximum macro expansion depth. The default is 256.
--max-if-nesting MAX_IF_NESTING
the maximum #if/#elif nesting depth. The default is 256.
--recursion-limit RECURSION_LIMIT
the maximum recursion depth allowed by the program. Applied to both Python and jiepp.exe. The default is the system default value.
--preprocess-only, -E
preprocessed only.; do not convert.
--max-cycles MAX_CYCLES
maximum number of scan cycles to execute. Default: 1 cycle when program __main__ is defined without a configuration; unlimited (runs until Ctrl+C) otherwise.
--trace [FILTER] emit [TRACE] lines to stderr. Default: off. Without FILTER, traces all PROGRAMs. FILTER: POU name to trace (all instances of that POU are traced together), or resource name (emit [TRACE] lines for all VAR_GLOBAL changes in that resource).
--watch WATCH comma-separated list of VAR_GLOBAL/VAR_EXTERNAL variable names to watch. Use * to watch all VAR_GLOBAL in the resource. Emits a [WATCH] line to stderr when a watched variable changes.
--ir-audit {warn,fail}
IR contract audit mode. warn: report violations to stderr and continue. fail: raise exception on violations. Default: warn.
--strict-ir alias for --ir-audit=fail. Enable strict IR validation.
--verbose show cycle state dump (cycle N: {...}) and run summary. Default: off.
--pp-output-pragma-style PP_OUTPUT_PRAGMA_STYLE
The format of preprocessor output pragmas. Possible values: annotated (*{~}*) or standard {~}. Default: annotated.
--remove-comments, -nC
remove comments in preprocessed output. The default is False.
-dM generate a list of #define directives for all the macros defined during the execution of the preprocessor, including predefined macros. must be invoked with -E.
-dD emit {#define}/{#undef} directives inline in preprocessed output. must be invoked with -E.
--silent activate silent mode to suppress error messages.
--undefine-macro, -U UNDEFINE_MACRO
undefine a macro. Processed after -D (explicit undefine overrides define).
-include FORCE_INCLUDE
force-include FILE before processing input (as if #include "FILE" appeared first).
-w suppress all preprocessor warnings.
-Werror promote preprocessor warnings to errors.
-P suppress line markers in preprocessed output.
-M output Makefile dependency rules (requires -E).
-MM output Makefile dependency rules, excluding system includes (requires -E).
-MD write dependency rules to .d file; keep normal output. Mutually exclusive with -M/-MM.
-MMD like -MD but exclude system includes. Mutually exclusive with -M/-MM.
-MF MF write dependency rules to FILE (requires -M, -MM, -MD, or -MMD).
-MT MT set the target name in dependency rules (requires -M, -MM, -MD, or -MMD).
--set SET set and lock options. e.g. creation-datetime=1999-12-31T23:59:59.999+11:59.
Jierは以下の標準関数をサポートしています。関数名は大文字・小文字を区別しません(IEC 61131-3仕様に準拠)。
| 関数名 | 戻り値型 | 説明 |
|---|---|---|
concat(s1, s2, ... s16) | string | 最大16個の文字列を連結します。 |
len(IN) | dint | 文字列の文字数を返します。 |
left(IN, L) | string | 文字列の左側 L 文字を返します。 |
right(IN, L) | string | 文字列の右側 L 文字を返します。 |
mid(IN, L, P) | string | 位置 P から L 文字分の部分文字列を返します。 |
delete(IN, L, P) | string | 位置 P から L 文字削除した文字列を返します。 |
find(IN1, IN2) | dint | IN1 内で IN2 が最初に現れる位置を返します(見つからない場合は0)。 |
insert(IN1, IN2, P) | string | IN1 の位置 P に IN2 を挿入した文字列を返します。 |
replace(IN1, IN2, L, P) | string | IN1 の位置 P から L 文字を IN2 で置換した文字列を返します。 |
| 関数名 | 戻り値型 | 説明 |
|---|---|---|
abs(IN) | lreal | 絶対値 |
sqrt(IN) | lreal | 平方根 |
ln(IN) | lreal | 自然対数 |
exp(IN) | lreal | 自然指数(e^IN) |
sin(IN) | lreal | サイン(ラジアン) |
cos(IN) | lreal | コサイン(ラジアン) |
tan(IN) | lreal | タンジェント(ラジアン) |
asin(IN) | lreal | アークサイン |
acos(IN) | lreal | アークコサイン |
atan(IN) | lreal | アークタンジェント |
expt(IN, EXPONENT) | lreal | 冪乗(IN ^ EXPONENT) |
trunc(IN) | lint | 小数部を切り捨て整数化 |
min(IN1, IN2) | lreal | 最小値 |
max(IN1, IN2) | lreal | 最大値 |
| 関数名 | 戻り値型 | 説明 |
|---|---|---|
shr(IN, N) | dint | 右論理シフト |
shl(IN, N) | dint | 左論理シフト |
ror(IN, N) | dint | 右循環シフト |
rol(IN, N) | dint | 左循環シフト |
| 関数名 | 戻り値型 | 説明 |
|---|---|---|
lower_bound(IN, DIM) | dint | 配列の次元 DIM の下限インデックスを返します。 |
upper_bound(IN, DIM) | dint | 配列の次元 DIM の上限インデックスを返します。 |
| 関数名 | 戻り値型 | 説明 |
|---|---|---|
dint_to_string(IN) | string | dint を文字列に変換 |
udint_to_string(IN) | string | udint を文字列に変換 |
lint_to_string(IN) | string | lint を文字列に変換 |
ulint_to_string(IN) | string | ulint を文字列に変換 |
lreal_to_string(IN) | string | lreal を文字列に変換 |
bool_to_string(IN) | string | bool を文字列に変換 |
lword_to_string(IN) | string | lword を文字列に変換 |
dword_to_string(IN) | string | dword を文字列に変換 |
dint_to_lreal(IN) | lreal | dint を lreal に変換 |
lreal_to_dint(IN) | dint | lreal を dint に変換(切り捨て) |
dint_to_lint(IN) | lint | dint を lint に変換 |
lint_to_dint(IN) | dint | lint を dint に変換 |
bool_to_dint(IN) | dint | bool を dint に変換(false=0, true=1) |
dint_to_bool(IN) | bool | dint を bool に変換(0=false, その他=true) |
その他の型変換関数(int/sint/uint/usint/real/udint/dword/byte/word 等を含む多数のX_TO_Y関数)についても対応しています。
| 関数名 | 戻り値型 | 説明 |
|---|---|---|
time_to_usec_dint(IN) | dint | time値をマイクロ秒(dint)に変換 |
date_to_string(IN) | string | date値を文字列(YYYY-MM-DD形式)に変換 |
tod_to_string(IN) | string | time_of_day値を文字列(HH:MM:SS形式)に変換 |
dt_to_string(IN) | string | date_and_time値を文字列に変換 |
JierのIEC 61131-3言語要素のサポート状況は下表の通りです。
| 機能 | サポート状況 |
|---|---|
| ST(構造化テキスト)言語 | Yes |
| LD(ラダー図)/ FBD / SFC / IL 言語 | 未サポート |
| program / function_block / function pou | Yes |
| configuration / resource / task | Yes |
| var / var_input / var_output / var_in_out / var_temp | Yes |
| var_global(configurationのvar_global) | Yes |
| var_external | Yes |
| 基本型: 符号有り整数型; sint, int, dint, lint | Yes |
| 基本型: 符号無し整数型; usint, uint, udint, ulint | Yes |
| 基本型: 実数型; real, lreal | Yes |
| 基本型: ビット列型; byte, word, dword, lword | Yes |
| 基本型: bool | Yes |
| 基本型: string | Yes |
| 基本型: time, date, time_of_day, date_and_time, ltime | Yes |
| ユーザー定義型: struct(構造体) | Yes |
| ユーザー定義型: enum(列挙型) | Yes |
| 配列(array); 多次元・非ゼロ下限含む | Yes |
| 再帰関数(直接・相互再帰) | Yes |
| en / eno | Yes |
| 形式パラメータ呼び出し(ファンクションの名前付き引数) | Yes |
| プリプロセス機能(-D / -I / {#include} 等) | Yes |
| 物理I/Oデバイス(PLC入出力変数) | 未サポート |
| 意味解析レベルの型検査 | 限定的 |
ST言語のプログラムコードはJieccと同様に{st}〜{end}プラグマで囲んで記述します(Jieccの記述方法参照)。
Jierは物理的なPLCのI/Oポート(入力変数・出力変数のハードウェアマッピング)には対応していません。ソフトウェアロジックのみのシミュレーションを行います。