Skip to content

Commit

Permalink
Support init global variable
Browse files Browse the repository at this point in the history
  • Loading branch information
kntkymt committed Jan 5, 2024
1 parent 1876ef8 commit 1174dee
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 11 deletions.
5 changes: 5 additions & 0 deletions ExecutableTests/086.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
int a = 3;

int main() {
return a;
}
5 changes: 5 additions & 0 deletions ExecutableTests/087.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
char b[5] = "aiueo";

int main() {
return b[4];
}
6 changes: 6 additions & 0 deletions ExecutableTests/088.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
char a = 10;
char* b = &a;

int main() {
return *b;
}
7 changes: 7 additions & 0 deletions ExecutableTests/089.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
char a = 10;
char b = 20;
char* c = &a + 1;

int main() {
return *c;
}
80 changes: 69 additions & 11 deletions Sources/Generator/Generator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
Expand All @@ -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
}
Expand Down
4 changes: 4 additions & 0 deletions test_exectable.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 1174dee

Please sign in to comment.