Added a program init function
This commit is contained in:
parent
00be603b8f
commit
9f125694be
8
lib/core/core_linux.q
Normal file
8
lib/core/core_linux.q
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
init() {
|
||||||
|
main.main()
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
exit() {
|
||||||
|
syscall(60, 0)
|
||||||
|
}
|
8
lib/core/core_mac.q
Normal file
8
lib/core/core_mac.q
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
init() {
|
||||||
|
main.main()
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
exit() {
|
||||||
|
syscall(0x2000001, 0)
|
||||||
|
}
|
20
lib/core/core_windows.q
Normal file
20
lib/core/core_windows.q
Normal 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)
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
constant, isConst := f.Constants[f.Package+"."+leftText+"."+rightText]
|
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)
|
||||||
if isConst {
|
return field.Type, nil
|
||||||
return f.TokenToRegister(constant.Value, register)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New(&errors.UnknownIdentifier{Name: leftText}, f.File, left.Token.Position)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
field := variable.Type.(*types.Pointer).To.(*types.Struct).FieldByName(rightText)
|
constant, isConst := f.Constants[f.Package+"."+leftText+"."+rightText]
|
||||||
f.MemoryRegister(asm.LOAD, asm.Memory{Base: variable.Register, Offset: int8(field.Offset), Length: byte(field.Type.Size())}, register)
|
|
||||||
return field.Type, nil
|
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 {
|
if len(node.Children) == 1 {
|
||||||
|
@ -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"}
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user