Execute Computer/Zero: Difference between revisions

Add Go
m (RPL: optimized version)
(Add Go)
Line 557:
0 1 : NOP 0 -> 0 2
0 2 : STP 0 -> 0 -1
 
=={{header|Go}}==
<syntaxhighlight lang="go">package main
 
import (
"bufio"
"fmt"
"io"
"regexp"
"strconv"
"strings"
)
 
const (
NOP = iota
LDA
STA
ADD
SUB
BRZ
JMP
STP
)
 
var opcodes = map[string]int{
"NOP": NOP,
"LDA": LDA,
"STA": STA,
"ADD": ADD,
"SUB": SUB,
"BRZ": BRZ,
"JMP": JMP,
"STP": STP,
}
 
var reIns = regexp.MustCompile(
`\s*(?:(\w+):)?\s*` + // label
`(NOP|LDA|STA|ADD|SUB|BRZ|JMP|STP)?\s*` + // opcode
`(\w+)?\s*` + // argument
`(?:;([\w\s]+))?`) // comment
 
type ByteCode [32]int
 
type instruction struct {
Label string
Opcode string
Arg string
}
 
type Program struct {
Instructions []instruction
Labels map[string]int
}
 
func newInstruction(line string) (*instruction, error) {
match := reIns.FindStringSubmatch(line)
if match == nil {
return nil, fmt.Errorf("syntax error: '%s'", line)
}
return &instruction{Label: match[1], Opcode: match[2], Arg: match[3]}, nil
}
 
func Parse(asm io.Reader) (*Program, error) {
var p Program
p.Labels = make(map[string]int, 32)
scanner := bufio.NewScanner(asm)
lineNumber := 0
 
for scanner.Scan() {
if instruction, err := newInstruction(scanner.Text()); err != nil {
return &p, err
} else {
if instruction.Label != "" {
p.Labels[instruction.Label] = lineNumber
}
p.Instructions = append(p.Instructions, *instruction)
lineNumber++
}
}
 
if err := scanner.Err(); err != nil {
return nil, err
}
 
return &p, nil
}
 
func (p *Program) Compile() (ByteCode, error) {
var bytecode ByteCode
var arg int
for i, ins := range p.Instructions {
if ins.Arg == "" {
arg = 0
} else if addr, err := strconv.Atoi(ins.Arg); err == nil {
arg = addr
} else if addr, ok := p.Labels[ins.Arg]; ok {
arg = addr
} else {
return bytecode, fmt.Errorf("unknown label %v", ins.Arg)
}
 
if opcode, ok := opcodes[ins.Opcode]; ok {
bytecode[i] = opcode<<5 | arg
} else {
bytecode[i] = arg
}
}
return bytecode, nil
}
 
func floorMod(a, b int) int {
return ((a % b) + b) % b
}
 
func Run(bytecode ByteCode) (int, error) {
acc := 0
pc := 0
mem := bytecode
 
var op int
var arg int
 
loop:
for pc < 32 {
op = mem[pc] >> 5
arg = mem[pc] & 31
pc++
 
switch op {
case NOP:
continue
case LDA:
acc = mem[arg]
case STA:
mem[arg] = acc
case ADD:
acc = floorMod(acc+mem[arg], 256)
case SUB:
acc = floorMod(acc-mem[arg], 256)
case BRZ:
if acc == 0 {
pc = arg
}
case JMP:
pc = arg
case STP:
break loop
default:
return acc, fmt.Errorf("runtime error: %v %v", op, arg)
}
}
 
return acc, nil
}
 
func Execute(asm string) (int, error) {
program, err := Parse(strings.NewReader(asm))
if err != nil {
return 0, fmt.Errorf("assembly error: %v", err)
}
 
bytecode, err := program.Compile()
if err != nil {
return 0, fmt.Errorf("compilation error: %v", err)
}
 
result, err := Run(bytecode)
if err != nil {
return 0, err
}
 
return result, nil
}
 
func main() {
examples := []string{
`LDA x
ADD y ; accumulator = x + y
STP
x: 2
y: 2`,
`loop: LDA prodt
ADD x
STA prodt
LDA y
SUB one
STA y
BRZ done
JMP loop
done: LDA prodt ; to display it
STP
x: 8
y: 7
prodt: 0
one: 1`,
`loop: LDA n
STA temp
ADD m
STA n
LDA temp
STA m
LDA count
SUB one
BRZ done
STA count
JMP loop
done: LDA n ; to display it
STP
m: 1
n: 1
temp: 0
count: 8 ; valid range: 1-11
one: 1`,
`start: LDA load
ADD car ; head of list
STA ldcar
ADD one
STA ldcdr ; next CONS cell
ldcar: NOP
STA value
ldcdr: NOP
BRZ done ; 0 stands for NIL
STA car
JMP start
done: LDA value ; CAR of last CONS
STP
load: LDA 0
value: 0
car: 28
one: 1
; order of CONS cells
; in memory
; does not matter
6
0 ; 0 stands for NIL
2 ; (CADR ls)
26 ; (CDDR ls) -- etc.
5
20
3
30
1 ; value of (CAR ls)
22 ; points to (CDR ls)
4
24`,
`LDA 3
SUB 4
STP 0
0
255`,
`LDA 3
SUB 4
STP 0
0
1`,
`LDA 3
ADD 4
STP 0
1
255`,
}
 
for _, asm := range examples {
if result, err := Execute(asm); err == nil {
fmt.Println(result)
} else {
fmt.Println(err)
}
}
}
</syntaxhighlight>
 
{{out}}
<pre>
4
56
55
6
1
255
0
</pre>
 
=={{header|J}}==
140

edits