preface

This chapter corresponds to chapter 8 of the official tutorial. This chapter explains how to compile a language as an object file.

The tutorial is as follows:

Write compiler toys using Swift (0)

Learn how to write compiler toys using Swift

Use Swift to write compiler toys (2)

Use swift to write compiler toys (3)

Learn how to write compiler toys using Swift

Learn how to write compiler toys using Swift

Learn how to write compiler toys using Swift

Learn how to write compiler toys using Swift

Learn how to write compiler toys using Swift

In the warehouse

start

Because we used the JIT before, but now we have to generate the target file as well, so we can now encapsulate the JIT and main file.

The first is to encapsulate the JIT, which I encapsulate here as the CodeRunner class.

class CodeRunner {
    
    private let jit: JIT
    
    private typealias fnPr = @convention(c) () - >Double
    
    init(machine: TargetMachine) {
        jit = JIT(machine: machine)
    }
    
    public func run(module: Module) {
        do {
            let handle = try jit.addEagerlyCompiledIR(module, { (_) - >JIT.TargetAddress in
                return JIT.TargetAddress()})let addr = try jit.address(of: "__anon_expr")
            let fn = unsafeBitCast(addr, to: fnPr.self)
            print("\(fn())")
            try jit.removeModule(handle)
        } catch {
            fatalError("Adds the IR from a given module failure.")}}}Copy the code

Next, the main file.

let isUseJIT = false

func readFile(_ path: String) -> String? {
    var path = path
    if path.hasSuffix("\n") {
        path.removeLast()
    }
    guard path.split(separator: ".").last! = ="k" else {
        print("Expected file is *.k.")
        return nil
    }
    do {
        return try String(contentsOfFile: path, encoding: .utf8)
    } catch {
        print("Read file \(path) failure.")
        return nil}}func main(a) {
    // Initialize the Module and the intermediate code optimizer
    initModule()
    / / the parser
    let parser = Parser(a)if let path = String(data: FileHandle.standardInput.availableData, encoding: .utf8) {
        if let str = readFile(path) {
            parser.parse(str)
          	// Specify the target
            theModule.targetTriple = .default
            do {
                // initializeLLVM() has been called in the initializeLLVM() method.
                let targetMachine = try TargetMachine(triple: .default,
                                                      cpu: "x86-64",
                                                      features: "",
                                                      optLevel: .default,
                                                      relocations: .default,
                                                      codeModel: .default)
              	// Specify the data layout
                theModule.dataLayout = targetMachine.dataLayout
              	// Put code optimizations here
                let pass = PassPipeliner(module: theModule)
                pass.execute()
                if isUseJIT {
                    let runner = CodeRunner(machine: targetMachine)
                    runner.run(module: theModule)
                } else {
                    // Change it to its own path
                    let path = "Fill in your own path."
                  	// Create the target file
                    try targetMachine.emitToFile(module: theModule, type: .object, path: path)
                    print("Wrote \(path)")}}catch {
                print("\(error)")
            }
        }
    }
}

main()
Copy the code

test

Let’s create a.k file, average.k.

Def def (x + y) (x + y) * 0.5;Copy the code

We run the code to generate the object file output.o. We can use the following command to see if the object file generates the symbol table.

objdump -t output.o
Copy the code

Output similar to the following.

output.o:	file format Mach-O 64-bit x86-64

SYMBOL TABLE:
0000000000000000 g     F __TEXT,__text	_average
Copy the code

After generating the object file we need to write a piece of C++ code to call.

#include <iostream>

extern "C" {
    double average(double.double);
}

int main(a) {
    std: :cout << "Average of 3.0 and 4.0:" << average(3.0.4.0) < <std: :endl;
}

Copy the code

Link the program to output.o and view the results

Clang++ main.cpp output.o -o main. /main // outputs average of 3.0 and 4.0:3.5Copy the code

Refer to the repository for complete code.

Possible problems

MacOS ‘wchar.h’ File Not Found

MacOS ‘wchar.h’ File Not Found

The open/Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10. 14. PKGCopy the code

Install the header file package under Mojava.