Example #1
0
        /// <summary>
        /// Assembles a plain text "EzLanguage" script into a list of CommandCall's.
        /// </summary>
        public static List <SoulsFormats.ESD.ESD.CommandCall> AssembleCommandScript(EzSembleContext context, string plaintext)
        {
            var result = new List <SoulsFormats.ESD.ESD.CommandCall>();

            foreach (var cmdTxt in plaintext.Split(';').Select(x =>
            {
                var cmdLine = x.Replace("\r", "").Trim(' ', '\n');
                if (cmdLine.Contains("//"))
                {
                    cmdLine = cmdLine.Substring(0, cmdLine.IndexOf("//"));
                }
                return(cmdLine);
            }).Where(x => !string.IsNullOrWhiteSpace(x)))
            {
                result.Add(AssembleCommandCall(context, cmdTxt.Replace("\n", "")));
            }
            return(result);
        }
Example #2
0
            //Get the precedence of the operator/function passed in
            private static int GetPrecedence(EzSembleContext context, string s)
            {
                int max = 0;

                //if the passed is a function, make it the highest precedence
                //we simply get the max precedence value for all maths operators and add 1

                if (IsFunction(context, s))
                {
                    max = Math.Max(Operators[Operators.Keys.First()][0], Operators[Operators.Keys.Last()][0]) + 1;
                }
                else
                {
                    max = Operators[s][0];
                }

                return(max);
            }
Example #3
0
        /// <summary>
        /// Assembles a plain text "EzLanguage" expression into bytecode.
        /// </summary>
        public static byte[] AssembleExpression(EzSembleContext context, string plaintext)
        {
            var postfixPlaintext = EzInfixor.InfixToPostFix(context, $"({plaintext.Trim('\n', ' ')})");

            using (var ms = new MemoryStream())
                using (var bw = new BinaryWriter(ms, Encoding.Unicode))
                {
                    int current = 0;
                    int next    = 0;

                    while (current < postfixPlaintext.Length)
                    {
                        next = current + 1;
                        Parse(postfixPlaintext, bw, current, ref next);
                        current = next;
                    }

                    bw.Write((byte)0xA1);
                    return(ms.ToArray());
                }
        }
