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
|
||||
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
|
||||
return c.assembleOutput(codeOutput), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,8 +130,8 @@ func (fh *FunctionHandler) HandleFuncDecl(line preproc.Line) ([]string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Look up variable in symbol table
|
||||
sym := fh.symTable.Lookup(varName, []string{funcName})
|
||||
// Look up variable in symbol table (validation only, not usage)
|
||||
sym := fh.symTable.LookupWithoutUsage(varName, []string{funcName})
|
||||
if sym == nil {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ const (
|
|||
FlagLabelRef
|
||||
)
|
||||
|
||||
// Usage tracking for variables
|
||||
const (
|
||||
UsageNone uint8 = iota
|
||||
UsageUsed
|
||||
)
|
||||
|
||||
// Symbol represents a variable or constant declaration
|
||||
type Symbol struct {
|
||||
Name string
|
||||
|
|
@ -34,6 +40,7 @@ type Symbol struct {
|
|||
Value uint16 // init value or const value
|
||||
AbsAddr uint16 // if FlagAbsolute set
|
||||
LabelRef string // if FlagLabelRef set
|
||||
Usage uint8 // tracks variable usage (see Usage constants)
|
||||
}
|
||||
|
||||
// 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) 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)
|
||||
func (s *Symbol) FullName() string {
|
||||
if s.Scope == "" {
|
||||
|
|
@ -208,12 +220,17 @@ func (st *SymbolTable) add(sym *Symbol) error {
|
|||
|
||||
// Lookup finds a symbol by name, resolving scope
|
||||
// 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 {
|
||||
// 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 {
|
||||
// Mark as used if it's a regular variable (not constant, not absolute)
|
||||
if !sym.IsConst() && !sym.IsAbsolute() {
|
||||
sym.MarkUsed()
|
||||
}
|
||||
return sym
|
||||
}
|
||||
}
|
||||
|
|
@ -222,6 +239,10 @@ func (st *SymbolTable) Lookup(name string, currentScopes []string) *Symbol {
|
|||
// Try global scope
|
||||
if scopeMap, ok := st.byScope[""]; 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
|
||||
}
|
||||
}
|
||||
|
|
@ -253,10 +274,33 @@ func (st *SymbolTable) ExpandName(name string, currentScopes []string) string {
|
|||
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
|
||||
// Returns (value, true) if symbol exists and is a constant, (0, false) otherwise
|
||||
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() {
|
||||
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
|
||||
func (s *Symbol) String() string {
|
||||
var parts []string
|
||||
|
|
|
|||
Loading…
Reference in a new issue