上位机已经有丰富的编程语言,所以不再需要完整的PLC功能。提供梯形图的指令是用于快速配置的。

以下是文本解释型虚拟PLC。

package pers.laserpen.util.automation.plcEmulator;

import java.io.File;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.*;

import pers.laserpen.util.awt.Tip;
import pers.laserpen.util.data.StaticDataUtils;
import pers.laserpen.util.file.FreeFileIO;
import pers.laserpen.util.java.StaticJavaUtils;
import pers.laserpen.util.math.calculator.standardCalculator.DoubleLineCalculator;
import pers.laserpen.util.math.calculator.standardCalculator.StackPriorityCalculator;
import pers.laserpen.util.math.calculator.standardCalculator.StandardCalculator;
import pers.laserpen.util.thread.AccuracyTimer;
import pers.laserpen.util.math.calculator.standardCalculator.DoubleLineCalculator.Analysor;
import pers.laserpen.util.string.RegexBuilder;
import pers.laserpen.util.string.StaticStringUtils;

public class MitsubishiPLCEmulator {

	private static final String SEPARATOR_IN_LINE = ((Supplier<String>) () -> {
		RegexBuilder regex = new RegexBuilder();
		regex.appendCharGroup(" \"\t,,\' \ufeff\0\f", false);
		return regex.toString();
	}).get();

	private static final BinaryOperator<Object> END = (u, t) -> u;
	private static final BinaryOperator<Object> CJ = (u, t) -> u;
	private static final BinaryOperator<Object> JMP = (u, t) -> u;
	private static final BinaryOperator<Object> CALL = (u, t) -> u;
	private static final BinaryOperator<Object> RET = (u, t) -> u;

	private Map<Integer, Integer> m_skipWhiteSpace = new HashMap<>();
	private Map<Integer, BinaryOperator<Object>> m_quickOperators = new HashMap<>();
	private Map<Integer, String> m_quickArgs = new HashMap<>();

	private Map<Integer, Integer> m_P = new HashMap<>();

	private Deque<Integer> m_retP = new ArrayDeque<>();
	private Deque<Object> m_retV = new ArrayDeque<>();

	private Map<Integer, Number> m_D = new HashMap<>();
	private FreeFileIO m_savedD = null;
	private int m_savedDOffset = 0;
	private Map<Integer, DigitalPackage> m_M = new HashMap<>();
	private FreeFileIO m_L = null;
	private Map<Integer, DigitalPackage> m_SM = new HashMap<>();
	private Map<Integer, DigitalPackage> m_mepOrMef = new HashMap<>();
	private Map<Integer, DigitalPackage> m_CC = new HashMap<>();
	private Map<Integer, Long> m_CN = new HashMap<>();
	private Map<Integer, Long> m_CLIMIT = new ConcurrentHashMap<>();
	private Map<Integer, DigitalPackage> m_CS = new HashMap<>();
	private Map<Integer, DigitalPackage> m_TC = new ConcurrentHashMap<>();
	private Map<Integer, Long> m_TN = new ConcurrentHashMap<>();
	private Map<Integer, Long> m_TLIMIT = new ConcurrentHashMap<>();
	private Map<Integer, DigitalPackage> m_TS = new ConcurrentHashMap<>();

	private AccuracyTimer m_timer = new AccuracyTimer();
	private Deque<Object> m_blockLogicStack = new ArrayDeque<>();
	private Deque<Object> m_mpsCommandStack = new ArrayDeque<>();

	private StackPriorityCalculator<Object> m_stackCalc = new StackPriorityCalculator<>(null);
	private List<Analysor<Object>> m_analysors = new ArrayList<>();
	private DoubleLineCalculator<Object> m_calc = new DoubleLineCalculator<>(m_stackCalc, m_analysors);

	private int m_lineNumber = 0;

	protected boolean m_operatorSetted = false;

	public MitsubishiPLCEmulator(long tickTime) {
		if (tickTime <= 0) {
			StaticJavaUtils.exit("不支持负的延时");
		}
		m_timer.setTask(ct -> {
			boolean doSth = false;
			for (Entry<Integer, DigitalPackage> entry : m_TC.entrySet()) {
				long tn = getTN(entry.getKey());
				long tlim = getTLim(entry.getKey());
				if (tn >= tlim) {
					continue;
				}
				setTN(entry.getKey(), tn + 1);
				doSth = true;
			}
			if (doSth) {
				return tickTime;
			} else {
				return 0;
			}
		});
		setSM(400, true);
		setSM(401, false);
		setM(8000, true);
		setM(8001, false);
		addOperators();
	}

