private static Instruction GetInstructions(ParserState state, Token previous)
        {
            Instruction inst = new Instruction();

            do
            {
                if (state.PeepToken().Name == ",")
                {
                    state.PopToken();
                }
                Token open = state.PopToken();
                if (open == null || open.Name != "(")
                {
                    previous.ThrowException("Expected program format: (A1,G1),(A2,G2),...,(An,Gn)");
                }
                Token a = state.PopToken();
                if (a == null)
                {
                    open.ThrowException("Expected action");
                }
                if (a.Name == ")")
                {
                    return(inst);
                }
                if (state.Action.ContainsKey(a.Name) == false)
                {
                    open.ThrowException("Expected action");
                }
                Token comma = state.PopToken();
                if (comma == null || comma.Name != ",")
                {
                    a.ThrowException("Comma should separate an action and a set of agents");
                }
                MultiAgentLanguageModels.Action a1 = new MultiAgentLanguageModels.Action(a.Name);
                AgentsList g     = GetAgentList(state);
                Token      close = state.PopToken();
                if (close == null || close.Name != ")")
                {
                    a.ThrowException("Expected )");
                }
                inst.Add(new Tuple <MultiAgentLanguageModels.Action, AgentsList>(a1, g));
            } while (state.PeepToken() != null && state.PeepToken().Name == ",");
            return(inst);
        }
        public static void ParseKeyword(ParserState state, Token firstToken)
        {
            switch (firstToken.Name)
            {
            case "initially":
                LogicElement le = EntryC1(state);
                Initially    st = new Initially(le);
                state.Expression.Add(st);
                break;

            case "noninertial":
                ParseNoninertial(state, firstToken);
                break;

            case "by":
                Token action = state.TokenList[state.TokenList.Count - 1];
                state.TokenList.RemoveAt(state.TokenList.Count - 1);
                AgentsList al = GetAgentList(state);
                if (al == null)
                {
                    firstToken.ThrowException("Expected ']' at the end of agents list.");
                }
                Token t = state.PopToken();
                if (t == null)
                {
                    firstToken.ThrowException("Expected 'causes' or 'releases'.");
                }

                LogicElement result = null;
                if (t.Name == "releases")
                {
                    Token fT = state.PopToken();
                    if (fT == null)
                    {
                        firstToken.ThrowException("Expected fluent after release.");
                    }
                    else if (!state.Fluent.ContainsKey(fT.Name))
                    {
                        firstToken.ThrowException("Attempting to use undeclared fluent.");
                    }
                    result = state.Fluent[fT.Name];
                }
                else
                if (t.Name == "causes")
                {
                    result = EntryC1(state);
                }
                else
                {
                    t.ThrowException("Expected 'causes' or 'releases'.");
                }

                if (t.Name == "releases" && (result is Fluent) == false)
                {
                    t.ThrowException("Expected fluent after release.");
                }

                LogicElement condition = null;
                Token        if_token  = state.PeepToken();
                if (if_token != null && if_token.Name == "if")
                {
                    state.PopToken();
                    condition = EntryC1(state);
                }
                if (t.Name == "causes")
                {
                    if (condition == null)
                    {
                        state.Expression.Add(new MultiAgentLanguageModels.Expressions.ByCauses(
                                                 new MultiAgentLanguageModels.Action(action.Name),
                                                 al, result));
                    }
                    else
                    {
                        state.Expression.Add(new MultiAgentLanguageModels.Expressions.ByCausesIf(
                                                 new MultiAgentLanguageModels.Action(action.Name),
                                                 al, result, condition));
                    }
                }
                if (t.Name == "releases")
                {
                    if (condition == null)
                    {
                        state.Expression.Add(new MultiAgentLanguageModels.Expressions.ByReleases(
                                                 new MultiAgentLanguageModels.Action(action.Name),
                                                 al, (Fluent)result));
                        state.Expression.Add(new MultiAgentLanguageModels.Expressions.ByCauses(
                                                 new MultiAgentLanguageModels.Action(action.Name),
                                                 al, new Or(result, new Not(result))));
                    }
                    else
                    {
                        state.Expression.Add(new MultiAgentLanguageModels.Expressions.ByReleasesIf(
                                                 new MultiAgentLanguageModels.Action(action.Name),
                                                 al, (Fluent)result, condition));
                        state.Expression.Add(new MultiAgentLanguageModels.Expressions.ByCausesIf(
                                                 new MultiAgentLanguageModels.Action(action.Name),
                                                 al, new Or(result, new Not(result)), condition));
                    }
                }
                break;

            case "causes":
                MultiAgentLanguageModels.Action act =
                    new MultiAgentLanguageModels.Action(state.TokenList[state.TokenList.Count - 1].Name);
                state.TokenList.RemoveAt(state.TokenList.Count - 1);
                LogicElement effect = EntryC1(state);
                Token        if_exp = state.PeepToken();
                if (if_exp != null && if_exp.Name == "if")
                {
                    state.PopToken();
                    LogicElement con = EntryC1(state);
                    state.Expression.Add(new CausesIf(act, effect, con));
                }
                else
                {
                    state.Expression.Add(new Causes(act, effect));
                }
                break;

            case "releases":
                MultiAgentLanguageModels.Action act1 =
                    new MultiAgentLanguageModels.Action(state.TokenList[state.TokenList.Count - 1].Name);
                state.TokenList.RemoveAt(state.TokenList.Count - 1);
                Token eff1 = state.PopToken();
                if (eff1 == null)
                {
                    firstToken.ThrowException("Expected fluent after release.");
                }
                else if (!state.Fluent.ContainsKey(eff1.Name))
                {
                    firstToken.ThrowException("Attempting to use undeclared fluent.");
                }
                Token if_expr = state.PeepToken();
                if (if_expr != null && if_expr.Name == "if")
                {
                    state.PopToken();
                    LogicElement con = EntryC1(state);
                    state.Expression.Add(new ReleasesIf(act1, state.Fluent[eff1.Name], con));
                    state.Expression.Add(new CausesIf(act1, new Or(state.Fluent[eff1.Name], new Not(state.Fluent[eff1.Name])), con));
                }
                else
                {
                    state.Expression.Add(new Releases(act1, state.Fluent[eff1.Name]));
                    state.Expression.Add(new Causes(act1, new Or(state.Fluent[eff1.Name], new Not(state.Fluent[eff1.Name]))));
                }
                break;

            case "if":
                firstToken.ThrowException("Unexpected 'if' token.");
                break;

            case "impossible":
                Token token = state.PopToken();
                if (token == null)
                {
                    firstToken.ThrowException("Expected action name.");
                }
                if (!state.Action.ContainsKey(token.Name))
                {
                    token.ThrowException("Unknown action name.");
                }
                MultiAgentLanguageModels.Action ac = new MultiAgentLanguageModels.Action(token.Name);
                Token key = state.PopToken();
                if (key == null)
                {
                    firstToken.ThrowException("Expected 'by' or 'if' token.");
                }
                AgentsList agentsList = null;
                if (key.Name == "by")
                {
                    agentsList = GetAgentList(state);
                    Token cond_st = state.PeepToken();
                    if (cond_st == null || cond_st.Name != "if")
                    {
                        state.Expression.Add(new ImpossibleBy(ac, agentsList));
                    }
                    else
                    {
                        state.PopToken();
                        LogicElement c = EntryC1(state);
                        state.Expression.Add(new ImpossibleByIf(ac, agentsList, c));
                    }
                }
                else if (key.Name == "if")
                {
                    //Token cond_st = state.PopToken();
                    //if (cond_st == null || cond_st.Name != "if")
                    //key.ThrowException("Expected if after the list of agents.");
                    LogicElement c = EntryC1(state);
                    state.Expression.Add(new ImpossibleIf(ac, c));
                }
                else
                {
                    firstToken.ThrowException("Expected 'by' or 'if' token.");
                }
                break;

            case "always":
                LogicElement cond = EntryC1(state);
                state.Expression.Add(new Always(cond));
                break;

            case "not":
                Token act2 = state.TokenList[state.TokenList.Count - 1];
                MultiAgentLanguageModels.Action actt = new MultiAgentLanguageModels.Action(act2.Name);
                state.TokenList.RemoveAt(state.TokenList.Count - 1);
                Token by = state.PopToken();
                if (by == null || by.Name != "by")
                {
                    firstToken.ThrowException("Expected 'by' after 'not'.");
                }
                AgentsList agents = GetAgentList(state);
                Token      if_st  = state.PeepToken();
                if (if_st != null && if_st.Name == "if")
                {
                    state.PopToken();
                    condition = EntryC1(state);
                    foreach (Agent a in agents)
                    {
                        state.Expression.Add(new ImpossibleByIf(actt, new AgentsList()
                        {
                            a
                        }, condition));
                        Output.Print($"{actt.Name} not by {a.Name} under cond {condition.ToString()}");
                    }
                }
                else
                {
                    foreach (Agent a in agents)
                    {
                        state.Expression.Add(new ImpossibleBy(actt, new AgentsList()
                        {
                            a
                        }));
                    }
                }
                break;

            case "after":
                LogicElement observable = EntryC1(state);
                Token        aft        = state.PopToken();
                if (aft == null || aft.Name != "after")
                {
                    firstToken.ThrowException("Expected 'after' after logic expression.");
                }
                Instruction instr     = GetInstructions(state, aft);
                After       after_exp = new After(observable, instr);
                state.Expression.Add(after_exp);
                break;

            case "observable":
                LogicElement obs   = EntryC1(state);
                Token        after = state.PopToken();
                if (after == null || after.Name != "after")
                {
                    firstToken.ThrowException("Expected 'after' after logic expression.");
                }
                Instruction     inst     = GetInstructions(state, after);
                ObservableAfter obsAfter = new ObservableAfter(obs, inst);
                state.Expression.Add(obsAfter);
                break;
            }
        }