diff --git a/builtins.go b/builtins.go index ab36b91..a4706f2 100644 --- a/builtins.go +++ b/builtins.go @@ -442,7 +442,7 @@ func (b *Builtins) Words(out io.Writer, d Dictionary) func(string) error { } // Flags outputs a list of all flags -func (b *Builtins) Flags(out io.Writer, c Context) func(string) error { +func (b *Builtins) Flags(out io.Writer, c *Context) func(string) error { if out == nil { out = os.Stdout } diff --git a/eval.go b/eval.go index 1bc8db6..147355d 100644 --- a/eval.go +++ b/eval.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "io" "strconv" "strings" ) @@ -16,6 +17,7 @@ type Context struct { Words []string Memory Memory StringBuffer string + Output io.Writer } // Eval evaulates a given line, recursively descending into given words as needed diff --git a/main.go b/main.go index 6d76a0f..f81afd0 100644 --- a/main.go +++ b/main.go @@ -3,12 +3,30 @@ package main import ( "bufio" "errors" + "flag" "fmt" "os" "strings" ) +type libraryFiles []string + +func (l *libraryFiles) String() string { + return strings.Join(*l, ", ") +} + +func (l *libraryFiles) Set(value string) error { + *l = append(*l, strings.TrimSpace(value)) + return nil +} + func main() { + // flag setup + var libs libraryFiles + flag.Var(&libs, "l", "propser library file (may be repeated)") + flag.Parse() + + // create main context stack := Stack{values: []int{}} rstack := Stack{values: []int{}} ifstack := Stack{values: []int{}} @@ -29,88 +47,22 @@ func main() { nextFree: 1, }, StringBuffer: "", + Output: os.Stdout, } - b := &Builtins{} - // word definitions - dict.AddWord(":", Word{Name: ":", Impl: b.Colon(&c)}) - dict.AddWord(";", Word{Name: ";", Impl: b.Semicolon(&c), Immediate: true}) - // comments and strings - dict.AddWord("(", Word{Name: "(", Impl: b.OpenComment(&c), Immediate: true}) - dict.AddWord(")", Word{Name: ")", Impl: b.CloseComment(&c), Immediate: true}) - dict.AddWord(`\`, Word{Name: `\`, Impl: b.EOLComment(&c), Immediate: true}) - dict.AddWord(`."`, Word{Name: `."`, Impl: b.OpenQuote(os.Stdout, &c, '"')}) - dict.AddWord(`"`, Word{Name: `"`, Impl: b.CloseQuote(&c)}) - dict.AddWord(`.(`, Word{Name: `.(`, Impl: b.OpenQuote(os.Stdout, &c, ')'), Immediate: true}) - dict.AddWord(`S"`, Word{Name: `S"`, Impl: b.StringBuffer(&c, '"')}) - dict.AddWord("LOAD", Word{Name: "LOAD", Impl: b.Load(&c)}) - // math - dict.AddWord("+", Word{Name: "+", Impl: b.Add(&stack)}) - dict.AddWord("-", Word{Name: "-", Impl: b.Sub(&stack)}) - dict.AddWord("*", Word{Name: "*", Impl: b.Mul(&stack)}) - dict.AddWord("/", Word{Name: "/", Impl: b.Div(&stack)}) - dict.AddWord("MOD", Word{Name: "MOD", Impl: b.Mod(&stack)}) - dict.AddWord("/MOD", Word{Name: "/MOD", Source: []string{"2DUP", "MOD", "ROT", "ROT", "/"}}) - dict.AddWord("1+", Word{Name: "1+", Source: []string{"1", "+"}}) - dict.AddWord("1-", Word{Name: "1-", Source: []string{"1", "-"}}) - dict.AddWord("ABS", Word{Name: "ABS", Source: []string{"DUP", "0<", "IF", "NEGATE", "THEN"}}) - dict.AddWord("NEGATE", Word{Name: "NEGATE", Source: []string{"-1", "*"}}) - dict.AddWord("MAX", Word{Name: "MAX", Source: []string{"2DUP", "<", "IF", "SWAP", "THEN", "DROP"}}) - dict.AddWord("MIN", Word{Name: "MIN", Source: []string{"2DUP", ">", "IF", "SWAP", "THEN", "DROP"}}) - // output - dict.AddWord(".", Word{Name: ".", Impl: b.Print(os.Stdout, &stack)}) - dict.AddWord("EMIT", Word{Name: "EMIT", Impl: b.Emit(os.Stdout, &stack)}) - dict.AddWord("CR", Word{Name: "CR", Source: []string{"10", "EMIT"}}) // emit a newline - // logic - dict.AddWord("=", Word{Name: "=", Impl: b.Eq(&stack)}) - dict.AddWord("0=", Word{Name: "0=", Source: []string{"0", "="}}) - dict.AddWord("<>", Word{Name: "<>", Impl: b.NEq(&stack)}) - dict.AddWord("0<>", Word{Name: "0<>", Source: []string{"0=", "0="}}) - dict.AddWord(">", Word{Name: ">", Impl: b.Gt(&stack)}) - dict.AddWord("<", Word{Name: "<", Impl: b.Lt(&stack)}) - dict.AddWord(">=", Word{Name: ">=", Impl: b.GtEq(&stack)}) - dict.AddWord("<=", Word{Name: "<=", Impl: b.LtEq(&stack)}) - dict.AddWord("0<", Word{Name: "0<", Source: []string{"0", "<"}}) - dict.AddWord("0>", Word{Name: "0>", Source: []string{"0", ">"}}) - // stack manipulation - dict.AddWord("DUP", Word{Name: "DUP", Impl: b.Dup(&stack)}) - dict.AddWord("?DUP", Word{Name: "?DUP", Source: []string{"DUP", "0<>", "IF", "DUP", "THEN"}}) - dict.AddWord("SWAP", Word{Name: "SWAP", Impl: b.Swap(&stack)}) - dict.AddWord("OVER", Word{Name: "OVER", Impl: b.Over(&stack)}) - dict.AddWord("DROP", Word{Name: "DROP", Impl: b.Drop(&stack)}) - dict.AddWord("ROT", Word{Name: "ROT", Impl: b.Rot(&stack)}) - dict.AddWord("PICK", Word{Name: "PICK", Impl: b.Pick(&stack)}) - dict.AddWord("NIP", Word{Name: "NIP", Source: []string{"SWAP", "DROP"}}) - dict.AddWord("TUCK", Word{Name: "TUCK", Source: []string{"SWAP", "OVER"}}) - // paired stack manipulation - dict.AddWord("2DROP", Word{Name: "2DROP", Source: []string{"DROP", "DROP"}}) - dict.AddWord("2DUP", Word{Name: "2DUP", Source: []string{"OVER", "OVER"}}) - dict.AddWord("2OVER", Word{Name: "2OVER", Source: []string{"3", "PICK", "3", "PICK"}}) - // memory access with variables and constants - dict.AddWord("VARIABLE", Word{Name: "VARIABLE", Impl: b.Variable(&c)}) - dict.AddWord("CONSTANT", Word{Name: "CONSTANT", Impl: b.Constant(&c)}) - dict.AddWord("!", Word{Name: "!", Impl: b.Store(&c)}) - dict.AddWord("@", Word{Name: "@", Impl: b.Fetch(&c)}) - // debugging - dict.AddWord("WORDS", Word{Name: "WORDS", Impl: b.Words(os.Stdout, dict)}) - dict.AddWord("SEE", Word{Name: "SEE", Impl: b.See(os.Stdout, &rstack, dict)}) - dict.AddWord("FLAGS", Word{Name: "FLAGS", Impl: b.Flags(os.Stdout, c)}) - dict.AddWord(".S", Word{Name: ".S", Impl: b.Debug(os.Stdout, &stack)}) - dict.AddWord(".R", Word{Name: ".R", Impl: b.Debug(os.Stdout, &rstack)}) - dict.AddWord(".I", Word{Name: ".I", Impl: b.Debug(os.Stdout, &ifstack)}) - dict.AddWord("DEPTH", Word{Name: "DEPTH", Impl: b.Depth(&stack)}) - dict.AddWord("R>", Word{Name: "R>", Impl: b.RFrom(&stack, &rstack)}) - dict.AddWord(">R", Word{Name: ">R", Impl: b.ToR(&stack, &rstack)}) - dict.AddWord("R@", Word{Name: "R@", Impl: b.RFetch(&stack, &rstack)}) - // branching - dict.AddWord("IF", Word{Name: "IF", Impl: b.If(&stack, &ifstack), BranchCheck: true}) - dict.AddWord("ELSE", Word{Name: "ELSE", Impl: b.Else(&ifstack), BranchCheck: true}) - dict.AddWord("THEN", Word{Name: "THEN", Impl: b.Then(&ifstack), BranchCheck: true}) - dict.AddWord("DO", Word{Name: "DO", Impl: b.Do(&stack, &rstack)}) - dict.AddWord("LOOP", Word{Name: "LOOP", Impl: b.Loop(&stack, &rstack)}) - dict.AddWord("I", Word{Name: "I", Impl: b.I(&stack, &rstack)}) - // exit - dict.AddWord("BYE", Word{Name: "BYE", Impl: b.Quit()}) + defineBuiltIns(&c) + + // load libraries + for l := range libs { + w, _ := c.Dictionary.GetWord("LOAD") + c.StringBuffer = libs[l] + err := w.Impl("") + if err != nil { + fmt.Fprintf(c.Output, "error in library %s: %v\n", libs[l], err) + } else { + fmt.Fprintf(c.Output, "loaded %s\n", libs[l]) + } + } reader := bufio.NewReader(os.Stdin) fmt.Print("prosper\n") @@ -140,3 +92,86 @@ func main() { } } } + +func defineBuiltIns(c *Context) { + b := &Builtins{} + // word definitions + c.Dictionary.AddWord(":", Word{Name: ":", Impl: b.Colon(c)}) + c.Dictionary.AddWord(";", Word{Name: ";", Impl: b.Semicolon(c), Immediate: true}) + // comments and strings + c.Dictionary.AddWord("(", Word{Name: "(", Impl: b.OpenComment(c), Immediate: true}) + c.Dictionary.AddWord(")", Word{Name: ")", Impl: b.CloseComment(c), Immediate: true}) + c.Dictionary.AddWord(`\`, Word{Name: `\`, Impl: b.EOLComment(c), Immediate: true}) + c.Dictionary.AddWord(`."`, Word{Name: `."`, Impl: b.OpenQuote(c.Output, c, '"')}) + c.Dictionary.AddWord(`"`, Word{Name: `"`, Impl: b.CloseQuote(c)}) + c.Dictionary.AddWord(`.(`, Word{Name: `.(`, Impl: b.OpenQuote(c.Output, c, ')'), Immediate: true}) + c.Dictionary.AddWord(`S"`, Word{Name: `S"`, Impl: b.StringBuffer(c, '"')}) + c.Dictionary.AddWord("LOAD", Word{Name: "LOAD", Impl: b.Load(c)}) + // math + c.Dictionary.AddWord("+", Word{Name: "+", Impl: b.Add(c.Stack)}) + c.Dictionary.AddWord("-", Word{Name: "-", Impl: b.Sub(c.Stack)}) + c.Dictionary.AddWord("*", Word{Name: "*", Impl: b.Mul(c.Stack)}) + c.Dictionary.AddWord("/", Word{Name: "/", Impl: b.Div(c.Stack)}) + c.Dictionary.AddWord("MOD", Word{Name: "MOD", Impl: b.Mod(c.Stack)}) + c.Dictionary.AddWord("/MOD", Word{Name: "/MOD", Source: []string{"2DUP", "MOD", "ROT", "ROT", "/"}}) + c.Dictionary.AddWord("1+", Word{Name: "1+", Source: []string{"1", "+"}}) + c.Dictionary.AddWord("1-", Word{Name: "1-", Source: []string{"1", "-"}}) + c.Dictionary.AddWord("ABS", Word{Name: "ABS", Source: []string{"DUP", "0<", "IF", "NEGATE", "THEN"}}) + c.Dictionary.AddWord("NEGATE", Word{Name: "NEGATE", Source: []string{"-1", "*"}}) + c.Dictionary.AddWord("MAX", Word{Name: "MAX", Source: []string{"2DUP", "<", "IF", "SWAP", "THEN", "DROP"}}) + c.Dictionary.AddWord("MIN", Word{Name: "MIN", Source: []string{"2DUP", ">", "IF", "SWAP", "THEN", "DROP"}}) + // output + c.Dictionary.AddWord(".", Word{Name: ".", Impl: b.Print(c.Output, c.Stack)}) + c.Dictionary.AddWord("EMIT", Word{Name: "EMIT", Impl: b.Emit(c.Output, c.Stack)}) + c.Dictionary.AddWord("CR", Word{Name: "CR", Source: []string{"10", "EMIT"}}) // emit a newline + // logic + c.Dictionary.AddWord("=", Word{Name: "=", Impl: b.Eq(c.Stack)}) + c.Dictionary.AddWord("0=", Word{Name: "0=", Source: []string{"0", "="}}) + c.Dictionary.AddWord("<>", Word{Name: "<>", Impl: b.NEq(c.Stack)}) + c.Dictionary.AddWord("0<>", Word{Name: "0<>", Source: []string{"0=", "0="}}) + c.Dictionary.AddWord(">", Word{Name: ">", Impl: b.Gt(c.Stack)}) + c.Dictionary.AddWord("<", Word{Name: "<", Impl: b.Lt(c.Stack)}) + c.Dictionary.AddWord(">=", Word{Name: ">=", Impl: b.GtEq(c.Stack)}) + c.Dictionary.AddWord("<=", Word{Name: "<=", Impl: b.LtEq(c.Stack)}) + c.Dictionary.AddWord("0<", Word{Name: "0<", Source: []string{"0", "<"}}) + c.Dictionary.AddWord("0>", Word{Name: "0>", Source: []string{"0", ">"}}) + // stack manipulation + c.Dictionary.AddWord("DUP", Word{Name: "DUP", Impl: b.Dup(c.Stack)}) + c.Dictionary.AddWord("?DUP", Word{Name: "?DUP", Source: []string{"DUP", "0<>", "IF", "DUP", "THEN"}}) + c.Dictionary.AddWord("SWAP", Word{Name: "SWAP", Impl: b.Swap(c.Stack)}) + c.Dictionary.AddWord("OVER", Word{Name: "OVER", Impl: b.Over(c.Stack)}) + c.Dictionary.AddWord("DROP", Word{Name: "DROP", Impl: b.Drop(c.Stack)}) + c.Dictionary.AddWord("ROT", Word{Name: "ROT", Impl: b.Rot(c.Stack)}) + c.Dictionary.AddWord("PICK", Word{Name: "PICK", Impl: b.Pick(c.Stack)}) + c.Dictionary.AddWord("NIP", Word{Name: "NIP", Source: []string{"SWAP", "DROP"}}) + c.Dictionary.AddWord("TUCK", Word{Name: "TUCK", Source: []string{"SWAP", "OVER"}}) + // paired stack manipulation + c.Dictionary.AddWord("2DROP", Word{Name: "2DROP", Source: []string{"DROP", "DROP"}}) + c.Dictionary.AddWord("2DUP", Word{Name: "2DUP", Source: []string{"OVER", "OVER"}}) + c.Dictionary.AddWord("2OVER", Word{Name: "2OVER", Source: []string{"3", "PICK", "3", "PICK"}}) + // memory access with variables and constants + c.Dictionary.AddWord("VARIABLE", Word{Name: "VARIABLE", Impl: b.Variable(c)}) + c.Dictionary.AddWord("CONSTANT", Word{Name: "CONSTANT", Impl: b.Constant(c)}) + c.Dictionary.AddWord("!", Word{Name: "!", Impl: b.Store(c)}) + c.Dictionary.AddWord("@", Word{Name: "@", Impl: b.Fetch(c)}) + // debugging + c.Dictionary.AddWord("WORDS", Word{Name: "WORDS", Impl: b.Words(c.Output, c.Dictionary)}) + c.Dictionary.AddWord("SEE", Word{Name: "SEE", Impl: b.See(c.Output, c.RStack, c.Dictionary)}) + c.Dictionary.AddWord("FLAGS", Word{Name: "FLAGS", Impl: b.Flags(c.Output, c)}) + c.Dictionary.AddWord(".S", Word{Name: ".S", Impl: b.Debug(c.Output, c.Stack)}) + c.Dictionary.AddWord(".R", Word{Name: ".R", Impl: b.Debug(c.Output, c.RStack)}) + c.Dictionary.AddWord(".I", Word{Name: ".I", Impl: b.Debug(c.Output, c.IfStack)}) + c.Dictionary.AddWord("DEPTH", Word{Name: "DEPTH", Impl: b.Depth(c.Stack)}) + c.Dictionary.AddWord("R>", Word{Name: "R>", Impl: b.RFrom(c.Stack, c.RStack)}) + c.Dictionary.AddWord(">R", Word{Name: ">R", Impl: b.ToR(c.Stack, c.RStack)}) + c.Dictionary.AddWord("R@", Word{Name: "R@", Impl: b.RFetch(c.Stack, c.RStack)}) + // branching + c.Dictionary.AddWord("IF", Word{Name: "IF", Impl: b.If(c.Stack, c.IfStack), BranchCheck: true}) + c.Dictionary.AddWord("ELSE", Word{Name: "ELSE", Impl: b.Else(c.IfStack), BranchCheck: true}) + c.Dictionary.AddWord("THEN", Word{Name: "THEN", Impl: b.Then(c.IfStack), BranchCheck: true}) + c.Dictionary.AddWord("DO", Word{Name: "DO", Impl: b.Do(c.Stack, c.RStack)}) + c.Dictionary.AddWord("LOOP", Word{Name: "LOOP", Impl: b.Loop(c.Stack, c.RStack)}) + c.Dictionary.AddWord("I", Word{Name: "I", Impl: b.I(c.Stack, c.RStack)}) + // exit + c.Dictionary.AddWord("BYE", Word{Name: "BYE", Impl: b.Quit()}) +}