Example #4
0
            public static string InfixToPostFix(EzSembleContext context, string expression)
            {
                //expression = expression.Replace("\n", "~");

                List <string>  queue = new List <string>();
                Stack <string> stack = new Stack <string>();

                List <string> stringSubstitutions = new List <string>();

                if (expression.Contains("\""))
                {
                    int current = 0;
                    int next    = current + 1;

                    while (current < expression.Length)
                    {
                        next = current + 1;

                        if (expression[current] == '"')
                        {
                            string thisText = "";

                            while (next < expression.Length && expression[next] != '"')
                            {
                                next++;
                            }

                            if (next == expression.Length)
                            {
                                throw new Exception("Unclosed string literal");
                            }

                            string value = expression.Substring(current + 1, next - current - 1);
                            if (value.Contains('\r') || value.Contains('\n'))
                            {
                                throw new Exception("String literals may not contain newlines");
                            }

                            stringSubstitutions.Add(value);
                            //expression = expression.Replace(value, $"{{{stringSubstitutions.Count - 1}}}");

                            next++;
                        }

                        current = next;
                    }

                    for (int i = 0; i < stringSubstitutions.Count; i++)
                    {
                        expression = expression.Replace(stringSubstitutions[i], $"{{{i}}}");
                    }
                }

                //populate operators
                //int format is {precedence, association -> 0=Left 1=Right}


                //string pattern = @"(?<=[^\\.a-zA-Z\\d])|(?=[^\\.a-zA-Z\\d])";
                string pattern = @"(?<=[-+*/(),^<>=&\|~])(?=.)|(?<=.)(?=[-+*/(),^<>=&\|~])";

                expression = expression.Replace(" ", "");
                Regex         regExPattern = new Regex(pattern);
                List <string> expr         = new List <string>(regExPattern.Split(expression));

                //expr.RemoveAll(s => String.IsNullOrEmpty(s.Trim()));

                //parse our expression and fix unary + and -
                ParseUnary(ref expr);

                //int continuationsQueued = 0;

                Stack <int> funcArgCounts = new Stack <int>();

                bool popAndEnqueue(bool rightParenthesis = false)
                {
                    var popped = stack.Pop();

                    if (IsFunction(context, popped))
                    {
                        //Queue<string> garbage = new Queue<string>();
                        //while (queue[queue.Count - 1] == "~")
                        //{
                        //    garbage.Enqueue(queue[queue.Count - 1]);
                        //    queue.RemoveAt(queue.Count - 1);
                        //}

                        var argCount = funcArgCounts.Pop();

                        if (popped.StartsWith("SetREG"))
                        {
                            queue.Add($">[{popped.Substring(popped.Length - 1, 1)}]");

                            //var argCount = int.Parse(queue[queue.Count - 1]);
                            //queue.RemoveAt(queue.Count - 1);

                            //if (argCount == 1)
                            //{
                            //    queue.Add($">[{popped.Substring(popped.Length - 1, 1)}]");
                            //}
                            //else
                            //{
                            //    throw new Exception("SetREG must be passed exactly 1 argument.");
                            //}
                        }
                        else if (popped.StartsWith("GetREG"))
                        {
                            queue.Add($"[{popped.Substring(popped.Length - 1, 1)}]>");
                        }
                        else if (popped == "AbortIfFalse")
                        {
                            if (queue.Count == 0 || argCount != 1)
                            {
                                throw new Exception("Invalid AbortIfFalse call");
                            }

                            queue.Add($".");
                        }
                        else
                        {
                            //queue.RemoveAt(queue.Count - 1);

                            queue.Add($"({argCount})");
                        }

                        //while (garbage.Count > 0)
                        //    queue.Add(garbage.Dequeue());
                        return(true);
                    }
                    else
                    {
                        queue.Add(popped);
                        //if (rightParenthesis)
                        //{
                        //    queue.Add("~");
                        //}
                        return(false);
                    }
                }

                void registArgument()
                {
                    if (funcArgCounts.Count > 0 && funcArgCounts.Peek() == 0)
                    {
                        funcArgCounts.Push(funcArgCounts.Pop() + 1);
                    }
                }

                foreach (var s in expr)
                {
                    //if (s == "~")
                    //{
                    //    continuationsQueued++;
                    //    //queue[queue.Count - 1] += "~";
                    //    //queue.Add("~");
                    //}
                    //else
                    if (Operators.ContainsKey(s))
                    {
                        //while the stack is not empty and the top of the stack is not an (
                        while (stack.Count > 0 && stack.Peek() != "(")
                        {
                            if ((GetAssociation(s) == 0 && GetPrecedence(context, s) <= GetPrecedence(context, stack.Peek())) ||
                                (GetAssociation(s) == 1 && GetPrecedence(context, s) < GetPrecedence(context, stack.Peek()))
                                )
                            {
                                popAndEnqueue();
                            }
                            else
                            {
                                break;
                            }
                        }

                        //push operator onto the stack
                        stack.Push(s);
                    }
                    //These things aren't technically functions and thus do not
                    //need to push their ID as an expression.
                    else if (s.StartsWith("GetREG") || s.StartsWith("SetREG") || s == "AbortIfFalse")
                    {
                        registArgument();
                        stack.Push(s);
                        funcArgCounts.Push(0);
                    }
                    //is our token on our defined functions
                    else if (IsFunction(context, s))
                    {
                        registArgument();
                        stack.Push(s);
                        queue.Add(context.GetFunctionID(s).ToString());
                        funcArgCounts.Push(0);
                    }

                    //handle opening parenthesis
                    //simply push this on the stack
                    else if (s == "(")
                    {
                        stack.Push(s);
                    }

                    //handle closing parenthesis
                    //pop all operators off the stack until the matching
                    //opening parenthesis is found and then discard the
                    //opening parenthesis
                    else if (s == ")")
                    {
                        while (stack.Count != 0 && stack.Peek() != "(")
                        {
                            if (!popAndEnqueue(rightParenthesis: true))
                            {
                                queue.Add("~");
                            }
                        }

                        //if (funcArgCounts.Count > 0)
                        //    queue.Add($"{funcArgCounts.Pop()}");
                        //forget the (
                        stack.Pop();
                    }

                    //do we have an argument separator, if so, pop everything off the stack
                    //until we reach the opening parenthesis, but leave that on the stack
                    else if (s == ",")
                    {
                        while (stack.Peek() != "(")
                        {
                            popAndEnqueue();
                        }
                        funcArgCounts.Push(funcArgCounts.Pop() + 1);
                    }
                    else
                    {
                        //none of the above so queue it
                        registArgument();
                        queue.Add(s);
                    }
                }

                //pop off the rest of the stack
                while (stack.Count != 0)
                {
                    popAndEnqueue();
                }

                var resultExpr = string.Join(" ", queue);

                for (int i = 0; i < stringSubstitutions.Count; i++)
                {
                    resultExpr = resultExpr.Replace($"{{{i}}}", stringSubstitutions[i]);
                }

                if (resultExpr == "GetStateChangeType 233")
                {
                    throw new Exception();
                }

                return(resultExpr);
            }
