umx_compiler

UMX virtual machine "Monkey" interpreter / bytecode compiler
git clone git://bsandro.tech/umx_compiler
Log | Files | Refs | README | LICENSE

commit 28a6cd1eae4f4335475575a2d06b1a81eeb4dd00
parent 5e0c380e9125e7688f5a88539d8f8afce5b9c2c9
Author: bsandro <email@bsandro.tech>
Date:   Tue, 19 Jul 2022 02:45:23 +0300

Added umx_asm module dependency

Diffstat:
Mgo.mod | 2++
Ago.sum | 2++
Mmain.go | 1+
Avendor/bsandro.tech/umx_asm.git/LICENSE | 24++++++++++++++++++++++++
Avendor/bsandro.tech/umx_asm.git/asm/instruction.go | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/bsandro.tech/umx_asm.git/asm/opcode.go | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/bsandro.tech/umx_asm.git/asm/opcode_string.go | 36++++++++++++++++++++++++++++++++++++
Avendor/bsandro.tech/umx_asm.git/asm/register.go | 23+++++++++++++++++++++++
Avendor/modules.txt | 3+++
9 files changed, 274 insertions(+), 0 deletions(-)

diff --git a/go.mod b/go.mod @@ -1,3 +1,5 @@ module umx_compiler +require bsandro.tech/umx_asm.git latest + go 1.18 diff --git a/go.sum b/go.sum @@ -0,0 +1,2 @@ +bsandro.tech/umx_asm.git v0.0.0-20220718233257-a67140298eec h1:Hri+dKd/0nk6tVqzpqY1EQ9q3z6gXQNvC/LQZMhEJ78= +bsandro.tech/umx_asm.git v0.0.0-20220718233257-a67140298eec/go.mod h1:yvskUDnx9Jh8M7coO0hFqYtoV32dD21bRXW01vWk8wQ= diff --git a/main.go b/main.go @@ -5,6 +5,7 @@ import ( "umx_compiler/repl" "os" "os/user" + _ "bsandro.tech/umx_asm.git/asm" ) func main() { diff --git a/vendor/bsandro.tech/umx_asm.git/LICENSE b/vendor/bsandro.tech/umx_asm.git/LICENSE @@ -0,0 +1,24 @@ +BSD 2-Clause License + +Copyright (c) 2022, bsandro. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/bsandro.tech/umx_asm.git/asm/instruction.go b/vendor/bsandro.tech/umx_asm.git/asm/instruction.go @@ -0,0 +1,122 @@ +package asm + +import ( + "bytes" + "fmt" + "log" + "regexp" + "strconv" + "strings" +) + +type Instruction struct { + Opcode Opcode + RegA, RegB, RegC Register + Value uint32 +} + +func NewInstruction(in string) *Instruction { + parsingRe := regexp.MustCompile(`[a-zA-Z0-9']+`) + input := parsingRe.FindAllString(in, -1) + cnt := len(input) + if cnt == 0 { + log.Fatal("invalid input - array cannot be empty") + } + opcode := NewOpcode(strings.ToUpper(input[0])) + instr := Instruction{Opcode: opcode} + errmsg := fmt.Sprintf("invalid number of operands for opcode %s", input[0]) + + switch opcode { + case CMOV, ARRI, ARRA, ADD, MUL, DIV, NOTA: + if cnt != 4 { + log.Fatal(errmsg) + } + instr.RegA = NewRegister(input[1]) + instr.RegB = NewRegister(input[2]) + instr.RegC = NewRegister(input[3]) + case HALT: // no operands + case ALLO, LOAD: + if cnt != 3 { + log.Fatal(errmsg) + } + instr.RegB = NewRegister(input[1]) + instr.RegC = NewRegister(input[2]) + case ABAN, OUTP, INP: + if cnt != 2 { + log.Fatal(errmsg) + } + instr.RegC = NewRegister(input[1]) + case ORTH: + if cnt != 3 { + log.Fatal(errmsg) + } + instr.RegA = NewRegister(input[1]) + instr.Value = parseValue(input[2]) + } + + return &instr +} + +func parseValue(s string) uint32 { + var val uint32 + if strings.ContainsRune(s, '\'') { + s = strings.Trim(s, "'") + if len(s) != 1 { + log.Fatalf("invalid character value '%s'", s) + } + val = uint32(s[0]) + } else { + if v, err := strconv.ParseUint(s, 10, 32); err != nil { + log.Fatal(err) + } else { + val = uint32(v) + } + } + return val +} + +//@todo make some kind of polymorphism for different opcodes +func (i *Instruction) Pack() uint32 { + const valueMask uint32 = 0x1FFFFFF + var ret uint32 = uint32(i.Opcode) << 28 + if i.Opcode == ORTH { + var v uint32 = i.Value & valueMask + var r1 uint32 = uint32(i.RegA) << 25 + ret = ret | r1 | v + } else { + var r1 uint32 = uint32(i.RegA) << 6 + var r2 uint32 = uint32(i.RegB) << 3 + var r3 uint32 = uint32(i.RegC) + ret = ret | r1 | r2 | r3 + } + return ret +} + +func (i *Instruction) String() string { + var buf bytes.Buffer + buf.WriteString(i.Opcode.String()) + buf.WriteString(" ") + + switch i.Opcode { + case CMOV, ARRI, ARRA, ADD, MUL, DIV, NOTA: + dumpRegisters(&buf, i.RegA, i.RegB, i.RegC) + case HALT: + // no operands + case ALLO, LOAD: + dumpRegisters(&buf, i.RegB, i.RegC) + case ABAN, OUTP, INP: + dumpRegisters(&buf, i.RegC) + case ORTH: + dumpRegisters(&buf, i.RegA) + buf.WriteString(strconv.Itoa(int(i.Value))) + } + + return buf.String() +} + +func dumpRegisters(buf *bytes.Buffer, regs ...Register) { + for _, reg := range regs { + buf.WriteString(reg.String()) + buf.WriteString(" ") + } +} diff --git a/vendor/bsandro.tech/umx_asm.git/asm/opcode.go b/vendor/bsandro.tech/umx_asm.git/asm/opcode.go @@ -0,0 +1,61 @@ +package asm + +import ( + "log" +) + +//go:generate go run golang.org/x/tools/cmd/stringer@latest -type=Opcode +type Opcode uint8 + +const ( + CMOV Opcode = iota + ARRI + ARRA + ADD + MUL + DIV + NOTA + HALT + ALLO + ABAN + OUTP + INP + LOAD + ORTH +) + +func NewOpcode(input string) Opcode { + switch { + case input == CMOV.String(): + return CMOV + case input == ARRI.String(): + return ARRI + case input == ARRA.String(): + return ARRA + case input == ADD.String(): + return ADD + case input == MUL.String(): + return MUL + case input == DIV.String(): + return DIV + case input == NOTA.String(): + return NOTA + case input == HALT.String(): + return HALT + case input == ALLO.String(): + return ALLO + case input == ABAN.String(): + return ABAN + case input == OUTP.String(): + return OUTP + case input == INP.String(): + return INP + case input == LOAD.String(): + return LOAD + case input == ORTH.String(): + return ORTH + default: + log.Fatalf("invalid opcode %s", input) + } + return CMOV // thanks Go +} diff --git a/vendor/bsandro.tech/umx_asm.git/asm/opcode_string.go b/vendor/bsandro.tech/umx_asm.git/asm/opcode_string.go @@ -0,0 +1,36 @@ +// Code generated by "stringer -type=Opcode"; DO NOT EDIT. + +package asm + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[CMOV-0] + _ = x[ARRI-1] + _ = x[ARRA-2] + _ = x[ADD-3] + _ = x[MUL-4] + _ = x[DIV-5] + _ = x[NOTA-6] + _ = x[HALT-7] + _ = x[ALLO-8] + _ = x[ABAN-9] + _ = x[OUTP-10] + _ = x[INP-11] + _ = x[LOAD-12] + _ = x[ORTH-13] +} + +const _Opcode_name = "CMOVARRIARRAADDMULDIVNOTAHALTALLOABANOUTPINPLOADORTH" + +var _Opcode_index = [...]uint8{0, 4, 8, 12, 15, 18, 21, 25, 29, 33, 37, 41, 44, 48, 52} + +func (i Opcode) String() string { + if i >= Opcode(len(_Opcode_index)-1) { + return "Opcode(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Opcode_name[_Opcode_index[i]:_Opcode_index[i+1]] +} diff --git a/vendor/bsandro.tech/umx_asm.git/asm/register.go b/vendor/bsandro.tech/umx_asm.git/asm/register.go @@ -0,0 +1,23 @@ +package asm + +import ( + "log" + "strconv" +) + +type Register uint8 + +func (r Register) String() string { + return strconv.Itoa(int(r)) +} + +func NewRegister(input string) Register { + val, err := strconv.ParseUint(input, 10, 8) + if err != nil { + log.Fatal(err) + } + if val >= 8 { // only 8 registers allowed + log.Fatalf("invalid register #%d", val) + } + return Register(uint8(val)) +} diff --git a/vendor/modules.txt b/vendor/modules.txt @@ -0,0 +1,3 @@ +# bsandro.tech/umx_asm.git v0.0.0-20220718233257-a67140298eec +## explicit; go 1.18 +bsandro.tech/umx_asm.git/asm