private static bool isKeyWordOrProcName(Token t)
 {
     return(t.Type == TknType.Word && (Syntax.IsKeyWord(t.Text) || defProcs.Contains(t.Text)));
 }
        /// <summary> Proc calls or keywords </summary>
        private static int readNextExpr(ref List <Token> ts, ref List <byte> bytes, ref List <string> vars, int i)
        {
            int argCount = 0;

            //[cmd] [ [ops | null] args | null]
            //Need command or newline:
            if (ts[i].Type == TknType.NewLine || Syntax.IsEnumOperator(ts[i]))
            {
                return(i + 1);
            }
            if (ts[i].Type != TknType.Word)
            {
                new CompileException(inFile(ref ts, i), inLine(ref ts, i), ErrCode.UndefinedCommand, ts[i].Text);
            }
            //
            string cmd = ts[i].Text;

            i++; //to args
            if (IsProcessName(cmd))
            {
                //push args:
                while (!isKeyWordOrProcName(ts[i]) && !Syntax.IsTokenHasOperator(ts[i], Syntax.OP_END))
                {
                    bytes.AddRange(pushArg(ts[i], ref vars, inFile(ref ts, i), inLine(ref ts, i)));
                    i++;
                }

                //call proc:
                bytes.AddCmd(CmdType.RUN_ID, (uint)getProcID(cmd));
            }
            else
            {
                switch (cmd)
                {
                //new var
                case Syntax.KW_BYTE:
                    while (!isKeyWordOrProcName(ts[i]))
                    {
                        if (Syntax.IsEnumOperator(ts[i]) || ts[i].Type == TknType.NewLine)
                        {
                            i++;
                            continue;
                        }

                        if (ts[i].Type != TknType.Word)
                        {
                            new CompileException(inFile(ref ts, i), inLine(ref ts, i), ErrCode.InvalidArgument, $"'{ts[i].Text}' for {cmd}");
                        }

                        if (!vars.Contains(ts[i].Text))
                        {
                            vars.Add(ts[i].Text);
                        }

                        bytes.AddCmd(CmdType.BYTE_I, (uint)getVarID(ref vars, ts[i].Text));
                        i++;
                    }
                    break;

                //var or value
                case Syntax.KW_ADD: i = readCmd(CmdType.ADD_V, CmdType.ADD_I, cmd, ref ts, ref bytes, ref vars, i); break;

                case Syntax.KW_DIVIDE: i = readCmd(CmdType.DIV_V, CmdType.DIV_I, cmd, ref ts, ref bytes, ref vars, i); break;

                case Syntax.KW_IS: i = readCmd(CmdType.IS_V, CmdType.IS_I, cmd, ref ts, ref bytes, ref vars, i); break;

                case Syntax.KW_MODULE: i = readCmd(CmdType.MOD_C, CmdType.MOD_B, cmd, ref ts, ref bytes, ref vars, i); break;

                case Syntax.KW_MULTIPLY: i = readCmd(CmdType.MUL_V, CmdType.MUL_I, cmd, ref ts, ref bytes, ref vars, i); break;

                case Syntax.KW_PUSH: i = readCmd(CmdType.PUSH_V, CmdType.PUSH_I, cmd, ref ts, ref bytes, ref vars, i); break;

                case Syntax.KW_SUBTRACT: i = readCmd(CmdType.SUB_V, CmdType.SUB_I, cmd, ref ts, ref bytes, ref vars, i); break;

                //roots
                case Syntax.KW_IF: i = readIf(ref ts, ref bytes, ref vars, i); break;

                case Syntax.KW_WHILE: i = readWhile(ref ts, ref bytes, ref vars, i); break;

                //var only
                case Syntax.KW_THIS: i = readVarArgOnlyCmd(CmdType.THIS_I, cmd, ref ts, ref bytes, ref vars, i, ref argCount); break;

                case Syntax.KW_POP:
                    i = readVarArgOnlyCmd(CmdType.POP_I, cmd, ref ts, ref bytes, ref vars, i, ref argCount);
                    if (argCount == 0)
                    {
                        bytes.AddCmd(CmdType.POP);
                    }
                    break;

                case Syntax.KW_PEEK: i = readVarArgOnlyCmd(CmdType.PEEK_B, cmd, ref ts, ref bytes, ref vars, i, ref argCount); break;

                case Syntax.KW_DECREMENT: i = readVarArgOnlyCmd(CmdType.DEC_B, cmd, ref ts, ref bytes, ref vars, i, ref argCount); break;

                case Syntax.KW_INCREMENT: i = readVarArgOnlyCmd(CmdType.INC_B, cmd, ref ts, ref bytes, ref vars, i, ref argCount); break;

                case Syntax.KW_NOT: i = readVarArgOnlyCmd(CmdType.NOT_B, cmd, ref ts, ref bytes, ref vars, i, ref argCount); break;

                case Syntax.KW_INPUT:
                    i = readVarArgOnlyCmd(CmdType.INPUT_B, cmd, ref ts, ref bytes, ref vars, i, ref argCount);
                    if (argCount == 0)
                    {
                        bytes.AddCmd(CmdType.INPUT);
                    }
                    break;

                //var or 3 value
                case Syntax.KW_OUTPUT: i = readOutput(CmdType.SUB_V, CmdType.SUB_I, cmd, ref ts, ref bytes, ref vars, i); break;

                //null
                case Syntax.KW_FLIP: bytes.AddCmd(CmdType.FLIP); break;

                case Syntax.KW_STOP: bytes.AddCmd(CmdType.PRC_STP); break;

                case Syntax.KW_OUTCLEAR: bytes.AddCmd(CmdType.CLR_OUT); break;

                case Syntax.KW_STACLEAR: bytes.AddCmd(CmdType.CLR_STK); break;

                case Syntax.KW_PUSH_THIS: bytes.AddCmd(CmdType.PUSH_T); break;

                case Syntax.KW_POP_THIS: bytes.AddCmd(CmdType.POP_T); break;

                //
                default: new CompileException(inFile(ref ts, i), inLine(ref ts, i), ErrCode.UndefinedCommand, cmd); break;
                }
            }

            Console.Write($"\r{(int)((float)i * 100.0 / ts.Count)}%");
            return(i);
        }
        private static int readIf(ref List <Token> ts, ref List <byte> bytes, ref List <string> vars, int i)
        {
            //if [var | has | pop | const] { ... }
            //ARGUMENT:
            Token arg = ts[i];

            switch (arg.Type)
            {
            case TknType.Number: bytes.AddCmd(CmdType.IF_C, toByte(arg.Text, inFile(ref ts, i), inLine(ref ts, i))); break;

            case TknType.Char: bytes.AddCmd(CmdType.IF_C, (byte)arg.Text[0]); break;

            case TknType.Word:
                switch (arg.Text)
                {
                case Syntax.OP_HAS: bytes.AddCmd(CmdType.IF_HAS); break;

                case Syntax.KW_POP: bytes.AddCmd(CmdType.IF_POP); break;

                default:
                    if (!vars.Contains(arg.Text))
                    {
                        new CompileException(inFile(ref ts, i), inLine(ref ts, i), ErrCode.UndefinedVariable, arg.Text);
                    }

                    bytes.AddCmd(CmdType.IF_B, (uint)getVarID(ref vars, arg.Text));
                    break;
                }
                break;

            default: new CompileException(inFile(ref ts, i), inLine(ref ts, i), ErrCode.InvalidArgument, $"'{arg.Text}' for if"); break;
            }
            //SEEK BODY ('{'):
            i++;
            while (!Syntax.IsTokenHasOperator(ts[i], Syntax.OP_BEGIN))
            {
                if (ts[i].Type != TknType.NewLine)
                {
                    new CompileException(inFile(ref ts, i), inLine(ref ts, i), ErrCode.UndefinedBody, "if");
                }
                i++;
            }
            //READ BODY:
            i = readNextBody(ref ts, ref bytes, ref vars, i) + 1;
            //SEEK ELSE:
            while (!Syntax.IsTokenHasKeyWord(ts[i], Syntax.KW_ELSE))
            {
                if (ts[i].Type != TknType.NewLine)
                {
                    break;
                }
                i++;
            }
            //IS ELSE?
            if (Syntax.IsTokenHasKeyWord(ts[i], Syntax.KW_ELSE))
            {
                bytes.AddCmd(CmdType.IF_ELSE);
                //SEEK ELSE BODY ('{'):
                i++;
                while (!Syntax.IsTokenHasOperator(ts[i], Syntax.OP_BEGIN))
                {
                    if (ts[i].Type != TknType.NewLine)
                    {
                        new CompileException(inFile(ref ts, i), inLine(ref ts, i), ErrCode.UndefinedBody, "else");
                    }
                    i++;
                }
                //READ ELSE BODY:
                i = readNextBody(ref ts, ref bytes, ref vars, i) + 1;
            }
            //END:
            bytes.AddCmd(CmdType.IF_END);

            return(i);
        }
        private static void seekProcDefs(ref List <Token> ts)
        {
            defProcs = new List <string>();

            int    L   = 1;
            string F   = "[not found]";
            int    lvl = 0;

            for (int i = 0; i < ts.Count; i++)
            {
                if (Syntax.IsTokenHasKeyWord(ts[i], Syntax.KW_PROCESS))
                {
                    if (lvl != 0)
                    {
                        new CompileException(F, L, ErrCode.ProcInProc);
                    }

                    i++;
                    if (ts[i].Type != TknType.Word)
                    {
                        new CompileException(F, L, ErrCode.ProcNameNotFound);
                    }

                    if (!Syntax.IsKeyWord(ts[i].Text))
                    {
                        addUniqueProcName(ts[i].Text);
                    }
                    else
                    {
                        new CompileException(F, L, ErrCode.KeyProc, ts[i].Text);
                    }
                    //skip args...
                    i = seekProcBodies(i, ref ts, F, ref L);
                }
                else
                {
                    if (ts[i].Type != TknType.FilePtr && ts[i].Type != TknType.NewLine && lvl == 0)
                    {
                        new CompileException(F, L, ErrCode.BadTokenArea, ts[i].Text);
                    }
                }

                if (ts[i].Type == TknType.Operator)
                {
                    if (ts[i].Text == Syntax.OP_BEGIN)
                    {
                        lvl++;
                    }
                    if (ts[i].Text == Syntax.OP_END)
                    {
                        lvl--;
                    }
                }

                if (ts[i].Type == TknType.FilePtr)
                {
                    F = ts[i].Text;
                    L = 1;
                }

                L += ts[i].Type == TknType.NewLine ? 1 : 0;
            }
        }