First main.go driver with only the BYTE command finished.

This commit is contained in:
Mattias Hansson 2025-11-01 18:55:48 +01:00
parent 89d8493192
commit ff64cc6b93
2 changed files with 46 additions and 207 deletions

View file

@ -31,7 +31,7 @@ func (HaltError) Error() string { return "preprocessor HALT" }
// PreProcess processes the given root source file and returns the flattened, define-expanded // PreProcess processes the given root source file and returns the flattened, define-expanded
// lines. Directive lines are not emitted. // lines. Directive lines are not emitted.
func PreProcess(rootFilename string, reader ...FileReader) ([]Line, error) { func PreProcess(rootFilename string, reader ...FileReader) ([]Line, *Pragma, error) {
var r FileReader var r FileReader
if len(reader) > 0 && reader[0] != nil { if len(reader) > 0 && reader[0] != nil {
r = reader[0] r = reader[0]
@ -39,7 +39,8 @@ func PreProcess(rootFilename string, reader ...FileReader) ([]Line, error) {
r = NewDiskFileReader() r = NewDiskFileReader()
} }
pp := newPreproc(r) pp := newPreproc(r)
return pp.run(rootFilename) lines, err := pp.run(rootFilename)
return lines, pp.pragma, err
} }
// -------------------- internal -------------------- // -------------------- internal --------------------

248
main.go
View file

@ -1,253 +1,91 @@
package main package main
import ( import (
"c65gm/internal/preproc"
"c65gm/internal/utils"
"flag" "flag"
"fmt" "fmt"
"os" "os"
"strings" "strings"
"c65gm/internal/commands"
"c65gm/internal/compiler"
"c65gm/internal/preproc"
) )
// c65cm - A 6502 Cross-Compiler for the ACME Cross-Assembler // c65gm - A 6502 Cross-Compiler for the ACME Cross-Assembler
// Copyright (C) 1999, 2025 Mattias Hansson // Copyright (C) 1999, 2025 Mattias Hansson
// Distributed under GPL. External library github.com/armon/go-radix under MIT. // Distributed under GPL.
// 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 testMultiIndex() {
type User struct {
ID string
FirstName string
LastName string
Email string
}
// 2 indexes: [0]=email only, [1]=firstname+lastname
idx := utils.NewMultiIndex[User](2)
idx.AddItem(User{"1", "John", "Doe", "john@example.com"}, [][]string{
{"john@example.com"},
{"john", "doe"},
})
idx.AddItem(User{"2", "Jane", "Smith", "jane@example.com"}, [][]string{
{"jane@example.com"},
{"jane", "smith"},
})
// Search by email (index 0, single string)
user, found := idx.FindItem(0, []string{"john@example.com"})
fmt.Println(user, found) // {1 John Doe john@example.com} true
// Search by name (index 1, two strings)
user, found = idx.FindItem(1, []string{"jane", "smith"})
fmt.Println(user, found) // {2 Jane Smith jane@example.com} true
// Wrong composite key fails
user, found = idx.FindItem(1, []string{"jane", "doe"})
fmt.Println(found) // false
// All items
fmt.Println(idx.Items()) // [{1 John Doe john@example.com} {2 Jane Smith jane@example.com}]
}
func main() { func main() {
testMultiIndex()
os.Exit(1)
fmt.Println("c65gm - A 6502 Cross-Compiler for the ACME Cross-Assembler.") fmt.Println("c65gm - A 6502 Cross-Compiler for the ACME Cross-Assembler.")
fmt.Println("Copyright (C) 1999, 2025 Mattias Hansson. v1.0.0") fmt.Println("Copyright (C) 1999, 2025 Mattias Hansson. v1.0.0")
fmt.Println("Distributed under GPL. External library github.com/armon/go-radix under MIT.") fmt.Println("Distributed under GPL.")
fmt.Println() fmt.Println()
inFile := flag.String("in", "", "input source file (required)") inFile := flag.String("in", "", "input source file (required)")
outFile := flag.String("out", "", "output assembly file (required)") outFile := flag.String("out", "", "output assembly file (required)")
view := flag.String("view", "lines", "output mode: none, count, lines")
flag.Parse() flag.Parse()
if *inFile == "" || *outFile == "" { if *inFile == "" || *outFile == "" {
fmt.Fprintln(os.Stderr, "Error: -in and -out are required") _, _ = fmt.Fprintln(os.Stderr, "Error: -in and -out are required")
flag.Usage() flag.Usage()
os.Exit(1) os.Exit(1)
} }
var showMode ShowMode if err := run(*inFile, *outFile); err != nil {
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 { if _, ok := err.(preproc.HaltError); ok {
os.Exit(0) fmt.Println("Halted by #HALT directive")
os.Exit(2)
} }
fmt.Fprintf(os.Stderr, "Error: %v\n", err) _, _ = fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1) os.Exit(1)
} }
fmt.Println("Compilation successful.")
} }
func run(inFile, outFile string, showMode ShowMode) error { func run(inFile, outFile string) error {
initSharedObjects() // Preprocess
return compile(inFile, outFile, showMode) lines, pragma, err := preproc.PreProcess(inFile)
}
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 { if err != nil {
return fmt.Errorf("preprocessor failed: %w", err) return fmt.Errorf("preprocessing failed: %w", err)
} }
asmSource := make([]string, 0, len(lines)*2) fmt.Printf("Preprocessed %d lines\n", len(lines))
lineCount := 0
for i := 0; i < len(lines); { // Create compiler and register commands
line := lines[i] comp := compiler.NewCompiler(pragma)
lineCount++ registerCommands(comp)
displayProgress(showMode, lineCount, line.Text) // Compile
asmLines, err := comp.Compile(lines)
// Handle inline ASM blocks if err != nil {
if isAsmStart(line) { return fmt.Errorf("compilation failed: %w", err)
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++
} }
/* fmt.Printf("Generated %d lines of assembly\n", len(asmLines))
VarList.WriteDownTypesToAsm(&asmSource)
ConstStrHandler.GenerateConstStrDecls(&asmSource)
VarList.WriteAbsVars(&asmSource)
VarList.WriteConstants(&asmSource)
*/
if err := writeLines(outFile, asmSource); err != nil { // Write output
if err := writeOutput(outFile, asmLines); err != nil {
return fmt.Errorf("failed to write output: %w", err) return fmt.Errorf("failed to write output: %w", err)
} }
if showMode != ShowNone {
fmt.Println("\ndone.")
}
return nil return nil
} }
func displayProgress(mode ShowMode, lineCount int, text string) { func registerCommands(comp *compiler.Compiler) {
switch mode { // Register all command handlers here
case ShowLineCount: // This is the single place where all commands are wired up
fmt.Printf("\rCompiling line: %d", lineCount)
case ShowLineView: comp.Registry().Register(&commands.ByteCommand{})
fmt.Println(text)
} // TODO: Add more commands as they're implemented:
// comp.Registry().Register(&commands.WordCommand{})
// comp.Registry().Register(&commands.LetCommand{})
// comp.Registry().Register(&commands.IfCommand{})
// comp.Registry().Register(&commands.WhileCommand{})
// etc.
} }
func isAsmStart(line preproc.Line) bool { func writeOutput(filename string, lines []string) error {
//return len(line.Tokens) == 1 && strings.ToUpper(line.Tokens[0]) == "ASM" return os.WriteFile(filename, []byte(strings.Join(lines, "\n")+"\n"), 0644)
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
} }