示例#1
0
        public static bool RemoveUnusedVariables(BlockNode block)
        {
            var usedvariables = block.GetReadVariables().ToArray();

            var changesmade = false;
            var i           = 0;

            foreach (var node in block.GetChildren().ToList())
            {
                if (node is VariableDeclarationNode dec)
                {
                    if (!usedvariables.Contains(dec.VariableName))
                    {
                        block.RemoveChild(i--);
                        changesmade = true;
                    }
                }
                else if (node is VariableAssignmentNode assignment)
                {
                    if (!usedvariables.Contains(assignment.VariableName))
                    {
                        block.RemoveChild(i--);
                        changesmade = true;
                    }
                }

                i++;
            }

            return(changesmade);
        }
示例#2
0
        public static IEnumerable <List <Node> > CreateBasicBlocks(BlockNode block)
        {
            var children     = block.GetChildren();
            var currentblock = new List <Node>();

            foreach (var child in children)
            {
                if (currentblock.Any() && child is LabelNode)
                {
                    yield return(currentblock);

                    currentblock = new List <Node>();
                }

                currentblock.Add(child);

                if (currentblock.Any() && child is GotoNode)
                {
                    yield return(currentblock);

                    currentblock = new List <Node>();
                }
            }

            if (currentblock.Any())
            {
                yield return(currentblock);
            }
        }
示例#3
0
        public static bool TransformToIncDec(BlockNode block)
        {
            var children    = block.GetChildren().ToList();
            var changesmade = false;

            for (var i = 0; i < children.Count; i++)
            {
                var node = children[i];

                if (!(node is VariableAssignmentNode assignment))
                {
                    continue;
                }

                BinaryOperatorNode expression = null;
                if (assignment.Value is AdditionNode add)
                {
                    expression = add;
                }
                if (assignment.Value is SubtractionNode sub)
                {
                    expression = sub;
                }
                if (expression == null)
                {
                    continue;
                }

                ExpressionNode left, right;
                if (expression.Left is ShortValueNode)
                {
                    left  = expression.Left;
                    right = expression.Right;
                }
                else
                {
                    right = expression.Left;
                    left  = expression.Right;
                }
                if (left is ShortValueNode value && value.Value == 1 && right is VariableValueNode var && var.VariableName == assignment.VariableName)
                {
                    children.RemoveAt(i);
                    block.RemoveChild(i);
                    if (expression is AdditionNode)
                    {
                        block.AddChild(new IncrementNode(assignment.VariableName));
                    }
                    else
                    {
                        block.AddChild(new DecrementNode(assignment.VariableName));
                    }

                    changesmade = true;
                }
            }

            return(changesmade);
        }
示例#4
0
        public static void Optimize(BlockNode block)
        {
            while (PropagateConstants(block) || RemoveUnusedVariables(block) || TransformToIncDec(block))
            {
            }

            foreach (var child in block.GetChildren())
            {
                if (child is IfNode ifnode)
                {
                    Optimize(ifnode.IfTrue);
                    Optimize(ifnode.IfFalse);
                }
            }
        }
示例#5
0
        public static void Simplify(BlockNode block)
        {
            while (TransformAdditionAssignmentToExpression(block) ||
                   TransformSubtractionAssignmentToExpression(block) ||
                   FlattenExpressions(block))
            {
            }

            foreach (var child in block.GetChildren())
            {
                if (child is IfNode ifnode)
                {
                    Simplify(ifnode.IfTrue);
                    Simplify(ifnode.IfFalse);
                }
            }
        }
示例#6
0
        public static bool FlattenExpressions(BlockNode block)
        {
            var changesmade = false;

            for (var i = 0; i < block.GetChildren().Count(); i++)
            {
                var addedinstructions = FlattenExpression(block, i);
                if (addedinstructions <= 0)
                {
                    continue;
                }

                changesmade = true;
                i          += addedinstructions;
            }

            return(changesmade);
        }
示例#7
0
        public static bool TransformSubtractionAssignmentToExpression(BlockNode block)
        {
            var changesmade = false;
            var children    = block.GetChildren().ToList();

            for (var i = 0; i < children.Count; i++)
            {
                var node = children[i];
                if (!(node is SubtractionAssignmentNode assignment))
                {
                    continue;
                }

                block.RemoveChild(i);
                block.InsertAt(new VariableAssignmentNode(assignment.VariableName, new SubtractionNode(new VariableValueNode(assignment.VariableName), assignment.Value)), i);
                changesmade = true;
            }

            return(changesmade);
        }
