New syntax to PEEK and added tests
This commit is contained in:
parent
4aa6641583
commit
1617297067
3 changed files with 510 additions and 20 deletions
|
|
@ -10,7 +10,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// PeekCommand handles PEEK statements
|
// PeekCommand handles PEEK statements
|
||||||
// Syntax: PEEK <address>[offset] GIVING|-> <dest>
|
// Syntax:
|
||||||
|
//
|
||||||
|
// PEEK <address>[offset] GIVING|-> <dest> # old syntax
|
||||||
|
// <dest> = PEEK <address>[offset] # new syntax
|
||||||
|
//
|
||||||
// Where address is:
|
// Where address is:
|
||||||
// - Byte variable (self-modifying code)
|
// - Byte variable (self-modifying code)
|
||||||
// - Word variable (self-modifying code or ZP pointer with offset)
|
// - Word variable (self-modifying code or ZP pointer with offset)
|
||||||
|
|
@ -38,7 +42,18 @@ func (c *PeekCommand) WillHandle(line preproc.Line) bool {
|
||||||
if err != nil || len(params) != 4 {
|
if err != nil || len(params) != 4 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return strings.ToUpper(params[0]) == "PEEK"
|
|
||||||
|
// Old syntax: PEEK ... (4 params)
|
||||||
|
if strings.ToUpper(params[0]) == "PEEK" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// New syntax: <dest> = PEEK <address>
|
||||||
|
if params[1] == "=" && strings.ToUpper(params[2]) == "PEEK" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PeekCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext) error {
|
func (c *PeekCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext) error {
|
||||||
|
|
@ -67,14 +82,37 @@ func (c *PeekCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
||||||
|
|
||||||
scope := ctx.CurrentScope()
|
scope := ctx.CurrentScope()
|
||||||
|
|
||||||
|
var addrParam string
|
||||||
|
var destParam string
|
||||||
|
|
||||||
|
// Determine syntax and parse accordingly
|
||||||
|
if strings.ToUpper(params[0]) == "PEEK" {
|
||||||
|
// Old syntax: PEEK <address> GIVING|-> <dest>
|
||||||
|
|
||||||
// Validate separator (param 3)
|
// Validate separator (param 3)
|
||||||
sep := strings.ToUpper(params[2])
|
sep := strings.ToUpper(params[2])
|
||||||
if sep != "GIVING" && sep != "->" {
|
if sep != "GIVING" && sep != "->" {
|
||||||
return fmt.Errorf("PEEK: parameter #3 must be 'GIVING' or '->', got %q", params[2])
|
return fmt.Errorf("PEEK: parameter #3 must be 'GIVING' or '->', got %q", params[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse address (param 2) - may have [offset]
|
addrParam = params[1]
|
||||||
addrParam := params[1]
|
destParam = params[3]
|
||||||
|
} else {
|
||||||
|
// New syntax: <dest> = PEEK <address>
|
||||||
|
|
||||||
|
if params[1] != "=" {
|
||||||
|
return fmt.Errorf("PEEK: expected '=' at position 2, got %q", params[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ToUpper(params[2]) != "PEEK" {
|
||||||
|
return fmt.Errorf("PEEK: expected 'PEEK' at position 3, got %q", params[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
destParam = params[0]
|
||||||
|
addrParam = params[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse address - may have [offset]
|
||||||
baseAddr, offsetParam := parseOffset(addrParam)
|
baseAddr, offsetParam := parseOffset(addrParam)
|
||||||
|
|
||||||
constLookup := func(name string) (int64, bool) {
|
constLookup := func(name string) (int64, bool) {
|
||||||
|
|
@ -145,8 +183,7 @@ func (c *PeekCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse destination variable (param 4)
|
// Parse destination variable
|
||||||
destParam := params[3]
|
|
||||||
destSym := ctx.SymbolTable.Lookup(destParam, scope)
|
destSym := ctx.SymbolTable.Lookup(destParam, scope)
|
||||||
if destSym == nil {
|
if destSym == nil {
|
||||||
return fmt.Errorf("PEEK: unknown destination variable %q", destParam)
|
return fmt.Errorf("PEEK: unknown destination variable %q", destParam)
|
||||||
|
|
|
||||||
416
internal/commands/peek_test.go
Normal file
416
internal/commands/peek_test.go
Normal file
|
|
@ -0,0 +1,416 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"c65gm/internal/compiler"
|
||||||
|
"c65gm/internal/preproc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPeekOldSyntax(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
line string
|
||||||
|
setupVars func(*compiler.SymbolTable)
|
||||||
|
wantAsm []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "peek constant address to byte",
|
||||||
|
line: "PEEK 1024 GIVING result",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tlda 1024",
|
||||||
|
"\tsta result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peek ZP pointer to byte",
|
||||||
|
line: "PEEK ptr GIVING result",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tldy #0",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peek ZP pointer with offset to byte",
|
||||||
|
line: "PEEK ptr[5] GIVING result",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tldy #5",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peek with -> separator",
|
||||||
|
line: "PEEK 2048 -> result",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tlda 2048",
|
||||||
|
"\tsta result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
pragma := preproc.NewPragma()
|
||||||
|
ctx := compiler.NewCompilerContext(pragma)
|
||||||
|
tt.setupVars(ctx.SymbolTable)
|
||||||
|
|
||||||
|
cmd := &PeekCommand{}
|
||||||
|
line := preproc.Line{
|
||||||
|
Text: tt.line,
|
||||||
|
Kind: preproc.Source,
|
||||||
|
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Interpret(line, ctx); err != nil {
|
||||||
|
t.Fatalf("Interpret() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
asm, err := cmd.Generate(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Generate() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !equalAsm(asm, tt.wantAsm) {
|
||||||
|
t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
|
||||||
|
strings.Join(asm, "\n"),
|
||||||
|
strings.Join(tt.wantAsm, "\n"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPeekNewSyntax(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
line string
|
||||||
|
setupVars func(*compiler.SymbolTable)
|
||||||
|
wantAsm []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "new syntax constant address to byte",
|
||||||
|
line: "result = PEEK 1024",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tlda 1024",
|
||||||
|
"\tsta result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax ZP pointer to byte",
|
||||||
|
line: "result = PEEK ptr",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tldy #0",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax ZP pointer with offset",
|
||||||
|
line: "result = PEEK ptr[10]",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tldy #10",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax ZP pointer with variable offset",
|
||||||
|
line: "result = PEEK ptr[idx]",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
|
||||||
|
st.AddVar("idx", "", compiler.KindByte, 0)
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tldy idx",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax to word destination",
|
||||||
|
line: "result = PEEK 2048",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("result", "", compiler.KindWord, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tlda 2048",
|
||||||
|
"\tsta result",
|
||||||
|
"\tlda #0",
|
||||||
|
"\tsta result+1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
pragma := preproc.NewPragma()
|
||||||
|
ctx := compiler.NewCompilerContext(pragma)
|
||||||
|
tt.setupVars(ctx.SymbolTable)
|
||||||
|
|
||||||
|
cmd := &PeekCommand{}
|
||||||
|
line := preproc.Line{
|
||||||
|
Text: tt.line,
|
||||||
|
Kind: preproc.Source,
|
||||||
|
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Interpret(line, ctx); err != nil {
|
||||||
|
t.Fatalf("Interpret() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
asm, err := cmd.Generate(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Generate() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !equalAsm(asm, tt.wantAsm) {
|
||||||
|
t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
|
||||||
|
strings.Join(asm, "\n"),
|
||||||
|
strings.Join(tt.wantAsm, "\n"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPeekWNewSyntax(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
line string
|
||||||
|
setupVars func(*compiler.SymbolTable)
|
||||||
|
wantAsm []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "new syntax constant address",
|
||||||
|
line: "result = PEEKW 1024",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("result", "", compiler.KindWord, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tlda 1024",
|
||||||
|
"\tsta result",
|
||||||
|
"\tlda 1025",
|
||||||
|
"\tsta result+1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax ZP pointer",
|
||||||
|
line: "result = PEEKW ptr",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
|
||||||
|
st.AddVar("result", "", compiler.KindWord, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tldy #0",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result",
|
||||||
|
"\tiny",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result+1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax ZP pointer with offset",
|
||||||
|
line: "result = PEEKW ptr[8]",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
|
||||||
|
st.AddVar("result", "", compiler.KindWord, 0)
|
||||||
|
},
|
||||||
|
wantAsm: []string{
|
||||||
|
"\tldy #8",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result",
|
||||||
|
"\tiny",
|
||||||
|
"\tlda (ptr),y",
|
||||||
|
"\tsta result+1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
pragma := preproc.NewPragma()
|
||||||
|
ctx := compiler.NewCompilerContext(pragma)
|
||||||
|
tt.setupVars(ctx.SymbolTable)
|
||||||
|
|
||||||
|
cmd := &PeekWCommand{}
|
||||||
|
line := preproc.Line{
|
||||||
|
Text: tt.line,
|
||||||
|
Kind: preproc.Source,
|
||||||
|
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Interpret(line, ctx); err != nil {
|
||||||
|
t.Fatalf("Interpret() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
asm, err := cmd.Generate(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Generate() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !equalAsm(asm, tt.wantAsm) {
|
||||||
|
t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
|
||||||
|
strings.Join(asm, "\n"),
|
||||||
|
strings.Join(tt.wantAsm, "\n"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPeekErrors(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
line string
|
||||||
|
setupVars func(*compiler.SymbolTable)
|
||||||
|
wantError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "unknown destination",
|
||||||
|
line: "PEEK 1024 GIVING unknown",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
},
|
||||||
|
wantError: "unknown destination variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "constant destination",
|
||||||
|
line: "PEEK 1024 GIVING CONST",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddConst("CONST", "", compiler.KindByte, 100)
|
||||||
|
},
|
||||||
|
wantError: "cannot PEEK into constant",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax unknown destination",
|
||||||
|
line: "unknown = PEEK 1024",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
},
|
||||||
|
wantError: "unknown destination variable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax constant destination",
|
||||||
|
line: "CONST = PEEK 1024",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddConst("CONST", "", compiler.KindByte, 100)
|
||||||
|
},
|
||||||
|
wantError: "cannot PEEK into constant",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "offset without ZP pointer old syntax",
|
||||||
|
line: "PEEK addr[5] GIVING result",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("addr", "", compiler.KindWord, 0)
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantError: "offset",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "offset without ZP pointer new syntax",
|
||||||
|
line: "result = PEEK addr[5]",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("addr", "", compiler.KindWord, 0)
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantError: "offset",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
pragma := preproc.NewPragma()
|
||||||
|
ctx := compiler.NewCompilerContext(pragma)
|
||||||
|
tt.setupVars(ctx.SymbolTable)
|
||||||
|
|
||||||
|
cmd := &PeekCommand{}
|
||||||
|
line := preproc.Line{
|
||||||
|
Text: tt.line,
|
||||||
|
Kind: preproc.Source,
|
||||||
|
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := cmd.Interpret(line, ctx)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Expected error but got none")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), tt.wantError) {
|
||||||
|
t.Errorf("Error message mismatch\ngot: %v\nwant substring: %s", err, tt.wantError)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPeekWErrors(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
line string
|
||||||
|
setupVars func(*compiler.SymbolTable)
|
||||||
|
wantError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "byte destination",
|
||||||
|
line: "PEEKW 1024 GIVING result",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantError: "must be word type",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "new syntax byte destination",
|
||||||
|
line: "result = PEEKW 1024",
|
||||||
|
setupVars: func(st *compiler.SymbolTable) {
|
||||||
|
st.AddVar("result", "", compiler.KindByte, 0)
|
||||||
|
},
|
||||||
|
wantError: "must be word type",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
pragma := preproc.NewPragma()
|
||||||
|
ctx := compiler.NewCompilerContext(pragma)
|
||||||
|
tt.setupVars(ctx.SymbolTable)
|
||||||
|
|
||||||
|
cmd := &PeekWCommand{}
|
||||||
|
line := preproc.Line{
|
||||||
|
Text: tt.line,
|
||||||
|
Kind: preproc.Source,
|
||||||
|
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := cmd.Interpret(line, ctx)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Expected error but got none")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), tt.wantError) {
|
||||||
|
t.Errorf("Error message mismatch\ngot: %v\nwant substring: %s", err, tt.wantError)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// PeekWCommand handles PEEKW statements (reads a word/2 bytes)
|
// PeekWCommand handles PEEKW statements (reads a word/2 bytes)
|
||||||
// Syntax: PEEKW <address>[offset] GIVING|-> <dest>
|
// Syntax:
|
||||||
|
//
|
||||||
|
// PEEKW <address>[offset] GIVING|-> <dest> # old syntax
|
||||||
|
// <dest> = PEEKW <address>[offset] # new syntax
|
||||||
|
//
|
||||||
// Where address is:
|
// Where address is:
|
||||||
// - Byte variable (zero-page indexed addressing)
|
// - Byte variable (zero-page indexed addressing)
|
||||||
// - Word variable (self-modifying code or ZP pointer with offset)
|
// - Word variable (self-modifying code or ZP pointer with offset)
|
||||||
|
|
@ -39,7 +43,18 @@ func (c *PeekWCommand) WillHandle(line preproc.Line) bool {
|
||||||
if err != nil || len(params) != 4 {
|
if err != nil || len(params) != 4 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return strings.ToUpper(params[0]) == "PEEKW"
|
|
||||||
|
// Old syntax: PEEKW ... (4 params)
|
||||||
|
if strings.ToUpper(params[0]) == "PEEKW" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// New syntax: <dest> = PEEKW <address>
|
||||||
|
if params[1] == "=" && strings.ToUpper(params[2]) == "PEEKW" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PeekWCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext) error {
|
func (c *PeekWCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext) error {
|
||||||
|
|
@ -68,14 +83,37 @@ func (c *PeekWCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
||||||
|
|
||||||
scope := ctx.CurrentScope()
|
scope := ctx.CurrentScope()
|
||||||
|
|
||||||
|
var addrParam string
|
||||||
|
var destParam string
|
||||||
|
|
||||||
|
// Determine syntax and parse accordingly
|
||||||
|
if strings.ToUpper(params[0]) == "PEEKW" {
|
||||||
|
// Old syntax: PEEKW <address> GIVING|-> <dest>
|
||||||
|
|
||||||
// Validate separator (param 3)
|
// Validate separator (param 3)
|
||||||
sep := strings.ToUpper(params[2])
|
sep := strings.ToUpper(params[2])
|
||||||
if sep != "GIVING" && sep != "->" {
|
if sep != "GIVING" && sep != "->" {
|
||||||
return fmt.Errorf("PEEKW: parameter #3 must be 'GIVING' or '->', got %q", params[2])
|
return fmt.Errorf("PEEKW: parameter #3 must be 'GIVING' or '->', got %q", params[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse address (param 2) - may have [offset]
|
addrParam = params[1]
|
||||||
addrParam := params[1]
|
destParam = params[3]
|
||||||
|
} else {
|
||||||
|
// New syntax: <dest> = PEEKW <address>
|
||||||
|
|
||||||
|
if params[1] != "=" {
|
||||||
|
return fmt.Errorf("PEEKW: expected '=' at position 2, got %q", params[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ToUpper(params[2]) != "PEEKW" {
|
||||||
|
return fmt.Errorf("PEEKW: expected 'PEEKW' at position 3, got %q", params[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
destParam = params[0]
|
||||||
|
addrParam = params[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse address - may have [offset]
|
||||||
baseAddr, offsetParam := parseOffsetW(addrParam)
|
baseAddr, offsetParam := parseOffsetW(addrParam)
|
||||||
|
|
||||||
constLookup := func(name string) (int64, bool) {
|
constLookup := func(name string) (int64, bool) {
|
||||||
|
|
@ -146,8 +184,7 @@ func (c *PeekWCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse destination variable (param 4)
|
// Parse destination variable
|
||||||
destParam := params[3]
|
|
||||||
destSym := ctx.SymbolTable.Lookup(destParam, scope)
|
destSym := ctx.SymbolTable.Lookup(destParam, scope)
|
||||||
if destSym == nil {
|
if destSym == nil {
|
||||||
return fmt.Errorf("PEEKW: unknown destination variable %q", destParam)
|
return fmt.Errorf("PEEKW: unknown destination variable %q", destParam)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue