private static STz3 MkDecode(STBuilderZ3 stb, Sort charSort)
{
var z3p = stb.Solver;
Expr tt = z3p.True;
Expr[] eps = new Expr[] { };
List<Move<Rulez3>> rules = new List<Move<Rulez3>>();
Expr x = stb.MkInputVariable(charSort);
Sort regSort = z3p.MkTupleSort(charSort, charSort);
//the compound register
Expr yz = stb.MkRegister(regSort);
//the individual registers
Expr y = z3p.MkProj(0, yz);
Expr z = z3p.MkProj(1, yz);
//constant characer values
Expr amp = z3p.MkNumeral((int)'&', charSort);
Expr sharp = z3p.MkNumeral((int)'#', charSort);
Expr semi = z3p.MkNumeral((int)';', charSort);
Expr zero = z3p.MkNumeral((int)'0', charSort);
Expr nine = z3p.MkNumeral((int)'9', charSort);
Expr _1 = z3p.MkNumeral(1, charSort);
Expr _0 = z3p.MkNumeral(0, charSort);
Expr _10 = z3p.MkNumeral(10, charSort);
Expr _48 = z3p.MkNumeral(48, charSort);
//initial register value
Expr _11 = z3p.MkTuple(_1, _1);
//various terms
Expr xNEQ0 = z3p.MkNeq(x, _0);
Expr xEQ0 = z3p.MkEq(x, _0);
Expr xNEQamp = z3p.MkNeq(x, amp);
Expr xEQamp = z3p.MkEq(x, amp);
Expr xNEQsharp = z3p.MkNeq(x, sharp);
Expr xEQsharp = z3p.MkEq(x, sharp);
Expr xNEQsemi = z3p.MkNeq(x, semi);
Expr xEQsemi = z3p.MkEq(x, semi);
Expr xIsDigit = z3p.MkAnd(z3p.MkCharLe(zero, x), z3p.MkCharLe(x, nine));
Expr yIsDigit = z3p.MkAnd(z3p.MkCharLe(zero, y), z3p.MkCharLe(y, nine));
Expr zIsDigit = z3p.MkAnd(z3p.MkCharLe(zero, z), z3p.MkCharLe(z, nine));
Expr yzAreDigits = z3p.MkAnd(yIsDigit, zIsDigit);
Expr xIsNotDigit = z3p.MkNot(xIsDigit);
Expr decode = z3p.MkCharAdd(z3p.MkCharMul(_10, z3p.MkCharSub(y, _48)), z3p.MkCharSub(z, _48));
//final state
rules.Add(stb.MkFinalOutput(5, tt));
//terminating rules
rules.Add(stb.MkRule(0, 5, xEQ0, _11, _0));
rules.Add(stb.MkRule(1, 5, xEQ0, _11, amp, _0));
rules.Add(stb.MkRule(2, 5, xEQ0, _11, amp, sharp, _0));
rules.Add(stb.MkRule(3, 5, xEQ0, _11, amp, sharp, y, _0));
rules.Add(stb.MkRule(4, 5, xEQ0, _11, amp, sharp, y, z, _0));
//main rules
//rules from state q0
rules.Add(stb.MkRule(0, 0, z3p.MkAnd(xNEQ0, xNEQamp), yz, x));
rules.Add(stb.MkRule(0, 1, z3p.MkAnd(xNEQ0, xEQamp), yz));
//rules from state q1
rules.Add(stb.MkRule(1, 0, z3p.MkAnd(xNEQ0, z3p.MkAnd(xNEQamp, xNEQsharp)), yz, amp, x));
rules.Add(stb.MkRule(1, 1, z3p.MkAnd(xNEQ0, xEQamp), yz, amp));
rules.Add(stb.MkRule(1, 2, z3p.MkAnd(xNEQ0, xEQsharp), yz));
//rules from state q2
rules.Add(stb.MkRule(2, 0, z3p.MkAnd(xNEQ0, z3p.MkAnd(xNEQamp, xIsNotDigit)), yz, amp, sharp, x));
rules.Add(stb.MkRule(2, 1, z3p.MkAnd(xNEQ0, xEQamp), yz, amp, sharp));
rules.Add(stb.MkRule(2, 3, z3p.MkAnd(xNEQ0, xIsDigit), z3p.MkTuple(x, z)));
//rules from state q3
rules.Add(stb.MkRule(3, 0, z3p.MkAnd(xNEQ0, z3p.MkAnd(xNEQamp, xIsNotDigit)), _11, amp, sharp, y, x));
rules.Add(stb.MkRule(3, 1, z3p.MkAnd(xNEQ0, xEQamp), _11, amp, sharp, y));
rules.Add(stb.MkRule(3, 4, z3p.MkAnd(xNEQ0, xIsDigit), z3p.MkTuple(y, x)));
//rules from state q4
rules.Add(stb.MkRule(4, 0, z3p.MkAnd(xNEQ0, xEQsemi), _11, decode));
rules.Add(stb.MkRule(4, 0, z3p.MkAnd(xNEQ0, z3p.MkAnd(xNEQsemi, xNEQamp)), _11, amp, sharp, y, z, x));
rules.Add(stb.MkRule(4, 1, z3p.MkAnd(xNEQ0, xEQamp), _11, amp, sharp, y, z));
STz3 st = stb.MkST("Decode", _11, charSort, charSort, regSort, 0, rules);
return st;
}