/// <summary>
        /// If t is a variable name then returns t as a f-o variable and sets psi=null.
        /// Else returns a fresh f-o variable x and outputs psi(x) s.t. psi(x) iff x=t.
        /// </summary>
        Variable ConvertTerm1(MonaExpr t, MapStack <string, MonaParam> locals, out MSOFormula <BDD> psi)
        {
            switch (t.symbol.Kind)
            {
            case Tokens.NAME:
            {
                MonaParam p;
                if (locals.TryGetValue(t.symbol.text, out p))
                {
                    if (p.kind == MonaParamKind.var1)
                    {
                        psi = null;
                        return(new Variable(t.symbol.text, true));
                    }
                    else
                    {
                        throw new NotImplementedException(t.ToString());
                    }
                }
                else
                {
                    MonaDecl d;
                    if (globals.TryGetValue(t.symbol.text, out d))
                    {
                        if (d.kind == MonaDeclKind.constant)
                        {
                            int      n    = ((MonaConstDecl)d).def.ToInt(globals);
                            Variable x    = MkNewVar1();
                            var      pred = new MSOeqN <BDD>(x, n);
                            psi = pred;
                            return(x);
                        }
                        else
                        {
                            throw new NotImplementedException(t.ToString());
                        }
                    }
                    else
                    {
                        throw new NotImplementedException(t.ToString());
                    }
                }
            }

            case Tokens.PLUS:
            {
                Variable y = MkNewVar1();
                if (t[0].symbol.Kind == Tokens.NAME)
                {
                    int      n = t[1].ToInt(globals);
                    Variable x = new Variable(t[0].symbol.text, true);
                    psi = new MSOSuccN <BDD>(x, y, n);        // y = x + n
                }
                else
                {
                    int n = t.ToInt(globals);
                    psi = new MSOeqN <BDD>(y, n);        // y = n
                }
                return(y);
            }

            case Tokens.MIN:
            {
                MSOFormula <BDD> X_psi;
                Variable         X   = ConvertTerm2(t[0], locals, out X_psi);
                Variable         x   = MkNewVar1();
                MSOFormula <BDD> min = new MSOMin <BDD>(x, X);
                if (X_psi != null)
                {
                    min = new MSOExists <BDD>(X, new MSOAnd <BDD>(X_psi, min));
                }
                psi = min;
                return(x);
            }

            case Tokens.MAX:
            {
                MSOFormula <BDD> X_psi;
                Variable         X   = ConvertTerm2(t[0], locals, out X_psi);
                Variable         x   = MkNewVar1();
                MSOFormula <BDD> max = new MSOMax <BDD>(x, X);
                if (X_psi != null)
                {
                    max = new MSOExists <BDD>(X, new MSOAnd <BDD>(X_psi, max));
                }
                psi = max;
                return(x);
            }

            default:
                throw new NotImplementedException(t.ToString());
            }
        }
        /// <summary>
        /// If t is a variable name then returns t as a f-o variable and sets psi=null.
        /// Else returns a fresh f-o variable x and outputs psi(x) s.t. psi(x) iff x=t.
        /// </summary>
        Variable ConvertTerm1(MonaExpr t, MapStack<string, MonaParam> locals, out MSOFormula<BDD> psi)
        {
            switch (t.symbol.Kind)
            {
                case Tokens.NAME:
                    {
                        MonaParam p;
                        if (locals.TryGetValue(t.symbol.text, out p))
                        {
                            if (p.kind == MonaParamKind.var1)
                            {
                                psi = null;
                                return new Variable(t.symbol.text, true);
                            }
                            else
                                throw new NotImplementedException(t.ToString());
                        }
                        else
                        {
                            MonaDecl d;
                            if (globals.TryGetValue(t.symbol.text, out d))
                            {
                                if (d.kind == MonaDeclKind.constant)
                                {
                                    int n = ((MonaConstDecl)d).def.ToInt(globals);
                                    Variable x = MkNewVar1();
                                    var pred = new MSOeqN<BDD>(x, n);
                                    psi = pred;
                                    return x;
                                }
                                else if (d.kind == MonaDeclKind.var1)
                                {
                                    psi = null;
                                    return new Variable(t.symbol.text, true);
                                }
                                else
                                    throw new NotImplementedException(t.ToString());
                            }
                            else
                                throw new NotImplementedException(t.ToString());
                        }
                    }
                case Tokens.PLUS:
                    {
                        Variable y = MkNewVar1();
                        if (t[0].symbol.Kind == Tokens.NAME)
                        {
                            int n = t[1].ToInt(globals);
                            Variable x = new Variable(t[0].symbol.text, true);
                            psi = new MSOSuccN<BDD>(x, y, n); // y = x + n
                        }
                        else
                        {
                            int n = t.ToInt(globals);
                            psi = new MSOeqN<BDD>(y, n); // y = n
                        }
                        return y;
                    }
                case Tokens.MIN:
                    {
                        MSOFormula<BDD> X_psi;
                        Variable X = ConvertTerm2(t[0], locals, out X_psi);
                        Variable x = MkNewVar1();
                        MSOFormula<BDD> min = new MSOMin<BDD>(x, X);
                        if (X_psi != null)
                            min = new MSOExists<BDD>(X, new MSOAnd<BDD>(X_psi, min));
                        psi = min;
                        return x;
                    }
                case Tokens.MAX:
                    {
                        MSOFormula<BDD> X_psi;
                        Variable X = ConvertTerm2(t[0], locals, out X_psi);
                        Variable x = MkNewVar1();
                        MSOFormula<BDD> max = new MSOMax<BDD>(x, X);
                        if (X_psi != null)
                            max = new MSOExists<BDD>(X, new MSOAnd<BDD>(X_psi, max));
                        psi = max;
                        return x;
                    }

                case Tokens.NUMBER:
                    {
                        Variable x = MkNewVar1();
                        int num = t.symbol.ToInt();
                        psi = new MSOeqN<BDD>(x,num);
                        return x;
                    }
                default:
                    throw new NotImplementedException(t.ToString());
            }
        }