Break fsplc Compiler type into a different file

This commit is contained in:
Sasha Koshka 2024-02-11 01:55:07 -05:00
parent 4895f09f99
commit 2bc5eb1f49
2 changed files with 105 additions and 92 deletions

105
cmd/fsplc/compiler.go Normal file
View File

@ -0,0 +1,105 @@
package main
import "os"
import "fmt"
import "errors"
import "strings"
import "os/exec"
import "path/filepath"
import "git.tebibyte.media/sashakoshka/fspl/llvm"
import "git.tebibyte.media/sashakoshka/fspl/lexer"
import "git.tebibyte.media/sashakoshka/fspl/parser"
import "git.tebibyte.media/sashakoshka/fspl/analyzer"
import "git.tebibyte.media/sashakoshka/fspl/generator/native"
type Compiler struct {
Output string
Optimization int
}
func (this *Compiler) Compile (inputs []string) error {
if len(inputs) == 0 {
return errors.New("no input files specified")
}
var syntaxTree parser.Tree
for _, name := range inputs {
lx, err := lexer.LexFile(name)
if err != nil { return err }
err = syntaxTree.Parse(lx)
if err != nil { return err }
}
var semanticTree analyzer.Tree
err := semanticTree.Analyze(syntaxTree)
if err != nil { return err }
module, err := native.NativeTarget().Generate(semanticTree)
if err != nil {
return errors.New(fmt.Sprintf("internal errror: %v", err))
}
if this.Output == "" {
this.Output = strings.TrimSuffix (
inputs[0],
filepath.Ext(inputs[0])) + ".o"
}
extension := filepath.Ext(this.Output)
switch extension {
case ".s":
return this.CompileModule(module, "asm")
case ".o":
return this.CompileModule(module, "obj")
case ".ll":
file, err := os.Create(this.Output)
if err != nil { return err }
defer file.Close()
_, err = module.WriteTo(file)
return err
default:
return errors.New(fmt.Sprintf (
"unknown output type %s", extension))
}
}
func (this *Compiler) CompileModule (module *llvm.Module, filetype string) error {
var commandName string
var args []string
_, err := exec.LookPath("llc")
if err == nil {
commandName = "llc"
args = []string {
"-",
fmt.Sprintf("-filetype=%s", filetype),
"-o", this.Output,
fmt.Sprintf("-O=%d", this.Optimization),
}
} else {
commandName = "clang"
if filetype != "obj" {
return errors.New("need 'llc' to compile to " + filetype)
}
args = []string {
"-c",
"-x", "ir",
"-o", this.Output,
fmt.Sprintf("-O%d", this.Optimization),
"-",
}
}
command := exec.Command(commandName, args...)
command.Stdout = os.Stdout
command.Stderr = os.Stderr
pipe, err := command.StdinPipe()
if err != nil { return err }
err = command.Start()
if err != nil { return err }
_, err = module.WriteTo(pipe)
if err != nil { return err }
pipe.Close()
return command.Wait()
}

View File

@ -14,11 +14,6 @@ import "git.tebibyte.media/sashakoshka/fspl/analyzer"
import ferrors "git.tebibyte.media/sashakoshka/fspl/errors"
import "git.tebibyte.media/sashakoshka/fspl/generator/native"
type Compiler struct {
Output string
Optimization int
}
func main () {
compiler := new(Compiler)
@ -37,90 +32,3 @@ func main () {
os.Exit(1)
}
}
func (this *Compiler) Compile (inputs []string) error {
if len(inputs) == 0 {
return errors.New("no input files specified")
}
var syntaxTree parser.Tree
for _, name := range inputs {
lx, err := lexer.LexFile(name)
if err != nil { return err }
err = syntaxTree.Parse(lx)
if err != nil { return err }
}
var semanticTree analyzer.Tree
err := semanticTree.Analyze(syntaxTree)
if err != nil { return err }
module, err := native.NativeTarget().Generate(semanticTree)
if err != nil {
return errors.New(fmt.Sprintf("internal errror: %v", err))
}
if this.Output == "" {
this.Output = strings.TrimSuffix (
inputs[0],
filepath.Ext(inputs[0])) + ".o"
}
extension := filepath.Ext(this.Output)
switch extension {
case ".s":
return this.CompileModule(module, "asm")
case ".o":
return this.CompileModule(module, "obj")
case ".ll":
file, err := os.Create(this.Output)
if err != nil { return err }
defer file.Close()
_, err = module.WriteTo(file)
return err
default:
return errors.New(fmt.Sprintf (
"unknown output type %s", extension))
}
}
func (this *Compiler) CompileModule (module *llvm.Module, filetype string) error {
var commandName string
var args []string
_, err := exec.LookPath("llc")
if err == nil {
commandName = "llc"
args = []string {
"-",
fmt.Sprintf("-filetype=%s", filetype),
"-o", this.Output,
fmt.Sprintf("-O=%d", this.Optimization),
}
} else {
commandName = "clang"
if filetype != "obj" {
return errors.New("need 'llc' to compile to " + filetype)
}
args = []string {
"-c",
"-x", "ir",
"-o", this.Output,
fmt.Sprintf("-O%d", this.Optimization),
"-",
}
}
command := exec.Command(commandName, args...)
command.Stdout = os.Stdout
command.Stderr = os.Stderr
pipe, err := command.StdinPipe()
if err != nil { return err }
err = command.Start()
if err != nil { return err }
_, err = module.WriteTo(pipe)
if err != nil { return err }
pipe.Close()
return command.Wait()
}