private static ST<FuncDecl, Expr, Sort> MkDecodeWithFinalOutputs(IContext<FuncDecl, Expr, Sort> z3p, Sort charSort)
{
Expr tt = z3p.True;
Expr[] eps = new Expr[] { };
List<Move<Rule<Expr>>> rules = new List<Move<Rule<Expr>>>();
Expr x = z3p.MkVar(0,charSort);
Sort regSort = z3p.MkTupleSort(charSort, charSort);
//the compound register
Expr yz = z3p.MkVar(1, 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(Move<Rule<Expr>>.Create(0, 0, Rule<Expr>.MkFinal(tt)));
rules.Add(Move<Rule<Expr>>.Create(1, 1, Rule<Expr>.MkFinal(tt, amp)));
rules.Add(Move<Rule<Expr>>.Create(2, 2, Rule<Expr>.MkFinal(tt, amp, sharp)));
rules.Add(Move<Rule<Expr>>.Create(3, 3, Rule<Expr>.MkFinal(tt, amp, sharp, y)));
rules.Add(Move<Rule<Expr>>.Create(4, 4, Rule<Expr>.MkFinal(tt, amp, sharp, y, z)));
//main rules
//rules from state q0
rules.Add(Move<Rule<Expr>>.Create(0, 0, Rule<Expr>.Mk(xNEQamp, yz, x)));
rules.Add(Move<Rule<Expr>>.Create(0, 1, Rule<Expr>.Mk(xEQamp, yz)));
//rules from state q1
rules.Add(Move<Rule<Expr>>.Create(1, 0, Rule<Expr>.Mk(z3p.MkAnd(xNEQamp, xNEQsharp), yz, amp, x)));
rules.Add(Move<Rule<Expr>>.Create(1, 1, Rule<Expr>.Mk(xEQamp, yz, amp)));
rules.Add(Move<Rule<Expr>>.Create(1, 2, Rule<Expr>.Mk( xEQsharp, yz)));
//rules from state q2
rules.Add(Move<Rule<Expr>>.Create(2, 0, Rule<Expr>.Mk(z3p.MkAnd(xNEQamp, xIsNotDigit), yz, amp, sharp, x)));
rules.Add(Move<Rule<Expr>>.Create(2, 1, Rule<Expr>.Mk(xEQamp, yz, amp, sharp)));
rules.Add(Move<Rule<Expr>>.Create(2, 3, Rule<Expr>.Mk(xIsDigit, z3p.MkTuple(x, z))));
//rules from state q3
rules.Add(Move<Rule<Expr>>.Create(3, 0, Rule<Expr>.Mk(z3p.MkAnd(xNEQamp, xIsNotDigit), _11, amp, sharp, y, x)));
rules.Add(Move<Rule<Expr>>.Create(3, 1, Rule<Expr>.Mk(xEQamp, _11, amp, sharp, y)));
rules.Add(Move<Rule<Expr>>.Create(3, 4, Rule<Expr>.Mk(xIsDigit, z3p.MkTuple(y, x))));
//rules from state q4
rules.Add(Move<Rule<Expr>>.Create(4, 0, Rule<Expr>.Mk(xEQsemi, _11, decode)));
rules.Add(Move<Rule<Expr>>.Create(4, 0, Rule<Expr>.Mk(z3p.MkAnd(xNEQsemi, xNEQamp), _11, amp, sharp, y, z, x)));
rules.Add(Move<Rule<Expr>>.Create(4, 1, Rule<Expr>.Mk(xEQamp, _11, amp, sharp, y, z)));
ST<FuncDecl, Expr, Sort> st = ST<FuncDecl, Expr, Sort>.Create(z3p, "Decode", _11, charSort, charSort, regSort, 0, rules);
return st;
}