예제 #1
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);
                }
        }
예제 #2
0
파일: EzInfixor.cs 프로젝트: vawser/ESDLang
            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);
            }