Example #5
0
            public static string BytecodeToInfix(EzSembleContext context, byte[] Bytes)
            {
                //string MEOWDEBUG_OLD_DISSEMBLE = MEOWDEBUG_OldDissemble(Bytes);

                var bigEndianReverseBytes = Bytes.Reverse().ToArray();

                Stack <string> stack = new Stack <string>();

                Queue <string> garbage = new Queue <string>();

                string popLastNonGarbageAndStoreGarbage(bool wantNumber = false)
                {
                    var popped = stack.Pop();

                    //while (popped == "~" || popped == ".")
                    //{
                    //    garbage.Enqueue(popped);
                    //    popped = stack.Pop();
                    //}

                    if (wantNumber)
                    {
                        return(popped.Trim('(', ')'));
                    }
                    else
                    {
                        return(popped);
                    }
                }

                void restoreGarbage()
                {
                    while (garbage.Count > 0)
                    {
                        stack.Push(garbage.Dequeue());
                    }
                }

                for (int i = 0; i < Bytes.Length; i++)
                {
                    var b = Bytes[i];
                    if (b >= 0 && b <= 0x7F)
                    {
                        stack.Push($"{b - 64}");
                    }
                    else if (b == 0xA5)
                    {
                        int j = 0;
                        while (Bytes[i + j + 1] != 0 || Bytes[i + j + 2] != 0)
                        {
                            j += 2;
                        }
                        string text = context.IsBigEndian ?
                                      Encoding.BigEndianUnicode.GetString(Bytes, i + 1, j)
                            : Encoding.Unicode.GetString(Bytes, i + 1, j);

                        if (text.Contains('"') || text.Contains('\r') || text.Contains('\n'))
                        {
                            throw new Exception("Illegal character in string literal");
                        }
                        stack.Push($"\"{text}\"");
                        i += j + 2;
                    }
                    else if (b == 0x80)
                    {
                        if (!context.IsBigEndian)
                        {
                            stack.Push($"{BitConverter.ToSingle(Bytes, i + 1)}");
                        }
                        else
                        {
                            stack.Push($"{BitConverter.ToSingle(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 4)}");
                        }

                        i += 4;
                    }
                    else if (b == 0x81)
                    {
                        if (!context.IsBigEndian)
                        {
                            stack.Push($"{BitConverter.ToDouble(Bytes, i + 1)}");
                        }
                        else
                        {
                            stack.Push($"{BitConverter.ToDouble(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 8)}");
                        }

                        i += 8;
                    }
                    else if (b == 0x82)
                    {
                        if (!context.IsBigEndian)
                        {
                            stack.Push($"{BitConverter.ToInt32(Bytes, i + 1)}");
                        }
                        else
                        {
                            stack.Push($"{BitConverter.ToInt32(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 4)}");
                        }


                        i += 4;
                    }
                    else if (b == 0x84)
                    {
                        var id = popLastNonGarbageAndStoreGarbage(true);
                        restoreGarbage();
                        stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}()");
                    }
                    else if (b == 0x85)
                    {
                        var arg1 = popLastNonGarbageAndStoreGarbage();
                        var id   = popLastNonGarbageAndStoreGarbage(true);
                        restoreGarbage();
                        stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1})");
                    }
                    else if (b == 0x86)
                    {
                        var arg2 = popLastNonGarbageAndStoreGarbage();
                        var arg1 = popLastNonGarbageAndStoreGarbage();
                        var id   = popLastNonGarbageAndStoreGarbage(true);
                        restoreGarbage();
                        stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2})");
                    }
                    else if (b == 0x87)
                    {
                        var arg3 = popLastNonGarbageAndStoreGarbage();
                        var arg2 = popLastNonGarbageAndStoreGarbage();
                        var arg1 = popLastNonGarbageAndStoreGarbage();
                        var id   = popLastNonGarbageAndStoreGarbage(true);
                        restoreGarbage();
                        stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2}, {arg3})");
                    }
                    else if (b == 0x88)
                    {
                        var arg4 = popLastNonGarbageAndStoreGarbage();
                        var arg3 = popLastNonGarbageAndStoreGarbage();
                        var arg2 = popLastNonGarbageAndStoreGarbage();
                        var arg1 = popLastNonGarbageAndStoreGarbage();
                        var id   = popLastNonGarbageAndStoreGarbage(true);
                        restoreGarbage();
                        stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2}, {arg3}, {arg4})");
                    }
                    else if (b == 0x89)
                    {
                        var arg5 = popLastNonGarbageAndStoreGarbage();
                        var arg4 = popLastNonGarbageAndStoreGarbage();
                        var arg3 = popLastNonGarbageAndStoreGarbage();
                        var arg2 = popLastNonGarbageAndStoreGarbage();
                        var arg1 = popLastNonGarbageAndStoreGarbage();
                        var id   = popLastNonGarbageAndStoreGarbage(true);
                        restoreGarbage();
                        stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2}, {arg3}, {arg4}, {arg5})");
                    }
                    else if (b == 0x8A)
                    {
                        var arg6 = popLastNonGarbageAndStoreGarbage();
                        var arg5 = popLastNonGarbageAndStoreGarbage();
                        var arg4 = popLastNonGarbageAndStoreGarbage();
                        var arg3 = popLastNonGarbageAndStoreGarbage();
                        var arg2 = popLastNonGarbageAndStoreGarbage();
                        var arg1 = popLastNonGarbageAndStoreGarbage();
                        var id   = popLastNonGarbageAndStoreGarbage(true);
                        restoreGarbage();
                        stack.Push($"{context.GetFunctionInfo(int.Parse(id)).Name}({arg1}, {arg2}, {arg3}, {arg4}, {arg5}, {arg6})");
                    }
                    else if (OperatorsByByte.ContainsKey(b))
                    {
                        var item2 = popLastNonGarbageAndStoreGarbage();
                        var item1 = popLastNonGarbageAndStoreGarbage();

                        restoreGarbage();

                        stack.Push($"{GetExpressionWithParenthesesIfContainsOperator(item1, OperatorsByByte[b])} " +
                                   $"{OperatorsByByte[b]} {GetExpressionWithParenthesesIfContainsOperator(item2, OperatorsByByte[b])}");
                    }
                    else if (b == 0xA6)
                    {
                        //if (stack.Count > 2)
                        //{
                        //    var stackContents = new string[stack.Count];
                        //    int j = stack.Count - 1;
                        //    while (stack.Count > 0)
                        //    {
                        //        var latest = stack.Pop();
                        //        stackContents[j] = latest;
                        //        j--;
                        //    }

                        //    stack.Push($"({string.Join(" ", stackContents)})");

                        //    Console.WriteLine("TEST");
                        //}
                        //else
                        //{
                        //    stack.Push($"({stack.Pop()})");
                        //}
                        stack.Push($"({stack.Pop()})");
                    }
                    else if (b >= 0xA7 && b <= 0xAE)
                    {
                        byte regIndex = (byte)(b - 0xA7);
                        var  item     = popLastNonGarbageAndStoreGarbage();
                        restoreGarbage();
                        stack.Push($"SetREG{regIndex}({item})");
                    }
                    else if (b >= 0xAF && b <= 0xB6)
                    {
                        byte regIndex = (byte)(b - 0xAF);
                        stack.Push($"GetREG{regIndex}()");
                    }
                    else if (b == 0xB7)
                    {
                        var item = stack.Pop();
                        stack.Push($"AbortIfFalse({item})");
                    }
                    else if (b == 0xA1)
                    {
                        //break;
                    }
                    else
                    {
                        stack.Push($"#{b:X2}");
                    }
                }

                return(string.Join(" ", stack));
            }
