split redbook into a and b

This commit is contained in:
Zellyn Hunter 2014-06-04 08:35:31 -07:00
parent 255fa86640
commit 48b5b11754
7 changed files with 156 additions and 129 deletions

View File

@ -19,8 +19,9 @@ var flavor string
func init() {
flavorsByName = map[string]flavors.F{
"scma": scma.New(),
"redbook": redbook.New(),
"scma": scma.New(),
"redbooka": redbook.NewRedbookA(),
"redbookb": redbook.NewRedbookB(),
}
var names []string
for name := range flavorsByName {

View File

@ -45,13 +45,14 @@ type Base struct {
Operators map[string]expr.Operator
context.SimpleContext
context.LabelerBase
LabelChars string
LabelColons Requiredness
ExplicitARegister Requiredness
ExtraCommenty func(string) bool
TwoSpacesIsComment bool // two spaces after command means comment field?
StringEndOptional bool // can omit closing delimeter from string args?
SetAsciiVariation func(*inst.I, *lines.Parse)
LabelChars string
LabelColons Requiredness
ExplicitARegister Requiredness
ExtraCommenty func(string) bool
SpacesForComment int // this many spaces after command means it's the comment field
StringEndOptional bool // can omit closing delimeter from string args?
SetAsciiVariation func(*inst.I, *lines.Parse)
CommentChar rune
}
// Parse an entire instruction, or return an appropriate error.
@ -83,7 +84,7 @@ func (a *Base) ParseInstr(line lines.Line) (inst.I, error) {
// Empty line or comment
trimmed := strings.TrimSpace(lp.Rest())
if trimmed == "" || trimmed[0] == '*' || trimmed[0] == ';' {
if trimmed == "" || trimmed[0] == '*' || rune(trimmed[0]) == a.CommentChar {
in.Type = inst.TypeNone
return in, nil
}
@ -253,11 +254,17 @@ func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary
}
// Nothing else on the line? Must be MODE_A
lp.Consume(whitespace)
if !a.TwoSpacesIsComment {
lp.IgnoreRun(whitespace)
lp.AcceptRun(whitespace)
ws := lp.Emit()
atEnd := false
if a.SpacesForComment != 0 && len(ws) >= a.SpacesForComment {
atEnd = true
}
if (a.TwoSpacesIsComment && lp.Consume(whitespace)) || lp.Peek() == lines.Eol || lp.Peek() == ';' {
if lp.Peek() == lines.Eol || lp.Peek() == a.CommentChar {
atEnd = true
}
if atEnd {
// Nothing left on line except comments.
if !summary.AnyModes(opcodes.MODE_A) {
return i, in.Errorf("%s with no arguments", in.Command)

View File

@ -14,42 +14,52 @@ type RedBook struct {
oldschool.Base
}
func New() *RedBook {
a := &RedBook{}
func NewRedbookA() *RedBook {
r := newRedbook()
return r
}
a.LabelChars = oldschool.Letters + oldschool.Digits + "."
a.LabelColons = oldschool.ReqOptional
a.ExplicitARegister = oldschool.ReqRequired
a.StringEndOptional = true
func NewRedbookB() *RedBook {
r := newRedbook()
r.ExplicitARegister = oldschool.ReqRequired
r.SpacesForComment = 3
return r
}
a.Directives = map[string]oldschool.DirectiveInfo{
".IN": {inst.TypeInclude, a.ParseInclude, 0},
"ORG": {inst.TypeOrg, a.ParseAddress, 0},
"OBJ": {inst.TypeNone, nil, 0},
".TF": {inst.TypeNone, nil, 0},
".EN": {inst.TypeEnd, a.ParseNoArgDir, 0},
"EQU": {inst.TypeEqu, a.ParseEquate, 0},
"DFB": {inst.TypeData, a.ParseData, inst.DataBytes},
"DW": {inst.TypeData, a.ParseData, inst.DataWordsLe},
"DDB": {inst.TypeData, a.ParseData, inst.DataWordsBe},
"ASC": {inst.TypeData, a.ParseAscii, inst.DataAscii},
"DCI": {inst.TypeData, a.ParseAscii, inst.DataAsciiFlip},
".BS": {inst.TypeBlock, a.ParseBlockStorage, 0},
".LIST": {inst.TypeNone, nil, 0},
".PG": {inst.TypeNone, nil, 0},
".DO": {inst.TypeIfdef, a.ParseDo, 0},
".ELSE": {inst.TypeIfdefElse, a.ParseNoArgDir, 0},
".FIN": {inst.TypeIfdefEnd, a.ParseNoArgDir, 0},
".MA": {inst.TypeMacroStart, a.ParseMacroStart, 0},
".EM": {inst.TypeMacroEnd, a.ParseNoArgDir, 0},
".US": {inst.TypeNone, a.ParseNotImplemented, 0},
"PAGE": {inst.TypeNone, nil, 0}, // New page
"SBTL": {inst.TypeNone, nil, 0}, // Subtitle
"SKP": {inst.TypeNone, nil, 0}, // Skip lines
"REP": {inst.TypeNone, nil, 0}, // Repeat character
"CHR": {inst.TypeNone, nil, 0}, // Set repeated character
func newRedbook() *RedBook {
r := &RedBook{}
r.LabelChars = oldschool.Letters + oldschool.Digits + "."
r.LabelColons = oldschool.ReqOptional
r.ExplicitARegister = oldschool.ReqRequired
r.StringEndOptional = true
r.CommentChar = ';'
r.Directives = map[string]oldschool.DirectiveInfo{
"ORG": {inst.TypeOrg, r.ParseAddress, 0},
"OBJ": {inst.TypeNone, nil, 0},
"ENDASM": {inst.TypeEnd, r.ParseNoArgDir, 0},
"EQU": {inst.TypeEqu, r.ParseEquate, inst.EquNormal},
"EPZ": {inst.TypeEqu, r.ParseEquate, inst.EquPageZero},
"DFB": {inst.TypeData, r.ParseData, inst.DataBytes},
"DW": {inst.TypeData, r.ParseData, inst.DataWordsLe},
"DDB": {inst.TypeData, r.ParseData, inst.DataWordsBe},
"ASC": {inst.TypeData, r.ParseAscii, inst.DataAscii},
"DCI": {inst.TypeData, r.ParseAscii, inst.DataAsciiFlip},
".DO": {inst.TypeIfdef, r.ParseDo, 0},
".ELSE": {inst.TypeIfdefElse, r.ParseNoArgDir, 0},
".FIN": {inst.TypeIfdefEnd, r.ParseNoArgDir, 0},
".MA": {inst.TypeMacroStart, r.ParseMacroStart, 0},
".EM": {inst.TypeMacroEnd, r.ParseNoArgDir, 0},
".US": {inst.TypeNone, r.ParseNotImplemented, 0},
"PAGE": {inst.TypeNone, nil, 0}, // New page
"TITLE": {inst.TypeNone, nil, 0}, // Title
"SBTL": {inst.TypeNone, nil, 0}, // Subtitle
"SKP": {inst.TypeNone, nil, 0}, // Skip lines
"REP": {inst.TypeNone, nil, 0}, // Repeat character
"CHR": {inst.TypeNone, nil, 0}, // Set repeated character
}
a.Operators = map[string]expr.Operator{
r.Operators = map[string]expr.Operator{
"*": expr.OpMul,
"/": expr.OpDiv,
"+": expr.OpPlus,
@ -59,14 +69,14 @@ func New() *RedBook {
"=": expr.OpEq,
}
a.OnOff = map[string]bool{
r.OnOff = map[string]bool{
"MSB": true, // MSB defaults to true, as per manual
"LST": true, // Display listing: not used
}
a.SetAsciiVariation = func(in *inst.I, lp *lines.Parse) {
r.SetAsciiVariation = func(in *inst.I, lp *lines.Parse) {
if in.Command == "ASC" {
if a.Setting("MSB") {
if r.Setting("MSB") {
in.Var = inst.DataAsciiHi
} else {
in.Var = inst.DataAscii
@ -80,5 +90,5 @@ func New() *RedBook {
}
}
return a
return r
}

View File

@ -23,7 +23,7 @@ func New() *SCMA {
a.LabelChars = oldschool.Letters + oldschool.Digits + ".:"
a.LabelColons = oldschool.ReqDisallowed
a.ExplicitARegister = oldschool.ReqDisallowed
a.TwoSpacesIsComment = true
a.SpacesForComment = 2
a.Directives = map[string]oldschool.DirectiveInfo{
".IN": {inst.TypeInclude, a.ParseInclude, 0},

View File

@ -26,7 +26,8 @@ func TestMultiline(t *testing.T) {
o := lines.NewTestOpener()
ss := asm.NewAssembler(scma.New(), o)
rb := asm.NewAssembler(redbook.New(), o)
ra := asm.NewAssembler(redbook.NewRedbookA(), o)
// rb := asm.NewAssembler(redbook.NewRedbookB(), o)
// aa := asm.NewAssembler(as65.New(), o)
// mm := asm.NewAssembler(merlin.New(), o)
@ -220,7 +221,7 @@ func TestMultiline(t *testing.T) {
}, true},
// Check turning MSB on and off
{rb, "MSB toggle", []string{
{ra, "MSB toggle", []string{
" ASC 'AB'",
" MSB OFF",
" ASC 'AB'",

View File

@ -14,9 +14,10 @@ import (
func TestSimpleCommonFunctions(t *testing.T) {
ss := scma.New()
rb := redbook.New()
aa := as65.New()
mm := merlin.New()
ra := redbook.NewRedbookA()
rb := redbook.NewRedbookB()
// aa := as65.New()
// mm := merlin.New()
tests := []struct {
a flavors.F // assembler flavor
@ -25,95 +26,99 @@ func TestSimpleCommonFunctions(t *testing.T) {
b string // bytes, expected
}{
{ss, "* Comment", "{-}", ""},
{rb, "* Comment", "{-}", ""},
{rb, " ; Comment", "{-}", ""},
{aa, "; Comment", "{-}", ""},
{mm, "* Comment", "{-}", ""},
{ra, "* Comment", "{-}", ""},
{ra, " ; Comment", "{-}", ""},
// {aa, "; Comment", "{-}", ""},
// {mm, "* Comment", "{-}", ""},
{ss, " far-out-comment", "{-}", ""},
{ss, "Label", "{- 'Label'}", ""},
{rb, "Label", "{- 'Label'}", ""},
{rb, "Label:", "{- 'Label'}", ""},
{aa, "Label", "{- 'Label'}", ""},
{mm, "Label", "{- 'Label'}", ""},
{ra, "Label", "{- 'Label'}", ""},
{ra, "Label:", "{- 'Label'}", ""},
// {aa, "Label", "{- 'Label'}", ""},
// {mm, "Label", "{- 'Label'}", ""},
{ss, " .IN FILE.NAME", "{inc 'FILE.NAME'}", ""},
{ss, " .IN S.DEFS", "{inc 'S.DEFS'}", ""},
{aa, ` include "FILE.NAME"`, "{inc 'FILE.NAME'}", ""},
{mm, " PUT !FILE.NAME", "{inc 'FILE.NAME'}", ""},
// {aa, ` include "FILE.NAME"`, "{inc 'FILE.NAME'}", ""},
// {mm, " PUT !FILE.NAME", "{inc 'FILE.NAME'}", ""},
{ss, " .TI 76,Title here", "{-}", ""},
{rb, ` SBTL Title here`, "{-}", ""},
{aa, ` title "Title here"`, "{-}", ""},
{mm, ` TTL "Title here"`, "{-}", ""},
{ra, ` SBTL Title here`, "{-}", ""},
{ra, ` TITLE Title here`, "{-}", ""},
// {aa, ` title "Title here"`, "{-}", ""},
// {mm, ` TTL "Title here"`, "{-}", ""},
{ss, " .TF OUT.BIN", "{-}", ""},
{mm, " DSK OUTFILE", "{-}", ""},
{mm, " SAV OUTFILE", "{-}", ""},
// {mm, " DSK OUTFILE", "{-}", ""},
// {mm, " SAV OUTFILE", "{-}", ""},
{ss, " .OR $D000", "{org $d000}", ""},
{rb, " ORG $D000", "{org $d000}", ""},
{aa, " org $D000", "{org $d000}", ""},
{mm, " ORG $D000", "{org $d000}", ""},
{ra, " ORG $D000", "{org $d000}", ""},
// {aa, " org $D000", "{org $d000}", ""},
// {mm, " ORG $D000", "{org $d000}", ""},
// {ss, " .TA *-1234", "{target (- * $04d2)}", ""},
{ss, " .DA $1234", "{data $1234}", "3412"},
{aa, " dw $1234", "{data/wle $1234}", "3412"},
{mm, " DW $1234", "{data/wle $1234}", "3412"},
// {aa, " dw $1234", "{data/wle $1234}", "3412"},
// {mm, " DW $1234", "{data/wle $1234}", "3412"},
{ss, " .DA/$1234,#$1234,$1234", "{data (msb $1234),(lsb $1234),$1234}", "12343412"},
{rb, " DFB $12", "{data/b $0012}", "12"},
{rb, " DFB $12,$34,$1234", "{data/b $0012,$0034,$1234}", "123434"},
{rb, " DW $12,$34,$1234", "{data/wle $0012,$0034,$1234}", "120034003412"},
{rb, " DDB $12,$34,$1234", "{data/wbe $0012,$0034,$1234}", "001200341234"},
{ra, " DFB $12", "{data/b $0012}", "12"},
{ra, " DFB $12,$34,$1234", "{data/b $0012,$0034,$1234}", "123434"},
{ra, " DW $12,$34,$1234", "{data/wle $0012,$0034,$1234}", "120034003412"},
{ra, " DDB $12,$34,$1234", "{data/wbe $0012,$0034,$1234}", "001200341234"},
{ss, " ROL", "{ROL/a}", "2a"},
{aa, " rol a", "{ROL/a}", "2a"},
{rb, " ROL A", "{ROL/a}", "2a"},
{rb, " ROL A", "{ROL/a}", "2a"}, // two spaces is no big deal
{mm, " ROL", "{ROL/a}", "2a"},
// {aa, " rol a", "{ROL/a}", "2a"},
{ra, " ROL A", "{ROL/a}", "2a"},
{ra, " ROL A", "{ROL/a}", "2a"}, // two spaces is no big deal
// {mm, " ROL", "{ROL/a}", "2a"},
{ss, " ROL Comment after two spaces", "{ROL/a}", "2a"},
{ss, " ROL X", "{ROL/a}", "2a"}, // two spaces = comment
{rb, " ROL", "{ROL/a}", "2a"},
{rb, " ROL Comment after three spaces", "{ROL/a}", "2a"},
{rb, " ROL X", "{ROL/a}", "2a"}, // two spaces = comment
{ss, " ROL $1234", "{ROL/abs $1234}", "2e3412"},
{aa, " rol $1234", "{ROL/abs $1234}", "2e3412"},
{mm, " ROL $1234", "{ROL/abs $1234}", "2e3412"},
// {aa, " rol $1234", "{ROL/abs $1234}", "2e3412"},
// {mm, " ROL $1234", "{ROL/abs $1234}", "2e3412"},
{ss, " ROL $12", "{ROL/zp $0012}", "2612"},
{aa, " rol $12", "{ROL/zp $0012}", "2612"},
{mm, " ROL $12", "{ROL/zp $0012}", "2612"},
// {aa, " rol $12", "{ROL/zp $0012}", "2612"},
// {mm, " ROL $12", "{ROL/zp $0012}", "2612"},
{ss, " LDA #$12", "{LDA/imm (lsb $0012)}", "a912"},
{aa, " lda #$12", "{LDA/imm (lsb $0012)}", "a912"},
{mm, " LDA #$12", "{LDA/imm (lsb $0012)}", "a912"},
// {aa, " lda #$12", "{LDA/imm (lsb $0012)}", "a912"},
// {mm, " LDA #$12", "{LDA/imm (lsb $0012)}", "a912"},
{ss, " JMP $1234", "{JMP/abs $1234}", "4c3412"},
{aa, " jmp $1234", "{JMP/abs $1234}", "4c3412"},
{mm, " JMP $1234", "{JMP/abs $1234}", "4c3412"},
// {aa, " jmp $1234", "{JMP/abs $1234}", "4c3412"},
// {mm, " JMP $1234", "{JMP/abs $1234}", "4c3412"},
{ss, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"},
{aa, " jmp ($1234)", "{JMP/ind $1234}", "6c3412"},
{mm, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"},
// {aa, " jmp ($1234)", "{JMP/ind $1234}", "6c3412"},
// {mm, " JMP ($1234)", "{JMP/ind $1234}", "6c3412"},
{ss, " BEQ $2345", "{BEQ/rel $2345}", "f0fe"},
{aa, " beq $2345", "{BEQ/rel $2345}", "f0fe"},
{mm, " BEQ $2345", "{BEQ/rel $2345}", "f0fe"},
// {aa, " beq $2345", "{BEQ/rel $2345}", "f0fe"},
// {mm, " BEQ $2345", "{BEQ/rel $2345}", "f0fe"},
{ss, " BEQ $2347", "{BEQ/rel $2347}", "f000"},
{aa, " beq $2347", "{BEQ/rel $2347}", "f000"},
{mm, " BEQ $2347", "{BEQ/rel $2347}", "f000"},
// {aa, " beq $2347", "{BEQ/rel $2347}", "f000"},
// {mm, " BEQ $2347", "{BEQ/rel $2347}", "f000"},
{ss, " BEQ $2343", "{BEQ/rel $2343}", "f0fc"},
{aa, " beq $2343", "{BEQ/rel $2343}", "f0fc"},
{mm, " BEQ $2343", "{BEQ/rel $2343}", "f0fc"},
// {aa, " beq $2343", "{BEQ/rel $2343}", "f0fc"},
// {mm, " BEQ $2343", "{BEQ/rel $2343}", "f0fc"},
{ss, " LDA $1234", "{LDA/abs $1234}", "ad3412"},
{aa, " lda $1234", "{LDA/abs $1234}", "ad3412"},
{mm, " LDA $1234", "{LDA/abs $1234}", "ad3412"},
// {aa, " lda $1234", "{LDA/abs $1234}", "ad3412"},
// {mm, " LDA $1234", "{LDA/abs $1234}", "ad3412"},
{ss, " LDA $1234,X", "{LDA/absX $1234}", "bd3412"},
{aa, " lda $1234,x", "{LDA/absX $1234}", "bd3412"},
{mm, " LDA $1234,X", "{LDA/absX $1234}", "bd3412"},
// {aa, " lda $1234,x", "{LDA/absX $1234}", "bd3412"},
// {mm, " LDA $1234,X", "{LDA/absX $1234}", "bd3412"},
{ss, " STA $1234,Y", "{STA/absY $1234}", "993412"},
{aa, " sta $1234,y", "{STA/absY $1234}", "993412"},
{mm, " STA $1234,Y", "{STA/absY $1234}", "993412"},
// {aa, " sta $1234,y", "{STA/absY $1234}", "993412"},
// {mm, " STA $1234,Y", "{STA/absY $1234}", "993412"},
{ss, " LDA $12", "{LDA/zp $0012}", "a512"},
{aa, " lda $12", "{LDA/zp $0012}", "a512"},
{mm, " LDA $12", "{LDA/zp $0012}", "a512"},
// {aa, " lda $12", "{LDA/zp $0012}", "a512"},
// {mm, " LDA $12", "{LDA/zp $0012}", "a512"},
{ss, " LDA $12,X", "{LDA/zpX $0012}", "b512"},
{aa, " lda $12,x", "{LDA/zpX $0012}", "b512"},
{mm, " LDA $12,X", "{LDA/zpX $0012}", "b512"},
// {aa, " lda $12,x", "{LDA/zpX $0012}", "b512"},
// {mm, " LDA $12,X", "{LDA/zpX $0012}", "b512"},
{ss, " LDX $12,Y", "{LDX/zpY $0012}", "b612"},
{aa, " ldx $12,y", "{LDX/zpY $0012}", "b612"},
{mm, " LDX $12,Y", "{LDX/zpY $0012}", "b612"},
// {aa, " ldx $12,y", "{LDX/zpY $0012}", "b612"},
// {mm, " LDX $12,Y", "{LDX/zpY $0012}", "b612"},
{ss, " LDA ($12),Y", "{LDA/indY $0012}", "b112"},
{aa, " lda ($12),y", "{LDA/indY $0012}", "b112"},
{mm, " LDA ($12),Y", "{LDA/indY $0012}", "b112"},
// {aa, " lda ($12),y", "{LDA/indY $0012}", "b112"},
// {mm, " LDA ($12),Y", "{LDA/indY $0012}", "b112"},
{ss, " LDA ($12,X)", "{LDA/indX $0012}", "a112"},
{aa, " lda ($12,x)", "{LDA/indX $0012}", "a112"},
{mm, " LDA ($12,X)", "{LDA/indX $0012}", "a112"},
// {aa, " lda ($12,x)", "{LDA/indX $0012}", "a112"},
// {mm, " LDA ($12,X)", "{LDA/indX $0012}", "a112"},
{ss, ` .AS "ABC"`, "{data/b}", "414243"},
{ss, ` .AT "ABC"`, "{data/b}", "4142c3"},
{ss, ` .AS /ABC/`, "{data/b}", "414243"},
@ -122,11 +127,11 @@ func TestSimpleCommonFunctions(t *testing.T) {
{ss, ` .AT -"ABC"`, "{data/b}", "c1c243"},
{ss, ` .AS -dABCd`, "{data/b}", "c1c2c3"},
{ss, ` .AT -dABCd`, "{data/b}", "c1c243"},
{rb, ` ASC "ABC"`, "{data/b}", "c1c2c3"},
{rb, ` ASC $ABC$ ;comment`, "{data/b}", "c1c2c3"},
{rb, ` ASC $ABC`, "{data/b}", "c1c2c3"},
{rb, ` DCI "ABC"`, "{data/b}", "4142c3"},
{rb, ` ASC -ABC-`, "{data/b}", "c1c2c3"},
{ra, ` ASC "ABC"`, "{data/b}", "c1c2c3"},
{ra, ` ASC $ABC$ ;comment`, "{data/b}", "c1c2c3"},
{ra, ` ASC $ABC`, "{data/b}", "c1c2c3"},
{ra, ` DCI "ABC"`, "{data/b}", "4142c3"},
{ra, ` ASC -ABC-`, "{data/b}", "c1c2c3"},
{ss, " .HS 0001ffAb", "{data/b}", "0001ffab"},
{ss, "A.B .EQ *-C.D", "{= 'A.B' (- * C.D)}", ""},
{ss, " .BS $8", "{block $0008}", "xxxxxxxxxxxxxxxx"},
@ -141,10 +146,10 @@ func TestSimpleCommonFunctions(t *testing.T) {
{ss, " LDX #']+$80", "{LDX/imm (lsb (+ $005d $0080))}", "a2dd"},
{ss, " CMP #';'+1", "{CMP/imm (lsb (+ $003b $0001))}", "c93c"},
{rb, " LST ON", "{set LST ON}", ""},
{rb, " LST OFF", "{set LST OFF}", ""},
{rb, " MSB ON", "{set MSB ON}", ""},
{rb, " MSB OFF", "{set MSB OFF}", ""},
{ra, " LST ON", "{set LST ON}", ""},
{ra, " LST OFF", "{set LST OFF}", ""},
{ra, " MSB ON", "{set MSB ON}", ""},
{ra, " MSB OFF", "{set MSB OFF}", ""},
}
// TODO(zellyn): Add tests for finalization of four SCMA directives:
@ -154,9 +159,6 @@ func TestSimpleCommonFunctions(t *testing.T) {
for i, tt := range tests {
// TODO(zellyn): Test AS65 and Merlin too.
if tt.a != ss && tt.a != rb {
continue
}
// Initialize to a known state for testing.
tt.a.Clear()

View File

@ -48,6 +48,12 @@ const (
DataAsciiHiFlip // Data: from ASCII strings, high bit set, except last char
)
// Variants for "TypeEqu" instructions.
const (
EquNormal = iota
EquPageZero
)
type I struct {
Type Type // Type of instruction
Label string // Text of label part