示例#8
0
        public static int FlattenExpression(BlockNode block, int index)
        {
            var currentblock = block.GetChildren().ToList()[index];

            if (currentblock is VariableAssignmentNode assignmentnode)
            {
                if (!(assignmentnode.Value is BinaryOperatorNode value))                 // Flat enough
                {
                    return(0);
                }

                // Single operations per assignment is what we want. This is good, stop.
                if (value.Left is ConstantNode && value.Right is ConstantNode)
                {
                    return(0);
                }

                block.RemoveChild(index);
                var count = 0;
                FlattenExpression(block, value, ref count, ref index, 0);
                count *= 2;
                block.InsertAt(assignmentnode, index);
                return(count);
            }
            if (currentblock is IfNode ifNode)
            {
                if (ifNode.Condition is VariableValueNode value)                 // Flat enough
                {
                    return(0);
                }

                var tempvarname = ExtractVariable(block, ifNode.Condition, ref index);
                ifNode.Condition = new VariableValueNode(tempvarname);

                return(2);
            }

            return(0);
        }
        public static IEnumerable <string> EmitAssembly(BlockNode rootnode, int startindex = 0)
        {
            char[] registernames = { 'C', 'D', 'E', 'H', 'L' };

            var variablealloc = AllocateRegisters(rootnode);

            // Check variable count is under the register limit
            if (variablealloc.Count > 0)             // .Max throws if collection is empty :/
            {
                if (variablealloc.Max(pair => pair.Value) >= registernames.Length)
                {
                    throw new OutOfSpaceException("Unable to allocate sufficent registers for optimized variable count");
                }
            }

            char GetVariableRegister(string name) => registernames[variablealloc[name]];

            string getValue(Node node)               // TODO: Make this ValueNode
            {
                if (node is VariableValueNode assignment)
                {
                    return(GetVariableRegister(assignment.VariableName).ToString());
                }
                if (node is ShortValueNode shortValue)
                {
                    return(shortValue.Value.ToString());
                }

                throw new NotSupportedException("This operator is not yet supported inside the assembler. Please implement.");
            }

            var r = 1;

            string getRandomLabelName() => "generatedLabel" + r++;

            // Cases must be in order of any inheritence because of the way `is` works
            foreach (var node in rootnode.GetChildren())
            {
                switch (node)
                {
                case VariableDeclarationNode _:
                    // Do nothing
                    break;

                case IncrementNode inc:
                    yield return($"INC {GetVariableRegister(inc.VariableName)}");

                    break;

                case DecrementNode dec:
                    yield return($"DEC {GetVariableRegister(dec.VariableName)}");

                    break;

                case LabelNode label:
                    yield return(label.Name + ':');

                    break;

                case GotoNode gotonode:
                    yield return("JP " + gotonode.LabelName);

                    break;

                case VariableAssignmentNode var when var.Value is VariableValueNode varval:
                    yield return($"LD {GetVariableRegister(var.VariableName)} {GetVariableRegister(varval.VariableName)}");

                    break;

                case VariableAssignmentNode var when var.Value is ShortValueNode imval:
                    yield return($"LD {GetVariableRegister(var.VariableName)} {imval.Value}");

                    break;

                case VariableAssignmentNode var when var.Value is MemoryValueNode memval:
                    yield return($"LD A ({memval.Address})");

                    yield return($"LD {GetVariableRegister(var.VariableName)} A");

                    break;

                case MemoryAssignmentNode var:
                    if (var.Value is VariableValueNode vval)
                    {
                        yield return($"LD ({var.Address}) {GetVariableRegister(vval.VariableName)}");
                    }
                    else if (var.Value is ShortValueNode shortval)
                    {
                        yield return("PUSH HL");

                        yield return($"LD HL {var.Address}");

                        yield return($"LD (HL) {shortval.Value}");

                        yield return("POP HL");
                    }
                    break;

                case VariableAssignmentNode var: {
                    if (var.Value is BinaryOperatorNode oprator)
                    {
                        if (var.Value is ComparisonNode comparison)
                        {
                            yield return($"LD A {getValue(comparison.Left)}");

                            yield return($"CP {getValue(comparison.Right)}");

                            var iffalselabelname = getRandomLabelName();
                            if (var.Value is LessThanComparisonNode)
                            {
                                yield return("JP NC " + iffalselabelname);
                            }
                            else if (var.Value is MoreThanComparisonNode)
                            {
                                yield return("JP C " + iffalselabelname);

                                yield return("JP NZ " + iffalselabelname);
                            }

                            yield return($"LD {GetVariableRegister(var.VariableName)} 1");

                            var iftruelabelname = getRandomLabelName();
                            yield return("JP " + iftruelabelname);

                            yield return(iffalselabelname + ':');

                            yield return($"LD {GetVariableRegister(var.VariableName)} 0");

                            yield return(iftruelabelname + ':');
                        }
                        else                                     // Only other operators should be addition and subtraction
                        {
                            yield return($"LD A {getValue(oprator.Left)}");

                            var rightoprand = getValue(oprator.Right);
                            if (var.Value is AdditionNode)
                            {
                                yield return($"ADD A {rightoprand}");
                            }
                            else if (var.Value is SubtractionNode)
                            {
                                yield return($"SUB A {rightoprand}");
                            }

                            yield return($"LD {GetVariableRegister(var.VariableName)} A");
                        }
                    }
                    else if (var.Value is UnaryOperatorNode operatorNode)
                    {
                        if (var.Value is NegateNode negatenode)
                        {
                            yield return("LD A 1");

                            yield return($"XOR {getValue(negatenode.Expression)}");

                            yield return($"LD {GetVariableRegister(var.VariableName)} A");
                        }
                    }

                    break;
                }

                case IfNode ifNode:
                    yield return("XOR A");

                    yield return($"CP {GetVariableRegister(((VariableValueNode)ifNode.Condition).VariableName)}");                            // Formatter should extract condition before it gets here

                    var iffalselabel = getRandomLabelName();
                    yield return($"JP NZ {iffalselabel}");

                    foreach (var asm in EmitAssembly(ifNode.IfTrue))
                    {
                        yield return(asm);
                    }

                    var falsebody   = ifNode.IfFalse.GetChildren();
                    var iftruelabel = getRandomLabelName();
                    if (falsebody.Any())
                    {
                        yield return("JP " + iftruelabel);
                    }
                    yield return(iffalselabel + ':');

                    if (falsebody.Any())
                    {
                        foreach (var asm in EmitAssembly(ifNode.IfFalse))
                        {
                            yield return(asm);
                        }
                        yield return(iftruelabel + ':');
                    }

                    break;
                }
            }
        }
