From 9f125694bec8a33eb800f93ccfd8a267654ae3f6 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Sun, 16 Feb 2025 15:46:54 +0100 Subject: [PATCH] Added a program init function --- lib/core/core_linux.q | 8 ++++++++ lib/core/core_mac.q | 8 ++++++++ lib/core/core_windows.q | 20 ++++++++++++++++++++ lib/thread/thread_linux.q | 3 ++- src/compiler/Compile.go | 8 ++++++++ src/compiler/Result.go | 1 + src/compiler/finalize.go | 29 +++-------------------------- src/core/CompileCall.go | 5 +++++ src/core/ExpressionToRegister.go | 32 +++++++++++++++++++++----------- src/errors/Common.go | 1 + src/scanner/Scan.go | 1 + 11 files changed, 78 insertions(+), 38 deletions(-) create mode 100644 lib/core/core_linux.q create mode 100644 lib/core/core_mac.q create mode 100644 lib/core/core_windows.q diff --git a/lib/core/core_linux.q b/lib/core/core_linux.q new file mode 100644 index 0000000..41e7100 --- /dev/null +++ b/lib/core/core_linux.q @@ -0,0 +1,8 @@ +init() { + main.main() + exit() +} + +exit() { + syscall(60, 0) +} \ No newline at end of file diff --git a/lib/core/core_mac.q b/lib/core/core_mac.q new file mode 100644 index 0000000..875a04a --- /dev/null +++ b/lib/core/core_mac.q @@ -0,0 +1,8 @@ +init() { + main.main() + exit() +} + +exit() { + syscall(0x2000001, 0) +} \ No newline at end of file diff --git a/lib/core/core_windows.q b/lib/core/core_windows.q new file mode 100644 index 0000000..2b50ec1 --- /dev/null +++ b/lib/core/core_windows.q @@ -0,0 +1,20 @@ +extern kernel32 { + SetConsoleCP(cp UInt) + SetConsoleOutputCP(cp UInt) + ExitProcess(code UInt) +} + +const cp { + utf8 65001 +} + +init() { + kernel32.SetConsoleCP(cp.utf8) + kernel32.SetConsoleOutputCP(cp.utf8) + main.main() + exit() +} + +exit() { + kernel32.ExitProcess(0) +} \ No newline at end of file diff --git a/lib/thread/thread_linux.q b/lib/thread/thread_linux.q index 5179bed..98b4d6f 100644 --- a/lib/thread/thread_linux.q +++ b/lib/thread/thread_linux.q @@ -1,3 +1,4 @@ +import core import sys const clone { @@ -15,7 +16,7 @@ create(func *Any) -> Int { stack := sys.mmap(0, size, 0x1|0x2, 0x02|0x20|0x100|0x20000) stack += size stack -= 8 - store(stack, 8, _exit) + store(stack, 8, core.exit) stack -= 8 store(stack, 8, func) return sys.clone(clone.vm|clone.fs|clone.files|clone.sighand|clone.parent|clone.thread|clone.io, stack) diff --git a/src/compiler/Compile.go b/src/compiler/Compile.go index f964d78..749b71b 100644 --- a/src/compiler/Compile.go +++ b/src/compiler/Compile.go @@ -98,6 +98,13 @@ func Compile(constants <-chan *core.Constant, files <-chan *fs.File, functions < } } + // Check for existence of `init` + init, exists := allFunctions["core.init"] + + if !exists { + return result, errors.MissingInitFunction + } + // Check for existence of `main` main, exists := allFunctions["main.main"] @@ -105,6 +112,7 @@ func Compile(constants <-chan *core.Constant, files <-chan *fs.File, functions < return result, errors.MissingMainFunction } + result.Init = init result.Main = main result.Functions = allFunctions result.finalize() diff --git a/src/compiler/Result.go b/src/compiler/Result.go index a0d6091..5c96bf3 100644 --- a/src/compiler/Result.go +++ b/src/compiler/Result.go @@ -7,6 +7,7 @@ import ( // Result contains everything we need to write an executable file to disk. type Result struct { + Init *core.Function Main *core.Function Functions map[string]*core.Function Traversed map[*core.Function]bool diff --git a/src/compiler/finalize.go b/src/compiler/finalize.go index c317754..e82a049 100644 --- a/src/compiler/finalize.go +++ b/src/compiler/finalize.go @@ -5,7 +5,6 @@ import ( "git.akyoto.dev/cli/q/src/asmc" "git.akyoto.dev/cli/q/src/config" "git.akyoto.dev/cli/q/src/core" - "git.akyoto.dev/cli/q/src/dll" "git.akyoto.dev/cli/q/src/x86" ) @@ -20,33 +19,11 @@ func (r *Result) finalize() { Data: make(map[string][]byte, r.DataCount), } - final.Call("main.main") - final.Label(asm.LABEL, "_exit") - - switch config.TargetOS { - case config.Linux: - final.RegisterNumber(asm.MOVE, x86.SyscallInputRegisters[0], LinuxExit) - final.RegisterNumber(asm.MOVE, x86.SyscallInputRegisters[1], 0) - final.Syscall() - case config.Mac: - final.RegisterNumber(asm.MOVE, x86.SyscallInputRegisters[0], MacExit) - final.RegisterNumber(asm.MOVE, x86.SyscallInputRegisters[1], 0) - final.Syscall() - case config.Windows: - final.RegisterNumber(asm.MOVE, x86.WindowsInputRegisters[0], 0) - final.RegisterNumber(asm.AND, x86.RSP, -16) - final.DLLCall("kernel32.ExitProcess") - } - - r.DLLs = dll.List{ - {Name: "kernel32", Functions: []string{"ExitProcess"}}, - } - r.Traversed = make(map[*core.Function]bool, len(r.Functions)) - // This will place the main function immediately after the entry point - // and also add everything the main function calls recursively. - r.eachFunction(r.Main, r.Traversed, func(f *core.Function) { + // This will place the init function immediately after the entry point + // and also add everything the init function calls recursively. + r.eachFunction(r.Init, r.Traversed, func(f *core.Function) { final.Merge(f.Assembler) for _, library := range f.DLLs { diff --git a/src/core/CompileCall.go b/src/core/CompileCall.go index 4973ce2..ee320f2 100644 --- a/src/core/CompileCall.go +++ b/src/core/CompileCall.go @@ -44,6 +44,11 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error name = nameNode.Token.Text(f.File.Bytes) } + if f.UniqueName == "core.init" && pkg == "main" && name == "main" { + f.Call("main.main") + return nil, nil + } + fn, exists = f.Functions[pkg+"."+name] if !exists { diff --git a/src/core/ExpressionToRegister.go b/src/core/ExpressionToRegister.go index b143fac..d2b0cae 100644 --- a/src/core/ExpressionToRegister.go +++ b/src/core/ExpressionToRegister.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "math" "git.akyoto.dev/cli/q/src/asm" @@ -91,19 +92,28 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp rightText := right.Token.Text(f.File.Bytes) variable := f.VariableByName(leftText) - if variable == nil { - constant, isConst := f.Constants[f.Package+"."+leftText+"."+rightText] - - if isConst { - return f.TokenToRegister(constant.Value, register) - } - - return nil, errors.New(&errors.UnknownIdentifier{Name: leftText}, f.File, left.Token.Position) + if variable != nil { + field := variable.Type.(*types.Pointer).To.(*types.Struct).FieldByName(rightText) + f.MemoryRegister(asm.LOAD, asm.Memory{Base: variable.Register, Offset: int8(field.Offset), Length: byte(field.Type.Size())}, register) + return field.Type, nil } - field := variable.Type.(*types.Pointer).To.(*types.Struct).FieldByName(rightText) - f.MemoryRegister(asm.LOAD, asm.Memory{Base: variable.Register, Offset: int8(field.Offset), Length: byte(field.Type.Size())}, register) - return field.Type, nil + constant, isConst := f.Constants[f.Package+"."+leftText+"."+rightText] + + if isConst { + return f.TokenToRegister(constant.Value, register) + } + + uniqueName := fmt.Sprintf("%s.%s", leftText, rightText) + function, exists := f.Functions[uniqueName] + + if exists { + f.File.Imports[leftText].Used = true + f.RegisterLabel(asm.MOVE, register, function.UniqueName) + return types.AnyPointer, nil + } + + return nil, errors.New(&errors.UnknownIdentifier{Name: leftText}, f.File, left.Token.Position) } if len(node.Children) == 1 { diff --git a/src/errors/Common.go b/src/errors/Common.go index 04638d8..3b1d665 100644 --- a/src/errors/Common.go +++ b/src/errors/Common.go @@ -17,6 +17,7 @@ var ( MissingExpression = &Base{"Missing expression"} MissingGroupStart = &Base{"Missing '('"} MissingGroupEnd = &Base{"Missing ')'"} + MissingInitFunction = &Base{"Missing init function"} MissingMainFunction = &Base{"Missing main function"} MissingOperand = &Base{"Missing operand"} MissingParameter = &Base{"Missing parameter"} diff --git a/src/scanner/Scan.go b/src/scanner/Scan.go index f745619..4295972 100644 --- a/src/scanner/Scan.go +++ b/src/scanner/Scan.go @@ -20,6 +20,7 @@ func Scan(files []string) (chan *core.Constant, <-chan *fs.File, <-chan *core.Fu } go func() { + scanner.queueDirectory(filepath.Join(config.Library, "core"), "core") scanner.queueDirectory(filepath.Join(config.Library, "mem"), "mem") scanner.queue(files...) scanner.group.Wait()