using System.Text; namespace Compiler; public sealed class Generator(List nodes) { public static string Emit(List nodes) { return new Generator(nodes).Emit(); } private IndentedTextWriter writer = new(); private string Emit() { writer.WriteLine(""" #include #include #include #include #include struct string { const char *data; int length; }; """); foreach (var node in nodes.OfType()) { var parameters = node.Parameters.Select(x => CType(x.Type, x.Name.Ident)); writer.WriteLine($"{CType(node.ReturnType, node.Name.Ident)}({string.Join(", ", parameters)});"); } writer.WriteLine(); foreach (var node in nodes.OfType()) { writer.WriteLine($"struct {node.Name.Ident}"); writer.WriteLine("{"); using (writer.Indent()) { foreach (var field in node.Fields) { writer.WriteLine($"{CType(field.Type, field.Name.Ident)};"); } } writer.WriteLine("};"); } writer.WriteLine(); foreach (var node in nodes.OfType()) { var parameters = node.Parameters.Select(x => CType(x.Type, x.Name.Ident)); writer.WriteLine($"{CType(node.ReturnType, node.Name.Ident)}({string.Join(", ", parameters)})"); writer.WriteLine("{"); using (writer.Indent()) { EmitStatement(node.Body); } writer.WriteLine("}"); writer.WriteLine(); } return writer.ToString(); } private void EmitStatement(NodeStatement node) { switch (node) { case NodeStatementBlock statement: EmitStatementBlock(statement); break; case NodeStatementFuncCall statement: EmitStatementFuncCall(statement); break; case NodeStatementReturn statement: EmitStatementReturn(statement); break; case NodeStatementVariableDeclaration statement: EmitStatementVariableDeclaration(statement); break; case NodeStatementAssignment statement: EmitStatementAssignment(statement); break; case NodeStatementIf statement: EmitStatementIf(statement); break; case NodeStatementWhile statement: EmitStatementWhile(statement); break; default: throw new ArgumentOutOfRangeException(nameof(node), node, null); } } private void EmitStatementBlock(NodeStatementBlock node) { writer.WriteLine("{"); using (writer.Indent()) { foreach (var statement in node.Statements) EmitStatement(statement); } writer.WriteLine("}"); } private void EmitStatementFuncCall(NodeStatementFuncCall node) { var name = EmitExpression(node.Target); var parameterValues = node.Parameters.Select(EmitExpression).ToList(); writer.WriteLine($"{name}({string.Join(", ", parameterValues)});"); } private void EmitStatementReturn(NodeStatementReturn statement) { var value = EmitExpression(statement.Value); writer.WriteLine($"return {value};"); } private void EmitStatementVariableDeclaration(NodeStatementVariableDeclaration statement) { var value = EmitExpression(statement.Value); writer.WriteLine($"{CType(statement.Type)} {statement.Name.Ident} = {value};"); } private void EmitStatementAssignment(NodeStatementAssignment statement) { var target = EmitExpression(statement.Target); var value = EmitExpression(statement.Value); writer.WriteLine($"{target} = {value};"); } private void EmitStatementIf(NodeStatementIf statement) { var condition = EmitExpression(statement.Condition); writer.WriteLine($"if ({condition})"); writer.WriteLine("{"); using (writer.Indent()) { EmitStatement(statement.ThenBlock); } writer.WriteLine("}"); if (statement.ElseBlock != null) { writer.Write("else"); if (statement.ElseBlock is NodeStatementIf) writer.Write(" "); else writer.WriteLine(); writer.WriteLine("{"); using (writer.Indent()) { EmitStatement(statement.ElseBlock); } writer.WriteLine("}"); } } private void EmitStatementWhile(NodeStatementWhile statement) { var condition = EmitExpression(statement.Condition); writer.WriteLine($"while ({condition})"); writer.WriteLine("{"); using (writer.Indent()) { EmitStatement(statement.Block); } writer.WriteLine("}"); } private string EmitExpression(NodeExpression node) { return node switch { NodeExpressionBinary expression => EmitExpressionBinary(expression), NodeExpressionBoolLiteral expression => expression.Value.Value ? "true" : "false", NodeExpressionIntLiteral expression => expression.Value.Value.ToString(), NodeExpressionStringLiteral expression => $"(struct string){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}", NodeExpressionStructLiteral expression => EmitStructLiteral(expression), NodeExpressionMemberAccess expression => EmitExpressionMemberAccess(expression), NodeExpressionIdent expression => expression.Value.Ident, _ => throw new ArgumentOutOfRangeException(nameof(node), node, null) }; } private string EmitExpressionBinary(NodeExpressionBinary expression) { var left = EmitExpression(expression.Left); var right = EmitExpression(expression.Right); return expression.Operation switch { NodeExpressionBinary.Op.Add => $"({left} + {right})", NodeExpressionBinary.Op.Subtract => $"({left} - {right})", NodeExpressionBinary.Op.Multiply => $"({left} * {right})", NodeExpressionBinary.Op.Divide => $"({left} / {right})", NodeExpressionBinary.Op.Modulo => $"({left} % {right})", NodeExpressionBinary.Op.Equal => $"({left} == {right})", NodeExpressionBinary.Op.NotEqual => $"({left} != {right})", NodeExpressionBinary.Op.LessThan => $"({left} < {right})", NodeExpressionBinary.Op.LessThanOrEqual => $"({left} <= {right})", NodeExpressionBinary.Op.GreaterThan => $"({left} > {right})", NodeExpressionBinary.Op.GreaterThanOrEqual => $"({left} >= {right})", NodeExpressionBinary.Op.LeftShift => $"({left} << {right})", NodeExpressionBinary.Op.RightShift => $"({left} >> {right})", NodeExpressionBinary.Op.LogicalAnd => $"({left} && {right})", NodeExpressionBinary.Op.LogicalOr => $"({left} || {right})", _ => throw new ArgumentOutOfRangeException() }; } private static string CType(NodeType node, string? varName = null) { return node switch { NodeTypeVoid => "void" + (varName != null ? $" {varName}" : ""), NodeTypeBool => "bool" + (varName != null ? $" {varName}" : ""), NodeTypeCustom type => $"struct {type.Name.Ident}" + (varName != null ? $" {varName}" : ""), NodeTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""), NodeTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""), NodeTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"), NodeTypeString => "struct string" + (varName != null ? $" {varName}" : ""), NodeTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})", _ => throw new ArgumentOutOfRangeException(nameof(node), node, null) }; } private string EmitStructLiteral(NodeExpressionStructLiteral expression) { var initializerValues = new Dictionary(); foreach (var initializer in expression.Initializers) { var values = EmitExpression(initializer.Value); initializerValues[initializer.Name.Ident] = values; } var initializerStrings = initializerValues.Select(x => $".{x.Key} = {x.Value}"); return $"(struct {expression.Name.Ident}){{ {string.Join(", ", initializerStrings)} }}"; } private string EmitExpressionMemberAccess(NodeExpressionMemberAccess expression) { var target = EmitExpression(expression.Target); return $"{target}.{expression.Name.Ident}"; } } internal class IndentedTextWriter { private readonly StringBuilder builder = new(); private int indentLevel; public IDisposable Indent() { indentLevel++; return new IndentScope(this); } public void WriteLine(string text) { WriteIndent(); builder.AppendLine(text); } public void Write(string text) { WriteIndent(); builder.Append(text); } public void WriteLine() { builder.AppendLine(); } public override string ToString() { return builder.ToString(); } private void WriteIndent() { if (builder.Length > 0) { var lastChar = builder[^1]; if (lastChar != '\n' && lastChar != '\r') return; } for (var i = 0; i < indentLevel; i++) { builder.Append(" "); } } private class IndentScope(IndentedTextWriter writer) : IDisposable { private bool disposed; public void Dispose() { if (disposed) return; writer.indentLevel--; disposed = true; } } }