parent
715c64b6ed
commit
725e443e56
@ -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…
Reference in new issue