Example #6
0
 private static bool IsFunction(EzSembleContext context, string s)
 {
     return(s.StartsWith("f") || context.FunctionIDsByName.ContainsKey(s) || s.StartsWith("GetREG") || s.StartsWith("SetREG") || (s == "AbortIfFalse"));
 }
Example #7
0
 /// <summary>
 /// Dissembles a list of CommandCall objects into a plain text "EzLanguage" script.
 /// </summary>
 public static string DissembleCommandScript(EzSembleContext context, List <SoulsFormats.ESD.ESD.CommandCall> script)
 {
     return(string.Join("\n", script.Select(x => $"{DissembleCommandCall(context, x)};")));
 }
Example #8
0
 /// <summary>
 /// Dissembles a CommandCall object into a line of "EzLanguage" plain text.
 /// </summary>
 public static string DissembleCommandCall(EzSembleContext context, SoulsFormats.ESD.ESD.CommandCall c)
 {
     return($"{context.GetCommandInfo(c.CommandBank, c.CommandID).Name}({string.Join(", ", c.Arguments.Select(a => DissembleExpression(context, a)))})");
 }
Example #9
0
        //public static string MEOWDEBUG_OldDissemble(byte[] bytes)
        //{
        //    if (bytes.Last() != 0xA1)
        //        throw new Exception("All evaluators must end with 0xA1");

        //    var sb = new StringBuilder();
        //    bool newline = true;

        //    for (int i = 0; i < bytes.Length - 1; i++)
        //    {
        //        byte b = bytes[i];
        //        if (TerminatorsByByte.ContainsKey(b))
        //        {
        //            newline = true;
        //            sb.Append(TerminatorsByByte[b]);
        //        }
        //        else
        //        {
        //            if (newline)
        //                newline = false;
        //            else
        //                sb.Append(" ");

        //            if (b >= 0 && b <= 0x7F)
        //            {
        //                sb.Append($"{b - 64}");
        //            }
        //            else if (b == 0xA5)
        //            {
        //                int j = 0;
        //                while (bytes[i + j + 1] != 0 || bytes[i + j + 2] != 0)
        //                    j += 2;
        //                string text = Encoding.Unicode.GetString(bytes, i + 1, j);
        //                if (text.Contains('"') || text.Contains('\r') || text.Contains('\n'))
        //                    throw new Exception("Illegal character in string literal");
        //                sb.Append($"\"{text}\"");
        //                i += j + 2;
        //            }
        //            else if (b == 0x80)
        //            {
        //                sb.Append($"{BitConverter.ToSingle(bytes, i + 1)}");
        //                i += 4;
        //            }
        //            else if (b == 0x81)
        //            {
        //                sb.Append($"{BitConverter.ToDouble(bytes, i + 1)}");
        //                i += 8;
        //            }
        //            else if (b == 0x82)
        //            {
        //                sb.Append($"{BitConverter.ToInt32(bytes, i + 1)}");
        //                i += 4;
        //            }
        //            else if (b >= 0x84 && b <= 0x8A)
        //            {
        //                sb.Append($"({b - 0x84})");
        //            }
        //            else if (OperatorsByByte.ContainsKey(b))
        //            {
        //                sb.Append(OperatorsByByte[b]);
        //            }
        //            else if (b >= 0xA7 && b <= 0xAE)
        //            {
        //                sb.Append($">[{b - 0xA7}]");
        //            }
        //            else if (b >= 0xAF && b <= 0xB6)
        //            {
        //                sb.Append($"[{b - 0xAF}]>");
        //            }
        //            else if (b == 0xA1)
        //            {
        //                throw new Exception("Evaluators may not contain more than one 0xA1");
        //            }
        //            else
        //            {
        //                sb.Append($"#{b.ToString("X2")}");
        //            }
        //        }
        //    }

        //    return sb.ToString().TrimEnd();
        //}

        /// <summary>
        /// Dissembles bytecode into an  "EzLanguage" plain text expression.
        /// </summary>
        public static string DissembleExpression(EzSembleContext context, byte[] bytes)
        {
            return(EzInfixor.BytecodeToInfix(context, bytes));
        }
