Added a program init function

This commit is contained in:
Eduard Urbach 2025-02-16 15:46:54 +01:00
parent 00be603b8f
commit 9f125694be
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
11 changed files with 78 additions and 38 deletions

8
lib/core/core_linux.q Normal file
View File

@ -0,0 +1,8 @@
init() {
main.main()
exit()
}
exit() {
syscall(60, 0)
}

8
lib/core/core_mac.q Normal file
View File

@ -0,0 +1,8 @@
init() {
main.main()
exit()
}
exit() {
syscall(0x2000001, 0)
}

20
lib/core/core_windows.q Normal file
View File

@ -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)
}

View File

@ -1,3 +1,4 @@
import core
import sys import sys
const clone { const clone {
@ -15,7 +16,7 @@ create(func *Any) -> Int {
stack := sys.mmap(0, size, 0x1|0x2, 0x02|0x20|0x100|0x20000) stack := sys.mmap(0, size, 0x1|0x2, 0x02|0x20|0x100|0x20000)
stack += size stack += size
stack -= 8 stack -= 8
store(stack, 8, _exit) store(stack, 8, core.exit)
stack -= 8 stack -= 8
store(stack, 8, func) store(stack, 8, func)
return sys.clone(clone.vm|clone.fs|clone.files|clone.sighand|clone.parent|clone.thread|clone.io, stack) return sys.clone(clone.vm|clone.fs|clone.files|clone.sighand|clone.parent|clone.thread|clone.io, stack)

View File

@ -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` // Check for existence of `main`
main, exists := allFunctions["main.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 return result, errors.MissingMainFunction
} }
result.Init = init
result.Main = main result.Main = main
result.Functions = allFunctions result.Functions = allFunctions
result.finalize() result.finalize()

View File

@ -7,6 +7,7 @@ import (
// Result contains everything we need to write an executable file to disk. // Result contains everything we need to write an executable file to disk.
type Result struct { type Result struct {
Init *core.Function
Main *core.Function Main *core.Function
Functions map[string]*core.Function Functions map[string]*core.Function
Traversed map[*core.Function]bool Traversed map[*core.Function]bool

View File

@ -5,7 +5,6 @@ import (
"git.akyoto.dev/cli/q/src/asmc" "git.akyoto.dev/cli/q/src/asmc"
"git.akyoto.dev/cli/q/src/config" "git.akyoto.dev/cli/q/src/config"
"git.akyoto.dev/cli/q/src/core" "git.akyoto.dev/cli/q/src/core"
"git.akyoto.dev/cli/q/src/dll"
"git.akyoto.dev/cli/q/src/x86" "git.akyoto.dev/cli/q/src/x86"
) )
@ -20,33 +19,11 @@ func (r *Result) finalize() {
Data: make(map[string][]byte, r.DataCount), 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)) r.Traversed = make(map[*core.Function]bool, len(r.Functions))
// This will place the main function immediately after the entry point // This will place the init function immediately after the entry point
// and also add everything the main function calls recursively. // and also add everything the init function calls recursively.
r.eachFunction(r.Main, r.Traversed, func(f *core.Function) { r.eachFunction(r.Init, r.Traversed, func(f *core.Function) {
final.Merge(f.Assembler) final.Merge(f.Assembler)
for _, library := range f.DLLs { for _, library := range f.DLLs {

View File

@ -44,6 +44,11 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error
name = nameNode.Token.Text(f.File.Bytes) 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] fn, exists = f.Functions[pkg+"."+name]
if !exists { if !exists {

View File

@ -1,6 +1,7 @@
package core package core
import ( import (
"fmt"
"math" "math"
"git.akyoto.dev/cli/q/src/asm" "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) rightText := right.Token.Text(f.File.Bytes)
variable := f.VariableByName(leftText) variable := f.VariableByName(leftText)
if variable == nil { 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
}
constant, isConst := f.Constants[f.Package+"."+leftText+"."+rightText] constant, isConst := f.Constants[f.Package+"."+leftText+"."+rightText]
if isConst { if isConst {
return f.TokenToRegister(constant.Value, register) return f.TokenToRegister(constant.Value, register)
} }
return nil, errors.New(&errors.UnknownIdentifier{Name: leftText}, f.File, left.Token.Position) 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
} }
field := variable.Type.(*types.Pointer).To.(*types.Struct).FieldByName(rightText) return nil, errors.New(&errors.UnknownIdentifier{Name: leftText}, f.File, left.Token.Position)
f.MemoryRegister(asm.LOAD, asm.Memory{Base: variable.Register, Offset: int8(field.Offset), Length: byte(field.Type.Size())}, register)
return field.Type, nil
} }
if len(node.Children) == 1 { if len(node.Children) == 1 {

View File

@ -17,6 +17,7 @@ var (
MissingExpression = &Base{"Missing expression"} MissingExpression = &Base{"Missing expression"}
MissingGroupStart = &Base{"Missing '('"} MissingGroupStart = &Base{"Missing '('"}
MissingGroupEnd = &Base{"Missing ')'"} MissingGroupEnd = &Base{"Missing ')'"}
MissingInitFunction = &Base{"Missing init function"}
MissingMainFunction = &Base{"Missing main function"} MissingMainFunction = &Base{"Missing main function"}
MissingOperand = &Base{"Missing operand"} MissingOperand = &Base{"Missing operand"}
MissingParameter = &Base{"Missing parameter"} MissingParameter = &Base{"Missing parameter"}

View File

@ -20,6 +20,7 @@ func Scan(files []string) (chan *core.Constant, <-chan *fs.File, <-chan *core.Fu
} }
go func() { go func() {
scanner.queueDirectory(filepath.Join(config.Library, "core"), "core")
scanner.queueDirectory(filepath.Join(config.Library, "mem"), "mem") scanner.queueDirectory(filepath.Join(config.Library, "mem"), "mem")
scanner.queue(files...) scanner.queue(files...)
scanner.group.Wait() scanner.group.Wait()