mirror of
https://github.com/zellyn/go6502.git
synced 2025-04-07 17:37:06 +00:00
Reorganize label fixing.
This commit is contained in:
parent
88ef7feee5
commit
54fe4809c1
33
asm/asm.go
33
asm/asm.go
@ -13,11 +13,10 @@ import (
|
||||
)
|
||||
|
||||
type Assembler struct {
|
||||
Flavor flavors.F
|
||||
Opener lines.Opener
|
||||
Insts []*inst.I
|
||||
LastLabel string
|
||||
Macros map[string]macros.M
|
||||
Flavor flavors.F
|
||||
Opener lines.Opener
|
||||
Insts []*inst.I
|
||||
Macros map[string]macros.M
|
||||
}
|
||||
|
||||
func NewAssembler(flavor flavors.F, opener lines.Opener) *Assembler {
|
||||
@ -44,14 +43,11 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if line.Parse != nil {
|
||||
// fmt.Fprintf("PLUGH: %s\n", line.Text())
|
||||
// }
|
||||
if done {
|
||||
lineSources = lineSources[1:]
|
||||
continue
|
||||
}
|
||||
in, parseErr := a.Flavor.ParseInstr(line)
|
||||
in, parseErr := a.Flavor.ParseInstr(line, false)
|
||||
if len(ifdefs) > 0 && !ifdefs[0] && in.Type != inst.TypeIfdefElse && in.Type != inst.TypeIfdefEnd {
|
||||
// we're in an inactive ifdef branch
|
||||
continue
|
||||
@ -61,9 +57,9 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := in.FixLabels(a.Flavor); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err := in.FixLabels(a.Flavor); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
if _, err := a.passInst(&in, false); err != nil {
|
||||
return err
|
||||
@ -76,7 +72,6 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
}
|
||||
return line.Errorf("unknown instruction: %s", line.Parse.Text())
|
||||
case inst.TypeMacroStart:
|
||||
|
||||
if err := a.readMacro(in, lineSources[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -92,6 +87,12 @@ func (a *Assembler) Load(filename string, prefix int) error {
|
||||
return in.Errorf(`error calling macro "%s": %v`, m.Name, err)
|
||||
}
|
||||
lineSources = append([]lines.LineSource{subLs}, lineSources...)
|
||||
a.Flavor.PushMacroCall(m.Name, macroCall, m.Locals)
|
||||
case inst.TypeMacroEnd:
|
||||
// If we reached here, it's in a macro call, not a definition.
|
||||
if !a.Flavor.PopMacroCall() {
|
||||
return in.Errorf("unexpected end of macro")
|
||||
}
|
||||
case inst.TypeIfdef:
|
||||
if len(in.Exprs) == 0 {
|
||||
panic(fmt.Sprintf("Ifdef got parsed with no expression: %s", line))
|
||||
@ -166,17 +167,16 @@ func (a *Assembler) readMacro(in inst.I, ls lines.LineSource) error {
|
||||
if done {
|
||||
return in.Errorf("end of file while reading macro %s", m.Name)
|
||||
}
|
||||
in2, err := a.Flavor.ParseInstr(line)
|
||||
in2, err := a.Flavor.ParseInstr(line, true)
|
||||
if a.Flavor.LocalMacroLabels() && in2.Label != "" {
|
||||
m.Locals[in2.Label] = true
|
||||
}
|
||||
m.Lines = append(m.Lines, line.Parse.Text())
|
||||
if err == nil && in2.Type == inst.TypeMacroEnd {
|
||||
m.Lines = append(m.Lines, line.Parse.Text())
|
||||
a.Macros[m.Name] = m
|
||||
a.Flavor.AddMacroName(m.Name)
|
||||
return nil
|
||||
}
|
||||
m.Lines = append(m.Lines, line.Parse.Text())
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,7 +246,6 @@ func (a *Assembler) RawBytes() ([]byte, error) {
|
||||
|
||||
func (a *Assembler) Reset() {
|
||||
a.Insts = nil
|
||||
a.LastLabel = ""
|
||||
}
|
||||
|
||||
func (a *Assembler) Membuf() (*membuf.Membuf, error) {
|
||||
|
42
asm/asm.org
42
asm/asm.org
@ -83,3 +83,45 @@ SOURCE FILE #01 =>FOO.TXT
|
||||
* Sweet 16
|
||||
http://amigan.1emu.net/kolsen/programming/sweet16.html
|
||||
http://twimgs.com/informationweek/byte/archive/Apple-II-Description/The-Apple-II-by-Stephen-Wozniak.pdf
|
||||
|
||||
| R0 | Accumulator |
|
||||
| R12 | Subroutine stack pointer |
|
||||
| R13 | Comparison results |
|
||||
| R14 | Status (prior result register << 8 + carry bit) |
|
||||
| R15 | PC |
|
||||
|
||||
| 00 | Return to 6502 mode | RTN | 1 | |
|
||||
| 01 | Branch always | BR | 2 | |
|
||||
| 02 | Branch if no carry | BNC | 2 | |
|
||||
| 03 | Branch if carry | BC | 2 | |
|
||||
| 04 | Branch if plus | BP | 2 | |
|
||||
| 05 | Branch if minus | BM | 2 | |
|
||||
| 06 | Branch if zero | BZ | 2 | |
|
||||
| 07 | Branch if nonzero | BNZ | 2 | |
|
||||
| 08 | Branch if minus 1 | BM1 | 2 | |
|
||||
| 09 | Branch if not minus 1 | BNM1 | 2 | |
|
||||
| 0A | Break | BK | 1 | BRK |
|
||||
| 0B | Return from subroutine | RS | 1 | PC <- [----R12] |
|
||||
| 0C | Branch to subroutine | BS | 2 | [R12++++] <- PC(R15); PC(R15) += offset |
|
||||
| 0D | - | | | |
|
||||
| 0E | - | | | |
|
||||
| 0F | - | | | |
|
||||
| 1n | Set | SET R7 | 3 | Rn <- constant |
|
||||
| 2n | Load | LD R7 | 1 | R0 <- Rn |
|
||||
| 3n | Store | ST R7 | 1 | Rn <- R0 |
|
||||
| 4n | Load indirect | LD @R7 | 1 | R0 <- byte[Rn++] |
|
||||
| 5n | Store indirect | ST @R7 | 1 | byte[Rn++] <- R0 |
|
||||
| 6n | Load double indirect | LDD @R7 | 1 | R0 <- word[Rn++++] |
|
||||
| 7n | Store double indirect | STD @R3 | 1 | word[Rn++++] <- R0 |
|
||||
| 8n | Pop indirect | POP @R3 | 1 | R0 <- byte[--Rn] |
|
||||
| 9n | Store pop indirect | STP @R3 | 1 | byte[--Rn] <- R0 |
|
||||
| An | Add | ADD R3 | 1 | R0 <- R0 + Rn |
|
||||
| Bn | Sub | SUB R3 | 1 | R0 <- R0 - Rn |
|
||||
| Cn | Pop double indirect | POPD @R3 | 1 | R0 <- word[----Rn] |
|
||||
| Dn | Compare | CPR R3 | 1 | R13 <- A0 - Rn |
|
||||
| En | Increment | INR R3 | 1 | Rn++ |
|
||||
| Fn | Decrement | DCR R3 | 1 | Rn-- |
|
||||
|
||||
* Horrible error messages
|
||||
** redbooka
|
||||
CPY $#0 COMMENT TEXT
|
||||
|
@ -6,10 +6,8 @@ type Context interface {
|
||||
Set(name string, value uint16)
|
||||
Get(name string) (uint16, bool)
|
||||
SetAddr(uint16)
|
||||
ClearAddr(message string)
|
||||
ClearMesg() string
|
||||
GetAddr() (uint16, bool)
|
||||
Zero() (uint16, error) // type ZeroFunc
|
||||
DivZero() (uint16, error)
|
||||
RemoveChanged()
|
||||
Clear()
|
||||
SettingOn(name string) error
|
||||
@ -18,17 +16,29 @@ type Context interface {
|
||||
HasSetting(name string) bool
|
||||
AddMacroName(name string)
|
||||
HasMacroName(name string) bool
|
||||
PushMacroCall(name string, number int, locals map[string]bool)
|
||||
PopMacroCall() bool
|
||||
GetMacroCall() (string, int, map[string]bool)
|
||||
|
||||
LastLabel() string
|
||||
SetLastLabel(label string)
|
||||
}
|
||||
|
||||
type macroCall struct {
|
||||
name string
|
||||
number int
|
||||
locals map[string]bool
|
||||
}
|
||||
|
||||
type SimpleContext struct {
|
||||
symbols map[string]symbolValue
|
||||
addr int32
|
||||
lastLabel string
|
||||
clearMesg string // Saved message describing why Addr was cleared.
|
||||
highbit byte // OR-mask for ASCII high bit
|
||||
highbit byte // OR-mask for ASCII high bit
|
||||
onOff map[string]bool
|
||||
onOffDefaults map[string]bool
|
||||
macroNames map[string]bool
|
||||
macroCalls []macroCall
|
||||
}
|
||||
|
||||
type symbolValue struct {
|
||||
@ -42,8 +52,8 @@ func (sc *SimpleContext) fix() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) Zero() (uint16, error) {
|
||||
return 0, fmt.Errorf("Not implemented: context.SimpleContext.Zero()")
|
||||
func (sc *SimpleContext) DivZero() (uint16, error) {
|
||||
return 0, fmt.Errorf("Not implemented: context.SimpleContext.DivZero()")
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) Get(name string) (uint16, bool) {
|
||||
@ -55,19 +65,10 @@ func (sc *SimpleContext) Get(name string) (uint16, bool) {
|
||||
return s.v, found
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) ClearAddr(message string) {
|
||||
sc.addr = -1
|
||||
sc.clearMesg = message
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) SetAddr(addr uint16) {
|
||||
sc.addr = int32(addr)
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) ClearMesg() string {
|
||||
return sc.clearMesg
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) GetAddr() (uint16, bool) {
|
||||
if sc.addr == -1 {
|
||||
return 0, false
|
||||
@ -156,3 +157,31 @@ func (sc *SimpleContext) SetOnOffDefaults(defaults map[string]bool) {
|
||||
sc.onOffDefaults = defaults
|
||||
sc.resetOnOff()
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) PushMacroCall(name string, number int, locals map[string]bool) {
|
||||
sc.macroCalls = append(sc.macroCalls, macroCall{name, number, locals})
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) PopMacroCall() bool {
|
||||
if len(sc.macroCalls) == 0 {
|
||||
return false
|
||||
}
|
||||
sc.macroCalls = sc.macroCalls[0 : len(sc.macroCalls)-1]
|
||||
return true
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) GetMacroCall() (string, int, map[string]bool) {
|
||||
if len(sc.macroCalls) == 0 {
|
||||
return "", 0, nil
|
||||
}
|
||||
mc := sc.macroCalls[len(sc.macroCalls)-1]
|
||||
return mc.name, mc.number, mc.locals
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) LastLabel() string {
|
||||
return sc.lastLabel
|
||||
}
|
||||
|
||||
func (sc *SimpleContext) SetLastLabel(l string) {
|
||||
sc.lastLabel = l
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
package context
|
||||
|
||||
/* Labeler is an interface that the flavors implement to handle label correction. */
|
||||
type Labeler interface {
|
||||
LastLabel() string
|
||||
SetLastLabel(label string)
|
||||
FixLabel(label string, macroCall int, locals map[string]bool) (string, error)
|
||||
IsNewParentLabel(label string) bool
|
||||
}
|
||||
|
||||
type LabelerBase struct {
|
||||
lastLabel string
|
||||
}
|
||||
|
||||
func (lb *LabelerBase) LastLabel() string {
|
||||
return lb.lastLabel
|
||||
}
|
||||
|
||||
func (lb *LabelerBase) SetLastLabel(l string) {
|
||||
lb.lastLabel = l
|
||||
}
|
@ -174,7 +174,7 @@ func (e *E) Eval(ctx context.Context, ln *lines.Line) (uint16, error) {
|
||||
return 0, nil
|
||||
case OpDiv:
|
||||
if r == 0 {
|
||||
return ctx.Zero()
|
||||
return ctx.DivZero()
|
||||
}
|
||||
return l / r, nil
|
||||
case OpAnd:
|
||||
@ -200,23 +200,3 @@ func (e *E) CheckedEval(ctx context.Context, ln *lines.Line) (val uint16, labelM
|
||||
}
|
||||
return val, false, err
|
||||
}
|
||||
|
||||
// FixLabels attempts to turn .1 into LAST_LABEL.1, etc.
|
||||
func (e *E) FixLabels(labeler context.Labeler, macroCall int, locals map[string]bool, ln *lines.Line) error {
|
||||
newL, err := labeler.FixLabel(e.Text, macroCall, locals)
|
||||
if err != nil {
|
||||
return ln.Errorf("%v", err)
|
||||
}
|
||||
e.Text = newL
|
||||
|
||||
if e.Left != nil {
|
||||
if err := e.Left.FixLabels(labeler, macroCall, locals, ln); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if e.Right != nil {
|
||||
return e.Right.FixLabels(labeler, macroCall, locals, ln)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
|
||||
type AS65 struct {
|
||||
context.SimpleContext
|
||||
context.LabelerBase
|
||||
}
|
||||
|
||||
func New() *AS65 {
|
||||
@ -21,7 +20,7 @@ func New() *AS65 {
|
||||
}
|
||||
|
||||
// Parse an entire instruction, or return an appropriate error.
|
||||
func (a *AS65) ParseInstr(line lines.Line) (inst.I, error) {
|
||||
func (a *AS65) ParseInstr(line lines.Line, quick bool) (inst.I, error) {
|
||||
return inst.I{}, nil
|
||||
}
|
||||
|
||||
@ -41,10 +40,6 @@ func (a *AS65) IsNewParentLabel(label string) bool {
|
||||
return label != "" && label[0] != '.'
|
||||
}
|
||||
|
||||
func (a *AS65) FixLabel(label string, macroCall int, locals map[string]bool) (string, error) {
|
||||
panic("AS65.FixLabel not implemented yet.")
|
||||
}
|
||||
|
||||
func (a *AS65) LocalMacroLabels() bool {
|
||||
return false
|
||||
}
|
||||
|
@ -8,10 +8,14 @@ import (
|
||||
"github.com/zellyn/go6502/opcodes"
|
||||
)
|
||||
|
||||
const xyzzy = false
|
||||
|
||||
// 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, forceWide bool) (inst.I, error) {
|
||||
ex := in.Exprs[0]
|
||||
val, err := ex.Eval(c, in.Line)
|
||||
valKnown := err == nil
|
||||
|
||||
// At this point we've parsed the Opcode. Let's see if it makes sense.
|
||||
if indirect {
|
||||
@ -69,6 +73,17 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
in.WidthKnown = true
|
||||
in.Width = 2
|
||||
in.Mode = opcodes.MODE_RELATIVE
|
||||
in.Mode = inst.VarRelative
|
||||
if valKnown && xyzzy {
|
||||
b, err := RelativeAddr(c, in, val)
|
||||
if err != nil {
|
||||
return in, err
|
||||
}
|
||||
fmt.Printf("b=$%02x\n", b)
|
||||
in.Data = []byte{in.Op, b}
|
||||
in.Final = true
|
||||
}
|
||||
|
||||
return in, nil
|
||||
}
|
||||
|
||||
@ -82,6 +97,8 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
in.WidthKnown = true
|
||||
in.Width = 2
|
||||
in.Mode = opcodes.MODE_IMMEDIATE
|
||||
in.Var = inst.VarBytes
|
||||
//xyzzy()
|
||||
return in, nil
|
||||
}
|
||||
|
||||
@ -152,3 +169,20 @@ func DecodeOp(c context.Context, in inst.I, summary opcodes.OpSummary, indirect
|
||||
in.Width = 2
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func RelativeAddr(c context.Context, in inst.I, val uint16) (byte, error) {
|
||||
curr, ok := c.GetAddr()
|
||||
if !ok {
|
||||
return 0, in.Errorf("cannot determine current address for '%s'", in.Command)
|
||||
}
|
||||
fmt.Printf("RelativeAddr: curr=%04x, val=%04x\n", curr, val)
|
||||
// Found both current and target addresses
|
||||
offset := int32(val) - (int32(curr) + 2)
|
||||
if offset > 127 {
|
||||
return 0, in.Errorf("%s cannot jump forward %d (max 127) from $%04x to $%04x", in.Command, offset, curr+2, val)
|
||||
}
|
||||
if offset < -128 {
|
||||
return 0, in.Errorf("%s cannot jump back %d (max -128) from $%04x to $%04x", in.Command, offset, curr+2, val)
|
||||
}
|
||||
return byte(offset), nil
|
||||
}
|
||||
|
@ -7,11 +7,10 @@ import (
|
||||
)
|
||||
|
||||
type F interface {
|
||||
ParseInstr(Line lines.Line) (inst.I, error)
|
||||
ParseInstr(Line lines.Line, quick bool) (inst.I, error)
|
||||
DefaultOrigin() uint16
|
||||
ReplaceMacroArgs(line string, args []string, kwargs map[string]string) (string, error)
|
||||
LocalMacroLabels() bool
|
||||
String() string
|
||||
context.Context
|
||||
context.Labeler
|
||||
}
|
||||
|
@ -43,14 +43,14 @@ func New() *Merlin {
|
||||
"ORG": {inst.TypeOrg, m.ParseAddress, 0},
|
||||
"OBJ": {inst.TypeNone, nil, 0},
|
||||
"ENDASM": {inst.TypeEnd, m.ParseNoArgDir, 0},
|
||||
"=": {inst.TypeEqu, m.ParseEquate, inst.EquNormal},
|
||||
"HEX": {inst.TypeData, m.ParseHexString, inst.DataBytes},
|
||||
"DFB": {inst.TypeData, m.ParseData, inst.DataBytes},
|
||||
"DB": {inst.TypeData, m.ParseData, inst.DataBytes},
|
||||
"DA": {inst.TypeData, m.ParseData, inst.DataWordsLe},
|
||||
"DDB": {inst.TypeData, m.ParseData, inst.DataWordsBe},
|
||||
"ASC": {inst.TypeData, m.ParseAscii, inst.DataAscii},
|
||||
"DCI": {inst.TypeData, m.ParseAscii, inst.DataAsciiFlip},
|
||||
"=": {inst.TypeEqu, m.ParseEquate, inst.VarEquNormal},
|
||||
"HEX": {inst.TypeData, m.ParseHexString, inst.VarBytes},
|
||||
"DFB": {inst.TypeData, m.ParseData, inst.VarBytes},
|
||||
"DB": {inst.TypeData, m.ParseData, inst.VarBytes},
|
||||
"DA": {inst.TypeData, m.ParseData, inst.VarWordsLe},
|
||||
"DDB": {inst.TypeData, m.ParseData, inst.VarWordsBe},
|
||||
"ASC": {inst.TypeData, m.ParseAscii, inst.VarAscii},
|
||||
"DCI": {inst.TypeData, m.ParseAscii, inst.VarAsciiFlip},
|
||||
".DO": {inst.TypeIfdef, m.ParseDo, 0},
|
||||
".ELSE": {inst.TypeIfdefElse, m.ParseNoArgDir, 0},
|
||||
".FIN": {inst.TypeIfdefEnd, m.ParseNoArgDir, 0},
|
||||
@ -94,13 +94,13 @@ func New() *Merlin {
|
||||
invertLast := in.Command == "DCI"
|
||||
switch {
|
||||
case !invert && !invertLast:
|
||||
in.Var = inst.DataAscii
|
||||
in.Var = inst.VarAscii
|
||||
case !invert && invertLast:
|
||||
in.Var = inst.DataAsciiFlip
|
||||
in.Var = inst.VarAsciiFlip
|
||||
case invert && !invertLast:
|
||||
in.Var = inst.DataAsciiHi
|
||||
in.Var = inst.VarAsciiHi
|
||||
case invert && invertLast:
|
||||
in.Var = inst.DataAsciiHiFlip
|
||||
in.Var = inst.VarAsciiHiFlip
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,6 +153,28 @@ func New() *Merlin {
|
||||
return in, true, nil
|
||||
}
|
||||
|
||||
m.FixLabel = func(label string) (string, error) {
|
||||
_, macroCount, locals := m.GetMacroCall()
|
||||
switch {
|
||||
case label == "":
|
||||
return label, nil
|
||||
case label[0] == ':':
|
||||
if last := m.LastLabel(); last == "" {
|
||||
return "", fmt.Errorf("sublabel '%s' without previous label", label)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", last, label), nil
|
||||
}
|
||||
case locals[label]:
|
||||
return fmt.Sprintf("%s{%d}", label, macroCount), nil
|
||||
|
||||
}
|
||||
return label, nil
|
||||
}
|
||||
|
||||
m.IsNewParentLabel = func(label string) bool {
|
||||
return label != "" && label[0] != ':'
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
@ -183,27 +205,6 @@ func (m *Merlin) ParseInclude(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (m *Merlin) IsNewParentLabel(label string) bool {
|
||||
return label != "" && label[0] != ':'
|
||||
}
|
||||
|
||||
func (m *Merlin) FixLabel(label string, macroCount int, locals map[string]bool) (string, error) {
|
||||
switch {
|
||||
case label == "":
|
||||
return label, nil
|
||||
case label[0] == ':':
|
||||
if last := m.LastLabel(); last == "" {
|
||||
return "", fmt.Errorf("sublabel '%s' without previous label", label)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", last, label), nil
|
||||
}
|
||||
case locals[label]:
|
||||
return fmt.Sprintf("%s{%d}", label, macroCount), nil
|
||||
|
||||
}
|
||||
return label, nil
|
||||
}
|
||||
|
||||
func (m *Merlin) LocalMacroLabels() bool {
|
||||
return true
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ type Base struct {
|
||||
Directives map[string]DirectiveInfo
|
||||
Operators map[string]expr.Operator
|
||||
context.SimpleContext
|
||||
context.LabelerBase
|
||||
LabelChars string
|
||||
LabelColons Requiredness
|
||||
ExplicitARegister Requiredness
|
||||
@ -57,13 +56,16 @@ type Base struct {
|
||||
MsbChars string
|
||||
LsbChars string
|
||||
ImmediateChars string
|
||||
ExtraCommenty func(string) bool
|
||||
SetAsciiVariation func(*inst.I, *lines.Parse)
|
||||
ParseMacroCall func(inst.I, *lines.Parse) (inst.I, bool, error)
|
||||
operatorChars string
|
||||
CharChars string
|
||||
InvCharChars string
|
||||
MacroArgSep string
|
||||
LocalMacroLabels bool
|
||||
ExtraCommenty func(string) bool
|
||||
SetAsciiVariation func(*inst.I, *lines.Parse)
|
||||
ParseMacroCall func(inst.I, *lines.Parse) (inst.I, bool, error)
|
||||
FixLabel func(label string) (string, error)
|
||||
IsNewParentLabel func(label string) bool
|
||||
}
|
||||
|
||||
func (a *Base) String() string {
|
||||
@ -71,7 +73,7 @@ func (a *Base) String() string {
|
||||
}
|
||||
|
||||
// Parse an entire instruction, or return an appropriate error.
|
||||
func (a *Base) ParseInstr(line lines.Line) (inst.I, error) {
|
||||
func (a *Base) ParseInstr(line lines.Line, quick bool) (inst.I, error) {
|
||||
lp := line.Parse
|
||||
in := inst.I{Line: &line}
|
||||
|
||||
@ -119,6 +121,20 @@ func (a *Base) ParseInstr(line lines.Line) (inst.I, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the label: munge for macros, relative labels, etc.
|
||||
// If appropriate, set the last parent label.
|
||||
if !quick {
|
||||
parent := a.IsNewParentLabel(in.Label)
|
||||
newL, err := a.FixLabel(in.Label)
|
||||
if err != nil {
|
||||
return in, in.Errorf("%v", err)
|
||||
}
|
||||
in.Label = newL
|
||||
if parent {
|
||||
a.SetLastLabel(in.Label)
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore whitespace at the start or after the label.
|
||||
lp.IgnoreRun(Whitespace)
|
||||
|
||||
@ -126,22 +142,32 @@ func (a *Base) ParseInstr(line lines.Line) (inst.I, error) {
|
||||
in.Type = inst.TypeNone
|
||||
return in, nil
|
||||
}
|
||||
return a.ParseCmd(in, lp)
|
||||
return a.parseCmd(in, lp, quick)
|
||||
}
|
||||
|
||||
func (a *Base) DefaultOrigin() uint16 {
|
||||
return 0x0800
|
||||
}
|
||||
|
||||
// ParseCmd parses the "command" part of an instruction: we expect to be
|
||||
// parseCmd parses the "command" part of an instruction: we expect to be
|
||||
// looking at a non-whitespace character.
|
||||
func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) parseCmd(in inst.I, lp *lines.Parse, quick bool) (inst.I, error) {
|
||||
if !lp.AcceptRun(cmdChars) && !(a.Directives["="].Func != nil && lp.Accept("=")) {
|
||||
c := lp.Next()
|
||||
return in, in.Errorf("expecting instruction, found '%c' (%d)", c, c)
|
||||
}
|
||||
in.Command = lp.Emit()
|
||||
|
||||
if quick {
|
||||
// all we care about is labels (already covered) and end-of-macro.
|
||||
if dir, ok := a.Directives[in.Command]; ok {
|
||||
if dir.Type == inst.TypeMacroEnd {
|
||||
in.Type = inst.TypeMacroEnd
|
||||
}
|
||||
return in, nil
|
||||
}
|
||||
|
||||
}
|
||||
// Give ParseMacroCall a chance
|
||||
if a.ParseMacroCall != nil {
|
||||
i, isMacro, err := a.ParseMacroCall(in, lp)
|
||||
@ -163,12 +189,12 @@ func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
}
|
||||
|
||||
if a.HasSetting(in.Command) {
|
||||
return a.ParseSetting(in, lp)
|
||||
return a.parseSetting(in, lp)
|
||||
}
|
||||
|
||||
if summary, ok := opcodes.ByName[in.Command]; ok {
|
||||
in.Type = inst.TypeOp
|
||||
return a.ParseOpArgs(in, lp, summary, false)
|
||||
return a.parseOpArgs(in, lp, summary, false)
|
||||
}
|
||||
|
||||
// Merlin lets you say "LDA:" or "LDA@" or "LDAZ" to force non-zero-page.
|
||||
@ -177,14 +203,14 @@ func (a *Base) ParseCmd(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
if summary, ok := opcodes.ByName[prefix]; ok {
|
||||
in.Command = prefix
|
||||
in.Type = inst.TypeOp
|
||||
return a.ParseOpArgs(in, lp, summary, true)
|
||||
return a.parseOpArgs(in, lp, summary, true)
|
||||
}
|
||||
}
|
||||
|
||||
return in, in.Errorf(`unknown command/instruction: "%s"`, in.Command)
|
||||
}
|
||||
|
||||
func (a *Base) ParseSetting(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
func (a *Base) parseSetting(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
in.Type = inst.TypeSetting
|
||||
lp.IgnoreRun(Whitespace)
|
||||
if !lp.AcceptRun(Letters) {
|
||||
@ -208,17 +234,17 @@ func (a *Base) ParseSetting(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
// character of a macro argument.
|
||||
func (a *Base) ParseMacroArg(in inst.I, lp *lines.Parse) (string, error) {
|
||||
if lp.Peek() == '"' {
|
||||
return a.ParseQuoted(in, lp)
|
||||
return a.parseQuoted(in, lp)
|
||||
}
|
||||
lp.AcceptUntil(Whitespace + a.MacroArgSep)
|
||||
return lp.Emit(), nil
|
||||
}
|
||||
|
||||
// ParseQuoted parses a single quoted string macro argument. We expect
|
||||
// parseQuoted parses a single quoted string macro argument. We expect
|
||||
// to be looking at the first quote.
|
||||
func (a *Base) ParseQuoted(in inst.I, lp *lines.Parse) (string, error) {
|
||||
func (a *Base) parseQuoted(in inst.I, lp *lines.Parse) (string, error) {
|
||||
if !lp.Consume(`"`) {
|
||||
panic(fmt.Sprintf("ParseQuoted called not looking at a quote"))
|
||||
panic(fmt.Sprintf("parseQuoted called not looking at a quote"))
|
||||
}
|
||||
for {
|
||||
lp.AcceptUntil(`"`)
|
||||
@ -241,9 +267,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
|
||||
// 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) {
|
||||
func (a *Base) parseOpArgs(in inst.I, lp *lines.Parse, summary opcodes.OpSummary, forceWide bool) (inst.I, error) {
|
||||
// MODE_IMPLIED: we don't really care what comes next: it's a comment.
|
||||
if summary.Modes == opcodes.MODE_IMPLIED {
|
||||
op := summary.Ops[0]
|
||||
@ -366,12 +392,12 @@ func (a *Base) ParseAscii(in inst.I, lp *lines.Parse) (inst.I, error) {
|
||||
a.SetAsciiVariation(&in, lp)
|
||||
var invert, invertLast byte
|
||||
switch in.Var {
|
||||
case inst.DataAscii:
|
||||
case inst.DataAsciiHi:
|
||||
case inst.VarAscii:
|
||||
case inst.VarAsciiHi:
|
||||
invert = 0x80
|
||||
case inst.DataAsciiFlip:
|
||||
case inst.VarAsciiFlip:
|
||||
invertLast = 0x80
|
||||
case inst.DataAsciiHiFlip:
|
||||
case inst.VarAsciiHiFlip:
|
||||
invert = 0x80
|
||||
invertLast = 0x80
|
||||
default:
|
||||
@ -662,6 +688,11 @@ func (a *Base) ParseTerm(in inst.I, lp *lines.Parse) (*expr.E, error) {
|
||||
|
||||
ex.Op = expr.OpLeaf
|
||||
ex.Text = lp.Emit()
|
||||
newL, err := a.FixLabel(ex.Text)
|
||||
if err != nil {
|
||||
return &expr.E{}, in.Errorf("%v", err)
|
||||
}
|
||||
ex.Text = newL
|
||||
return top, nil
|
||||
}
|
||||
|
||||
@ -680,11 +711,11 @@ func (a *Base) ReplaceMacroArgs(line string, args []string, kwargs map[string]st
|
||||
return line, err
|
||||
}
|
||||
|
||||
func (a *Base) IsNewParentLabel(label string) bool {
|
||||
func (a *Base) DefaultIsNewParentLabel(label string) bool {
|
||||
return label != "" && label[0] != '.'
|
||||
}
|
||||
|
||||
func (a *Base) FixLabel(label string, macroCall int, locals map[string]bool) (string, error) {
|
||||
func (a *Base) DefaultFixLabel(label string) (string, error) {
|
||||
switch {
|
||||
case label == "":
|
||||
return label, nil
|
||||
@ -695,6 +726,7 @@ func (a *Base) FixLabel(label string, macroCall int, locals map[string]bool) (st
|
||||
return fmt.Sprintf("%s/%s", last, label), nil
|
||||
}
|
||||
case label[0] == ':':
|
||||
_, macroCall, _ := a.GetMacroCall()
|
||||
if macroCall == 0 {
|
||||
return "", fmt.Errorf("macro-local label '%s' seen outside macro", label)
|
||||
} else {
|
||||
|
@ -42,14 +42,14 @@ func newRedbook(name string) *RedBook {
|
||||
"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},
|
||||
"HEX": {inst.TypeData, r.ParseHexString, inst.DataBytes},
|
||||
"EQU": {inst.TypeEqu, r.ParseEquate, inst.VarEquNormal},
|
||||
"EPZ": {inst.TypeEqu, r.ParseEquate, inst.VarEquPageZero},
|
||||
"DFB": {inst.TypeData, r.ParseData, inst.VarBytes},
|
||||
"DW": {inst.TypeData, r.ParseData, inst.VarWordsLe},
|
||||
"DDB": {inst.TypeData, r.ParseData, inst.VarWordsBe},
|
||||
"ASC": {inst.TypeData, r.ParseAscii, inst.VarAscii},
|
||||
"DCI": {inst.TypeData, r.ParseAscii, inst.VarAsciiFlip},
|
||||
"HEX": {inst.TypeData, r.ParseHexString, inst.VarBytes},
|
||||
"PAGE": {inst.TypeNone, nil, 0}, // New page
|
||||
"TITLE": {inst.TypeNone, nil, 0}, // Title
|
||||
"SBTL": {inst.TypeNone, nil, 0}, // Subtitle
|
||||
@ -75,19 +75,22 @@ func newRedbook(name string) *RedBook {
|
||||
r.SetAsciiVariation = func(in *inst.I, lp *lines.Parse) {
|
||||
if in.Command == "ASC" {
|
||||
if r.Setting("MSB") {
|
||||
in.Var = inst.DataAsciiHi
|
||||
in.Var = inst.VarAsciiHi
|
||||
} else {
|
||||
in.Var = inst.DataAscii
|
||||
in.Var = inst.VarAscii
|
||||
}
|
||||
return
|
||||
}
|
||||
if in.Command == "DCI" {
|
||||
in.Var = inst.DataAsciiFlip
|
||||
in.Var = inst.VarAsciiFlip
|
||||
} else {
|
||||
panic(fmt.Sprintf("Unknown ascii directive: '%s'", in.Command))
|
||||
}
|
||||
}
|
||||
|
||||
r.FixLabel = r.DefaultFixLabel
|
||||
r.IsNewParentLabel = r.DefaultIsNewParentLabel
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
|
@ -37,10 +37,10 @@ func New() *SCMA {
|
||||
".TF": {inst.TypeNone, nil, 0},
|
||||
".EN": {inst.TypeEnd, a.ParseNoArgDir, 0},
|
||||
".EQ": {inst.TypeEqu, a.ParseEquate, 0},
|
||||
".DA": {inst.TypeData, a.ParseData, inst.DataMixed},
|
||||
".HS": {inst.TypeData, a.ParseHexString, inst.DataBytes},
|
||||
".AS": {inst.TypeData, a.ParseAscii, inst.DataBytes},
|
||||
".AT": {inst.TypeData, a.ParseAscii, inst.DataBytes},
|
||||
".DA": {inst.TypeData, a.ParseData, inst.VarMixed},
|
||||
".HS": {inst.TypeData, a.ParseHexString, inst.VarBytes},
|
||||
".AS": {inst.TypeData, a.ParseAscii, inst.VarBytes},
|
||||
".AT": {inst.TypeData, a.ParseAscii, inst.VarBytes},
|
||||
".BS": {inst.TypeBlock, a.ParseBlockStorage, 0},
|
||||
".TI": {inst.TypeNone, nil, 0},
|
||||
".LIST": {inst.TypeNone, nil, 0},
|
||||
@ -73,13 +73,13 @@ func New() *SCMA {
|
||||
invertLast := in.Command == ".AT"
|
||||
switch {
|
||||
case !invert && !invertLast:
|
||||
in.Var = inst.DataAscii
|
||||
in.Var = inst.VarAscii
|
||||
case !invert && invertLast:
|
||||
in.Var = inst.DataAsciiFlip
|
||||
in.Var = inst.VarAsciiFlip
|
||||
case invert && !invertLast:
|
||||
in.Var = inst.DataAsciiHi
|
||||
in.Var = inst.VarAsciiHi
|
||||
case invert && invertLast:
|
||||
in.Var = inst.DataAsciiHiFlip
|
||||
in.Var = inst.VarAsciiHiFlip
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,6 +112,9 @@ func New() *SCMA {
|
||||
return in, true, nil
|
||||
}
|
||||
|
||||
a.FixLabel = a.DefaultFixLabel
|
||||
a.IsNewParentLabel = a.DefaultIsNewParentLabel
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package flavors
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -292,6 +293,7 @@ func TestMultiline(t *testing.T) {
|
||||
if !tt.active {
|
||||
continue
|
||||
}
|
||||
fmt.Println(tt.name)
|
||||
if tt.b == "" && len(tt.ps) == 0 {
|
||||
t.Fatalf(`%d("%s" - %s): test case must specify bytes or pieces`, i, tt.name, tt.a.Flavor)
|
||||
}
|
||||
@ -302,41 +304,34 @@ func TestMultiline(t *testing.T) {
|
||||
o[k] = strings.Join(v, "\n")
|
||||
}
|
||||
if err := tt.a.Load("TESTFILE", 0); err != nil {
|
||||
t.Errorf(`%d("%s" - %s): tt.a.Load("TESTFILE") failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
continue
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.Load("TESTFILE") failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
}
|
||||
isFinal, err := tt.a.Pass(true)
|
||||
if err != nil {
|
||||
t.Errorf(`%d("%s" - %s): tt.a.Pass(true) failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
continue
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.Pass(true) failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
}
|
||||
if !isFinal {
|
||||
t.Errorf(`%d("%s" - %s): tt.a.Pass(true) couldn't finalize`, i, tt.name, tt.a.Flavor)
|
||||
continue
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.Pass(true) couldn't finalize`, i, tt.name, tt.a.Flavor)
|
||||
}
|
||||
|
||||
if tt.b != "" {
|
||||
bb, err := tt.a.RawBytes()
|
||||
if err != nil {
|
||||
t.Errorf(`%d("%s" - %s): tt.a.RawBytes() failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
continue
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.RawBytes() failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
}
|
||||
hx := hex.EncodeToString(bb)
|
||||
if hx != tt.b {
|
||||
t.Errorf(`%d("%s" - %s): tt.a.RawBytes()=[%s]; want [%s]`, i, tt.name, tt.a.Flavor, hx, tt.b)
|
||||
continue
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.RawBytes()=[%s]; want [%s]`, i, tt.name, tt.a.Flavor, hx, tt.b)
|
||||
}
|
||||
}
|
||||
if len(tt.ps) != 0 {
|
||||
m, err := tt.a.Membuf()
|
||||
if err != nil {
|
||||
t.Errorf(`%d("%s" - %s): tt.a.Membuf() failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
continue
|
||||
t.Fatalf(`%d("%s" - %s): tt.a.Membuf() failed: %s`, i, tt.name, tt.a.Flavor, err)
|
||||
}
|
||||
ps := m.Pieces()
|
||||
if !reflect.DeepEqual(ps, tt.ps) {
|
||||
t.Errorf(`%d("%s" - %s): tt.Membuf().Pieces() = %v; want %v`, i, tt.name, tt.a.Flavor, ps, tt.ps)
|
||||
continue
|
||||
t.Fatalf(`%d("%s" - %s): tt.Membuf().Pieces() = %v; want %v`, i, tt.name, tt.a.Flavor, ps, tt.ps)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ func TestSimpleCommonFunctions(t *testing.T) {
|
||||
tt.a.AddMacroName("INCW")
|
||||
tt.a.AddMacroName("M1")
|
||||
|
||||
inst, err := tt.a.ParseInstr(lines.NewSimple(tt.i))
|
||||
inst, err := tt.a.ParseInstr(lines.NewSimple(tt.i), false)
|
||||
if err != nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") => error: %s`, i, tt.a, tt.i, err)
|
||||
continue
|
||||
@ -293,7 +293,7 @@ func TestSimpleErrors(t *testing.T) {
|
||||
if tt.a != ss {
|
||||
continue
|
||||
}
|
||||
inst, err := tt.a.ParseInstr(lines.NewSimple(tt.i))
|
||||
inst, err := tt.a.ParseInstr(lines.NewSimple(tt.i), false)
|
||||
if err == nil {
|
||||
t.Errorf(`%d. %s.ParseInstr("%s") want err; got %s`, i, tt.a, tt.i, inst)
|
||||
continue
|
||||
|
@ -36,22 +36,20 @@ const (
|
||||
TypeSetting // An on/off setting toggle
|
||||
)
|
||||
|
||||
// Variants for "TypeData" instructions.
|
||||
// Variants for instructions. These tell the instruction how to
|
||||
// interpret the raw data that comes in on the first or second pass.
|
||||
const (
|
||||
DataBytes = iota // Data: expressions, but forced to one byte per
|
||||
DataMixed // Bytes or words (LE), depending on individual expression widths
|
||||
DataWordsLe // Data: expressions, but forced to one word per, little-endian
|
||||
DataWordsBe // Data: expressions, but forced to one word per, big-endian
|
||||
DataAscii // Data: from ASCII strings, high bit clear
|
||||
DataAsciiFlip // Data: from ASCII strings, high bit clear, except last char
|
||||
DataAsciiHi // Data: from ASCII strings, high bit set
|
||||
DataAsciiHiFlip // Data: from ASCII strings, high bit set, except last char
|
||||
)
|
||||
|
||||
// Variants for "TypeEqu" instructions.
|
||||
const (
|
||||
EquNormal = iota
|
||||
EquPageZero
|
||||
VarBytes = iota // Data: expressions, but forced to one byte per
|
||||
VarMixed // Bytes or words (LE), depending on individual expression widths
|
||||
VarWordsLe // Data: expressions, but forced to one word per, little-endian
|
||||
VarWordsBe // Data: expressions, but forced to one word per, big-endian
|
||||
VarAscii // Data: from ASCII strings, high bit clear
|
||||
VarAsciiFlip // Data: from ASCII strings, high bit clear, except last char
|
||||
VarAsciiHi // Data: from ASCII strings, high bit set
|
||||
VarAsciiHiFlip // Data: from ASCII strings, high bit set, except last char
|
||||
VarRelative // For branches: a one-byte relative address
|
||||
VarEquNormal // Equ: a normal equate
|
||||
VarEquPageZero // Equ: a page-zero equate
|
||||
)
|
||||
|
||||
type I struct {
|
||||
@ -98,15 +96,15 @@ func (i I) TypeString() string {
|
||||
return "inc"
|
||||
case TypeData:
|
||||
switch i.Var {
|
||||
case DataMixed:
|
||||
case VarMixed:
|
||||
return "data"
|
||||
case DataBytes:
|
||||
case VarBytes:
|
||||
return "data/b"
|
||||
case DataWordsLe:
|
||||
case VarWordsLe:
|
||||
return "data/wle"
|
||||
case DataWordsBe:
|
||||
case VarWordsBe:
|
||||
return "data/wbe"
|
||||
case DataAscii, DataAsciiHi, DataAsciiFlip, DataAsciiHiFlip:
|
||||
case VarAscii, VarAsciiHi, VarAsciiFlip, VarAsciiHiFlip:
|
||||
return "data/b"
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown data variant: %d", i.Var))
|
||||
@ -217,29 +215,6 @@ func (i *I) Compute(c context.Context, final bool) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// FixLabels attempts to turn .1 into LAST_LABEL.1, etc.
|
||||
func (i *I) FixLabels(labeler context.Labeler) error {
|
||||
macroCall := i.Line.GetMacroCall()
|
||||
macroLocals := i.Line.GetMacroLocals()
|
||||
parent := labeler.IsNewParentLabel(i.Label)
|
||||
newL, err := labeler.FixLabel(i.Label, macroCall, macroLocals)
|
||||
if err != nil {
|
||||
return i.Errorf("%v", err)
|
||||
}
|
||||
i.Label = newL
|
||||
if parent {
|
||||
labeler.SetLastLabel(i.Label)
|
||||
}
|
||||
|
||||
for _, e := range i.Exprs {
|
||||
if err := e.FixLabels(labeler, macroCall, macroLocals, i.Line); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// computeLabel attempts to compute equates and label values.
|
||||
func (i *I) computeLabel(c context.Context, final bool) error {
|
||||
if i.Label == "" {
|
||||
@ -277,11 +252,11 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) {
|
||||
for _, e := range i.Exprs {
|
||||
var w uint16
|
||||
switch i.Var {
|
||||
case DataMixed:
|
||||
case VarMixed:
|
||||
w = e.Width()
|
||||
case DataBytes:
|
||||
case VarBytes:
|
||||
w = 1
|
||||
case DataWordsLe, DataWordsBe:
|
||||
case VarWordsLe, VarWordsBe:
|
||||
w = 2
|
||||
}
|
||||
width += w
|
||||
@ -296,18 +271,18 @@ func (i *I) computeData(c context.Context, final bool) (bool, error) {
|
||||
}
|
||||
}
|
||||
switch i.Var {
|
||||
case DataMixed:
|
||||
case VarMixed:
|
||||
switch w {
|
||||
case 1:
|
||||
data = append(data, byte(val))
|
||||
case 2:
|
||||
data = append(data, byte(val), byte(val>>8))
|
||||
}
|
||||
case DataBytes:
|
||||
case VarBytes:
|
||||
data = append(data, byte(val))
|
||||
case DataWordsLe:
|
||||
case VarWordsLe:
|
||||
data = append(data, byte(val), byte(val>>8))
|
||||
case DataWordsBe:
|
||||
case VarWordsBe:
|
||||
data = append(data, byte(val>>8), byte(val))
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown data variant handed to computeData: %d", i.Var))
|
||||
|
@ -13,7 +13,7 @@ func TestComputeLabel(t *testing.T) {
|
||||
Label: "L1",
|
||||
}
|
||||
c := &context.SimpleContext{}
|
||||
i.computeLabel(c, false, false)
|
||||
i.computeLabel(c, false)
|
||||
}
|
||||
|
||||
func TestWidthDoesNotChange(t *testing.T) {
|
||||
@ -27,8 +27,7 @@ func TestWidthDoesNotChange(t *testing.T) {
|
||||
Right: &expr.E{Op: expr.OpLeaf, Text: "L2"},
|
||||
},
|
||||
},
|
||||
MinWidth: 0x2,
|
||||
MaxWidth: 0x3,
|
||||
Width: 0x2,
|
||||
Final: false,
|
||||
Op: 0xad,
|
||||
Mode: 0x2,
|
||||
@ -38,15 +37,7 @@ func TestWidthDoesNotChange(t *testing.T) {
|
||||
}
|
||||
c := &context.SimpleContext{}
|
||||
c.Set("L1", 0x102)
|
||||
final, err := i.Compute(c, false, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if final {
|
||||
t.Fatal("First pass shouldn't be able to finalize expression with unknown width")
|
||||
}
|
||||
|
||||
final, err = i.Compute(c, true, false)
|
||||
final, err := i.Compute(c, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -56,16 +47,13 @@ func TestWidthDoesNotChange(t *testing.T) {
|
||||
if !i.WidthKnown {
|
||||
t.Fatal("Second pass should have set width.")
|
||||
}
|
||||
if i.MinWidth != i.MaxWidth {
|
||||
t.Fatalf("i.WidthKnown, but i.MinWidth(%d) != i.MaxWidth(%d)", i.MinWidth, i.MaxWidth)
|
||||
}
|
||||
if i.MinWidth != 3 {
|
||||
t.Fatalf("i.MinWidth should be 3; got %d", i.MinWidth)
|
||||
if i.Width != 3 {
|
||||
t.Fatalf("i.Width should be 3; got %d", i.Width)
|
||||
}
|
||||
|
||||
c.Set("L2", 0x101)
|
||||
|
||||
final, err = i.Compute(c, true, true)
|
||||
final, err = i.Compute(c, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -75,10 +63,7 @@ func TestWidthDoesNotChange(t *testing.T) {
|
||||
if !i.WidthKnown {
|
||||
t.Fatal("Third pass should left width unchanged.")
|
||||
}
|
||||
if i.MinWidth != i.MaxWidth {
|
||||
t.Fatalf("i.WidthKnown, but i.MinWidth(%d) != i.MaxWidth(%d)", i.MinWidth, i.MaxWidth)
|
||||
}
|
||||
if i.MinWidth != 3 {
|
||||
t.Fatalf("i.MinWidth should still be 3; got %d", i.MinWidth)
|
||||
if i.Width != 3 {
|
||||
t.Fatalf("i.Width should still be 3; got %d", i.Width)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user