Example #10
0
        /// <summary>
        /// Assembles a plain text "EzLanguage" command call into a CommandCall object.
        /// </summary>
        public static SoulsFormats.ESD.ESD.CommandCall AssembleCommandCall(EzSembleContext context, string plaintext)
        {
            var regex = System.Text.RegularExpressions.Regex.Match(plaintext, @"^([A-Za-z0-9_:]+)\((.*)\)$");

            if (regex.Groups.Count != 3)
            {
                throw new Exception($"Invalid EzLanguage command call text: \"{plaintext}\"");
            }

            var command  = regex.Groups[1].Value;
            var cmdId    = context.GetCommandID(command);
            var argsText = regex.Groups[2].Value.Trim();

            var finalArgs = new List <string>();

            if (!string.IsNullOrWhiteSpace(argsText))
            {
                // If <= 2 chars theres no way there can be more than 1 arg
                // And obviously if there's no commas
                if (argsText.Length <= 2 || !argsText.Contains(","))
                {
                    finalArgs = new List <string>()
                    {
                        argsText
                    };
                }
                else
                {
                    int thisArgStartIndex     = 0;
                    int innerParenthesisLevel = 0;
                    for (int i = 0; i < argsText.Length; i++)
                    {
                        if (i < argsText.Length - 1)
                        {
                            if (argsText[i] == '(')
                            {
                                innerParenthesisLevel++;
                            }
                            else if (argsText[i] == ')')
                            {
                                if (innerParenthesisLevel > 0)
                                {
                                    innerParenthesisLevel--;
                                }
                                else
                                {
                                    throw new Exception("Extra parenthesis found in command call args.");
                                }
                            }

                            if (argsText[i] == ',')
                            {
                                if (innerParenthesisLevel == 0)
                                {
                                    finalArgs.Add(argsText.Substring(thisArgStartIndex, i - thisArgStartIndex));
                                    thisArgStartIndex = i + 1;
                                }
                            }
                        }
                        else //Very last char
                        {
                            if (argsText[i] == ',' || argsText[i] == '(')
                            {
                                throw new Exception("Very last char in command args cannot be a '(' or ','");
                            }
                            else if (argsText[i] == ')')
                            {
                                if (innerParenthesisLevel > 0)
                                {
                                    innerParenthesisLevel--;
                                }
                                else
                                {
                                    throw new Exception("Extra parenthesis found in command call args.");
                                }
                            }
                        }
                    }

                    if (thisArgStartIndex < argsText.Length - 1)
                    {
                        finalArgs.Add(argsText.Substring(thisArgStartIndex, (argsText.Length) - thisArgStartIndex));
                    }

                    if (innerParenthesisLevel != 0)
                    {
                        throw new Exception("Unclosed parenthesis found in command call args.");
                    }
                }
            }

            return(new SoulsFormats.ESD.ESD.CommandCall()
            {
                CommandBank = cmdId.Bank,
                CommandID = cmdId.ID,
                Arguments = finalArgs.Select(x => AssembleExpression(context, x)).ToList(),
            });
        }