diff --git a/ExecutableTests/086.c b/ExecutableTests/086.c new file mode 100644 index 0000000..673c879 --- /dev/null +++ b/ExecutableTests/086.c @@ -0,0 +1,5 @@ +int a = 3; + +int main() { + return a; +} diff --git a/ExecutableTests/087.c b/ExecutableTests/087.c new file mode 100644 index 0000000..1b9c3c1 --- /dev/null +++ b/ExecutableTests/087.c @@ -0,0 +1,5 @@ +char b[5] = "aiueo"; + +int main() { + return b[4]; +} diff --git a/ExecutableTests/088.c b/ExecutableTests/088.c new file mode 100644 index 0000000..cef495e --- /dev/null +++ b/ExecutableTests/088.c @@ -0,0 +1,6 @@ +char a = 10; +char* b = &a; + +int main() { + return *b; +} diff --git a/ExecutableTests/089.c b/ExecutableTests/089.c new file mode 100644 index 0000000..407efbc --- /dev/null +++ b/ExecutableTests/089.c @@ -0,0 +1,7 @@ +char a = 10; +char b = 20; +char* c = &a + 1; + +int main() { + return *c; +} diff --git a/Sources/Generator/Generator.swift b/Sources/Generator/Generator.swift index d9ec0f8..8f1c0df 100644 --- a/Sources/Generator/Generator.swift +++ b/Sources/Generator/Generator.swift @@ -42,9 +42,12 @@ public final class Generator { public func generate(sourceFileNode: SourceFileNode) throws -> String { - var variableDeclResult = "" - for variableDecl in sourceFileNode.globalVariables { - variableDeclResult += try generateGlobalVariableDecl(node: variableDecl) + var dataSection = "" + if !sourceFileNode.globalVariables.isEmpty { + dataSection += ".section __DATA,__data\n" + for variableDecl in sourceFileNode.globalVariables { + dataSection += try generateGlobalVariableDecl(node: variableDecl) + } } var functionDeclResult = "" @@ -55,27 +58,82 @@ public final class Generator { let functionMeta = ".globl \(functionLabels.joined(separator: ", "))\n" - // data section - var dataSection = "" if !stringLiteralLabels.isEmpty { - dataSection = ".section __TEXT,__cstring,cstring_literals\n" + dataSection += ".section __TEXT,__cstring,cstring_literals\n" for (literal, label) in stringLiteralLabels { dataSection += "\(label):\n" dataSection += " .asciz \"\(literal)\"\n" } } - return variableDeclResult + functionMeta + functionDeclResult + dataSection + return functionMeta + functionDeclResult + dataSection } func generateGlobalVariableDecl(node: VariableDeclNode) throws -> String { + globalVariables[node.identifierName] = node.type + var result = "" - // g: .zeroじゃApple Clangは動かない? - let alignment = isElementOrReferenceTypeMemorySizeOf(1, identifierName: node.identifierName) ? 0 : 8 - result += ".comm \(node.identifierName),\(node.type.memorySize),\(alignment)\n" + if let initializerExpr = node.initializerExpr { - globalVariables[node.identifierName] = node.type + result += ".globl \(node.identifierName)\n" + if node.type.memorySize != 1 { + result += ".p2align 3, 0x0\n" + } + result += "\(node.identifierName):\n" + + switch initializerExpr.kind { + case .integerLiteral: + let sizeKind = node.type.memorySize == 1 ? "byte" : "quad" + let value = try initializerExpr.casted(IntegerLiteralNode.self).literal + result += " .\(sizeKind) \(value)\n" + + case .stringLiteral: + let value = try initializerExpr.casted(StringLiteralNode.self).value + result += " .asciz \"\(value)\"\n" + + case .prefixOperatorExpr: + let prefixOperatorExpr = try initializerExpr.casted(PrefixOperatorExpressionNode.self) + if prefixOperatorExpr.operatorKind == .address { + let value = try prefixOperatorExpr.right.casted(IdentifierNode.self).identifierName + result += " .quad \(value)\n" + } else { + throw GenerateError.invalidSyntax(index: initializerExpr.sourceTokens.first!.sourceIndex) + } + + case .infixOperatorExpr: + let infixOperator = try initializerExpr.casted(InfixOperatorExpressionNode.self) + + func generateAddressValue(referenceNode: any NodeProtocol, integerLiteralNode: any NodeProtocol) -> String? { + if let prefix = referenceNode as? PrefixOperatorExpressionNode, + prefix.operatorKind == .address, + let identifier = prefix.right as? IdentifierNode, + let binaryOperator = infixOperator.operator as? BinaryOperatorNode, + (binaryOperator.operatorKind == .add || binaryOperator.operatorKind == .sub), + let integerLiteral = integerLiteralNode as? IntegerLiteralNode { + return " .quad \(identifier.identifierName) \(binaryOperator.token.value) \(integerLiteral.literal)\n" + } else { + return nil + } + } + + // 左右一方が「&変数」, 他方が「IntergerLiteral」のはず + if let leftIsReference = generateAddressValue(referenceNode: infixOperator.left, integerLiteralNode: infixOperator.right) { + result += leftIsReference + } else if let rightIsReference = generateAddressValue(referenceNode: infixOperator.right, integerLiteralNode: infixOperator.left) { + result += rightIsReference + } else { + throw GenerateError.invalidSyntax(index: initializerExpr.sourceTokens.first!.sourceIndex) + } + + default: + throw GenerateError.invalidSyntax(index: initializerExpr.sourceTokens.first!.sourceIndex) + } + } else { + // Apple Clangでは初期化がない場合は.commじゃないとダメっぽい? + let alignment = isElementOrReferenceTypeMemorySizeOf(1, identifierName: node.identifierName) ? 0 : 3 + result += ".comm \(node.identifierName),\(node.type.memorySize),\(alignment)\n" + } return result } diff --git a/test_exectable.sh b/test_exectable.sh index 1758903..f584e0a 100755 --- a/test_exectable.sh +++ b/test_exectable.sh @@ -102,5 +102,9 @@ assert 15 "082.c" assert 6 "083.c" assert 111 "084.c" assert 0 "085.c" +assert 3 "086.c" +assert 111 "087.c" +assert 10 "088.c" +assert 20 "089.c" echo OK