private static STz3 MkDecodeWithFinalOutputs(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 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 outputs
rules.Add(stb.MkFinalOutput(0, tt));
rules.Add(stb.MkFinalOutput(1, tt, amp));
rules.Add(stb.MkFinalOutput(2, tt, amp, sharp));
rules.Add(stb.MkFinalOutput(3, tt, amp, sharp, y));
rules.Add(stb.MkFinalOutput(4, tt, amp, sharp, y, z));
//main rules
//rules from state q0
rules.Add(stb.MkRule(0, 0, xNEQamp, yz, x));
rules.Add(stb.MkRule(0, 1, xEQamp, yz));
//rules from state q1
rules.Add(stb.MkRule(1, 0, z3p.MkAnd(xNEQamp, xNEQsharp), yz, amp, x));
rules.Add(stb.MkRule(1, 1, xEQamp, yz, amp));
rules.Add(stb.MkRule(1, 2, xEQsharp, yz));
//rules from state q2
rules.Add(stb.MkRule(2, 0, z3p.MkAnd(xNEQamp, xIsNotDigit), yz, amp, sharp, x));
rules.Add(stb.MkRule(2, 1, xEQamp, yz, amp, sharp));
rules.Add(stb.MkRule(2, 3, xIsDigit, z3p.MkTuple(x, z)));
//rules from state q3
rules.Add(stb.MkRule(3, 0, z3p.MkAnd(xNEQamp, xIsNotDigit), _11, amp, sharp, y, x));
rules.Add(stb.MkRule(3, 1, xEQamp, _11, amp, sharp, y));
rules.Add(stb.MkRule(3, 4, xIsDigit, z3p.MkTuple(y, x)));
//rules from state q4
rules.Add(stb.MkRule(4, 0, xEQsemi, _11, decode));
rules.Add(stb.MkRule(4, 0, z3p.MkAnd(xNEQsemi, xNEQamp), _11, amp, sharp, y, z, x));
rules.Add(stb.MkRule(4, 1, xEQamp, _11, amp, sharp, y, z));
STz3 st = stb.MkST("Decode", _11, charSort, charSort, regSort, 0, rules);
return st;
}