package main import ( "c65gm/internal/preproc" "flag" "fmt" "os" "strings" ) // c65cm - A 6502 Cross-Compiler for the ACME Cross-Assembler // Copyright (C) 1999, 2025 Mattias Hansson // Distributed under GPL. External library github.com/armon/go-radix under MIT. // Package-level shared state accessible by other compilation units var ( /* VarList *VarList WhileStack *LabelStack WendStack *LabelStack IfStack *LabelStack GeneralStack *LabelStack FuncList *FunctionHandler ConstStrHandler *ConstantStringHandler Pragmas []string */ ) type ShowMode int const ( ShowNone ShowMode = iota ShowLineCount ShowLineView ) func main() { fmt.Println("c65cm - A 6502 Cross-Compiler for the ACME Cross-Assembler.") fmt.Println("Copyright (C) 1999, 2025 Mattias Hansson. v0.7") fmt.Println("Distributed under GPL. External library github.com/armon/go-radix under MIT.") fmt.Println() inFile := flag.String("in", "", "input source file (required)") outFile := flag.String("out", "", "output assembly file (required)") view := flag.String("view", "lines", "output mode: none, count, lines") flag.Parse() if *inFile == "" || *outFile == "" { fmt.Fprintln(os.Stderr, "Error: -in and -out are required") flag.Usage() os.Exit(1) } var showMode ShowMode switch strings.ToLower(*view) { case "none": showMode = ShowNone case "count": showMode = ShowLineCount case "lines": showMode = ShowLineView default: fmt.Fprintf(os.Stderr, "Error: invalid view mode: %s\n", *view) os.Exit(1) } if err := run(*inFile, *outFile, showMode); err != nil { if _, ok := err.(preproc.HaltError); ok { os.Exit(0) } fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } } func run(inFile, outFile string, showMode ShowMode) error { initSharedObjects() return compile(inFile, outFile, showMode) } func initSharedObjects() { /* VarList = NewVarList() WhileStack = NewLabelStack("whilelbl") WendStack = NewLabelStack("wendlbl") IfStack = NewLabelStack("iflbl") GeneralStack = NewLabelStack("General") FuncList = NewFunctionHandler() ConstStrHandler = NewConstantStringHandler() Pragmas = make([]string, 0) */ } func compile(inFile, outFile string, showMode ShowMode) error { lines, err := preproc.PreProcess(inFile) if err != nil { return fmt.Errorf("preprocessor failed: %w", err) } asmSource := make([]string, 0, len(lines)*2) lineCount := 0 for i := 0; i < len(lines); { line := lines[i] lineCount++ displayProgress(showMode, lineCount, line.Text) // Handle inline ASM blocks if isAsmStart(line) { asmSource = append(asmSource, ";"+line.Text) i++ for i < len(lines) && !isAsmEnd(lines[i]) { lineCount++ displayProgress(showMode, lineCount, lines[i].Text) if lines[i].Text != "" { //processed := LocalVarsInAsmLine(lines[i].Text) processed := lines[i].Text asmSource = append(asmSource, processed) } i++ } i++ // Skip ENDASM line continue } if isAsmEnd(line) { i++ continue } text := stripComments(line.Text) if text == "" { i++ continue } /* if !InterpretLine(text, &asmSource) { return fmt.Errorf("line not recognized: %s", text) } */ i++ } /* VarList.WriteDownTypesToAsm(&asmSource) ConstStrHandler.GenerateConstStrDecls(&asmSource) VarList.WriteAbsVars(&asmSource) VarList.WriteConstants(&asmSource) */ if err := writeLines(outFile, asmSource); err != nil { return fmt.Errorf("failed to write output: %w", err) } if showMode != ShowNone { fmt.Println("\ndone.") } return nil } func displayProgress(mode ShowMode, lineCount int, text string) { switch mode { case ShowLineCount: fmt.Printf("\rCompiling line: %d", lineCount) case ShowLineView: fmt.Println(text) } } func isAsmStart(line preproc.Line) bool { //return len(line.Tokens) == 1 && strings.ToUpper(line.Tokens[0]) == "ASM" return false } func isAsmEnd(line preproc.Line) bool { //return len(line.Tokens) == 1 && strings.ToUpper(line.Tokens[0]) == "ENDASM" return false } func stripComments(s string) string { if strings.HasPrefix(s, "//") { return "" } if idx := strings.Index(s, "//"); idx >= 0 { return strings.TrimSpace(s[:idx]) } return s } func writeLines(filename string, lines []string) error { f, err := os.Create(filename) if err != nil { return err } defer f.Close() for _, line := range lines { if _, err := fmt.Fprintln(f, line); err != nil { return err } } return nil }