示例#10
0
        public static bool PropagateConstants(BlockNode block)
        {
            var changesmade = false;

            var variablevalues = new Dictionary <string, ushort>();
            var children       = block.GetChildren().ToList();

            for (var i = 0; i < children.Count; i++)
            {
                var node = children[i];

                if (node is AssignmentNode assignment)
                {
                    var newvalue = assignment.Value.Optimize(variablevalues);
                    if (!assignment.Value.Matches(newvalue))
                    {
                        changesmade = true;
                    }

                    assignment.Value = newvalue;
                }

                if (node is VariableAssignmentNode varassignment)
                {
                    if (varassignment.Value is ConstantNode value)
                    {
                        if (variablevalues.ContainsKey(varassignment.VariableName))
                        {
                            variablevalues[varassignment.VariableName] = value.GetValue();
                        }
                        else
                        {
                            variablevalues.Add(varassignment.VariableName, value.GetValue());
                        }
                    }
                }
                else if (node is IncrementNode inc)
                {
                    if (variablevalues.ContainsKey(inc.VariableName))
                    {
                        variablevalues[inc.VariableName]++;
                        children.RemoveAt(i);
                        block.RemoveChild(i--);
                        changesmade = true;
                    }
                }
                else if (node is DecrementNode dec)
                {
                    if (variablevalues.ContainsKey(dec.VariableName))
                    {
                        variablevalues[dec.VariableName]--;
                        children.RemoveAt(i);
                        block.RemoveChild(i--);
                        changesmade = true;
                    }
                }
                else if (node is IfNode ifnode)
                {
                    if (!(ifnode.Condition is ExpressionNode condition))
                    {
                        continue;
                    }
                    ifnode.Condition = condition.Optimize(variablevalues);
                    if (!(ifnode.Condition is ConstantNode c))
                    {
                        continue;
                    }

                    children.RemoveAt(i);
                    block.RemoveChild(i);
                    changesmade = true;

                    if (IsTrue(c))
                    {
                        children.InsertRange(i, ifnode.IfTrue.GetChildren());
                        var ifchildren = ifnode.IfTrue.GetChildren().ToList();
                        for (var j = 0; j < ifchildren.Count; j++)
                        {
                            block.InsertAt(ifchildren[j], i + j);
                        }
                    }
                    else
                    {
                        children.InsertRange(i, ifnode.IfFalse.GetChildren());
                        var ifchildren = ifnode.IfFalse.GetChildren().ToList();
                        for (var j = 0; j < ifchildren.Count; j++)
                        {
                            block.InsertAt(ifchildren[j], i + j);
                        }
                    }
                    i--;
                }
            }

            return(changesmade);
        }