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