merlin: simple tests passing, only macros remain

This commit is contained in:
Zellyn Hunter 2014-06-19 08:24:54 -07:00
parent a31ee8b1d1
commit 65c391cc46
4 changed files with 52 additions and 15 deletions

View File

@ -10,7 +10,7 @@ import (
// DecodeOp contains the common code that decodes an Opcode, once we
// have fully parsed it.
func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect bool, xy rune) (inst.I, error) {
func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect bool, xy rune, forceWide bool) (inst.I, error) {
i := inst.I{}
ex := in.Exprs[0]
@ -20,7 +20,10 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
case 'x':
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT_X)
if !ok {
return i, fmt.Errorf("%s doesn't support indexed indirect (addr,X) mode", in.Command)
return i, in.Errorf("%s doesn't support indexed indirect (addr,X) mode", in.Command)
}
if forceWide {
return i, in.Errorf("%s (addr,X) doesn't have a wide variant", in.Command)
}
in.Op = op.Byte
in.WidthKnown = true
@ -31,7 +34,10 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
case 'y':
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT_Y)
if !ok {
return i, fmt.Errorf("%s doesn't support indirect indexed (addr),Y mode", in.Command)
return i, in.Errorf("%s doesn't support indirect indexed (addr),Y mode", in.Command)
}
if forceWide {
return i, fmt.Errorf("%s (addr),Y doesn't have a wide variant", in.Command)
}
in.WidthKnown = true
in.MinWidth = 2
@ -42,7 +48,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
default:
op, ok := summary.OpForMode(opcodes.MODE_INDIRECT)
if !ok {
return i, fmt.Errorf("%s doesn't support indirect (addr) mode", in.Command)
return i, in.Errorf("%s doesn't support indirect (addr) mode", in.Command)
}
in.Op = op.Byte
in.WidthKnown = true
@ -59,6 +65,10 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
if !ok {
panic(fmt.Sprintf("opcode error: %s has no MODE_RELATIVE opcode", in.Command))
}
if forceWide {
return i, fmt.Errorf("%s doesn't have a wide variant", in.Command)
}
in.Op = op.Byte
in.WidthKnown = true
in.MinWidth = 2
@ -68,7 +78,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
}
// No ,X or ,Y, and width is forced to 1-byte: immediate mode.
if xy == '-' && ex.Width() == 1 && summary.AnyModes(opcodes.MODE_IMMEDIATE) {
if xy == '-' && ex.Width() == 1 && summary.AnyModes(opcodes.MODE_IMMEDIATE) && !forceWide {
op, ok := summary.OpForMode(opcodes.MODE_IMMEDIATE)
if !ok {
panic(fmt.Sprintf("opcode error: %s has no MODE_IMMEDIATE opcode", in.Command))
@ -99,7 +109,7 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
opZp, zpOk := summary.OpForMode(zp)
if !summary.AnyModes(zp | wide) {
return i, fmt.Errorf("%s opcode doesn't support %s or %s modes.", zpS, wideS)
return i, in.Errorf("%s opcode doesn't support %s or %s modes.", zpS, wideS)
}
if !summary.AnyModes(zp) {
@ -117,6 +127,9 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
if !zpOk {
panic(fmt.Sprintf("opcode error: %s has no %s opcode", in.Command, zpS))
}
if forceWide {
return i, fmt.Errorf("%s doesn't have a wide variant", in.Command)
}
in.Op = opZp.Byte
in.WidthKnown = true
in.MinWidth = 2
@ -125,6 +138,15 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
return in, nil
}
if forceWide {
in.Op = opWide.Byte
in.WidthKnown = true
in.MinWidth = 3
in.MaxWidth = 3
in.Mode = wide
return in, nil
}
// Okay, we don't know whether it's wide or narrow: store enough info for either.
if !zpOk {
panic(fmt.Sprintf("opcode error: %s has no %s opcode", in.Command, zpS))

View File

@ -36,6 +36,7 @@ func New() *Merlin {
m.CharChars = "'"
m.InvCharChars = `"`
m.MacroArgSep = ";"
m.SuffixForWide = true
m.Directives = map[string]oldschool.DirectiveInfo{
"ORG": {inst.TypeOrg, m.ParseAddress, 0},

View File

@ -20,7 +20,7 @@ const Digits = "0123456789"
const binarydigits = "01"
const hexdigits = Digits + "abcdefABCDEF"
const Whitespace = " \t"
const cmdChars = Letters + Digits + ".>_"
const cmdChars = Letters + Digits + ".<>_:@"
const fileChars = Letters + Digits + "."
type DirectiveInfo struct {
@ -50,6 +50,7 @@ type Base struct {
HexCommas Requiredness
SpacesForComment int // this many spaces after command means it's the comment field
StringEndOptional bool // can omit closing delimeter from string args?
SuffixForWide bool // is eg. "LDA:" a force-wide on "LDA"? (Merlin)
CommentChar rune
BinaryChar rune
MsbChars string
@ -166,7 +167,17 @@ func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
if summary, ok := opcodes.ByName[in.Command]; ok {
in.Type = inst.TypeOp
return a.ParseOpArgs(in, lp, summary)
return a.ParseOpArgs(in, lp, summary, false)
}
// Merlin lets you say "LDA:" or "LDA@" or "LDAZ" to force non-zero-page.
if a.SuffixForWide {
prefix := in.Command[:len(in.Command)-1]
if summary, ok := opcodes.ByName[prefix]; ok {
in.Command = prefix
in.Type = inst.TypeOp
return a.ParseOpArgs(in, lp, summary, true)
}
}
return inst.I{}, in.Errorf(`unknown command/instruction: "%s"`, in.Command)
@ -229,9 +240,9 @@ func (a *Base) ParseQuoted(in inst.I, lp *lines.Parse) (string, error) {
return strings.Replace(s, `""`, `"`, -1), nil
}
// ParseOpArgs parses the arguments to an assembly op. We expect to be looking at the first
// non-op character (probably whitespace)
func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary) (inst.I, error) {
// ParseOpArgs parses the arguments to an assembly op. We expect to be
// looking at the first non-op character (probably whitespace)
func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary, forceWide bool) (inst.I, error) {
i := inst.I{}
// MODE_IMPLIED: we don't really care what comes next: it's a comment.
@ -338,7 +349,7 @@ func (a *Base) ParseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary
}
}
return common.DecodeOp(a, in, summary, indirect, xy)
return common.DecodeOp(a, in, summary, indirect, xy, forceWide)
}
func (a *Base) ParseAddress(in inst.I, lp *lines.Parse) (inst.I, error) {

View File

@ -49,6 +49,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
// {aa, ` include "FILE.NAME"`, "{inc 'FILE.NAME'}", ""},
// {aa, ` title "Title here"`, "{-}", ""},
// {ss, " .TA *-1234", "{target (- * $04d2)}", ""},
{mm, " <<<", `{endm}`, ""},
{mm, " >>> M1,$42 ;$43", `{call M1 {"$42"}}`, ""},
{mm, " >>> M1.$42", `{call M1 {"$42"}}`, ""},
{mm, " >>> M1/$42;$43", `{call M1 {"$42", "$43"}}`, ""},
@ -61,6 +62,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
{mm, " DFB $12,$34,$1234", "{data/b $0012,$0034,$1234}", "123434"},
{mm, " DFB $34,100,$81A2-$77C4,%1011,>$81A2-$77C4", "{data/b $0034,$0064,(- $81a2 $77c4),$000b,(msb (- $81a2 $77c4))}", "3464de0b09"},
{mm, " DSK OUTFILE", "{-}", ""},
{mm, " EOM", `{endm}`, ""},
{mm, " HEX 00,01,FF,AB", "{data/b}", "0001ffab"},
{mm, " HEX 0001FFAB", "{data/b}", "0001ffab"},
{mm, " INCW $42;$43", `{call INCW {"$42", "$43"}}`, ""},
@ -79,9 +81,9 @@ func TestSimpleCommonFunctions(t *testing.T) {
{mm, " LDA $1234,X", "{LDA/absX $1234}", "bd3412"},
{mm, " LDA ($12),Y", "{LDA/indY $0012}", "b112"},
{mm, " LDA ($12,X)", "{LDA/indX $0012}", "a112"},
{mm, " LDA: $12", "{LDA/zp $0012}", "ad1200"},
{mm, " LDA@ $12", "{LDA/zp $0012}", "ad1200"},
{mm, " LDAX $12", "{LDA/zp $0012}", "ad1200"},
{mm, " LDA: $12", "{LDA/abs $0012}", "ad1200"},
{mm, " LDA@ $12", "{LDA/abs $0012}", "ad1200"},
{mm, " LDAX $12", "{LDA/abs $0012}", "ad1200"},
{mm, " LDX $12,Y", "{LDX/zpY $0012}", "b612"},
{mm, " ORG $D000", "{org $d000}", ""},
{mm, " PMC M1($42", `{call M1 {"$42"}}`, ""},
@ -107,6 +109,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
{mm, "Label", "{- 'Label'}", ""},
{mm, "Label;Comment", "{- 'Label'}", ""},
{mm, "MacroName MAC", `{macro "MacroName"}`, ""},
{mm, "MacroName MAC", `{macro "MacroName"}`, ""},
{mm, ` ASC !ABC!`, "{data/b}", "c1c2c3"},
{mm, ` ASC "ABC"`, "{data/b}", "c1c2c3"},
{mm, ` ASC #ABC#`, "{data/b}", "c1c2c3"},