示例#1
0
        public static List <ESD.CommandCall> AssembleCommandScript(EzSembleContext context, Block block)
        {
            var result = new List <ESD.CommandCall>();

            foreach (Statement st in block.Cmds)
            {
                var cmdId = context.GetCommandID(st.Name);
                result.Add(new ESD.CommandCall()
                {
                    CommandBank = cmdId.Bank,
                    CommandID   = cmdId.ID,
                    Arguments   = st.Args.Select(x => AssembleExpression(context, x)).ToList(),
                });
            }
            return(result);
        }
示例#2
0
        /// <summary>
        /// Assembles a plain text "EzLanguage" script into a list of CommandCall's.
        /// </summary>
        public static List <ESD.CommandCall> AssembleCommandScript(EzSembleContext context, string plaintext)
        {
            var result = new List <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);
        }
示例#3
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);
            }
示例#4
0
        /// <summary>
        /// Assembles a plain text "EzLanguage" expression into bytecode.
        /// </summary>
        public static byte[] AssembleExpression(EzSembleContext context, string plaintext)
        {
            var postfixPlaintext = EzInfixor.InfixToEzLanguage(context, plaintext);

            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());
                }
        }
示例#5
0
        /// <summary>
        /// Assembles a plain text "EzLanguage" command call into a CommandCall object.
        /// </summary>
        public static 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 ESD.CommandCall()
            {
                CommandBank = cmdId.Bank,
                CommandID = cmdId.ID,
                Arguments = finalArgs.Select(x => AssembleExpression(context, x)).ToList(),
            });
        }
示例#6
0
        /// <summary>
        /// Assembles an Expr into bytecode.
        /// </summary>
        public static byte[] AssembleExpression(EzSembleContext context, Expr topExpr)
        {
            using (var ms = new MemoryStream())
                using (var bw = new BinaryWriter(ms, Encoding.Unicode))
                {
                    void writeExpr(Expr expr)
                    {
                        // Number
                        if (expr is ConstExpr ce)
                        {
                            if (ce.Value is int i)
                            {
                                bw.Write((byte)0x82);
                                bw.Write(i);
                            }
                            else if (ce.Value is sbyte b)
                            {
                                bw.Write((byte)(b + 64));
                            }
                            else if (ce.Value is float f)
                            {
                                bw.Write((byte)0x80);
                                bw.Write(f);
                            }
                            else if (ce.Value is double d)
                            {
                                bw.Write((byte)0x81);
                                bw.Write(d);
                            }
                            else if (ce.Value is string s)
                            {
                                if (s.Contains('\r') || s.Contains('\n'))
                                {
                                    throw new Exception("String literals may not contain newlines");
                                }
                                bw.Write((byte)0xA5);
                                bw.Write(Encoding.Unicode.GetBytes(s + "\0"));
                            }
                            else
                            {
                                throw new Exception($"Invalid type {ce.Value.GetType()} for ConstExpr {ce} in {topExpr}");
                            }
                        }
                        else if (expr is UnaryExpr ue)
                        {
                            writeExpr(ue.Arg);
                            bw.Write(BytesByOperator[ue.Op]);
                        }
                        else if (expr is BinaryExpr be)
                        {
                            writeExpr(be.Lhs);
                            writeExpr(be.Rhs);
                            bw.Write(BytesByOperator[be.Op]);
                        }
                        else if (expr is FunctionCall func)
                        {
                            string name = func.Name;
                            if (name.StartsWith("SetREG"))
                            {
                                int regIndex = byte.Parse(name.Substring(name.Length - 1));
                                writeExpr(func.Args[0]);
                                bw.Write((byte)(0xA7 + regIndex));
                            }
                            else if (name.StartsWith("GetREG"))
                            {
                                int regIndex = byte.Parse(name.Substring(name.Length - 1));
                                bw.Write((byte)(0xAF + regIndex));
                            }
                            else if (name.StartsWith("StateGroupArg"))
                            {
                                int index = func.Args[0].AsInt();
                                bw.Write((byte)(index + 64));
                                bw.Write((byte)0xB8);
                            }
                            else
                            {
                                int id = context.GetFunctionID(name);
                                if (id >= -64 && id <= 63)
                                {
                                    bw.Write((byte)(id + 64));
                                }
                                else
                                {
                                    bw.Write((byte)0x82);
                                    bw.Write(id);
                                }
                                // for (int i = func.Args.Count - 1; i >= 0; i--)
                                for (int i = 0; i < func.Args.Count; i++)
                                {
                                    writeExpr(func.Args[i]);
                                }
                                bw.Write((byte)(0x84 + func.Args.Count));
                            }
                        }
                        else if (expr is CallResult)
                        {
                            bw.Write((byte)0xB9);
                        }
                        else if (expr is CallOngoing)
                        {
                            bw.Write((byte)0xBA);
                        }
                        else if (expr is Unknown huh)
                        {
                            bw.Write(huh.Opcode);
                        }
                        else
                        {
                            throw new Exception($"Unknown expression subclass {expr.GetType()}: {expr} in {topExpr}");
                        }
                        if (expr.IfFalse == FalseCond.CONTINUE)
                        {
                            bw.Write(BytesByTerminator['~']);
                        }
                        else if (expr.IfFalse == FalseCond.ABORT)
                        {
                            bw.Write(BytesByTerminator['.']);
                        }
                    }

                    writeExpr(topExpr);
                    bw.Write((byte)0xA1);
                    byte[] arr = ms.ToArray();
                    if (arr.Length == 1)
                    {
                        throw new Exception($"{topExpr}");
                    }
                    return(arr);
                }
        }
