go-first

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

first.go (5163B)


      1 package main
      2 
      3 import (
      4 	"fmt"
      5 	"bufio"
      6 	"os"
      7 	"io"
      8 	"strconv"
      9 	"strings"
     10 )
     11 
     12 const (
     13 	rsp int = 1
     14 	dep int = 0
     15 	
     16 	rstacksize  = 512
     17 	rstackstart = 32
     18 )
     19 
     20 var laswor string
     21 
     22 type Mem struct {
     23 	data []int
     24 }
     25 
     26 func NewMem() *Mem {
     27 	var mem = new(Mem)
     28 	mem.data = make([]int, 0)
     29 	return mem
     30 }
     31 
     32 func (m *Mem) Fetch(addr int) (int, error) {
     33 	if (addr >= len(m.data)) || (addr < 0) {
     34 		return 0, fmt.Errorf("memfetch: addr %d out of bonds", addr)
     35 	}
     36 	return m.data[addr], nil
     37 }
     38 
     39 func (m *Mem) Store(addr, val int) {
     40 	if addr >= len(m.data) {
     41 		buf := make([]int, addr - len(m.data) + 1)
     42 		m.data = append(m.data, buf...)
     43 	}
     44 	m.data[addr] = val
     45 }
     46 
     47 type Stack struct {
     48 	data []int
     49 }
     50 
     51 func NewStack() *Stack {
     52 	stack := new(Stack)
     53 	stack.data = make([]int, 1)
     54 	return stack
     55 }
     56 
     57 func (s *Stack) Push(val int) {
     58 	s.data = append(s.data, val)
     59 }
     60 
     61 func (s *Stack) Pop() (int, error) {
     62 	if s.data == nil {
     63 		return 0, fmt.Errorf("stack is empty")
     64 	}
     65 	x := s.data[len(s.data) - 1]
     66 	s.data = s.data[:len(s.data) - 1]
     67 	return x, nil
     68 }
     69 
     70 func (s *Stack) TOS() *int {
     71 	return &s.data[len(s.data) - 1]
     72 }
     73 
     74 type First struct {
     75 	stack *Stack
     76 	mem *Mem
     77 	strings []string
     78 	pc, lwp int
     79 	run bool
     80 	in *bufio.Reader
     81 }
     82 
     83 func NewFirst() (*First, error) {
     84 	const builtins string = ": immediate _read @ ! - * / <0 exit echo key _pick"
     85 	first := new(First)
     86 	*first = First{
     87 		NewStack(),
     88 		NewMem(),
     89 		make([]string, 0),
     90 		0, 0,
     91 		true,
     92 		nil,
     93 	}
     94 	first.mem.Store(dep, rstackstart + rstacksize)
     95 	first.mem.Store(rsp, rstackstart)
     96 	first.in = bufio.NewReader(strings.NewReader(builtins))
     97 
     98 	first.define(3)
     99 	first.define(4)
    100 	first.define(1)
    101 	loopword := first.mem.data[dep]
    102 	first.Compile(5, 2)
    103 	first.pc = first.mem.data[dep]
    104 	first.Compile(loopword, first.pc - 1)
    105 	for i := 6; i < 16; i++ {
    106 		first.define(1)
    107 		first.Compile(i)
    108 	}
    109 	return first, nil
    110 }
    111 
    112 func (F *First) findWord(s string) int {
    113 	var err error
    114 	for wp := F.lwp; wp != 0; wp, err = F.mem.Fetch(wp) {
    115 		if err != nil {
    116 			return 0
    117 		}
    118 		id, err := F.mem.Fetch(wp + 1)
    119 		if err != nil {
    120 			return 0
    121 		}
    122 		if F.strings[id] == s {
    123 			return wp
    124 		}
    125 	}
    126 	return 0
    127 }
    128 
    129 func (F *First) rpush(val int) (error) {
    130 	if F.mem.data[rsp] >= rstacksize + rstackstart {
    131 		return fmt.Errorf("rstack is full")
    132 	}
    133 	F.mem.data[rsp]++
    134 	F.mem.Store(F.mem.data[rsp], val)
    135 	return nil
    136 }
    137 
    138 func (F *First) rpop() (int, error) {
    139 	if F.mem.data[rsp] <= rstackstart {
    140 		return 0, fmt.Errorf("rstack is empty")
    141 	}
    142 	x, err := F.mem.Fetch(F.mem.data[rsp])
    143 	F.mem.data[rsp]--
    144 	return x, err
    145 }
    146 
    147 func (F *First) Compile(vals ...int) {
    148 	for _, val := range vals {
    149 		F.mem.Store(F.mem.data[dep], val)
    150 		F.mem.data[dep]++
    151 	}
    152 }
    153 
    154 func (F *First) define(code int) error {
    155 	var s string
    156 	F.Compile(F.lwp)
    157 	F.lwp = F.mem.data[dep] - 1
    158 	F.Compile(len(F.strings), code)
    159 	if _, err := fmt.Fscan(F.in, &s); err != nil {
    160 		return err
    161 	}
    162 	F.strings = append(F.strings, s)
    163 	return nil
    164 }
    165 
    166 func (F *First) _read() error {
    167 	var (
    168 		s string
    169 		num, wp int
    170 		err error
    171 	)
    172 	if _, err = fmt.Fscan(F.in, &s); err != nil {
    173 		return err
    174 	}
    175 	wp = F.findWord(s)
    176 	if wp != 0 {
    177 		return F.Step(wp + 2)
    178 	}
    179 	if num, err = strconv.Atoi(s); err != nil {
    180 		return err
    181 	}
    182 	F.Compile(2, num)
    183 	return nil
    184 }
    185 
    186 func (F *First) Run(input *bufio.Reader) error {
    187 	F.in = input
    188 	var (
    189 		addr int
    190 		err error
    191 	)
    192 	for err == nil {
    193 		addr, err = F.mem.Fetch(F.pc)
    194 		F.pc++
    195 		if err != nil {
    196 			break
    197 		}
    198 		err = F.Step(addr)
    199 	} 
    200 	if err == io.EOF {
    201 		return nil
    202 	}
    203 	return err
    204 }
    205 
    206 func (F *First) Step(addr int) error {
    207 	var x, y int
    208 	inst, err := F.mem.Fetch(addr)
    209 	addr++
    210 	switch inst {
    211 	case 0: // internal builtin "pushint"
    212 		x, err = F.mem.Fetch(F.pc)
    213 		F.pc++
    214 		F.stack.Push(x)
    215 	case 1: // compile
    216 		F.Compile(addr)
    217 	case 2: // run
    218 		F.rpush(F.pc)
    219 		F.pc = addr
    220 	case 3: // builtin "define", ":"
    221 		err = F.define(1)
    222 		F.Compile(2)
    223 	case 4: // builtin "immediate"
    224 		F.mem.data[dep] -= 2
    225 		F.Compile(2)
    226 	case 5: // builtin "_read"
    227 		err = F._read()
    228 	case 6: // builtin "fetch", "@"
    229 		x, err = F.stack.Pop()
    230 		y, err = F.mem.Fetch(x)
    231 		F.stack.Push(y)
    232 	case 7: // builtin "store", "!"
    233 		x, err = F.stack.Pop()
    234 		y, err = F.stack.Pop()
    235 		F.mem.Store(x, y)
    236 	case 8: // builtin "minus", "-"
    237 		x, err = F.stack.Pop()
    238 		y, err = F.stack.Pop()
    239 		F.stack.Push(y - x)
    240 	case 9: // builtin "mulitply", "*"
    241 		x, err = F.stack.Pop()
    242 		y, err = F.stack.Pop()
    243 		F.stack.Push(y * x)
    244 	case 10: // builtin "divide", "/"
    245 		x, err = F.stack.Pop()
    246 		y, err = F.stack.Pop()
    247 		F.stack.Push(y / x)
    248 	case 11: // builtin "less than 0", "<0"
    249 		x, err = F.stack.Pop()
    250 		if (x < 0) {
    251 			F.stack.Push(1)
    252 		} else {
    253 			F.stack.Push(0)
    254 		}
    255 	case 12: // builtin "exit"
    256 		F.pc, err = F.rpop()
    257 	case 13: // builtin "echo"
    258 		x, err = F.stack.Pop()
    259 		if err == nil {
    260 			fmt.Printf("%c", x)
    261 		}
    262 	case 14: // builtin "key"
    263 		var r rune
    264 		r, _, err = F.in.ReadRune()
    265 		F.stack.Push(int(r))
    266 	case 15: // builtin "_pick"
    267 		x, err = F.stack.Pop()
    268 		y = F.stack.data[len(F.stack.data) - x - 1]
    269 		F.stack.Push(y)
    270 	default:
    271 		err = fmt.Errorf("unexpected instruction %d", inst)
    272 	}
    273 	return err
    274 }
    275 
    276 func main() {
    277 	first, err := NewFirst()
    278 	if err != nil {
    279 		fmt.Println(err)
    280 	} else if err = first.Run(bufio.NewReader(os.Stdin));
    281 	  err != nil {
    282 		fmt.Println(err)
    283 	}
    284 }