	private void addOperators() {
		addOperator("LDP", (last, key) -> {
			if (last != null) {
				m_blockLogicStack.push(last);
			}
			return toDigitalP(key);
		});
		addOperator("LDPI", (last, key) -> {
			if (last != null) {
				m_blockLogicStack.push(last);
			}
			return toDigitalPI(key);
		});
		addOperator("LDF", (last, key) -> {
			if (last != null) {
				m_blockLogicStack.push(last);
			}
			return toDigitalF(key);
		});
		addOperator("LDFI", (last, key) -> {
			if (last != null) {
				m_blockLogicStack.push(last);
			}
			return toDigitalFI(key);
		});
		addOperator("LDI", (last, key) -> {
			if (last != null) {
				m_blockLogicStack.push(last);
			}
			return toDigitalI(key);
		});
		addOperator("LD", (last, key) -> {
			if (last != null) {
				m_blockLogicStack.push(last);
			}
			return toDigital(key);
		});
		addOperator("LD>", (a, b) -> {
			if (a != null) {
				m_blockLogicStack.push(a);
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			return n1.doubleValue() > n2.doubleValue();
		});
		addOperator("LD>=", (a, b) -> {
			if (a != null) {
				m_blockLogicStack.push(a);
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			return n1.doubleValue() >= n2.doubleValue();
		});
		addOperator("LD<", (a, b) -> {
			if (a != null) {
				m_blockLogicStack.push(a);
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			return n1.doubleValue() < n2.doubleValue();
		});
		addOperator("LD<=", (a, b) -> {
			if (a != null) {
				m_blockLogicStack.push(a);
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			return n1.doubleValue() <= n2.doubleValue();
		});
		addOperator("LD<>", (a, b) -> {
			if (a != null) {
				m_blockLogicStack.push(a);
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			return n1.doubleValue() != n2.doubleValue();
		});
		addOperator("LD=", (a, b) -> {
			if (a != null) {
				m_blockLogicStack.push(a);
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			return n1.doubleValue() == n2.doubleValue();
		});
		addOperator("OUT", (a, b) -> {
			m_blockLogicStack.clear();
			String to = b.toString();
			to = to.toUpperCase();
			String[] args = to.split(SEPARATOR_IN_LINE);
			int index = Integer.parseInt(args[0].substring(1));

			if (to.startsWith("M")) {
				setM(index, (Boolean) a);
			} else if (to.startsWith("T")) {
				if (args.length < 2) {
					Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
				}
				setTLim(index, toNumber(args[1]).intValue());
				setTC(index, (Boolean) a);
			} else if (to.startsWith("C")) {
				if (args.length < 2) {
					Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
				}
				setCLim(index, toNumber(args[1]).intValue());
				setCC(index, (Boolean) a);
			} else if (to.startsWith("L")) {
				setL(index, (Boolean) a);
			}
			return a;
		});
		addOperator("AND", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigital(b);
			return b1 && b2;
		});
		addOperator("ANI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalI(b);
			return b1 && b2;
		});
		addOperator("ANDP", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalP(b);
			return b1 && b2;
		});
		addOperator("ANDPI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalPI(b);
			return b1 && b2;
		});
		addOperator("ANDF", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalF(b);
			return b1 && b2;
		});
		addOperator("ANDFI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalFI(b);
			return b1 && b2;
		});
		addOperator("AND<", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (!b1) {
				return false;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() < n2.doubleValue();
			return b1 && b2;
		});
		addOperator("AND<=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (!b1) {
				return false;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() <= n2.doubleValue();
			return b1 && b2;
		});
		addOperator("AND>", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (!b1) {
				return false;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() > n2.doubleValue();
			return b1 && b2;
		});
		addOperator("AND>=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (!b1) {
				return false;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() >= n2.doubleValue();
			return b1 && b2;
		});
		addOperator("AND<>", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (!b1) {
				return false;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() != n2.doubleValue();
			return b1 && b2;
		});
		addOperator("AND=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (!b1) {
				return false;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() == n2.doubleValue();
			return b1 && b2;
		});
		addOperator("OR", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigital(b);
			return b1 || b2;
		});
		addOperator("ORI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalI(b);
			return b1 || b2;
		});
		addOperator("ORP", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalP(b);
			return b1 || b2;
		});
		addOperator("ORPI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalPI(b);
			return b1 || b2;
		});
		addOperator("ORF", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalF(b);
			return b1 || b2;
		});
		addOperator("ORFI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalFI(b);
			return b1 || b2;
		});
		addOperator("OR<", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (b1) {
				return true;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() < n2.doubleValue();
			return b1 || b2;
		});
		addOperator("OR<=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (b1) {
				return true;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() <= n2.doubleValue();
			return b1 || b2;
		});
		addOperator("OR>", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (b1) {
				return true;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() > n2.doubleValue();
			return b1 || b2;
		});
		addOperator("OR>=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (b1) {
				return true;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() >= n2.doubleValue();
			return b1 || b2;
		});
		addOperator("OR<>", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (b1) {
				return true;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() != n2.doubleValue();
			return b1 || b2;
		});
		addOperator("OR=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			if (b1) {
				return true;
			}
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() == n2.doubleValue();
			return b1 || b2;
		});
		addOperator("XOR", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigital(b);
			return b1 != b2;
		});
		addOperator("XORI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalI(b);
			return b1 != b2;
		});
		addOperator("XORP", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalP(b);
			return b1 != b2;
		});
		addOperator("XORPI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalPI(b);
			return b1 != b2;
		});
		addOperator("XORF", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalF(b);
			return b1 != b2;
		});
		addOperator("XORFI", (a, b) -> {
			boolean b1 = toDigital(a), b2 = toDigitalFI(b);
			return b1 != b2;
		});
		addOperator("XOR<", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() < n2.doubleValue();
			return b1 != b2;
		});
		addOperator("XOR<=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() <= n2.doubleValue();
			return b1 != b2;
		});
		addOperator("XOR>", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() > n2.doubleValue();
			return b1 != b2;
		});
		addOperator("XOR>=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() >= n2.doubleValue();
			return b1 != b2;
		});
		addOperator("XOR<>", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() != n2.doubleValue();
			return b1 != b2;
		});
		addOperator("XOR=", (a, b) -> {
			boolean b1 = toDigital(a), b2;
			String[] args = b.toString().split(SEPARATOR_IN_LINE);
			if (args.length < 2) {
				Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
			}
			Number n1 = toNumber(args[0]);
			Number n2 = toNumber(args[1]);
			b2 = n1.doubleValue() == n2.doubleValue();
			return b1 != b2;
		});
		addOperator("ANB", (a, b) -> {
			boolean b1 = toDigital(a), b2 = (boolean) m_blockLogicStack.pop();
			return b1 && b2;
		});
		addOperator("ORB", (a, b) -> {
			boolean b1 = toDigital(a), b2 = (boolean) m_blockLogicStack.pop();
			return b1 || b2;
		});
		addOperator("XORB", (a, b) -> {
			boolean b1 = toDigital(a), b2 = (boolean) m_blockLogicStack.pop();
			return b1 != b2;
		});
		addOperator("MPS", (a, b) -> {
			m_mpsCommandStack.push(a);
			return a;
		});
		addOperator("MPP", (a, b) -> {
			return m_mpsCommandStack.pop();
		});
		addOperator("MPD", (a, b) -> {
			return m_mpsCommandStack.peek();
		});
		addOperator("INV", (a, b) -> {
			return !(boolean) a;
		});
		addOperator("SET", (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String to = b.toString();
				to = to.toUpperCase();
				int index = Integer.parseInt(to.substring(1));
				if (to.startsWith("M")) {
					setM(index, true);
				} else if (to.startsWith("L")) {
					setL(index, true);
				}
			}
			return a;
		});
		addOperator("RST", (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String to = b.toString();
				to = to.toUpperCase();
				int index = Integer.parseInt(to.substring(1));
				if (to.startsWith("M")) {
					setM(index, false);
				} else if (to.startsWith("L")) {
					setL(index, false);
				} else {
					setNumber(to, 0, 0);
				}
			}
			return a;
		});
		addOperator("MOV", (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				if (args.length < 2) {
					Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
				}
				Number value = toNumber(args[0]);
				setNumber(args[1], 0, value);
			}
			return a;
		});
		addOperator("WAND", (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				if (args.length < 3) {
					Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
				}
				Number addition1 = toNumber(args[0]);
				Number addition2 = toNumber(args[1]);
				Number ans = addition1.longValue() & addition2.longValue();
				setNumber(args[2], 0, ans);
			}
			return a;
		});
		addOperator("WOR", (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				if (args.length < 3) {
					Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
				}
				Number addition1 = toNumber(args[0]);
				Number addition2 = toNumber(args[1]);
				Number ans = addition1.longValue() | addition2.longValue();
				setNumber(args[2], 0, ans);
			}
			return a;
		});
		addOperator("WXOR", (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				if (args.length < 3) {
					Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
				}
				Number addition1 = toNumber(args[0]);
				Number addition2 = toNumber(args[1]);
				Number ans = addition1.longValue() ^ addition2.longValue();
				setNumber(args[2], 0, ans);
			}
			return a;
		});
		addOperator("CML", (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				if (args.length < 2) {
					Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
				}
				Number addition1 = toNumber(args[0]);
				Number ans = ~addition1.longValue();
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("NEG", (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				if (args.length < 1) {
					Tip.defaultTip("参数数量错误,检查操作数的数量(" + m_lineNumber + ")");
				}
				Number num = toNumber(args[0]);
				setNumber(args[0], 0, -num.doubleValue());
			}
			return a;
		});
		BinaryOperator<Object> ADD = (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				Number addition1 = toNumber(args[0]);
				Number addition2 = toNumber(args[1]);
				Number ans = addition1.doubleValue() + addition2.doubleValue();
				setNumber(args.length == 2 ? args[1] : args[2], 0, ans);
			}
			return a;
		};
		addOperator("ADD", ADD);
		addOperator("+", ADD);
		BinaryOperator<Object> SUB = (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				if (args.length == 3) {
					Number addition1 = toNumber(args[0]);
					Number addition2 = toNumber(args[1]);
					Number ans = addition1.doubleValue() - addition2.doubleValue();
					setNumber(args[2], 0, ans);
				} else if (args.length == 2) {
					Number addition1 = toNumber(args[1]);
					Number addition2 = toNumber(args[0]);
					Number ans = addition1.doubleValue() - addition2.doubleValue();
					setNumber(args[1], 0, ans);
				}
			}
			return a;
		};
		addOperator("SUB", SUB);
		addOperator("-", SUB);
		BinaryOperator<Object> MUL = (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				Number addition1 = toNumber(args[0]);
				Number addition2 = toNumber(args[1]);
				Number ans = addition1.doubleValue() * addition2.doubleValue();
				setNumber(args.length == 2 ? args[1] : args[2], 0, ans);
			}
			return a;
		};
		addOperator("MUL", MUL);
		addOperator("*", MUL);
		BinaryOperator<Object> DIV = (a, b) -> {
			m_blockLogicStack.clear();
			if (toDigital(a)) {
				String[] args = b.toString().toUpperCase().split(SEPARATOR_IN_LINE);
				if (args.length == 3) {
					Number addition1 = toNumber(args[0]);
					Number addition2 = toNumber(args[1]);
					Number ans = addition1.doubleValue() / addition2.doubleValue();
					Number ans1 = addition1.doubleValue() % addition2.doubleValue();
					setNumber(args[2], 0, ans);
					setNumber(args[2], 1, ans1);
				} else if (args.length == 2) {
					Number addition1 = toNumber(args[1]);
					Number addition2 = toNumber(args[0]);
					Number ans = addition1.doubleValue() / addition2.doubleValue();
					Number ans1 = addition1.doubleValue() % addition2.doubleValue();
					setNumber(args[1], 0, ans);
					setNumber(args[1], 1, ans1);
				}
			}
			return a;
		};
		addOperator("DIV", DIV);
		addOperator("/", DIV);
		addOperator("SIN", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.sin(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("COS", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.cos(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("TAN", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.tan(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("ASIN", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.asin(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("ACOS", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.acos(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("ATAN", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.atan(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("EXP", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.exp(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("LOG", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.log(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("LOG10", (a, b) -> {
			if (toDigital(a)) {
				String[] args = b.toString().split(SEPARATOR_IN_LINE);
				Number x = toNumber(args[0]);
				double ans = Math.log10(x.doubleValue());
				setNumber(args[1], 0, ans);
			}
			return a;
		});
		addOperator("P", (a, b) -> {
			return a;
		});
		addJUMP("CJ", CJ, true, false);
		addJUMP("JMP", JMP, false, false);
		addJUMP("CALL", CALL, true, true);
		addRET();
		addEnd();
		addMep();
		addMef();
		addQuickOperator();

		Collections.sort(m_analysors, (a, b) -> {
			String s1 = a.toString();
			String s2 = b.toString();
			int comp = s2.length() - s1.length();
			if (comp != 0) {
				return comp;
			}
			return s2.compareTo(s1);
		});

		addOperationNum();

		System.out.println(m_analysors);
	}

	private void addQuickOperator() {
		Analysor<Object> analysor = new Analysor<Object>() {
			@Override
			public String toString() {
				return "QUICK OPERATOR";
			}

			@Override
			public int analyse(StandardCalculator<Object> calculator, String command, int offset) {
				BinaryOperator<Object> quickOper = m_quickOperators.get(offset);
				if (quickOper == null) {
					return SKIP;
				} else if (quickOper == CJ) {
					calculator.calculate();
					if (!(boolean) calculator.getValue()) {
						return readToEndAndSkipNextLineBlankChars(offset, command, null);
					} else {
						Integer jumpTo = m_P.get(offset);
						if (jumpTo == null) {
							return SKIP;
						} else {
							return jumpTo;
						}
					}
				} else if (quickOper == JMP) {
					Integer jumpTo = m_P.get(offset);
					if (jumpTo == null) {
						return SKIP;
					} else {
						return jumpTo;
					}
				} else if (quickOper == CALL) {
					calculator.calculate();
					if (!(boolean) calculator.getValue()) {
						return readToEndAndSkipNextLineBlankChars(offset, command, null);
					} else {
						m_retV.push(calculator.getValue());
						m_retP.push(offset);
						Integer jumpTo = m_P.get(offset);
						if (jumpTo == null) {
							return SKIP;
						} else {
							return jumpTo;
						}
					}
				} else if (quickOper == RET) {
					Integer retP = m_retP.pop();
					Object retV = m_retV.pop();
					calculator.calculate();
					calculator.setValue(retV);
					retP = readToEndAndSkipNextLineBlankChars(retP, command, null);
					return retP;
				} else if (quickOper == END) {
					return OVER;
				}
				calculator.binaryOperate(0, quickOper);
				String quickArgs = m_quickArgs.get(offset);
				if (quickArgs != null) {
					calculator.setValue(quickArgs);
					return readToEndAndSkipNextLineBlankChars(offset, command, null);
				}
				{
					final String cmd = quickOper.toString();
					m_operatorSetted = true;
					int i = offset + cmd.length();
					// 跳过分隔符
					i = skipBlankChars(i, command);
					++m_lineNumber;
					if (!m_operatorSetted) {
						return -1;
					}
					m_operatorSetted = false;
					// 读取到换行
					String[] sb = new String[1];
					i = readToEndAndSkipNextLineBlankChars(i, command, sb);
					calculator.setValue(sb[0]);
					m_quickArgs.put(offset, sb[0]);
					return i;
				}
			}
		};
		m_analysors.add(analysor);
	}

	private void addMef() {
		addMepOrMef("MEF", false);
	}

	private void addMep() {
		addMepOrMef("MEP", true);
	}

	private void addMepOrMef(String cmd, boolean isUp) {
		Analysor<Object> analysor = new Analysor<Object>() {
			@Override
			public String toString() {
				return cmd;
			}

			@Override
			public int analyse(StandardCalculator<Object> calculator, String command, int offset) {
				if (!command.startsWith(cmd, offset)) {
					return SKIP;
				}

				BinaryOperator<Object> operator = new BinaryOperator<Object>() {
					@Override
					public String toString() {
						return cmd;
					}

					public Object apply(Object a, Object b) {
						DigitalPackage mepOrMef = m_mepOrMef.get(offset);
						if (mepOrMef == null) {
							mepOrMef = new DigitalPackage();
							m_mepOrMef.put(offset, mepOrMef);
						}
						mepOrMef.transfer();
						mepOrMef.set(toDigital(a));
						if (isUp) {
							return mepOrMef.isUp();
						} else {
							return mepOrMef.isDown();
						}
					}
				};

				m_quickOperators.put(offset, operator);

				calculator.binaryOperate(0, operator);

				int i = offset + cmd.length();
				i = readToEndAndSkipNextLineBlankChars(i, command, null);
				return i;
			}
		};
		m_analysors.add(analysor);
	}

	private void addEnd() {
		Analysor<Object> analysor = new Analysor<Object>() {
			@Override
			public String toString() {
				return "END";
			}

			@Override
			public int analyse(StandardCalculator<Object> calculator, String command, int offset) {
				if (command.startsWith("END", offset)) {
					m_quickOperators.put(offset, END);
					return OVER;
				} else {
					return SKIP;
				}
			}
		};
		m_analysors.add(analysor);
	}

	private void addRET() {
		Analysor<Object> analysor = new Analysor<Object>() {
			@Override
			public String toString() {
				return "RET";
			}

			@Override
			public int analyse(StandardCalculator<Object> calculator, String command, int offset) {
				if (!command.startsWith("RET", offset)) {
					return SKIP;
				}

				m_quickOperators.put(offset, RET);

				Integer retP = m_retP.pop();
				Object retV = m_retV.pop();
				calculator.calculate();
				calculator.setValue(retV);
				retP = readToEndAndSkipNextLineBlankChars(retP, command, null);
				return retP;
			}
		};
		m_analysors.add(analysor);
	}

	private void addJUMP(String name, BinaryOperator<Object> operator, boolean conditional, boolean isCall) {
		Analysor<Object> analysor = new Analysor<Object>() {
			@Override
			public String toString() {
				return name;
			}

			@Override
			public int analyse(StandardCalculator<Object> calculator, String command, int offset) {
				if (!command.startsWith(name, offset)) {
					return SKIP;
				}

				m_quickOperators.put(offset, operator);

				m_blockLogicStack.clear();

				calculator.calculate();
				if (conditional && !(boolean) calculator.getValue()) {
					return readToEndAndSkipNextLineBlankChars(offset, command, null);
				}

				if (isCall) {
					m_retV.push(calculator.getValue());
					m_retP.push(offset);
				}

				Integer idx = m_P.get(offset);
				if (idx != null) {
					return idx;
				}

				int i = offset + name.length();

				i = skipBlankChars(i, command);
				String[] pLabelBuilder = new String[1];
				i = readToEndAndSkipNextLineBlankChars(i, command, pLabelBuilder);

				String pLabel = pLabelBuilder[0];
				idx = -1;
				for (;;) {
					idx = command.indexOf(pLabel, idx + 1);
					if (idx == 0) {
						break;
					}
					char c = command.charAt(idx - 2);
					if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z') {
						break;
					}
				}
				m_P.put(offset, idx);
				return idx;
			}
		};
		m_analysors.add(analysor);
	}

	/**
	 * 设置锁存器文件路径
	 * 
	 * @param file
	 *             锁存文件
	 */
	public void setLockedMiddleRelayFile(File file) {
		m_L = new FreeFileIO(file);
		m_L.setLittleEndianAccodingToNative();
	}

	/**
	 * 设置锁存寄存器文件路径
	 * 
	 * @param file
	 *               锁存文件
	 * @param offset
	 *               第一个锁存的寄存器地址
	 */
	public void setSavedDigister(File file, int offset) {
		m_savedD = new FreeFileIO(file);
		m_L.setLittleEndianAccodingToNative();
		m_savedDOffset = offset;
	}

	public void setD(int key, Number value) {
		if (key < m_savedDOffset) {
			m_D.put(key, value);
		} else {
			if (m_savedD == null) {
				StaticJavaUtils.exit("没有配置用于保存D点的文件");
			}
			m_savedD.writeDouble((key - m_savedDOffset) * Double.BYTES, value.doubleValue());
		}
	}

	public Number getD(int key) {
		if (key < m_savedDOffset) {
			return m_D.getOrDefault(key, 0);
		} else {
			if (m_savedD == null) {
				StaticJavaUtils.exit("没有配置用于保存D点的文件");
			}
			return m_savedD.readDouble((key - m_savedDOffset) * Double.BYTES);
		}
	}

	private void setKM(int k, int key, long value) {
		for (int i = 0; i < k * 4; ++i) {
			setM(key + i, StaticDataUtils.getBit(value, i));
		}
	}

	private long getKM(int k, int key) {
		long value = 0;
		for (int i = 0; i < k * 4; ++i) {
			value = StaticDataUtils.setBit(value, i, getM(key + i));
		}
		return value;
	}

	public void setM(int key, boolean value) {
		DigitalPackage pkg = m_M.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_M.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	public boolean getM(int key) {
		return m_M.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setKL(int k, int key, long value) {
		for (int i = 0; i < k * 4; ++i) {
			setL(key + i, StaticDataUtils.getBit(value, i));
		}
	}

	private long getKL(int k, int key) {
		long value = 0;
		for (int i = 0; i < k * 4; ++i) {
			value = StaticDataUtils.setBit(value, i, getL(key + i));
		}
		return value;
	}

	private void setL(int key, boolean value) {
		if (m_L == null) {
			StaticJavaUtils.exit("没有配置用于保存L点的文件");
		}
		key *= 2;
		boolean lastBit = m_L.readBit(key / 8, key % 8);
		m_L.writeBit(key / 8, key % 8 + 1, lastBit);
		m_L.writeBit(key / 8, key % 8, value);
	}

	private boolean getL(int key) {
		if (m_L == null) {
			StaticJavaUtils.exit("没有配置用于保存L点的文件");
		}
		key *= 2;
		return m_L.readBit(key / 8, key % 8);
	}

	private void setSM(int key, boolean value) {
		DigitalPackage pkg = m_SM.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_SM.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	private boolean getSM(int key) {
		return m_SM.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setCC(int key, boolean value) {
		DigitalPackage pkg = m_CC.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_CC.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
		if (pkg.isUp()) {
			long cn = getCN(key);
			cn += 1;
			setCN(key, cn);
		}
	}

	@SuppressWarnings("unused")
	private boolean getCC(int key) {
		return m_CC.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setCLim(int key, long value) {
		m_CLIMIT.put(key, value);
	}

	private long getCLim(int key) {
		return m_CLIMIT.getOrDefault(key, (long) 0);
	}

	private void setCN(int key, long value) {
		m_CN.put(key, value);
		long cLim = getCLim(key);
		setCS(key, value >= cLim);
	}

	private long getCN(int key) {
		return m_CN.getOrDefault(key, (long) 0);
	}

	private void setCS(int key, boolean value) {
		DigitalPackage pkg = m_CS.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_CS.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	private boolean getCS(int key) {
		return m_CS.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setTC(int key, boolean value) {
		DigitalPackage pkg = m_TC.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_TC.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
		long tlim = getTLim(key);
		if (pkg.get() == false) {
			setTN(key, 0);
			setTS(key, false);
			return;
		}
		long tn = getTN(key);
		if (tn > tlim) {
			setTN(key, tlim);
		}
		setTS(key, tn >= tlim);
		m_timer.start();
	}

	@SuppressWarnings("unused")
	private boolean getTC(int key) {
		return m_TC.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setTN(int key, long value) {
		m_TN.put(key, value);
	}

	private long getTN(int key) {
		return m_TN.getOrDefault(key, (long) 0);
	}

	private void setTLim(int key, long value) {
		m_TLIMIT.put(key, value);
	}

	private long getTLim(int key) {
		return m_TLIMIT.getOrDefault(key, (long) 0);
	}

	private void setTS(int key, boolean value) {
		DigitalPackage pkg = m_TS.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_TS.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	private boolean getTS(int key) {
		return m_TS.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	public void reset() {
		m_P.clear();
		m_skipWhiteSpace.clear();
		m_quickOperators.clear();
		m_quickArgs.clear();
	}

	@Override
	public String toString() {
		return "" + m_stackCalc.getValue();
	}

	public void calc(String string) {
		m_blockLogicStack.clear();
		m_mpsCommandStack.clear();
		m_retP.clear();
		m_retV.clear();
		m_lineNumber = 0;
		m_calc.calculate(string.toUpperCase());
	}

	private void addOperationNum() {
		Analysor<Object> analysor = new Analysor<Object>() {
			@Override
			public String toString() {
				return "";
			}

			@Override
			public int analyse(StandardCalculator<Object> calculator, String command, int offset) {
				++m_lineNumber;
				if (!m_operatorSetted) {
					return -1;
				}
				m_operatorSetted = false;
				int i = offset;
				// 读取到换行
				String[] sb = new String[1];
				i = readToEndAndSkipNextLineBlankChars(i, command, sb);
				calculator.setValue(sb[0]);
				return i;
			}
		};
		m_analysors.add(analysor);
	}

	private void addOperator(String cmd, BinaryOperator<Object> operator) {
		Analysor<Object> analysor = new Analysor<Object>() {
			@Override
			public String toString() {
				return cmd;
			}

			@Override
			public int analyse(StandardCalculator<Object> calculator, String command, int offset) {
				if (!command.startsWith(cmd, offset)) {
					return SKIP;
				}

				m_operatorSetted = true;
				int i = offset + cmd.length();
				// 跳过分隔符
				i = skipBlankChars(i, command);
				BinaryOperator<Object> namedOperator = new BinaryOperator<Object>() {
					@Override
					public String toString() {
						return cmd;
					}

					@Override
					public Object apply(Object t, Object u) {
						return operator.apply(t, u);
					}
				};
				calculator.binaryOperate(0, namedOperator);
				m_quickOperators.put(offset, namedOperator);
				return i;
			}
		};
		m_analysors.add(analysor);
	}

	private static final boolean isCmdCharFound(char c) {
		if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
			return true;
		}
		if ("+-*/".indexOf(c) >= 0) {
			return true;
		}
		return false;
	}

	private int readToEndAndSkipNextLineBlankChars(int i, String command, String[] out) {
		final int from = i;
		if (out == null || out.length == 0) {
			// 没有输出,可以直接跳到行尾
			Integer to = m_skipWhiteSpace.get(i);
			if (to != null) {
				i = to;
			} else {
				for (; i < command.length(); ++i) {
					char c = command.charAt(i);
					if (c == '\r' || c == '\n') {
						break;
					}
				}
				for (; i < command.length(); ++i) {
					char c = command.charAt(i);
					if (isCmdCharFound(c)) {
						break;
					}
				}
				m_skipWhiteSpace.put(from, i);
			}
			return i;
		} else {
			// 有输出,需要复制,用查表法更慢,可能是JVM的优化造成的。
			StringBuilder sb = new StringBuilder();
			for (; i < command.length(); ++i) {
				char c = command.charAt(i);
				if (c == '\r' || c == '\n') {
					break;
				}
				sb.append(c);
			}
			out[0] = sb.toString().trim();
			// 跳过换行和下一行的缩进、行号
			{
				Integer to = m_skipWhiteSpace.get(i);
				if (to != null) {
					i = to;
				} else {
					int from2 = i;
					for (; i < command.length(); ++i) {
						char c = command.charAt(i);
						if (isCmdCharFound(c)) {
							break;
						}
					}
					m_skipWhiteSpace.put(from2, i);
				}
			}
			return i;
		}
	}

	private int skipBlankChars(int i, String command) {
		Integer to = m_skipWhiteSpace.get(i);
		if (to != null) {
			i = to;
		} else {
			int from = i;
			for (; i < command.length(); ++i) {
				char c = command.charAt(i);
				if (SEPARATOR_IN_LINE.indexOf(c) < 0) {
					break;
				}
			}
			m_skipWhiteSpace.put(from, i);
		}
		return i;
	}

	private boolean toDigital(Object d) {
		if (d instanceof Boolean) {
			return (boolean) d;
		}
		String label = d.toString().toUpperCase();
		if ("true".equalsIgnoreCase(label)) {
			return true;
		} else if ("false".equalsIgnoreCase(label)) {
			return false;
		}
		if (label.startsWith("SM")) {
			return getSM(Integer.parseInt(label.substring(2)));
		} else if (label.startsWith("M")) {
			return getM(Integer.parseInt(label.substring(1)));
		} else if (label.startsWith("C")) {
			return getCS(Integer.parseInt(label.substring(1)));
		} else if (label.startsWith("T")) {
			return getTS(Integer.parseInt(label.substring(1)));
		} else if (label.startsWith("L")) {
			int key = Integer.parseInt(label.substring(1));
			return getL(key);
		} else {
			StaticJavaUtils.exit(label + " is not a digital");
			return false;
		}
	}

	private boolean toDigitalI(Object d) {
		return !toDigital(d);
	}

	private boolean toDigitalP(Object d) {
		String label = d.toString().toUpperCase();
		if ("true".equalsIgnoreCase(label)) {
			return true;
		} else if ("false".equalsIgnoreCase(label)) {
			return false;
		}
		if (label.startsWith("SM")) {
			return m_SM.getOrDefault(Integer.parseInt(label.substring(2)), DigitalPackage.DEFAULT).isUp();
		} else if (label.startsWith("M")) {
			return m_M.getOrDefault(Integer.parseInt(label.substring(1)), DigitalPackage.DEFAULT).isUp();
		} else if (label.startsWith("C")) {
			return m_CS.getOrDefault(Integer.parseInt(label.substring(1)), DigitalPackage.DEFAULT).isUp();
		} else if (label.startsWith("T")) {
			return m_TS.getOrDefault(Integer.parseInt(label.substring(1)), DigitalPackage.DEFAULT).isUp();
		} else if (label.startsWith("L")) {
			if (m_L == null) {
				StaticJavaUtils.exit("没有配置用于保存L点的文件");
			}
			int key = Integer.parseInt(label.substring(1)) * 2;
			boolean current = m_L.readBit(key / 8, key % 8);
			boolean last = m_L.readBit(key / 8, key % 8 + 1);
			return current && !last;
		} else {
			StaticJavaUtils.exit(label + " is not a digital");
			return false;
		}
	}

	private boolean toDigitalPI(Object d) {
		return !toDigitalP(d);
	}

	private boolean toDigitalF(Object d) {
		String label = d.toString().toUpperCase();
		if ("true".equalsIgnoreCase(label)) {
			return true;
		} else if ("false".equalsIgnoreCase(label)) {
			return false;
		}
		if (label.startsWith("SM")) {
			return m_SM.getOrDefault(Integer.parseInt(label.substring(2)), DigitalPackage.DEFAULT).isDown();
		} else if (label.startsWith("M")) {
			return m_M.getOrDefault(Integer.parseInt(label.substring(1)), DigitalPackage.DEFAULT).isDown();
		} else if (label.startsWith("C")) {
			return m_CS.getOrDefault(Integer.parseInt(label.substring(1)), DigitalPackage.DEFAULT).isDown();
		} else if (label.startsWith("T")) {
			return m_TS.getOrDefault(Integer.parseInt(label.substring(1)), DigitalPackage.DEFAULT).isDown();
		} else if (label.startsWith("L")) {
			if (m_L == null) {
				StaticJavaUtils.exit("没有配置用于保存L点的文件");
			}
			int key = Integer.parseInt(label.substring(1)) * 2;
			boolean current = m_L.readBit(key / 8, key % 8);
			boolean last = m_L.readBit(key / 8, key % 8 + 1);
			return !current && last;
		} else {
			StaticJavaUtils.exit(label + " is not a digital");
			return false;
		}
	}

	private boolean toDigitalFI(Object d) {
		return !toDigitalF(d);
	}

	private Number toNumber(final String label) {
		int radix = 10;
		String n;
		if (label.startsWith("K")) {
			if (label.contains("M")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(label, "K%dM%d", nums);
				return getKM(nums.get(0).intValue(), nums.get(1).intValue());
			} else if (label.contains("L")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(label, "K%dL%d", nums);
				return getKL(nums.get(0).intValue(), nums.get(1).intValue());
			} else {
				n = label.substring(1);
			}
		} else if (label.startsWith("H")) {
			n = label.substring(1);
			radix = 16;
		} else if (label.startsWith("D")) {
			n = label.substring(1);
			return getD(Integer.parseInt(n));
		} else if (label.startsWith("C")) {
			n = label.substring(1);
			return getCN(Integer.parseInt(n));
		} else if (label.startsWith("T")) {
			n = label.substring(1);
			return getTN(Integer.parseInt(n));
		} else {
			StaticJavaUtils.exit(label + " is not a number");
			return null;
		}
		try {
			if (radix == 16) {
				return Long.valueOf(n, radix);
			} else {
				return Double.valueOf(n);
			}
		} catch (NumberFormatException e) {
		}
		StaticJavaUtils.exit(label + " is not a number");
		return null;
	}

	private void setNumber(String name, int offset, Number value) {
		if (name.startsWith("K")) {
			if (name.contains("M")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(name, "K%dM%d", nums);
				setKM(nums.get(0).intValue(), nums.get(1).intValue(), value.longValue());
			} else if (name.contains("L")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(name, "K%dL%d", nums);
				setKL(nums.get(0).intValue(), nums.get(1).intValue(), value.longValue());
			}
		} else {
			int index = Integer.parseInt(name.substring(1));
			index += offset;
			if (name.startsWith("D")) {
				setD(index, value);
			} else if (name.startsWith("C")) {
				setCN(index, value.longValue());
			} else if (name.startsWith("T")) {
				setTN(index, value.longValue());
			} else {
			}
		}
	}
}

没有实现X和Y。在上位机上X和Y前缀没有意义,所以就直接不要了。也没有特殊功能寄存器。如果需要用到那些功能,干脆直接用Java或Python好了,Matlab也很好。这个三菱模拟器就是用来解决复杂的二值逻辑问题的。

再上个双行计算器标准模板,双行计算器是PLC核心算法的框架类,用于承载分析器。分析器中调用单行计算器。单行计算器是执行类。在单行计算器中可以通过Lambda方式添加一元操作符或二元操作符。不过代码太大,放上来也没人看得懂。本文只给出一个示范性的思路,并没有把PLC模拟器内核全部放进来。

package pers.laserpen.util.math.calculator.standardCalculator;

import java.util.Objects;

public final class DoubleLineCalculator<VALUE_TYPE> {

	private StandardCalculator<VALUE_TYPE> m_calculator;

	private Iterable<Analysor<VALUE_TYPE>> m_analysors;

	public DoubleLineCalculator(StandardCalculator<VALUE_TYPE> calculator,
			Iterable<Analysor<VALUE_TYPE>> analysors) {
		m_calculator = Objects.requireNonNull(calculator);
		m_analysors = Objects.requireNonNull(analysors);
	}

	/**
	 * 计算正确返回结果,计算错误返回null。<br/>
	 * 核心函数区分大小写,自带的操作符全为小写。<br/>
	 * 如有需要,请在调用前转换为全小写。【该注释是配套的科学计算器的注释,对应梯形图计算器应该是默认全大写】
	 * 
	 * @param command
	 * @return
	 */
	public VALUE_TYPE calculate(String command) {
		// 防止受上一次的结果干扰
		m_calculator.reset();
		int index = 0;
		while (index < command.length()) {
			boolean failed = true;
			for (Analysor<VALUE_TYPE> analysor : m_analysors) {
				int next = analysor.analyse(m_calculator, command, index);
				if (next >= 0) {
					index = next;
					failed = false;
					break;
				}
			}
			if (failed) {
				++index;
			}
			// System.out.println(m_calculator);
		}
		m_calculator.calculate();
		if (m_calculator.isCorrect()) {
			return m_calculator.getValue();
		} else {
			return null;
		}
	}

	public StandardCalculator<VALUE_TYPE> getCalculator() {
		return m_calculator;
	}

	public Iterable<Analysor<VALUE_TYPE>> getAnalysors() {
		return m_analysors;
	}

	@Override
	public String toString() {
		return m_calculator.toString();
	}

	/**
	 * 算式分析器
	 * 
	 * @author Laserpen
	 */
	@FunctionalInterface
	public static interface Analysor<VALUE_TYPE> {
		/** 跳过后面的字符串,结束扫描 */
		public static final int OVER = Integer.MAX_VALUE;
		/** 跳过当前扫描模块 */
		public static final int SKIP = -1;

		/**
		 * @param calculator
		 *                   核心计算器
		 * @param command
		 *                   算式。 传入完整算式,以支持跳转指令。
		 * @param offset
		 *                   字符串索引偏移。绝对地址。
		 * @return >=0 分析成功,并返回下一个索引 <0 分析不成功。返回0表示回到原点,用于复位指令。
		 */
		public int analyse(StandardCalculator<VALUE_TYPE> calculator, String command, int offset);
	}

}

由于命令长度超过1万行时,对跳转指令的操作需要很长的时间,又新增一个伪编译型的PLC虚拟机。

package pers.laserpen.util.automation.plcEmulator;

import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;

import pers.laserpen.util.data.StaticDataUtils;
import pers.laserpen.util.file.FreeFileIO;
import pers.laserpen.util.java.StaticJavaUtils;
import pers.laserpen.util.string.RegexBuilder;
import pers.laserpen.util.string.StaticStringUtils;
import pers.laserpen.util.thread.AccuracyTimer;

/**
 * 伪编译型三菱PLC执行器
 * 
 * @author Laserpen
 */
public class MitsubishiPLCRunner {

	private static final String SEPARATOR_IN_LINE = ((Supplier<String>) () -> {
		RegexBuilder regex = new RegexBuilder();
		regex.appendCharGroup(" \"\t,,\' \ufeff\0\f", false);
		return regex.toString();
	}).get();

	private Map<Integer, Number> m_D = new HashMap<>();
	private FreeFileIO m_savedD = null;
	private int m_savedDOffset = 0;
	private Map<Integer, DigitalPackage> m_X = new HashMap<>();
	private Map<Integer, DigitalPackage> m_Y = new HashMap<>();
	private Map<Integer, DigitalPackage> m_M = new HashMap<>();
	private FreeFileIO m_L = null;
	private Map<Integer, DigitalPackage> m_SM = new HashMap<>();
	private Map<Integer, DigitalPackage> m_mepOrMef = new HashMap<>();
	private Map<Integer, DigitalPackage> m_CC = new HashMap<>();
	private Map<Integer, Long> m_CN = new HashMap<>();
	private Map<Integer, Long> m_CLIMIT = new HashMap<>();
	private Map<Integer, DigitalPackage> m_CS = new HashMap<>();
	private Map<Integer, DigitalPackage> m_TC = new HashMap<>();
	private Map<Integer, Long> m_TN = new HashMap<>();
	private Map<Integer, Long> m_TLIMIT = new HashMap<>();
	private Map<Integer, DigitalPackage> m_TS = new HashMap<>();

	private AccuracyTimer m_timer = new AccuracyTimer();
	private AtomicLong m_tickTimerFlag = new AtomicLong();
	private long m_addPlcTimerFlag = 0;

	private Deque<Boolean> m_blockLogicStack = new ArrayDeque<>();
	private Deque<Boolean> m_mpsCommandStack = new ArrayDeque<>();
	private Deque<Integer> m_retPositionStack = new ArrayDeque<>();
	private Deque<Boolean> m_retValueStack = new ArrayDeque<>();

	private PLCCommand[] m_compileProgram = null;

	private Map<String, Function<String[], PLCCommand>> m_compMap = new HashMap<>();
	private int m_programPointer = 0;

	public MitsubishiPLCRunner(long tickTime) {
		if (tickTime <= 0) {
			StaticJavaUtils.exit("不支持负的延时");
		}
		setSM(400, true);
		setSM(401, false);
		setM(8000, true);
		setM(8001, false);
		addOperators();
		m_timer.setTask(ct -> {
			if (m_tickTimerFlag.getAndIncrement() > 1000 / tickTime) {
				m_tickTimerFlag.set(0);
//				System.out.println("plc timer auto closed");
				return 0;
			} else {
				return tickTime;
			}
		});
	}

	private void addOperators() {
		m_compMap.put("LDP", sa -> {
			if (sa.length < 2) {
				return null;
			}
			final String key = sa[1];
			BooleanSupplier sup = toDigitalPSupplier(key);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				return sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("LDPI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			final String key = sa[1];
			BooleanSupplier sup = toDigitalPISupplier(key);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				return sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("LDF", sa -> {
			if (sa.length < 2) {
				return null;
			}
			final String key = sa[1];
			BooleanSupplier sup = toDigitalFSupplier(key);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				return sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("LDFI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			final String key = sa[1];
			BooleanSupplier sup = toDigitalFISupplier(key);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				return sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("LDI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			final String key = sa[1];
			BooleanSupplier sup = toDigitalISupplier(key);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				return sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("LD", sa -> {
			if (sa.length < 2) {
				return null;
			}
			final String key = sa[1];
			BooleanSupplier sup = toDigitalSupplier(key);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				return sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("LD>", sa -> {
			if (sa.length < 3) {
				return null;
			}
			final String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				return n1.doubleValue() > n2.doubleValue();
			};
			return cmd;
		});
		m_compMap.put("LDD>", m_compMap.get("LD>"));
		m_compMap.put("LD>=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			final String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				return n1.doubleValue() >= n2.doubleValue();
			};
			return cmd;
		});
		m_compMap.put("LDD>=", m_compMap.get("LD>="));
		m_compMap.put("LD<", sa -> {
			if (sa.length < 3) {
				return null;
			}
			final String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				return n1.doubleValue() < n2.doubleValue();
			};
			return cmd;
		});
		m_compMap.put("LDD<", m_compMap.get("LD<"));
		m_compMap.put("LD<=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			final String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				return n1.doubleValue() <= n2.doubleValue();
			};
			return cmd;
		});
		m_compMap.put("LDD<=", m_compMap.get("LD<="));
		m_compMap.put("LD<>", sa -> {
			if (sa.length < 3) {
				return null;
			}
			final String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				return n1.doubleValue() != n2.doubleValue();
			};
			return cmd;
		});
		m_compMap.put("LDD<>", m_compMap.get("LD<>"));
		m_compMap.put("LD=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			final String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				m_blockLogicStack.push(b);
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				return n1.doubleValue() == n2.doubleValue();
			};
			return cmd;
		});
		m_compMap.put("LDD=", m_compMap.get("LD="));
		m_compMap.put("OUT", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			int index = Integer.parseInt(key.substring(1));
			PLCCommand cmd = null;
			if (key.startsWith("M")) {
				DigitalPackage pkg = m_M.get(index);
				if (pkg == null) {
					pkg = new DigitalPackage();
					m_M.put(index, pkg);
				}
				DigitalPackage PKG = pkg;
				cmd = b -> {
					m_blockLogicStack.clear();
					PKG.transfer();
					PKG.set(b);
					return b;
				};
			} else if (key.startsWith("X")) {
				DigitalPackage pkg = m_X.get(index);
				if (pkg == null) {
					pkg = new DigitalPackage();
					m_X.put(index, pkg);
				}
				DigitalPackage PKG = pkg;
				cmd = b -> {
					m_blockLogicStack.clear();
					PKG.transfer();
					PKG.set(b);
					return b;
				};
			} else if (key.startsWith("Y")) {
				DigitalPackage pkg = m_Y.get(index);
				if (pkg == null) {
					pkg = new DigitalPackage();
					m_Y.put(index, pkg);
				}
				DigitalPackage PKG = pkg;
				cmd = b -> {
					m_blockLogicStack.clear();
					PKG.transfer();
					PKG.set(b);
					return b;
				};
			} else if (key.startsWith("T")) {
				if (sa.length < 3) {
					return null;
				}
				String key2 = sa[2];
				Supplier<Number> sup = toNumberSupplier(key2);
				cmd = b -> {
					m_blockLogicStack.clear();
					setTLim(index, sup.get().longValue());
					setTC(index, b);
					return b;
				};
			} else if (key.startsWith("C")) {
				if (sa.length < 3) {
					return null;
				}
				String key2 = sa[2];
				Supplier<Number> sup = toNumberSupplier(key2);
				cmd = b -> {
					m_blockLogicStack.clear();
					setCLim(index, sup.get().longValue());
					setCC(index, b);
					return b;
				};
			} else if (key.startsWith("L")) {
				cmd = b -> {
					m_blockLogicStack.clear();
					setL(index, b);
					return b;
				};
			}
			return cmd;
		});
		m_compMap.put("AND", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalSupplier(key);
			PLCCommand cmd = b -> {
				return b && sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ANI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalISupplier(key);
			PLCCommand cmd = b -> {
				return b && sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ANDP", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalPSupplier(key);
			PLCCommand cmd = b -> {
				return b && sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ANDPI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalPISupplier(key);
			PLCCommand cmd = b -> {
				return b && sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ANDF", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalFSupplier(key);
			PLCCommand cmd = b -> {
				return b && sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ANDFI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalFISupplier(key);
			PLCCommand cmd = b -> {
				return b && sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("AND<", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() < n2.doubleValue();
				return b && b2;
			};
			return cmd;
		});
		m_compMap.put("ANDD<", m_compMap.get("AND<"));
		m_compMap.put("AND<=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() <= n2.doubleValue();
				return b && b2;
			};
			return cmd;
		});
		m_compMap.put("ANDD<=", m_compMap.get("AND<="));
		m_compMap.put("AND>", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() > n2.doubleValue();
				return b && b2;
			};
			return cmd;
		});
		m_compMap.put("ANDD>", m_compMap.get("AND>"));
		m_compMap.put("AND>=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() >= n2.doubleValue();
				return b && b2;
			};
			return cmd;
		});
		m_compMap.put("ANDD>=", m_compMap.get("AND>="));
		m_compMap.put("AND<>", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() != n2.doubleValue();
				return b && b2;
			};
			return cmd;
		});
		m_compMap.put("ANDD<>", m_compMap.get("AND<>"));
		m_compMap.put("AND=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() == n2.doubleValue();
				return b && b2;
			};
			return cmd;
		});
		m_compMap.put("ANDD=", m_compMap.get("AND="));

		m_compMap.put("OR", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalSupplier(key);
			PLCCommand cmd = b -> {
				return b || sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ORI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalISupplier(key);
			PLCCommand cmd = b -> {
				return b || sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ORP", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalPSupplier(key);
			PLCCommand cmd = b -> {
				return b || sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ORPI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalPISupplier(key);
			PLCCommand cmd = b -> {
				return b || sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ORF", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalFSupplier(key);
			PLCCommand cmd = b -> {
				return b || sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("ORFI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalFISupplier(key);
			PLCCommand cmd = b -> {
				return b || sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("OR<", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() < n2.doubleValue();
				return b || b2;
			};
			return cmd;
		});
		m_compMap.put("ORD<", m_compMap.get("OR<"));
		m_compMap.put("OR<=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() <= n2.doubleValue();
				return b || b2;
			};
			return cmd;
		});
		m_compMap.put("ORD<=", m_compMap.get("OR<="));
		m_compMap.put("OR>", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() > n2.doubleValue();
				return b || b2;
			};
			return cmd;
		});
		m_compMap.put("ORD>", m_compMap.get("OR>"));
		m_compMap.put("OR>=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() >= n2.doubleValue();
				return b || b2;
			};
			return cmd;
		});
		m_compMap.put("ORD>=", m_compMap.get("OR>="));
		m_compMap.put("OR<>", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() != n2.doubleValue();
				return b || b2;
			};
			return cmd;
		});
		m_compMap.put("ORD<>", m_compMap.get("OR<>"));
		m_compMap.put("OR=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() == n2.doubleValue();
				return b || b2;
			};
			return cmd;
		});
		m_compMap.put("ORD=", m_compMap.get("OR="));

		m_compMap.put("XOR", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalSupplier(key);
			PLCCommand cmd = b -> {
				return b != sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("XORI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalISupplier(key);
			PLCCommand cmd = b -> {
				return b != sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("XORP", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalPSupplier(key);
			PLCCommand cmd = b -> {
				return b != sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("XORPI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalPISupplier(key);
			PLCCommand cmd = b -> {
				return b != sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("XORF", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalFSupplier(key);
			PLCCommand cmd = b -> {
				return b != sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("XORFI", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			BooleanSupplier sup = toDigitalFISupplier(key);
			PLCCommand cmd = b -> {
				return b != sup.getAsBoolean();
			};
			return cmd;
		});
		m_compMap.put("XOR<", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() < n2.doubleValue();
				return b != b2;
			};
			return cmd;
		});
		m_compMap.put("XORD<", m_compMap.get("XOR<"));
		m_compMap.put("XOR<=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() <= n2.doubleValue();
				return b != b2;
			};
			return cmd;
		});
		m_compMap.put("XORD<=", m_compMap.get("XOR<="));
		m_compMap.put("XOR>", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() > n2.doubleValue();
				return b != b2;
			};
			return cmd;
		});
		m_compMap.put("XORD>", m_compMap.get("XOR>"));
		m_compMap.put("XOR>=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() >= n2.doubleValue();
				return b != b2;
			};
			return cmd;
		});
		m_compMap.put("XORD>=", m_compMap.get("XOR>="));
		m_compMap.put("XOR<>", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() != n2.doubleValue();
				return b != b2;
			};
			return cmd;
		});
		m_compMap.put("XORD<>", m_compMap.get("XOR<>"));
		m_compMap.put("XOR=", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			PLCCommand cmd = b -> {
				Number n1 = sup1.get();
				Number n2 = sup2.get();
				boolean b2 = n1.doubleValue() == n2.doubleValue();
				return b != b2;
			};
			return cmd;
		});
		m_compMap.put("XORD=", m_compMap.get("XOR="));

		m_compMap.put("ANB", sa -> {
			PLCCommand cmd = b -> {
				return b & (boolean) m_blockLogicStack.pop();
			};
			return cmd;
		});
		m_compMap.put("ORB", sa -> {
			PLCCommand cmd = b -> {
				return b | (boolean) m_blockLogicStack.pop();
			};
			return cmd;
		});
		m_compMap.put("XORB", sa -> {
			PLCCommand cmd = b -> {
				return b != (boolean) m_blockLogicStack.pop();
			};
			return cmd;
		});
		m_compMap.put("MPS", sa -> {
			PLCCommand cmd = b -> {
				m_mpsCommandStack.push(b);
				return b;
			};
			return cmd;
		});
		m_compMap.put("MPP", sa -> {
			PLCCommand cmd = b -> {
				return (boolean) m_mpsCommandStack.pop();
			};
			return cmd;
		});
		m_compMap.put("MPD", sa -> {
			PLCCommand cmd = b -> {
				return (boolean) m_mpsCommandStack.peek();
			};
			return cmd;
		});
		m_compMap.put("INV", sa -> {
			PLCCommand cmd = b -> {
				return !b;
			};
			return cmd;
		});
		m_compMap.put("SET", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			int index = Integer.parseInt(key.substring(1));
			PLCCommand cmd = null;
			if (key.startsWith("M")) {
				DigitalPackage pkg = m_M.get(index);
				if (pkg == null) {
					pkg = new DigitalPackage();
					m_M.put(index, pkg);
				}
				DigitalPackage PKG = pkg;
				cmd = b -> {
					m_blockLogicStack.clear();
					if (b) {
						PKG.transfer();
						PKG.set(true);
					}
					return b;
				};
			} else if (key.startsWith("L")) {
				cmd = b -> {
					m_blockLogicStack.clear();
					if (b) {
						setL(index, true);
					}
					return b;
				};
			}
			return cmd;
		});
		m_compMap.put("RST", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String key = sa[1];
			int index = Integer.parseInt(key.substring(1));
			PLCCommand cmd = null;
			if (key.startsWith("M")) {
				DigitalPackage pkg = m_M.get(index);
				if (pkg == null) {
					pkg = new DigitalPackage();
					m_M.put(index, pkg);
				}
				DigitalPackage PKG = pkg;
				cmd = b -> {
					m_blockLogicStack.clear();
					if (b) {
						PKG.transfer();
						PKG.set(false);
					}
					return b;
				};
			} else if (key.startsWith("L")) {
				cmd = b -> {
					m_blockLogicStack.clear();
					if (b) {
						setL(index, false);
					}
					return b;
				};
			} else {
				Consumer<Number> con = setNumberConsumer(key, 0);
				cmd = b -> {
					m_blockLogicStack.clear();
					if (b) {
						con.accept(0);
					}
					return b;
				};
			}
			return cmd;
		});
		m_compMap.put("MOV", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number value = sup.get();
					con.accept(value);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("DMOV", m_compMap.get("MOV"));
		m_compMap.put("WAND", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2], key3 = sa.length == 3 ? key2 : sa[3];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			Consumer<Number> con = setNumberConsumer(key3, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number addition1 = sup1.get();
					Number addition2 = sup2.get();
					Number ans = addition1.longValue() & addition2.longValue();
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("DAND", m_compMap.get("WAND"));
		m_compMap.put("WOR", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2], key3 = sa.length == 3 ? key2 : sa[3];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			Consumer<Number> con = setNumberConsumer(key3, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number addition1 = sup1.get();
					Number addition2 = sup2.get();
					Number ans = addition1.longValue() | addition2.longValue();
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("DOR", m_compMap.get("WOR"));
		m_compMap.put("WXOR", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2], key3 = sa.length == 3 ? key2 : sa[3];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			Consumer<Number> con = setNumberConsumer(key3, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number addition1 = sup1.get();
					Number addition2 = sup2.get();
					Number ans = addition1.longValue() ^ addition2.longValue();
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("DXOR", m_compMap.get("WXOR"));
		m_compMap.put("CML", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number num = sup.get();
					Number ans = ~num.longValue();
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("DCML", m_compMap.get("CML"));
		m_compMap.put("NEG", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number num = sup.get();
					Number ans = -num.doubleValue();
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("DNEG", m_compMap.get("NEG"));
		m_compMap.put("ADD", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2], key3 = sa.length == 3 ? key2 : sa[3];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			Consumer<Number> con = setNumberConsumer(key3, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number addition1 = sup1.get();
					Number addition2 = sup2.get();
					Number ans = addition1.doubleValue() + addition2.doubleValue();
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("+", m_compMap.get("ADD"));
		m_compMap.put("D+", m_compMap.get("ADD"));
		m_compMap.put("SUB", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2], key3 = sa.length == 3 ? key2 : sa[3];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			Consumer<Number> con = setNumberConsumer(key3, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number addition1 = sup1.get();
					Number addition2 = sup2.get();
					Number ans = addition1.doubleValue() - addition2.doubleValue();
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("-", m_compMap.get("SUB"));
		m_compMap.put("D-", m_compMap.get("SUB"));
		m_compMap.put("MUL", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2], key3 = sa.length == 3 ? key2 : sa[3];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			Consumer<Number> con = setNumberConsumer(key3, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number addition1 = sup1.get();
					Number addition2 = sup2.get();
					Number ans = addition1.doubleValue() * addition2.doubleValue();
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("*", m_compMap.get("MUL"));
		m_compMap.put("D*", m_compMap.get("MUL"));
		m_compMap.put("DIV", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2], key3 = sa.length == 3 ? key2 : sa[3];
			Supplier<Number> sup1 = toNumberSupplier(key1);
			Supplier<Number> sup2 = toNumberSupplier(key2);
			Consumer<Number> con = setNumberConsumer(key3, 0);
			Consumer<Number> conMod = setNumberConsumer(key3, 1);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number addition1 = sup1.get();
					Number addition2 = sup2.get();
					Number ans = addition1.doubleValue() / addition2.doubleValue();
					Number ansMod = addition1.doubleValue() % addition2.doubleValue();
					con.accept(ans);
					conMod.accept(ansMod);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("/", m_compMap.get("DIV"));
		m_compMap.put("D/", m_compMap.get("DIV"));
		m_compMap.put("SIN", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.sin(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("COS", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.cos(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("TAN", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.tan(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});

		m_compMap.put("ASIN", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.asin(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("ACOS", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.acos(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("ATAN", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.atan(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("EXP", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.exp(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("LOG", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.log(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("LOG10", sa -> {
			if (sa.length < 3) {
				return null;
			}
			String key1 = sa[1], key2 = sa[2];
			Supplier<Number> sup = toNumberSupplier(key1);
			Consumer<Number> con = setNumberConsumer(key2, 0);
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				if (b) {
					Number x = sup.get();
					double ans = Math.log10(x.doubleValue());
					con.accept(ans);
				}
				return b;
			};
			return cmd;
		});
		m_compMap.put("CJ", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String position = sa[1];
			PLCJump cmd = new PLCJump() {
				private int jump = Integer.MAX_VALUE;

				@Override
				public boolean execute(boolean enabled) {
					m_blockLogicStack.clear();
					if (enabled) {
						m_programPointer = jump;
					}
					return enabled;
				}

				@Override
				public void setJumpIndex(int index) {
					jump = index;
				}

				@Override
				public String getPositionFlag() {
					return position;
				}
			};
			return cmd;
		});
		m_compMap.put("JMP", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String position = sa[1];
			PLCJump cmd = new PLCJump() {
				private int jump = Integer.MAX_VALUE;

				@Override
				public boolean execute(boolean enabled) {
					m_blockLogicStack.clear();
					m_programPointer = jump;
					return enabled;
				}

				@Override
				public void setJumpIndex(int index) {
					jump = index;
				}

				@Override
				public String getPositionFlag() {
					return position;
				}
			};
			return cmd;
		});
		m_compMap.put("CALL", sa -> {
			if (sa.length < 2) {
				return null;
			}
			String position = sa[1];
			PLCJump cmd = new PLCJump() {
				private int jump = Integer.MAX_VALUE;

				@Override
				public boolean execute(boolean enabled) {
					m_blockLogicStack.clear();
					if (enabled) {
						m_retValueStack.push(enabled);
						m_retPositionStack.push(m_programPointer);
						m_programPointer = jump;
					}
					return enabled;
				}

				@Override
				public void setJumpIndex(int index) {
					jump = index;
				}

				@Override
				public String getPositionFlag() {
					return position;
				}
			};
			return cmd;
		});
		m_compMap.put("RET", sa -> {
			PLCCommand cmd = b -> {
				m_blockLogicStack.clear();
				boolean lastEnabled = (boolean) m_retValueStack.pop();
				m_programPointer = m_retPositionStack.pop();
				return lastEnabled;
			};
			return cmd;
		});
		m_compMap.put("END", sa -> {
			PLCCommand cmd = b -> {
				m_programPointer = m_compileProgram.length;
				return b;
			};
			return cmd;
		});
		m_compMap.put("MEP", sa -> {
			PLCCommand cmd = b -> {
				DigitalPackage mepOrMef = m_mepOrMef.get(m_programPointer);
				if (mepOrMef == null) {
					mepOrMef = new DigitalPackage();
					m_mepOrMef.put(m_programPointer, mepOrMef);
				}
				mepOrMef.transfer();
				mepOrMef.set(b);
				return mepOrMef.isUp();
			};
			return cmd;
		});
		m_compMap.put("MEF", sa -> {
			PLCCommand cmd = b -> {
				DigitalPackage mepOrMef = m_mepOrMef.get(m_programPointer);
				if (mepOrMef == null) {
					mepOrMef = new DigitalPackage();
					m_mepOrMef.put(m_programPointer, mepOrMef);
				}
				mepOrMef.transfer();
				mepOrMef.set(b);
				return mepOrMef.isDown();
			};
			return cmd;
		});
	}

	/**
	 * 编译
	 * 
	 * @param program
	 * @return true 成功 false 失败
	 */
	public boolean compile(String program) {
		BufferedReader reader;
		{
			StringReader reader2 = new StringReader(program);
			reader = new BufferedReader(reader2);
		}
		List<PLCCommand> compileList = new ArrayList<>(65535);
		List<PLCJump> jumpList = new ArrayList<>(8192);
		Map<String, Integer> jumpPositionIndex = new HashMap<>(8192);
		try {
			for (;;) {
				String line = reader.readLine();
				if (line == null) {
					break;
				}
				boolean ok = compileLine(compileList, jumpList, jumpPositionIndex, line);
				if (!ok) {
					System.err.println("编译失败,第" + (compileList.size() - 1) + "行");
					return false;
				}
			}
			for (PLCJump jump : jumpList) {
				String flag = jump.getPositionFlag();
				Integer position = jumpPositionIndex.get(flag);
				if (position == null) {
					System.err.println("链接失败,没有找到标签" + flag);
					return false;
				}
				jump.setJumpIndex(position);
			}
			m_compileProgram = compileList.toArray(new PLCCommand[compileList.size()]);
			return true;
		} catch (Throwable t) {
			t.printStackTrace();
		}
		return false;
	}

	private boolean compileLine(List<PLCCommand> compileList, List<PLCJump> jumpList,
			Map<String, Integer> jumpPositionIndex,
			String line) {
		{
			int index = 0;
			for (;; ++index) {
				if (index >= line.length()) {
					// 跳过空行
					return true;
				}
				char c = line.charAt(index);
				if (isCmdCharFound(c)) {
					line = line.substring(index);
					break;
				}
			}
		}
		{
			if (line.startsWith("P")) {
				String pNumberStr = line.trim().substring(1);
				try {
					Integer.parseInt(pNumberStr);
					jumpPositionIndex.put(line.trim(), compileList.size());
					// 找到了标签
					return true;
				} catch (NumberFormatException e) {
				}
			}
		}
		{
			String[] subLine = line.split(SEPARATOR_IN_LINE);
			String cmdStr = subLine[0];
			Function<String[], PLCCommand> cmdBuilder = m_compMap.get(cmdStr);
			if (cmdBuilder == null) {
				return false;
			}
			PLCCommand plccmd = cmdBuilder.apply(subLine);
			if (plccmd == null) {
				return false;
			}
			compileList.add(plccmd);
			if (plccmd instanceof PLCJump) {
				PLCJump plcjmp = (PLCJump) plccmd;
				jumpList.add(plcjmp);
			}
			return true;
		}
	}

	/**
	 * 设置锁存器文件路径
	 * 
	 * @param file
	 *             锁存文件
	 */
	public void setLockedMiddleRelayFile(File file) {
		if (file == null) {
			m_L = null;
		} else {
			m_L = new FreeFileIO(file);
			m_L.setLittleEndian(true);
		}
	}

	/**
	 * 设置锁存寄存器文件路径
	 * 
	 * @param file
	 *               锁存文件
	 * @param offset
	 *               第一个锁存的寄存器地址
	 */
	public void setSavedDigister(File file, int offset) {
		if (file == null || offset < 0) {
			m_savedD = null;
			m_savedDOffset = -1;
		} else {
			m_savedD = new FreeFileIO(file);
			m_savedD.setLittleEndian(true);
			m_savedDOffset = offset;
		}
	}

	public void setD(int key, Number value) {
		if (m_savedD == null || key < m_savedDOffset) {
			m_D.put(key, value);
		} else {
			m_savedD.writeDouble((key - m_savedDOffset) * Double.BYTES, value.doubleValue());
		}
	}

	public Number getD(int key) {
		if (m_savedD == null || key < m_savedDOffset) {
			return m_D.getOrDefault(key, 0);
		} else {
			return m_savedD.readDouble((key - m_savedDOffset) * Double.BYTES);
		}
	}

	private void setKX(int k, int key, long value) {
		for (int i = 0; i < k * 4; ++i) {
			setX(key + i, StaticDataUtils.getBit(value, i));
		}
	}

	private long getKX(int k, int key) {
		long value = 0;
		for (int i = 0; i < k * 4; ++i) {
			value = StaticDataUtils.setBit(value, i, getX(key + i));
		}
		return value;
	}

	public void setX(int key, boolean value) {
		DigitalPackage pkg = m_X.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_X.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	public boolean getX(int key) {
		return m_X.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setKY(int k, int key, long value) {
		for (int i = 0; i < k * 4; ++i) {
			setY(key + i, StaticDataUtils.getBit(value, i));
		}
	}

	private long getKY(int k, int key) {
		long value = 0;
		for (int i = 0; i < k * 4; ++i) {
			value = StaticDataUtils.setBit(value, i, getY(key + i));
		}
		return value;
	}

	public void setY(int key, boolean value) {
		DigitalPackage pkg = m_Y.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_Y.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	public boolean getY(int key) {
		return m_Y.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setKM(int k, int key, long value) {
		for (int i = 0; i < k * 4; ++i) {
			setM(key + i, StaticDataUtils.getBit(value, i));
		}
	}

	private long getKM(int k, int key) {
		long value = 0;
		for (int i = 0; i < k * 4; ++i) {
			value = StaticDataUtils.setBit(value, i, getM(key + i));
		}
		return value;
	}

	public void setM(int key, boolean value) {
		DigitalPackage pkg = m_M.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_M.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	public boolean getM(int key) {
		return m_M.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setKL(int k, int key, long value) {
		for (int i = 0; i < k * 4; ++i) {
			setL(key + i, StaticDataUtils.getBit(value, i));
		}
	}

	private long getKL(int k, int key) {
		long value = 0;
		for (int i = 0; i < k * 4; ++i) {
			value = StaticDataUtils.setBit(value, i, getL(key + i));
		}
		return value;
	}

	private void setL(int key, boolean value) {
		if (m_L == null) {
			StaticJavaUtils.exit("没有配置用于保存L点的文件");
		}
		key *= 2;
		boolean lastBit = m_L.readBit(key / 8, key % 8);
		m_L.writeBit(key / 8, key % 8 + 1, lastBit);
		m_L.writeBit(key / 8, key % 8, value);
	}

	private boolean getL(int key) {
		if (m_L == null) {
			StaticJavaUtils.exit("没有配置用于保存L点的文件");
		}
		key *= 2;
		return m_L.readBit(key / 8, key % 8);
	}

	private void setSM(int key, boolean value) {
		DigitalPackage pkg = m_SM.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_SM.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	@SuppressWarnings("unused")
	private boolean getSM(int key) {
		return m_SM.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setCC(int key, boolean value) {
		DigitalPackage pkg = m_CC.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_CC.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
		if (pkg.isUp()) {
			long cn = getCN(key);
			cn += 1;
			setCN(key, cn);
		}
	}

	private void setCLim(int key, long value) {
		m_CLIMIT.put(key, value);
	}

	private long getCLim(int key) {
		return m_CLIMIT.getOrDefault(key, (long) 0);
	}

	private void setCN(int key, long value) {
		m_CN.put(key, value);
		long cLim = getCLim(key);
		setCS(key, value >= cLim);
	}

	private long getCN(int key) {
		return m_CN.getOrDefault(key, (long) 0);
	}

	private void setCS(int key, boolean value) {
		DigitalPackage pkg = m_CS.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_CS.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	@SuppressWarnings("unused")
	private boolean getCS(int key) {
		return m_CS.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	private void setTC(int key, boolean value) {
		DigitalPackage pkg = m_TC.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_TC.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
		if (value == false) {
			setTN(key, 0);
			setTS(key, false);
			return;
		}
		if (m_addPlcTimerFlag > 0) {
			long tlim = getTLim(key);
			long tn = getTN(key);
			tn += m_addPlcTimerFlag;
			if (tn > tlim) {
				tn = tlim;
			}
			setTN(key, tn);
		}
	}

	private void setTN(int key, long value) {
		m_TN.put(key, value);
		long tLim = getTLim(key);
		setTS(key, value >= tLim);
	}

	private long getTN(int key) {
		return m_TN.getOrDefault(key, (long) 0);
	}

	private void setTLim(int key, long value) {
		m_TLIMIT.put(key, value);
	}

	private long getTLim(int key) {
		return m_TLIMIT.getOrDefault(key, (long) 0);
	}

	private void setTS(int key, boolean value) {
		DigitalPackage pkg = m_TS.get(key);
		if (pkg == null) {
			pkg = new DigitalPackage();
			m_TS.put(key, pkg);
		}
		pkg.transfer();
		pkg.set(value);
	}

	@SuppressWarnings("unused")
	private boolean getTS(int key) {
		return m_TS.getOrDefault(key, DigitalPackage.DEFAULT).get();
	}

	public void clearMemory() {
		m_CC = new HashMap<>();
		m_CLIMIT = new HashMap<>();
		m_CN = new HashMap<>();
		m_CS = new HashMap<>();
		m_TC = new HashMap<>();
		m_TLIMIT = new HashMap<>();
		m_TN = new HashMap<>();
		m_TS = new HashMap<>();
		m_M = new HashMap<>();
		setM(8000, true);
		setM(8001, false);
		m_D = new HashMap<>();
		m_mepOrMef = new HashMap<>();
		m_timer.stop();
		m_tickTimerFlag.set(0);
	}

	@Override
	public String toString() {
		return super.toString();
	}

	public void execute() {
		if (m_compileProgram == null) {
			StaticJavaUtils.exit("没有编译程序");
		}
		m_timer.start(r -> {
			Thread t = new Thread(r);
			t.setDaemon(true);
			t.setPriority(Thread.MAX_PRIORITY);
			return t;
		});

		m_addPlcTimerFlag = m_tickTimerFlag.getAndSet(0);
		boolean primarySignal = false;
		m_programPointer = 0;
		for (;;) {
			if (m_programPointer < 0) {
				break;
			} else if (m_programPointer >= m_compileProgram.length) {
				break;
			}
			PLCCommand cmd = m_compileProgram[m_programPointer++];
			primarySignal = cmd.execute(primarySignal);
		}
		m_addPlcTimerFlag = 0;

		m_blockLogicStack.clear();
		m_mpsCommandStack.clear();
		m_retPositionStack.clear();
		m_retValueStack.clear();
	}

	private static final boolean isCmdCharFound(char c) {
		if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
			return true;
		}
		if ("+-*/".indexOf(c) >= 0) {
			return true;
		}
		return false;
	}

	private BooleanSupplier toDigitalSupplier(Object d) {
		if (d instanceof Boolean) {
			return () -> (boolean) d;
		}
		String label = d.toString().toUpperCase();
		if ("true".equalsIgnoreCase(label)) {
			return () -> true;
		} else if ("false".equalsIgnoreCase(label)) {
			return () -> false;
		}
		if (label.startsWith("SM")) {
			DigitalPackage pkg = m_SM.get(Integer.parseInt(label.substring(2)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_SM.put(Integer.parseInt(label.substring(2)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.get();
		} else if (label.startsWith("X")) {
			DigitalPackage pkg = m_X.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_X.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.get();
		} else if (label.startsWith("Y")) {
			DigitalPackage pkg = m_Y.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_Y.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.get();
		} else if (label.startsWith("M")) {
			DigitalPackage pkg = m_M.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_M.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.get();
		} else if (label.startsWith("C")) {
			DigitalPackage pkg = m_CS.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_CS.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.get();
		} else if (label.startsWith("T")) {
			DigitalPackage pkg = m_TS.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_TS.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.get();
		} else if (label.startsWith("L")) {
			if (m_L == null) {
				StaticJavaUtils.exit("没有配置用于保存L点的文件");
			}
			int key = Integer.parseInt(label.substring(1)) * 2;
			return () -> m_L.readBit(key / 8, key % 8);
		} else {
			StaticJavaUtils.exit(label + " is not a digital");
			return null;
		}
	}

	private BooleanSupplier toDigitalISupplier(Object d) {
		BooleanSupplier sup = toDigitalSupplier(d);
		return () -> !sup.getAsBoolean();
	}

	private BooleanSupplier toDigitalPSupplier(Object d) {
		String label = d.toString().toUpperCase();
		if ("true".equalsIgnoreCase(label)) {
			return () -> true;
		} else if ("false".equalsIgnoreCase(label)) {
			return () -> false;
		}
		if (label.startsWith("SM")) {
			DigitalPackage pkg = m_SM.get(Integer.parseInt(label.substring(2)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_SM.put(Integer.parseInt(label.substring(2)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isUp();
		} else if (label.startsWith("X")) {
			DigitalPackage pkg = m_X.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_X.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isUp();
		} else if (label.startsWith("Y")) {
			DigitalPackage pkg = m_Y.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_Y.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isUp();
		} else if (label.startsWith("M")) {
			DigitalPackage pkg = m_M.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_M.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isUp();
		} else if (label.startsWith("C")) {
			DigitalPackage pkg = m_CS.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_CS.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isUp();
		} else if (label.startsWith("T")) {
			DigitalPackage pkg = m_TS.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_TS.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isUp();
		} else if (label.startsWith("L")) {
			if (m_L == null) {
				StaticJavaUtils.exit("没有配置用于保存L点的文件");
			}
			int key = Integer.parseInt(label.substring(1)) * 2;
			return () -> {
				boolean current = m_L.readBit(key / 8, key % 8);
				boolean last = m_L.readBit(key / 8, key % 8 + 1);
				return current && !last;
			};
		} else {
			StaticJavaUtils.exit(label + " is not a digital");
			return null;
		}
	}

	private BooleanSupplier toDigitalPISupplier(Object d) {
		BooleanSupplier sup = toDigitalPSupplier(d);
		return () -> !sup.getAsBoolean();
	}

	private BooleanSupplier toDigitalFSupplier(Object d) {
		String label = d.toString().toUpperCase();
		if ("true".equalsIgnoreCase(label)) {
			return () -> true;
		} else if ("false".equalsIgnoreCase(label)) {
			return () -> false;
		}
		if (label.startsWith("SM")) {
			DigitalPackage pkg = m_SM.get(Integer.parseInt(label.substring(2)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_SM.put(Integer.parseInt(label.substring(2)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isDown();
		} else if (label.startsWith("X")) {
			DigitalPackage pkg = m_X.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_X.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isDown();
		} else if (label.startsWith("Y")) {
			DigitalPackage pkg = m_Y.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_Y.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isDown();
		} else if (label.startsWith("M")) {
			DigitalPackage pkg = m_M.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_M.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isDown();
		} else if (label.startsWith("C")) {
			DigitalPackage pkg = m_CS.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_CS.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isDown();
		} else if (label.startsWith("T")) {
			DigitalPackage pkg = m_TS.get(Integer.parseInt(label.substring(1)));
			if (pkg == null) {
				pkg = new DigitalPackage();
				m_TS.put(Integer.parseInt(label.substring(1)), pkg);
			}
			DigitalPackage PKG = pkg;
			return () -> PKG.isDown();
		} else if (label.startsWith("L")) {
			if (m_L == null) {
				StaticJavaUtils.exit("没有配置用于保存L点的文件");
			}
			int key = Integer.parseInt(label.substring(1)) * 2;
			return () -> {
				boolean current = m_L.readBit(key / 8, key % 8);
				boolean last = m_L.readBit(key / 8, key % 8 + 1);
				return current && !last;
			};
		} else {
			StaticJavaUtils.exit(label + " is not a digital");
			return null;
		}
	}

	private BooleanSupplier toDigitalFISupplier(Object d) {
		BooleanSupplier sup = toDigitalFSupplier(d);
		return () -> !sup.getAsBoolean();
	}

	private Supplier<Number> toNumberSupplier(final String label) {
		int radix = 10;
		String n;
		if (label.startsWith("K")) {
			if (label.contains("M")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(label, "K%dM%d", nums);
				int i1 = nums.get(0).intValue();
				int i2 = nums.get(1).intValue();
				return () -> getKM(i1, i2);
			} else if (label.contains("L")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(label, "K%dL%d", nums);
				int i1 = nums.get(0).intValue();
				int i2 = nums.get(1).intValue();
				return () -> getKL(i1, i2);
			} else if (label.contains("X")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(label, "K%dX%d", nums);
				int i1 = nums.get(0).intValue();
				int i2 = nums.get(1).intValue();
				return () -> getKX(i1, i2);
			} else if (label.contains("Y")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(label, "K%dY%d", nums);
				int i1 = nums.get(0).intValue();
				int i2 = nums.get(1).intValue();
				return () -> getKY(i1, i2);
			} else {
				n = label.substring(1);
			}
		} else if (label.startsWith("H")) {
			n = label.substring(1);
			radix = 16;
		} else if (label.startsWith("D")) {
			n = label.substring(1);
			int key = Integer.parseInt(n);
			if (m_savedD == null || key < m_savedDOffset) {
				return () -> m_D.getOrDefault(key, 0);
			} else {
				return () -> m_savedD.readDouble((key - m_savedDOffset) * Double.BYTES);
			}
		} else if (label.startsWith("C")) {
			n = label.substring(1);
			int key = Integer.parseInt(n);
			return () -> m_CN.getOrDefault(key, (long) 0);
		} else if (label.startsWith("T")) {
			n = label.substring(1);
			int key = Integer.parseInt(n);
			return () -> m_TN.getOrDefault(key, (long) 0);
		} else {
			n = label;
		}
		try {
			if (radix == 16) {
				long value = Long.parseLong(n, radix);
				return () -> value;
			} else {
				double value = Double.parseDouble(n);
				return () -> value;
			}
		} catch (NumberFormatException e) {
		}
		StaticJavaUtils.exit(label + " is not a number");
		return null;
	}

	private Consumer<Number> setNumberConsumer(String name, int offset) {
		if (name.startsWith("K")) {
			if (name.contains("M")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(name, "K%dM%d", nums);
				int i1 = nums.get(0).intValue();
				int i2 = nums.get(1).intValue();
				return value -> setKM(i1, i2, value.longValue());
			} else if (name.contains("L")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(name, "K%dL%d", nums);
				int i1 = nums.get(0).intValue();
				int i2 = nums.get(1).intValue();
				return value -> setKL(i1, i2, value.longValue());
			} else if (name.contains("X")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(name, "K%dX%d", nums);
				int i1 = nums.get(0).intValue();
				int i2 = nums.get(1).intValue();
				return value -> setKX(i1, i2, value.longValue());
			} else if (name.contains("Y")) {
				List<Number> nums = new ArrayList<>();
				StaticStringUtils.sscanf(name, "K%dY%d", nums);
				int i1 = nums.get(0).intValue();
				int i2 = nums.get(1).intValue();
				return value -> setKY(i1, i2, value.longValue());
			}
		} else {
			int index = Integer.parseInt(name.substring(1)) + offset;
			if (name.startsWith("D")) {
				if (m_savedD == null || index < m_savedDOffset) {
					return value -> m_D.put(index, value);
				} else {
					return value -> m_savedD.writeDouble((index - m_savedDOffset) * Double.BYTES, value.doubleValue());
				}
			} else if (name.startsWith("C")) {
				return value -> setCN(index, value.longValue());
			} else if (name.startsWith("T")) {
				return value -> setTN(index, value.longValue());
			} else {
				StaticJavaUtils.exit(name + " is not a number");
			}
		}
		return null;
	}
}