Now unused vars seem to work
This commit is contained in:
parent
b25c11ae64
commit
0bfbfcdde5
3 changed files with 76 additions and 3 deletions
|
|
@ -222,6 +222,12 @@ func (c *Compiler) Compile(lines []preproc.Line) ([]string, error) {
|
||||||
// Analyze for overlapping absolute addresses in function call chains
|
// Analyze for overlapping absolute addresses in function call chains
|
||||||
c.checkAbsoluteOverlaps()
|
c.checkAbsoluteOverlaps()
|
||||||
|
|
||||||
|
// Check for unused variables and print warnings
|
||||||
|
warnings := c.ctx.SymbolTable.CheckUnused()
|
||||||
|
for _, warning := range warnings {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "%s\n", warning)
|
||||||
|
}
|
||||||
|
|
||||||
// Assemble final output with headers and footers
|
// Assemble final output with headers and footers
|
||||||
return c.assembleOutput(codeOutput), nil
|
return c.assembleOutput(codeOutput), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,8 @@ func (fh *FunctionHandler) HandleFuncDecl(line preproc.Line) ([]string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up variable in symbol table
|
// Look up variable in symbol table (validation only, not usage)
|
||||||
sym := fh.symTable.Lookup(varName, []string{funcName})
|
sym := fh.symTable.LookupWithoutUsage(varName, []string{funcName})
|
||||||
if sym == nil {
|
if sym == nil {
|
||||||
fh.currentFuncs = fh.currentFuncs[:len(fh.currentFuncs)-1]
|
fh.currentFuncs = fh.currentFuncs[:len(fh.currentFuncs)-1]
|
||||||
return nil, fmt.Errorf("%s:%d: FUNC %s: parameter %q not declared", line.Filename, line.LineNo, funcName, varName)
|
return nil, fmt.Errorf("%s:%d: FUNC %s: parameter %q not declared", line.Filename, line.LineNo, funcName, varName)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,12 @@ const (
|
||||||
FlagLabelRef
|
FlagLabelRef
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Usage tracking for variables
|
||||||
|
const (
|
||||||
|
UsageNone uint8 = iota
|
||||||
|
UsageUsed
|
||||||
|
)
|
||||||
|
|
||||||
// Symbol represents a variable or constant declaration
|
// Symbol represents a variable or constant declaration
|
||||||
type Symbol struct {
|
type Symbol struct {
|
||||||
Name string
|
Name string
|
||||||
|
|
@ -34,6 +40,7 @@ type Symbol struct {
|
||||||
Value uint16 // init value or const value
|
Value uint16 // init value or const value
|
||||||
AbsAddr uint16 // if FlagAbsolute set
|
AbsAddr uint16 // if FlagAbsolute set
|
||||||
LabelRef string // if FlagLabelRef set
|
LabelRef string // if FlagLabelRef set
|
||||||
|
Usage uint8 // tracks variable usage (see Usage constants)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper methods for Symbol
|
// Helper methods for Symbol
|
||||||
|
|
@ -52,6 +59,11 @@ func (s *Symbol) IsAbsolute() bool { return s.Has(FlagAbsolute) }
|
||||||
func (s *Symbol) IsZeroPage() bool { return s.Has(FlagZeroPage) }
|
func (s *Symbol) IsZeroPage() bool { return s.Has(FlagZeroPage) }
|
||||||
func (s *Symbol) IsZeroPagePointer() bool { return s.HasAll(FlagAbsolute | FlagZeroPage | FlagWord) }
|
func (s *Symbol) IsZeroPagePointer() bool { return s.HasAll(FlagAbsolute | FlagZeroPage | FlagWord) }
|
||||||
|
|
||||||
|
// MarkUsed marks the symbol as used (should not be called for constants or absolutes)
|
||||||
|
func (s *Symbol) MarkUsed() {
|
||||||
|
s.Usage = UsageUsed
|
||||||
|
}
|
||||||
|
|
||||||
// FullName returns the fully qualified name (scope.name or just name)
|
// FullName returns the fully qualified name (scope.name or just name)
|
||||||
func (s *Symbol) FullName() string {
|
func (s *Symbol) FullName() string {
|
||||||
if s.Scope == "" {
|
if s.Scope == "" {
|
||||||
|
|
@ -208,12 +220,17 @@ func (st *SymbolTable) add(sym *Symbol) error {
|
||||||
|
|
||||||
// Lookup finds a symbol by name, resolving scope
|
// Lookup finds a symbol by name, resolving scope
|
||||||
// Searches local scope first (if currentScopes provided), then global
|
// Searches local scope first (if currentScopes provided), then global
|
||||||
|
// Marks non-constant, non-absolute variables as used
|
||||||
func (st *SymbolTable) Lookup(name string, currentScopes []string) *Symbol {
|
func (st *SymbolTable) Lookup(name string, currentScopes []string) *Symbol {
|
||||||
// Try local scopes first (innermost to outermost)
|
// Try local scopes first (innermost to outermost)
|
||||||
for i := len(currentScopes) - 1; i >= 0; i-- {
|
for i := len(currentScopes) - 1; i >= 0; i-- {
|
||||||
scope := currentScopes[i]
|
scope := currentScopes[i]
|
||||||
if scopeMap, ok := st.byScope[scope]; ok {
|
if scopeMap, ok := st.byScope[scope]; ok {
|
||||||
if sym, ok := scopeMap[name]; ok {
|
if sym, ok := scopeMap[name]; ok {
|
||||||
|
// Mark as used if it's a regular variable (not constant, not absolute)
|
||||||
|
if !sym.IsConst() && !sym.IsAbsolute() {
|
||||||
|
sym.MarkUsed()
|
||||||
|
}
|
||||||
return sym
|
return sym
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -222,6 +239,10 @@ func (st *SymbolTable) Lookup(name string, currentScopes []string) *Symbol {
|
||||||
// Try global scope
|
// Try global scope
|
||||||
if scopeMap, ok := st.byScope[""]; ok {
|
if scopeMap, ok := st.byScope[""]; ok {
|
||||||
if sym, ok := scopeMap[name]; ok {
|
if sym, ok := scopeMap[name]; ok {
|
||||||
|
// Mark as used if it's a regular variable (not constant, not absolute)
|
||||||
|
if !sym.IsConst() && !sym.IsAbsolute() {
|
||||||
|
sym.MarkUsed()
|
||||||
|
}
|
||||||
return sym
|
return sym
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -253,10 +274,33 @@ func (st *SymbolTable) ExpandName(name string, currentScopes []string) string {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LookupWithoutUsage finds a symbol by name without marking it as used
|
||||||
|
// Used for validation-only lookups (e.g., checking if variable exists)
|
||||||
|
func (st *SymbolTable) LookupWithoutUsage(name string, currentScopes []string) *Symbol {
|
||||||
|
// Try local scopes first (innermost to outermost)
|
||||||
|
for i := len(currentScopes) - 1; i >= 0; i-- {
|
||||||
|
scope := currentScopes[i]
|
||||||
|
if scopeMap, ok := st.byScope[scope]; ok {
|
||||||
|
if sym, ok := scopeMap[name]; ok {
|
||||||
|
return sym
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try global scope
|
||||||
|
if scopeMap, ok := st.byScope[""]; ok {
|
||||||
|
if sym, ok := scopeMap[name]; ok {
|
||||||
|
return sym
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// LookupConstant looks up a constant by name and returns its value if found
|
// LookupConstant looks up a constant by name and returns its value if found
|
||||||
// Returns (value, true) if symbol exists and is a constant, (0, false) otherwise
|
// Returns (value, true) if symbol exists and is a constant, (0, false) otherwise
|
||||||
func (st *SymbolTable) LookupConstant(name string, currentScopes []string) (int64, bool) {
|
func (st *SymbolTable) LookupConstant(name string, currentScopes []string) (int64, bool) {
|
||||||
sym := st.Lookup(name, currentScopes)
|
sym := st.LookupWithoutUsage(name, currentScopes)
|
||||||
if sym != nil && sym.IsConst() {
|
if sym != nil && sym.IsConst() {
|
||||||
return int64(sym.Value), true
|
return int64(sym.Value), true
|
||||||
}
|
}
|
||||||
|
|
@ -271,6 +315,29 @@ func (st *SymbolTable) ConstantLookupFunc(currentScopes []string) func(string) (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckUnused returns warnings for unused variables
|
||||||
|
// Returns slice of warning messages for regular variables (not constants, not absolutes) that were never used
|
||||||
|
func (st *SymbolTable) CheckUnused() []string {
|
||||||
|
var warnings []string
|
||||||
|
for _, sym := range st.symbols {
|
||||||
|
// Skip constants and absolute variables
|
||||||
|
if sym.IsConst() || sym.IsAbsolute() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Check if variable was never used
|
||||||
|
if sym.Usage == UsageNone {
|
||||||
|
// Format warning message
|
||||||
|
var scopeInfo string
|
||||||
|
if sym.Scope != "" {
|
||||||
|
scopeInfo = fmt.Sprintf(" in function '%s'", sym.Scope)
|
||||||
|
}
|
||||||
|
warning := fmt.Sprintf("warning: variable '%s'%s declared but never used", sym.Name, scopeInfo)
|
||||||
|
warnings = append(warnings, warning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return warnings
|
||||||
|
}
|
||||||
|
|
||||||
// String representation for debugging
|
// String representation for debugging
|
||||||
func (s *Symbol) String() string {
|
func (s *Symbol) String() string {
|
||||||
var parts []string
|
var parts []string
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue