Initial commit

This commit is contained in:
sloum 2023-12-31 16:28:43 -08:00
commit a71e8032ef
5 changed files with 194 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
bird-asm

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module tildegit.org/sloum/bird-asm
go 1.21.5

44
helpers.go Normal file
View File

@ -0,0 +1,44 @@
package main
import (
"flag"
"fmt"
"os"
)
func fileExists(p string) (bool, error) {
_, err := os.Stat(p)
if err == nil { return true, nil }
if os.IsNotExist(err) { return false, nil }
return false, err
}
func setIn() {
args := flag.Args()
if len(args) == 0 {
fmt.Fprintf(os.Stderr, "no input file\n")
os.Exit(1)
} else if len(args) > 1 {
fmt.Fprintf(os.Stderr, "too many input files (%d), needed 1\n", len(args))
os.Exit(2)
}
in = args[0]
exists, err := fileExists(in)
if err != nil {
fmt.Fprintf(os.Stderr, "could not open file\n\t%s", err.Error())
os.Exit(3)
} else if !exists {
fmt.Fprintf(os.Stderr, "%q does not exist\n", in)
os.Exit(4)
}
}
func setOut(o string) {
if o == "" {
out = "out.rom"
} else {
out = o
}
}

42
main.go Normal file
View File

@ -0,0 +1,42 @@
package main
import (
"flag"
"fmt"
)
var (
version string = "0.01"
in string
out string
longMask byte = 1 << 7
returnMask byte = 1 << 6
verbose bool
dryRun bool
ops = map[string]uint8{
"NOP": 0x00, "SET": 0x01, "GET": 0x02, "SEI": 0x03, "GEI": 0x04,
"PSH": 0x07, "POP": 0x08, "OVR": 0x09, "SWP": 0x0A, "ROT": 0x0B, "DUP": 0x0C, "SSW": 0x0D,
"ADD": 0x0E, "SUB": 0x0F, "MUL": 0x10, "DIV": 0x11, "INC": 0x12, "DEC": 0x13,
"AND": 0x15, "BOR": 0x16, "XOR": 0x17, "SHR": 0x18, "SHL": 0x19,
"JMP": 0x1C, "CAL": 0x1D, "JCD": 0x1E, "RET": 0x1F,
"GCH": 0x23, "GST": 0x24, "PCH": 0x25, "PST": 0x26, "HLT": 0x27, "PHX": 0x28,
"GRT": 0x2A, "LST": 0x2B, "GTE": 0x2C, "LTE": 0x2D, "EQL": 0x2E,
}
)
func main() {
flag.BoolVar(&dryRun, "dry", false, "Does a dry run (doesnot produce output file, but shows errors)")
flag.BoolVar(&verbose, "v", false, "Run in verbose mode")
ver := flag.Bool("version", false, "Print version information and exit")
outFile := flag.String("o", "", "Output file path")
flag.Parse()
if *ver {
fmt.Printf("bird-asm, version %s\n", version)
return
}
setIn()
setOut(*outFile)
}

104
types.go Normal file
View File

@ -0,0 +1,104 @@
package main
import (
"fmt"
"os"
"regexp"
)
type label struct {
ref uint16
count uint16
parent string
isSublabel bool
}
func (l *label) Inc() {
l.count++
}
type prog struct {
labels map[string]label
sublabels map[string]label
macros map[string]string
source string
mp uint16
cp uint16
unknownWords []string
}
func (p *prog) Compile() {
// 1. Strip comments from source file
p.stripComments()
// 2. Expand macros
p.expandMacros()
}
func (p *prog) stripComments() {
if verbose {
fmt.Fprint(os.Stderr, "Stripping comments\n")
}
slc := regexp.MustCompile(`\/\/.*`)
mlc := regexp.MustCompile(`(?s)\/\*.*\*\/`)
p.source = slc.ReplaceAllString(p.source, "")
p.source = mlc.ReplaceAllString(p.source, "")
}
func (p *prog) expandMacros() {
if verbose {
fmt.Fprint(os.Stderr, "+ Expanding macros\n")
}
// Found all macro declarations
re := regexp.MustCompile(`%(\w+)\s+([^;]*)\s+\;`)
macrosFound := re.FindAllStringSubmatch(p.source, -1)
// If there were none, return
if macrosFound == nil {
if verbose {
fmt.Fprint(os.Stderr, "\t└ No macros were found\n")
}
return
}
// Load the macros into our map
for i := range macrosFound {
p.macros[macrosFound[i][1]] = macrosFound[i][2]
}
// Remove the declarations
p.source = re.ReplaceAllString(p.source, "")
var twice bool
Twice:
// Expand the macros in the raw source
for k, v := range p.macros {
reM := regexp.MustCompile(`(?m)(\s|^)(?:`+k+`)(\s|$)`)
p.source = reM.ReplaceAllString(p.source, `${1}`+v+`${2}`)
}
if !twice {
twice = true
goto Twice
}
if verbose {
fmt.Fprintf(os.Stderr, "\t└ %d macros declarations were found and references were expanded\n", len(p.macros))
}
}
/* 1. Strip comments (using regex for dev speed at the moment)
* 2. Do a pass for expanding macros
* 3. Do a pass for finding labels
* 4.
*
* :Label1 (refers to program counter)
* @var1 (var is a pointer to memory)
* +subvar (creates a subvar at current mem pointer)
* $2 (pads the mem pointer to create sizes of vars)
* %macro1 #2c pch .
* Err should be thrown if an attempt to jump tp a var/subvar
* is made.
*/