131 lines
3.9 KiB
C#
131 lines
3.9 KiB
C#
using System.Diagnostics;
|
|
using NubLang.TypeChecking.Node;
|
|
|
|
namespace NubLang.Generation.QBE;
|
|
|
|
public partial class QBEGenerator
|
|
{
|
|
private void EmitStatement(Statement statement)
|
|
{
|
|
switch (statement)
|
|
{
|
|
case Assignment assignment:
|
|
EmitAssignment(assignment);
|
|
break;
|
|
case Break:
|
|
EmitBreak();
|
|
break;
|
|
case Continue:
|
|
EmitContinue();
|
|
break;
|
|
case If ifStatement:
|
|
EmitIf(ifStatement);
|
|
break;
|
|
case Return @return:
|
|
EmitReturn(@return);
|
|
break;
|
|
case StatementExpression statementExpression:
|
|
EmitExpression(statementExpression.Expression);
|
|
break;
|
|
case VariableDeclaration variableDeclaration:
|
|
EmitVariableDeclaration(variableDeclaration);
|
|
break;
|
|
case While whileStatement:
|
|
EmitWhile(whileStatement);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(statement));
|
|
}
|
|
}
|
|
|
|
private void EmitAssignment(Assignment assignment)
|
|
{
|
|
var destination = EmitExpression(assignment.Target);
|
|
Debug.Assert(destination.Kind == ValKind.Pointer);
|
|
EmitCopyIntoOrInitialize(assignment.Value, destination.Name);
|
|
}
|
|
|
|
private void EmitBreak()
|
|
{
|
|
_writer.Indented($"jmp {_breakLabels.Peek()}");
|
|
_codeIsReachable = false;
|
|
}
|
|
|
|
private void EmitContinue()
|
|
{
|
|
_writer.Indented($"jmp {_continueLabels.Peek()}");
|
|
_codeIsReachable = false;
|
|
}
|
|
|
|
private void EmitIf(If ifStatement)
|
|
{
|
|
var trueLabel = LabelName();
|
|
var falseLabel = LabelName();
|
|
var endLabel = LabelName();
|
|
|
|
var result = EmitUnwrap(EmitExpression(ifStatement.Condition));
|
|
_writer.Indented($"jnz {result}, {trueLabel}, {falseLabel}");
|
|
_writer.WriteLine(trueLabel);
|
|
EmitBlock(ifStatement.Body);
|
|
_writer.Indented($"jmp {endLabel}");
|
|
_writer.WriteLine(falseLabel);
|
|
if (ifStatement.Else.HasValue)
|
|
{
|
|
ifStatement.Else.Value.Match
|
|
(
|
|
elseIfNode => EmitIf(elseIfNode),
|
|
elseNode => EmitBlock(elseNode)
|
|
);
|
|
}
|
|
|
|
_writer.WriteLine(endLabel);
|
|
}
|
|
|
|
private void EmitReturn(Return @return)
|
|
{
|
|
if (@return.Value.HasValue)
|
|
{
|
|
var result = EmitUnwrap(EmitExpression(@return.Value.Value));
|
|
_writer.Indented($"ret {result}");
|
|
}
|
|
else
|
|
{
|
|
_writer.Indented("ret");
|
|
}
|
|
}
|
|
|
|
private void EmitVariableDeclaration(VariableDeclaration variableDeclaration)
|
|
{
|
|
var name = $"%{variableDeclaration.Name}";
|
|
_writer.Indented($"{name} =l alloc8 8");
|
|
|
|
if (variableDeclaration.Assignment.HasValue)
|
|
{
|
|
var value = EmitCreateCopyOrInitialize(variableDeclaration.Assignment.Value);
|
|
EmitStore(variableDeclaration.Assignment.Value.Type, value, name);
|
|
}
|
|
|
|
Scope.Declare(variableDeclaration.Name, new Val(name, variableDeclaration.Type, ValKind.Pointer));
|
|
}
|
|
|
|
private void EmitWhile(While whileStatement)
|
|
{
|
|
var conditionLabel = LabelName();
|
|
var iterationLabel = LabelName();
|
|
var endLabel = LabelName();
|
|
|
|
_breakLabels.Push(endLabel);
|
|
_continueLabels.Push(conditionLabel);
|
|
|
|
_writer.Indented($"jmp {conditionLabel}");
|
|
_writer.WriteLine(iterationLabel);
|
|
EmitBlock(whileStatement.Body);
|
|
_writer.WriteLine(conditionLabel);
|
|
var result = EmitUnwrap(EmitExpression(whileStatement.Condition));
|
|
_writer.Indented($"jnz {result}, {iterationLabel}, {endLabel}");
|
|
_writer.WriteLine(endLabel);
|
|
|
|
_continueLabels.Pop();
|
|
_breakLabels.Pop();
|
|
}
|
|
} |