Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,17 @@ Build the compiler:

go build .

Use it to compile and link a program:
Then use it to compile and link a program:

./slisp -compile example.lisp

That will create "example.asm", and "example.o", before creating "example". If you prefer to run the commands manually you can do it this way:

./slisp example.lisp > example.s
nasm -f elf64 example.s
ld -o example example.o

Finally execute your program:
Finally you may execute your compiled program:

./example

Expand Down
1 change: 0 additions & 1 deletion compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,6 @@ func (c *Compiler) emitCallable(obj any) error {
for _, cap := range l.Captures {
ev.DefineCapture(cap)
}
fmt.Printf("; lambda %s captures %v\n", l.Name, l.Captures)
}

//
Expand Down
71 changes: 63 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/skx/slisp/compiler"
)

//go:embed stdlib.slisp
var stdlibLisp string

// compile is a helper to compile a program
func compile(prg string) (string, error) {
// generate is a helper to compile a program
func generate(prg string) (string, error) {

// Create a compiler
c := compiler.New(prg)
Expand All @@ -28,16 +31,64 @@ func compile(prg string) (string, error) {
return txt, nil
}

// compile will compile the given program into an object,
// then a binary.
func compile(name string, txt string) {

// Get the basename
nm := filepath.Base(name)

// Remove the .lisp suffix
nm = strings.TrimSuffix(nm, filepath.Ext(nm))

// write the assembly
err := os.WriteFile(nm+".asm", []byte(txt), 0644)
if err != nil {
fmt.Printf("failed to write assembly to %s: %s\n",
nm+".asm", err)
return
}

// nasm
assembleCmd := []string{"nasm", "-f", "elf64", nm + ".asm"}

c := exec.Command(assembleCmd[0], assembleCmd[1:]...)
c.Stdout = os.Stdout
c.Stderr = os.Stderr

err = c.Run()
if err != nil {
fmt.Printf("error running assembler %v: %s\n", assembleCmd, err)
return
}

// link
linkCmd := []string{"ld", "-o", nm, "--gc-sections", "-s", nm + ".o"}

c = exec.Command(linkCmd[0], linkCmd[1:]...)
c.Stdout = os.Stdout
c.Stderr = os.Stderr

err = c.Run()
if err != nil {
fmt.Printf("error running linker %v: %s\n", linkCmd, err)
return
}

}

// main is our entry-point
func main() {

// CLI flags
stdlib := flag.Bool("stdlib", true, "Prepend our Lisp standard library to user-programs")
stdlibFlag := flag.Bool("stdlib", true, "Prepend our Lisp standard library to user-programs.")
compileFlag := flag.Bool("compile", false, "Automatically generate a binary.")
c := flag.Bool("c", false, "Automatically generate a binary.s")
flag.Parse()

// Do we have a file?
if len(flag.Args()) != 1 {
fmt.Println("usage: slisp [-stdlib=false] file.lisp")
fmt.Println("usage: slisp [flags] file.lisp")
os.Exit(1)
}

Expand All @@ -50,16 +101,20 @@ func main() {

// Prepend the stdlib if we should.
prg := string(data)
if *stdlib {
if *stdlibFlag {
prg = stdlibLisp + "\n" + prg
}

txt, err := compile(prg)
txt, err := generate(prg)
if err != nil {
fmt.Printf("error processing: %s\n", err)
return
}

// Print the code to STDOUT
fmt.Print(txt)
if *c || *compileFlag {
compile(flag.Args()[0], txt)
} else {
// Print the code to STDOUT
fmt.Print(txt)
}
}
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

func TestOK(t *testing.T) {

out, err := compile("(defun main() (print 22))")
out, err := generate("(defun main() (print 22))")
if err != nil {
t.Fatalf("unexpected error compiling: %s", err)
}
Expand Down
Loading