lcc/Compiler/Generator/Generator.cs
2021-01-12 22:20:37 +01:00

112 lines
No EOL
4.6 KiB
C#

using System;
using System.Linq;
using Compiler.Parser;
using Compiler.Parser.Nodes;
namespace Compiler.Generator
{
public class Generator
{
public string Generate(Node rootNode)
{
string s = "";
switch (rootNode.NodeType)
{
case NodeType.ProgramNode:
foreach (Node rootNodeChild in rootNode.Children)
{
s += Generate(rootNodeChild);
}
break;
case NodeType.FunctionNode:
string identifier = ((FunctionNode) rootNode).Name;
string functionBody = "";
foreach (Node rootNodeChild in rootNode.Children)
{
functionBody += Generate(rootNodeChild);
}
s = $".globl {identifier}\n" +
$"{identifier}:\n" +
$"{functionBody}";
break;
case NodeType.ReturnStatementNode:
s = $"{Generate(rootNode.Children[0])}" +
"ret\n";
break;
case NodeType.ExpressionNode:
s = Generate(rootNode.Children[0]);
break;
case NodeType.ConstantNode:
s = $"movl ${((ConstantNode) rootNode).value.ToString()}, %eax\n";
break;
case NodeType.UnaryOperatorNode:
switch (((UnaryOperatorNode) rootNode).OperatorType)
{
case OperatorType.Negation:
s = $"{Generate(rootNode.Children[0])}" +
"neg %eax\n";
break;
case OperatorType.BitwiseComplement:
s = $"{Generate(rootNode.Children[0])}" +
"not %eax\n";
break;
case OperatorType.LogicalNegation:
s = $"{Generate(rootNode.Children[0])}" +
"cmpl $0, %eax\n" +
"movl $0, %eax\n" +
"sete %al\n";
break;
default:
throw new NotSpecifiedException(NodeType.UnaryOperatorNode,
((UnaryOperatorNode) rootNode).OperatorType);
}
break;
case NodeType.BinaryOperatorNode:
switch (((BinaryOperatorNode) rootNode).OperatorType)
{
case OperatorType.Addition:
s = $"{Generate(rootNode.Children[0])}" +
"push %rax\n" +
$"{Generate(rootNode.Children[1])}" +
"pop %rcx\n" +
"add %ecx, %eax\n";
break;
case OperatorType.Subtraction:
s = $"{Generate(rootNode.Children[1])}" +
"push %rax\n" +
$"{Generate(rootNode.Children[0])}" +
"pop %rcx\n" +
"sub %ecx, %eax\n";
break;
case OperatorType.Multiplication:
s = $"{Generate(rootNode.Children[0])}" +
"push %rax\n" +
$"{Generate(rootNode.Children[1])}" +
"pop %rcx\n" +
"imul %rcx, %rax\n";
break;
case OperatorType.Division:
s = $"{Generate(rootNode.Children[0])}" +
"push %rax\n" +
$"{Generate(rootNode.Children[1])}" +
"movl %eax, %ecx\n" + //move calculated divisor to %ecx
"pop %rax\n" + //pop divident do %eax
"cdq\n" +
"idivl %ecx\n"; //eax contains the result, edx the rest
break;
default:
throw new ArgumentOutOfRangeException();
}
break;
default:
throw new NotSpecifiedException(rootNode.NodeType);
}
return s;
}
}
}