예제 #1
0
        private void ParseScript(string data, string[] args, int lnoffs, ref Stack <ScriptArray> stack)
        {
            // chars to trim from strings
            char[] trim = new char[] { ' ', '\t' };

            // some variables to help with stuff
            Stack <ScriptCondition> co = new Stack <ScriptCondition>();

            if (debug)
            {
                Debug(new string('-', 80));
            }

            // use line num to accurately report issues
            uint lnum = (uint)lnoffs, tabs = 0;

            foreach (string ln in data.Replace("\r", "").Split('\n'))
            {
                lnum++;

                // trim whitespaces and tabs from start. Also C# is gay sometimes
                string line = ln.Trim(trim);
                // ignore empty lines
                if (line.Length > 0)
                {
                    try {
                        switch (line.ElementAt(0))
                        {
                        case '#':
                            //ignore comments
                            break;

                        case '}':
                            tabs--;
                            // we need 2 entries to remove one of them, to have one entry still in stack
                            if (stack.Count < 2)
                            {
                                screrr(lnum, "Stack is empty. Maybe there is an extra script block end?");
                            }

                            // } { -> else
                            if (line.EndsWith("{"))
                            {
                                // if co not set, its a problem
                                if (co.Count <= 0)
                                {
                                    screrr(lnum, "Else called when not in condition block");
                                }
                                // if already in false block, error
                                if (stack.Peek() == co.Peek().False)
                                {
                                    screrr(lnum, "Else called when already inside else block");
                                }

                                // pop last entry and push false block in
                                stack.Pop();
                                stack.Push(co.Peek().False);
                                if (debug)
                                {
                                    Debug(lnum, tabs++, "}{");
                                }
                            }
                            else
                            {
                                // pop from co stack (NEEDS TO BE FIRST FUU)
                                if (co.Count > 0 && (co.Peek().True == stack.Peek() || co.Peek().False == stack.Peek()))
                                {
                                    co.Pop();
                                }

                                stack.Pop();
                                if (debug)
                                {
                                    Debug(lnum, tabs, "}");
                                }
                            }
                            break;

                        case '?':
                            if (line.Length < 3)
                            {
                                // if line is too short, it is a major problem
                                screrr(lnum, "Name not specified.");
                            }

                            string name = line.Substring(1, line.Length - 2).Trim(trim);
                            if (name.Length <= 0)
                            {
                                // no usable name
                                screrr(lnum, "Name not specified.");
                            }

                            if (line.EndsWith("{"))
                            {
                                // declaring subscript
                                ScriptArray f = new ScriptArray(stack.Peek());
                                subscripts.Add(name, f);
                                stack.Push(f);
                                if (debug)
                                {
                                    Debug(lnum, tabs++, '?' + name + " {");
                                }
                            }
                            else if (line.EndsWith(";"))
                            {
                                // subscript importing
                                stack.Peek().Add(new ScriptImport(lnum, stack.Peek(), name));
                                if (debug)
                                {
                                    Debug(lnum, tabs, '?' + name + ';');
                                }
                            }
                            else
                            {
                                // if line doesnt end with ; or {, there is an issue
                                screrr(lnum, "invalid end token.");
                            }
                            break;

                        case '/':
                            // get the label only if there is a space char
                            bool singlemode = line.Length > 1 && line.ElementAt(1) == '/';
                            line = line.Substring(singlemode ? 2 : 1);

                            string lbl = "";
                            int    ind;
                            if ((ind = line.IndexOf(' ')) != -1)
                            {
                                lbl  = line.Substring(0, ind);
                                line = line.Substring(ind + 1);
                            }

                            // check if rest of the info exists
                            if (line.Length < 2)
                            {
                                screrr(lnum, "Illegal line");
                            }

                            List <bool>   types = new List <bool>();
                            List <string> names = new List <string>();

                            while (line.Length > 0)
                            {
                                // get the caller type
                                types.Add(line.StartsWith("?"));
                                if (!types.Last() && !line.StartsWith(">"))
                                {
                                    screrr(lnum, "Illegal type '" + line.ElementAt(0) + "'");
                                }

                                // get the offset of the last char
                                int last = line.IndexOf(' ') + 1;
                                if (last == 0)
                                {
                                    last = line.Length;
                                }

                                // add the string in and remove from line
                                names.Add(line.Substring(1, last - 1).Trim(trim));
                                line = line.Substring(last);
                            }

                            stack.Peek().Add(new ScriptExecute(lnum, stack.Peek(), lbl, types.ToArray(), names.ToArray(), singlemode));

                            // write debug info
                            if (debug)
                            {
                                string db = '/' + lbl;
                                for (int i = 0; i < types.Count; i++)
                                {
                                    db += ' ' + (types[i] ? "?" : ">") + names[i];
                                }

                                Debug(lnum, tabs, db);
                            }
                            break;

                        case '=':
                            int indx = line.IndexOf(' ');
                            if (indx == -1)
                            {
                                screrr(lnum, "Expected a whitespace (' '), but found none.");
                            }

                            // just some sanity checks, dont worry
                            string equ = line.Substring(1, indx - 1), val = line.Substring(indx + 1);
                            if (equ.Length < 1)
                            {
                                screrr(lnum, "Equate name not specified.");
                            }
                            if (val.Length < 1)
                            {
                                screrr(lnum, "Equate value not specified.");
                            }

                            ScriptEquate scre = new ScriptEquate(lnum, stack.Peek(), equ, val);
                            stack.Peek().Add(scre);
                            if (debug)
                            {
                                string n = scre.GetName();
                                Equate e = GetEquate(n);
                                Debug(lnum, tabs, '=' + n + ' ' + val + (e.calculated ? " " + e.value : ""));
                            }
                            break;

                        case '!':
                            // skip ! and any spaces
                            line = line.Substring(1).TrimStart(trim);

                            // loop til all arguments are found
                            int           index;
                            List <string> pre = new List <string>();
                            while (!line.StartsWith(">"))
                            {
                                // find the next ,
                                index = line.IndexOf(',');
                                // if > is earlier than , (because arguments also can have them), then use > instead
                                if (line.IndexOf('>') < index || index < 1)
                                {
                                    index = line.IndexOf('>');
                                }
                                if (index < 1)
                                {
                                    screrr(lnum, "Invalid or nonexistent trigger byte at macro block.");
                                }

                                // create new argument and
                                pre.Add(line.Substring(0, index).Trim(trim));
                                line = line.Substring(index);
                                // if starts with , then remove it
                                if (line.StartsWith(","))
                                {
                                    line = line.Substring(1);
                                }
                            }

                            // get the name
                            index = line.IndexOf(':');
                            if (index == -1)
                            {
                                screrr(lnum, "Expecting semicolon (':')");
                            }
                            string nam = line.Substring(1, index - 1).Trim(trim);
                            line = line.Substring(index + 1).TrimStart(trim);
                            if (nam.Length < 1)
                            {
                                screrr(lnum, "Invalid name");
                            }

                            // get the arguments
                            List <string> arg = new List <string>();
                            while (!line.StartsWith(";") && !line.StartsWith("{"))
                            {
                                // find the next ,
                                index = line.IndexOf(',');
                                // if failed, then try to find the end icon
                                if (index < 1)
                                {
                                    index = line.IndexOf(';');
                                }
                                if (index < 1)
                                {
                                    index = line.IndexOf('{');
                                }
                                if (index < 1)
                                {
                                    screrr(lnum, "Invalid or nonexistent argument at macro block.");
                                }

                                // create new argument and
                                arg.Add(line.Substring(0, index).Trim(trim));
                                line = line.Substring(index);
                                // if starts with , then remove it
                                if (line.StartsWith(","))
                                {
                                    line = line.Substring(1);
                                }
                            }

                            // create a new macro
                            ScriptMacro s = new ScriptMacro(lnum, stack.Peek(), nam, pre.ToArray(), arg.ToArray());
                            stack.Peek().Add(s);

                            // if ends with this, put shit in inner block
                            if (line.EndsWith("{"))
                            {
                                stack.Push(s.Inner);
                            }

                            // write debug shit
                            if (debug)
                            {
                                Debug(lnum, tabs, '!' + string.Join(", ", pre) + " > " + nam + ": " + string.Join(", ", arg) + line.ElementAt(line.Length - 1));
                                if (line.EndsWith("{"))
                                {
                                    tabs++;
                                }
                            }
                            break;

                        case '@':
                            // check if there is a space
                            int indie = line.IndexOf(' ');
                            if (indie == -1)
                            {
                                screrr(lnum, "Expected whitespace (' '), but found none.");
                            }
                            // get the equate name and remove from line
                            string eqq = line.Substring(1, indie - 1);
                            line = line.Substring(indie + 1).TrimStart(trim);

                            // check for next space
                            indie = line.IndexOf(' ');
                            if (indie == -1)
                            {
                                screrr(lnum, "Expected whitespace (' '), but found none.");
                            }
                            // get the arg number
                            int argnum;
                            if (!Int32.TryParse(line.Substring(0, indie), out argnum))
                            {
                                screrr(lnum, "Line '" + line.Substring(0, indie) + "' can not be parsed as a number!");
                            }

                            string da;
                            // check if there are arguments at this offset
                            if (argnum >= args.Length)
                            {
                                // print out the string
                                indie = line.IndexOf("\"") + 1;
                                if (indie == 0)
                                {
                                    screrr(lnum, "Expected string, but found none.");
                                }
                                Console.Write(line.Substring(indie, line.LastIndexOf("\"") - indie) + ": ");

                                da = ConsoleArguments.Get(args, new ArgHandler[] { new ArgHandler(line.Substring(indie, line.LastIndexOf("\"") - indie) + ":", (_data, ret) => ret ? _data : null), }, new ButtonHandler[] { })[0];
                                if (debug)
                                {
                                    Debug(lnum, tabs, "@? " + eqq + ' ' + argnum + ' ' + (indie > 0 ? line.Substring(indie, line.LastIndexOf("\"") - indie) : "INVALID") + ' ' + da);
                                }
                            }
                            else
                            {
                                // read argument
                                da = args[argnum];
                                if (debug)
                                {
                                    indie = line.IndexOf("\"") + 1;
                                    Debug(lnum, tabs, "@ " + eqq + ' ' + argnum + ' ' + (indie > 0 ? line.Substring(indie, line.LastIndexOf("\"") - indie) : "INVALID") + ' ' + da);
                                }
                            }

                            stack.Peek().Add(new ScriptEquate(lnum, stack.Peek(), eqq, da));
                            break;

                        case 'c':
                            // ehhhhhhh =/
                            if (!line.EndsWith("{"))
                            {
                                screrr(lnum, "No opening script block.");
                            }
                            // create the condition block, and push true block in stack
                            co.Push(new ScriptCondition(lnum, stack.Peek(), line.Substring(1, line.Length - 2).Trim(trim)));
                            stack.Peek().Add(co.Peek());
                            stack.Push(co.Peek().True);
                            if (debug)
                            {
                                Debug(lnum, tabs++, "c " + line.Substring(1, line.Length - 2).Trim(trim) + " {");
                            }
                            break;

                        case 'f':
                            // check for { at the end of line
                            int inde = line.IndexOf('{');
                            if (inde == -1 || !line.EndsWith("{"))
                            {
                                screrr(lnum, "Expected block start ('{') at end of line, but found none.");
                            }
                            string       counter = line.Substring(1, inde - 1).Trim(trim);
                            ScriptRepeat r       = new ScriptRepeat(lnum, stack.Peek(), counter);
                            stack.Peek().Add(r);
                            stack.Push(r.Inner);
                            if (debug)
                            {
                                Debug(lnum, tabs++, "f " + counter + " {");
                            }
                            break;

                        case 'w':
                            // check for { at the end of line
                            int ine = line.IndexOf('{');
                            if (ine == -1 || !line.EndsWith("{"))
                            {
                                screrr(lnum, "Expected block start ('{') at end of line, but found none.");
                            }
                            string      cond = line.Substring(1, ine - 1).Trim(trim);
                            ScriptWhile w    = new ScriptWhile(lnum, stack.Peek(), cond);
                            stack.Peek().Add(w);
                            stack.Push(w.Inner);
                            if (debug)
                            {
                                Debug(lnum, tabs++, "w " + cond + " {");
                            }
                            break;

                        case ':':
                            if (line.Length < 3)
                            {
                                screrr(lnum, "Unexpected end of line!");
                            }

                            switch (line[1])
                            {
                            case '?': {
                                // check for { at the end of line
                                int inxd = line.IndexOf('{');
                                if (inxd == -1)
                                {
                                    screrr(lnum, "Expected block start ('{') at end of line, but found none.");
                                }
                                string num = line.Substring(2, inxd - 2).Trim(trim);

                                try {
                                    ScriptArgMod m = new ScriptArgMod(lnum, stack.Peek(), num);
                                    stack.Peek().Add(m);
                                    stack.Push(m.Inner);
                                    if (debug)
                                    {
                                        Debug(lnum, tabs++, ":? " + m.num + " {");
                                    }
                                } catch (Exception) {
                                    screrr(lnum, "Failed to parse '" + num + "'!");
                                }
                            }
                            break;

                            case '-': {
                                string num = line.Substring(2, line.Length - 2).Trim(trim);

                                try {
                                    ScriptArgRmv m = new ScriptArgRmv(lnum, stack.Peek(), num);
                                    stack.Peek().Add(m);
                                    if (debug)
                                    {
                                        Debug(lnum, tabs++, ":- " + m.num);
                                    }
                                } catch (Exception) {
                                    screrr(lnum, "Failed to parse '" + num + "'!");
                                }
                            }
                            break;

                            case '=': {
                                int inxd = line.IndexOf(' ');
                                if (inxd == -1)
                                {
                                    screrr(lnum, "Expected space separator (' ') in the middle of the line, but found none.");
                                }
                                string num  = line.Substring(2, inxd - 2).Trim(trim);
                                string oper = line.Substring(inxd, line.Length - inxd).Trim(trim);

                                try {
                                    ScriptArgEqu m = new ScriptArgEqu(lnum, stack.Peek(), num, oper);
                                    stack.Peek().Add(m);
                                    if (debug)
                                    {
                                        Debug(lnum, tabs++, ":= " + m.num + " " + m.operation);
                                    }
                                } catch (Exception) {
                                    screrr(lnum, "Failed to parse '" + num + "'!");
                                }
                            }
                            break;

                            default:
                                screrr(lnum, "Unrecognized argument modifier type '" + line[1] + "'!");
                                break;
                            }
                            break;

                        case '~':
                            int indix = line.IndexOf(' ');
                            if (indix == -1)
                            {
                                screrr(lnum, "Expected a whitespace (' '), but found none.");
                            }

                            // just some sanity checks, dont worry
                            string labl = line.Substring(1, indix - 1), type = line.Substring(indix + 1);
                            if (labl.Length < 1)
                            {
                                screrr(lnum, "Lable name not specified.");
                            }
                            if (type.Length < 1)
                            {
                                screrr(lnum, "Lable type or command not specified.");
                            }

                            if (type.StartsWith(":"))
                            {
                                // lable mod
                                LableMod l = new LableMod(lnum, stack.Peek(), labl, type.Substring(1));
                                stack.Peek().Add(l);
                                if (debug)
                                {
                                    Debug(lnum, tabs, '~' + labl + " :" + l.num);
                                }
                            }
                            else                                         // lable create
                            {
                                stack.Peek().Add(new LableCreate(lnum, stack.Peek(), labl.Trim(trim), type));
                                if (debug)
                                {
                                    Debug(lnum, tabs, '~' + labl + ' ' + type);
                                }
                            }
                            break;

                        case '$':
                            stack.Peek().Add(new ScriptOperation(lnum, stack.Peek(), line = line.Substring(1).Trim(trim)));
                            if (debug)
                            {
                                Debug(lnum, tabs, '$' + line);
                            }
                            break;

                        case '>':
                            // if line not long enough, problem
                            if (line.Length < 3)
                            {
                                screrr(lnum, "Expected type and offset!");
                            }
                            // check if valid type
                            char ttype = line.ElementAt(1);
                            if (ttype != 'a' && ttype != 'b' && ttype != 'f')
                            {
                                screrr(lnum, "Goto type '" + ttype + "' not recognized!");
                            }

                            // arg1 = type (char), arg2 = rest of the line
                            stack.Peek().Add(new ScriptGoto(lnum, stack.Peek(), ttype, line = line.Substring(2).Trim(trim)));
                            if (debug)
                            {
                                Debug(lnum, tabs, ">" + ttype + " " + line);
                            }
                            break;

                        case ';':
                            stack.Peek().Add(new ScriptStop(lnum, stack.Peek()));
                            if (debug)
                            {
                                Debug(lnum, tabs, ";");
                            }
                            break;

                        case '%':
                            stack.Peek().Add(new ScriptComment(lnum, stack.Peek(), line.Substring(1)));
                            if (debug)
                            {
                                Debug(lnum, tabs, line);
                            }
                            break;

                        case '+':
                            stack.Peek().Add(new ScriptPrint(lnum, stack.Peek(), line.Substring(1)));
                            if (debug)
                            {
                                Debug(lnum, tabs, line);
                            }
                            break;

                        case 's': {
                            int    idx = line.IndexOf(' ');
                            string mac = line.Substring(1, idx >= 0 ? idx - 1 : line.Length - 1);

                            switch (mac.ToLowerInvariant())
                            {
                            case "inc": {
                                if (idx == -1)
                                {
                                    screrr(lnum, "Macro does not have a file name!");
                                }
                                string path = line.Substring(idx + 1, line.Length - idx - 1);

                                if (path.StartsWith("\"") && path.EndsWith("\""))
                                {
                                    path = path.Substring(1, path.Length - 2);
                                }

                                if (!File.Exists(path))
                                {
                                    screrr(lnum, "File '" + path + "' does not exist!");
                                }

                                try {
                                    string[] file = File.ReadAllLines(path);
                                    if (debug)
                                    {
                                        Debug(lnum, tabs, "--; macro: parse another file '" + path + "' (" + file.Length + " lines)");
                                    }
                                    ParseScript(string.Join("\n", file), args, 0, ref stack);
                                    if (debug)
                                    {
                                        Debug(lnum, tabs, "--; return to previous file");
                                    }
                                } catch (Exception) {
                                    screrr(lnum, "Failed to load file contents for file '" + path + "'!");
                                }
                            }
                            break;

                            case "datamacro": {
                                if (idx == -1)
                                {
                                    screrr(lnum, "Data macro has not been defined!");
                                }
                                Output.DataMacro = line.Substring(idx + 1, line.Length - idx - 1).Trim();
                            }
                            break;

                            case "lablenumber": {
                                if (idx == -1)
                                {
                                    screrr(lnum, "Lable number format has not been defined!");
                                }
                                string fmt = line.Substring(idx + 1, line.Length - idx - 1).Trim().ToLowerInvariant();

                                if (LableRule.RandomRules[fmt] == null)
                                {
                                    screrr(lnum, "Invalid lable number format '" + fmt + "'!");
                                }

                                LableRule.GetNextRandom = LableRule.RandomRules[fmt];
                            }
                            break;

                            case "version":
                                if (line.Substring(idx + 1, line.Length - idx - 1).Trim().ToLowerInvariant() != VERSION)
                                {
                                    screrr(lnum, "Your script is out of date, and may not be executed! Please update the script to " + VERSION + "!");
                                }
                                break;

                            default:
                                screrr(lnum, "Macro type '" + mac + "' not recognized!");
                                break;
                            }
                        }
                        break;

                        default:
                            // incase we cant figure out what command this is
                            screrr(lnum, "Symbol not recognized: '" + line.ElementAt(0) + "'");
                            return;
                        }
                    } catch (Exception e) {
                        screrr(lnum, e.ToString());
                    }
                }
            }

            if (debug)
            {
                Debug(new string('-', 80));
            }
        }
예제 #2
0
 private void AddLine(uint pos, uint len, ScriptEquate s)
 {
     AddLine(pos++, 1, "\b " + s.GetName());
 }