main.go (3084B)
1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "os" 9 "strconv" 10 "strings" 11 12 "github.com/alecthomas/participle/v2" 13 "github.com/alecthomas/participle/v2/lexer" 14 15 "git.defalsify.org/vise.git/asm" 16 ) 17 18 type arg struct { 19 One *string `(@Sym | @NumFirst)` 20 Two *string `((@Sym | @NumFirst) Whitespace?)?` 21 Three *string `((@Sym | @NumFirst) Whitespace?)?` 22 } 23 24 type instruction struct { 25 OpCode string `@Ident` 26 OpArg arg `(Whitespace @@)?` 27 Comment string `Comment? EOL` 28 } 29 30 type asmAsm struct { 31 Instructions []*instruction `@@*` 32 } 33 34 type processor struct { 35 *asm.FlagParser 36 } 37 38 func newProcessor(fp string) (*processor, error) { 39 o := &processor{ 40 asm.NewFlagParser(), 41 } 42 _, err := o.Load(fp) 43 return o, err 44 } 45 46 func (p *processor) processFlag(s []string, one *string, two *string) ([]string, error) { 47 _, err := strconv.Atoi(*one) 48 if err != nil { 49 r, err := p.GetAsString(*one) 50 if err != nil { 51 return nil, err 52 } 53 log.Printf("translated flag %s to %s", *one, r) 54 s = append(s, r) 55 } else { 56 s = append(s, *one) 57 } 58 return append(s, *two), nil 59 } 60 61 func (p *processor) pass(s []string, a arg) []string { 62 for _, r := range []*string{a.One, a.Two, a.Three} { 63 if r == nil { 64 break 65 } 66 s = append(s, *r) 67 } 68 return s 69 } 70 71 func (pp *processor) run(b []byte) ([]byte, error) { 72 asmLexer := lexer.MustSimple([]lexer.SimpleRule{ 73 {"Comment", `(?:#)[^\n]*`}, 74 {"Ident", `^[A-Z]+`}, 75 {"NumFirst", `[0-9][a-zA-Z0-9]*`}, 76 {"Sym", `[a-zA-Z_\*\.\^\<\>][a-zA-Z0-9_]*`}, 77 {"Whitespace", `[ \t]+`}, 78 {"EOL", `[\n\r]+`}, 79 {"Quote", `["']`}, 80 }) 81 asmParser := participle.MustBuild[asmAsm]( 82 participle.Lexer(asmLexer), 83 participle.Elide("Comment", "Whitespace"), 84 ) 85 ast, err := asmParser.ParseString("preprocessor", string(b)) 86 if err != nil { 87 return nil, err 88 } 89 90 b = []byte{} 91 for _, v := range ast.Instructions { 92 s := []string{v.OpCode} 93 if v.OpArg.One != nil { 94 switch v.OpCode { 95 case "CATCH": 96 s = append(s, *v.OpArg.One) 97 s, err = pp.processFlag(s, v.OpArg.Two, v.OpArg.Three) 98 if err != nil { 99 return nil, err 100 } 101 case "CROAK": 102 s, err = pp.processFlag(s, v.OpArg.One, v.OpArg.Two) 103 if err != nil { 104 return nil, err 105 } 106 default: 107 s = pp.pass(s, v.OpArg) 108 } 109 } 110 b = append(b, []byte(strings.Join(s, " "))...) 111 b = append(b, 0x0a) 112 } 113 114 return b, nil 115 } 116 117 func main() { 118 var ppfp string 119 flag.StringVar(&ppfp, "f", "", "preprocessor data to load") 120 flag.Parse() 121 if len(flag.Args()) < 1 { 122 os.Exit(1) 123 } 124 fp := flag.Arg(0) 125 v, err := ioutil.ReadFile(fp) 126 if err != nil { 127 fmt.Fprintf(os.Stderr, "read error: %v\n", err) 128 os.Exit(1) 129 } 130 131 if len(ppfp) > 0 { 132 pp, err := newProcessor(ppfp) 133 if err != nil { 134 fmt.Fprintf(os.Stderr, "preprocessor load error: %v\n", err) 135 os.Exit(1) 136 } 137 138 v, err = pp.run(v) 139 if err != nil { 140 fmt.Fprintf(os.Stderr, "preprocess error: %v\n", err) 141 os.Exit(1) 142 } 143 } 144 log.Printf("preprocessor done") 145 146 n, err := asm.Parse(string(v), os.Stdout) 147 if err != nil { 148 fmt.Fprintf(os.Stderr, "parse error: %v\n", err) 149 os.Exit(1) 150 } 151 log.Printf("parsed total %v bytes", n) 152 }