Initial commit
This commit is contained in:
commit
a71e8032ef
|
@ -0,0 +1 @@
|
|||
bird-asm
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
}
|
|
@ -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.
|
||||
*/
|
||||
|
||||
|
Loading…
Reference in New Issue