示例#7
0
            public static string InfixToEzLanguage(EzSembleContext context, string expression)
            {
                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] == '"')
                        {
                            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);

                            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 = @"(?<=[-+*/(),^<>=&\|~!\[\]])(?=.)|(?<=.)(?=[-+*/(),^<>=&\|~!\[\]])";


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

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

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

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

                    if (IsFunction(context, popped))
                    {
                        var argCount = funcArgCounts.Pop();

                        if (popped.StartsWith("SetREG"))
                        {
                            queue.Add($">[{popped.Substring(popped.Length - 1, 1)}]");
                        }
                        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 if (popped == "StateGroupArg")
                        {
                            if (queue.Count == 0 || argCount != 1)
                            {
                                throw new Exception("Invalid StateGroupArg call");
                            }

                            queue.Add($"#B8");
                        }
                        else
                        {
                            queue.Add($"({argCount})");
                        }
                        return(true);
                    }
                    else
                    {
                        queue.Add(popped);
                        return(false);
                    }
                }

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

                foreach (var s in expr)
                {
                    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" || s == "StateGroupArg")
                    {
                        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 == "(" || s == "[")
                    {
                        stack.Push("(");
                    }

                    //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 == ")" || s == "]")
                    {
                        while (stack.Count != 0 && stack.Peek() != "(" && stack.Peek() != "[")
                        {
                            // This is where we'd add ContinueIfFalse if we cared about it.
                            popAndEnqueue();
                        }

                        //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() != "(" && 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);
            }
示例#8
0
            public static Expr BytecodeToInfix(EzSembleContext context, byte[] Bytes)
            {
                var bigEndianReverseBytes = Bytes.Reverse().ToArray();

                Stack <Expr> exprs = new Stack <Expr>();

                List <Expr> popArgs(int amount)
                {
                    List <Expr> args = new List <Expr>();

                    for (int i = 0; i < amount; i++)
                    {
                        args.Add(exprs.Pop());
                    }
                    args.Reverse();
                    return(args);
                }

                for (int i = 0; i < Bytes.Length; i++)
                {
                    var b = Bytes[i];
                    if (b >= 0 && b <= 0x7F)
                    {
                        exprs.Push(new ConstExpr {
                            Value = (sbyte)(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");
                        }
                        exprs.Push(new ConstExpr {
                            Value = text
                        });
                        i += j + 2;
                    }
                    else if (b == 0x80)
                    {
                        float val;
                        if (!context.IsBigEndian)
                        {
                            val = BitConverter.ToSingle(Bytes, i + 1);
                        }
                        else
                        {
                            val = BitConverter.ToSingle(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 4);
                        }
                        exprs.Push(new ConstExpr {
                            Value = val
                        });

                        i += 4;
                    }
                    else if (b == 0x81)
                    {
                        double val;
                        if (!context.IsBigEndian)
                        {
                            val = BitConverter.ToDouble(Bytes, i + 1);
                        }
                        else
                        {
                            val = BitConverter.ToDouble(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 8);
                        }
                        exprs.Push(new ConstExpr {
                            Value = val
                        });

                        i += 8;
                    }
                    else if (b == 0x82)
                    {
                        int val;
                        if (!context.IsBigEndian)
                        {
                            val = BitConverter.ToInt32(Bytes, i + 1);
                        }
                        else
                        {
                            val = BitConverter.ToInt32(bigEndianReverseBytes, (bigEndianReverseBytes.Length - 1) - (i + 1) - 4);
                        }
                        exprs.Push(new ConstExpr {
                            Value = val
                        });

                        i += 4;
                    }
                    else if (b == 0x84)
                    {
                        exprs.Push(new FunctionCall {
                            Args = popArgs(0), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name
                        });
                    }
                    else if (b == 0x85)
                    {
                        exprs.Push(new FunctionCall {
                            Args = popArgs(1), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name
                        });
                    }
                    else if (b == 0x86)
                    {
                        exprs.Push(new FunctionCall {
                            Args = popArgs(2), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name
                        });
                    }
                    else if (b == 0x87)
                    {
                        exprs.Push(new FunctionCall {
                            Args = popArgs(3), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name
                        });
                    }
                    else if (b == 0x88)
                    {
                        exprs.Push(new FunctionCall {
                            Args = popArgs(4), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name
                        });
                    }
                    else if (b == 0x89)
                    {
                        exprs.Push(new FunctionCall {
                            Args = popArgs(5), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name
                        });
                    }
                    else if (b == 0x8A)
                    {
                        exprs.Push(new FunctionCall {
                            Args = popArgs(6), Name = context.GetFunctionInfo(exprs.Pop().AsInt()).Name
                        });
                    }
                    else if (OperatorsByByte.ContainsKey(b))
                    {
                        if (OperatorsByByte[b] == "N")
                        {
                            exprs.Push(new UnaryExpr {
                                Op = "N", Arg = exprs.Pop()
                            });
                        }
                        else
                        {
                            exprs.Push(new BinaryExpr {
                                Op = OperatorsByByte[b], Rhs = exprs.Pop(), Lhs = exprs.Pop()
                            });
                        }
                    }
                    else if (b == 0xA6)
                    {
                        Expr top = exprs.Peek();
                        top.IfFalse = FalseCond.CONTINUE;
                    }
                    else if (b >= 0xA7 && b <= 0xAE)
                    {
                        byte regIndex = (byte)(b - 0xA7);
                        exprs.Push(new FunctionCall {
                            Args = popArgs(1), Name = $"SetREG{regIndex}"
                        });
                    }
                    else if (b >= 0xAF && b <= 0xB6)
                    {
                        byte regIndex = (byte)(b - 0xAF);
                        exprs.Push(new FunctionCall {
                            Args = popArgs(0), Name = $"GetREG{regIndex}"
                        });
                    }
                    else if (b == 0xB7)
                    {
                        Expr top = exprs.Peek();
                        top.IfFalse = FalseCond.ABORT;
                    }
                    else if (b == 0xB8)
                    {
                        // exprs.Push(new FunctionCall { Args = popArgs(1), Name = "StateGroupArg" });
                        FunctionCall func = new FunctionCall {
                            Args = popArgs(1), Name = "StateGroupArg"
                        };
                        ConstExpr ce = func.Args[0] as ConstExpr;
                        // Console.WriteLine($"{ce} {ce.Value.GetType()}");
                        exprs.Push(func);
                    }
                    else if (b == 0xB9)
                    {
                        exprs.Push(new CallResult());
                    }
                    else if (b == 0xBA)
                    {
                        // This opcode just returns a constant value 0x7FFFFFFF
                        // But use higher-level representation of it
                        exprs.Push(new CallOngoing());
                    }
                    else if (b == 0xA1)
                    {
                        //break;
                    }
                    else
                    {
                        exprs.Push(new Unknown {
                            Opcode = b
                        });
                    }
                }
                if (exprs.Count != 1)
                {
                    throw new Exception("Could not parse expr. Remaining stack: " + string.Join("; ", exprs) + $"; = {string.Join(" ", Bytes.Select(x => x.ToString("X2")))}");
                }
                return(exprs.Pop());
            }
示例#9
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" || s == "StateGroupArg");
 }
示例#10
0
 /// <summary>
 /// Dissembles bytecode into an "EzLanguage" expression.
 /// </summary>
 public static Expr DissembleExpression(EzSembleContext context, byte[] bytes)
 {
     return(EzInfixor.BytecodeToInfix(context, bytes));
 }
示例#11
0
 /// <summary>
 /// Dissembles a list of CommandCall objects into a plain text "EzLanguage" script.
 /// </summary>
 public static Block DissembleCommandScript(EzSembleContext context, List <ESD.CommandCall> script)
 {
     return(new Block {
         Cmds = script.Select(x => DissembleCommandCall(context, x)).ToList()
     });
 }
示例#12
0
 /// <summary>
 /// Dissembles a CommandCall object into a line of "EzLanguage" plain text.
 /// </summary>
 public static Statement DissembleCommandCall(EzSembleContext context, ESD.CommandCall c)
 {
     return(new Statement {
         Name = context.GetCommandInfo(c.CommandBank, c.CommandID).Name, Args = c.Arguments.Select(a => DissembleExpression(context, a)).ToList()
     });
 }