Add hal module

Add instructions
Add parser
master
Jonas Franz 4 years ago
parent 715c64b6ed
commit 725e443e56
Signed by: JonasFranzDEV
GPG Key ID: 7293A220B7C38080
  1. 55
      cmd/root.go
  2. 18
      go.mod
  3. 7
      hal.go
  4. 72
      hal/instructions.go
  5. 33
      hal/module.go
  6. 47
      parser/program_parser.go

@ -0,0 +1,55 @@
package cmd
import (
"bufio"
"fmt"
"os"
"github.com/spf13/cobra"
"git.jfdev.de/JonasFranzDEV/hal/hal"
"git.jfdev.de/JonasFranzDEV/hal/parser"
)
func Execute() {
if err := rootCommand.Execute(); err != nil {
fmt.Printf("%v\n", err)
os.Exit(1)
}
}
var rootCommand = &cobra.Command{
Args: cobra.ExactArgs(1),
Use: "hal",
RunE: runRootCommand,
}
func init() {
rootCommand.Flags().BoolP("debug", "d", false, "Enable debug mode")
}
func runRootCommand(cmd *cobra.Command, args []string) error {
filename := args[0]
if stats, err := os.Stat(filename); err != nil || stats.IsDir() {
return err
}
file, err := os.Open(filename)
if err != nil {
return err
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var input []string
for scanner.Scan() {
input = append(input, scanner.Text())
}
if err := file.Close(); err != nil {
return err
}
program, err := parser.ParseProgram(input)
if err != nil {
return err
}
hal.NewHALModule(program, 256)
return nil
}

@ -1 +1,17 @@
module "git.jfdev.de/JonasFranzDEV/hal"
module git.jfdev.de/JonasFranzDEV/hal
go 1.14
require (
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/mitchellh/mapstructure v1.3.0 // indirect
github.com/pelletier/go-toml v1.8.0 // indirect
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.0.0
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.7.0 // indirect
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect
gopkg.in/ini.v1 v1.56.0 // indirect
)

@ -0,0 +1,7 @@
package main
import "git.jfdev.de/JonasFranzDEV/hal/cmd"
func main() {
cmd.Execute()
}

@ -0,0 +1,72 @@
package hal
import (
"fmt"
"strings"
)
type ProgrammedInstruction struct {
Instruction *Instruction
Operand int64
}
func (pi *ProgrammedInstruction) Execute(module *Module) error {
if pi.Instruction.ExecuteWithOperand != nil {
pi.Instruction.ExecuteWithOperand(module, pi.Operand)
} else if pi.Instruction.Execute != nil {
pi.Instruction.Execute(module)
} else {
return fmt.Errorf("instruction is not implemented")
}
return nil
}
type Instruction struct {
Name string
ExecuteWithOperand func(module *Module, operand int64)
Execute func(module *Module)
}
func FindInstructionByName(name string) *Instruction {
for _, instruction := range instructions {
if instruction.Name == strings.ToUpper(name) {
return instruction
}
}
return nil
}
var instructions = []*Instruction{
InstructionStart,
InstructionStop,
InstructionIn,
InstructionOut,
}
var InstructionStart = &Instruction{
Name: "START",
Execute: func(module *Module) {
// TODO implement
},
}
var InstructionStop = &Instruction{
Name: "STOP",
Execute: func(module *Module) {
// TODO implement
},
}
var InstructionOut = &Instruction{
Name: "OUT",
Execute: func(module *Module) {
// TODO implement
},
}
var InstructionIn = &Instruction{
Name: "IN",
Execute: func(module *Module) {
// TODO implement
},
}

@ -0,0 +1,33 @@
package hal
import "fmt"
type Program []*ProgrammedInstruction
type Module struct {
Accumulator int64
ProgramStorage Program
Register []int64
}
func (h *Module) ProgramCounter() int64 {
return h.Register[0]
}
func (h *Module) Step() error {
instruction := h.ProgramStorage[h.ProgramCounter()]
if instruction == nil {
return fmt.Errorf("instruction not found for program counter = %d", h.ProgramCounter())
}
return instruction.Execute(h)
}
func NewHALModule(program Program, registerSize uint64) (*Module, error) {
if registerSize <= 10 {
return nil, fmt.Errorf("register size must be greater then 10 [ registerSize = %d ]", registerSize)
}
return &Module{
ProgramStorage: program,
Register: make([]int64, registerSize),
}, nil
}

@ -0,0 +1,47 @@
package parser
import (
"fmt"
"strconv"
"strings"
"git.jfdev.de/JonasFranzDEV/hal/hal"
)
// ParseProgram parses an program by the following specification: LINE_NUMBER INSTRUCTION OPERAND(optional)
func ParseProgram(input []string) (hal.Program, error) {
program := make(hal.Program, len(input))
var err error
for index, line := range input {
program[index], err = parseInstruction(line)
if err != nil {
return nil, fmt.Errorf("error while parsing line %d: %v", index+1, err)
}
}
return program, nil
}
func parseInstruction(input string) (*hal.ProgrammedInstruction, error) {
args := strings.Split(input, " ")
if len(args) != 0 && len(args) != 1 {
return nil, fmt.Errorf("malformated instruction '%s'", input)
}
instruction := hal.FindInstructionByName(args[0])
if instruction == nil {
return nil, fmt.Errorf("unknown instruction '%s'", args[0])
}
programmedInstruction := &hal.ProgrammedInstruction{
Instruction: instruction,
}
if len(args) == 1 {
operand, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return nil, fmt.Errorf("error while parsing operand for instruction '%s': %v", input, err)
}
if instruction.ExecuteWithOperand == nil {
return nil, fmt.Errorf("instruction '%s' has no operand, got operand %d", instruction.Name, operand)
}
programmedInstruction.Operand = operand
}
return programmedInstruction, nil
}
Loading…
Cancel
Save