...
1
2
3
4
5 package xeddata
6
7 import (
8 "bufio"
9 "errors"
10 "fmt"
11 "io"
12 "regexp"
13 "strings"
14 )
15
16
17 type Reader struct {
18 scanner *bufio.Scanner
19
20 lines []string
21
22
23 joinLines bool
24 }
25
26
27 func NewReader(r io.Reader) *Reader {
28 return newReader(bufio.NewScanner(r))
29 }
30
31 func newReader(scanner *bufio.Scanner) *Reader {
32 r := &Reader{
33 lines: make([]string, 0, 64),
34 scanner: scanner,
35 }
36 scanner.Split(r.split)
37 return r
38 }
39
40
41 func (r *Reader) split(data []byte, atEOF bool) (int, []byte, error) {
42
43
44 advance, tok, err := bufio.ScanLines(data, atEOF)
45 if err == nil && len(tok) >= 1 {
46 r.joinLines = tok[len(tok)-1] == '\\'
47 }
48 return advance, tok, err
49 }
50
51
52
53
54
55
56 func (r *Reader) Read() (*Object, error) {
57 for line := r.scanLine(); line != ""; line = r.scanLine() {
58 if line[0] != '{' {
59 continue
60 }
61 lines := r.lines[:0]
62 for line := r.scanLine(); line != ""; line = r.scanLine() {
63 if line[0] == '}' {
64 return r.parseLines(lines)
65 }
66 lines = append(lines, line)
67 }
68 return nil, errors.New("no matching '}' found")
69 }
70
71 return nil, io.EOF
72 }
73
74
75
76
77 func (r *Reader) ReadAll() ([]*Object, error) {
78 objects := []*Object{}
79 for {
80 o, err := r.Read()
81 if err == io.EOF {
82 return objects, nil
83 }
84 if err != nil {
85 return objects, err
86 }
87 objects = append(objects, o)
88 }
89 }
90
91
92
93
94
95
96
97
98
99
100 var instLineRE = regexp.MustCompile(`^([A-Z_]+)\s*:\s*([^#]*)`)
101
102
103 func (r *Reader) parseLines(lines []string) (*Object, error) {
104 o := &Object{}
105
106
107
108
109 var (
110 operands []string
111 iforms []string
112 patterns []string
113 )
114
115 for _, l := range lines {
116 if l[0] == '#' {
117 continue
118 }
119 m := instLineRE.FindStringSubmatch(l)
120 if len(m) == 0 {
121 return nil, fmt.Errorf("malformed line: %s", l)
122 }
123 key, val := m[1], m[2]
124 val = strings.TrimSpace(val)
125
126 switch key {
127 case "ICLASS":
128 o.Iclass = val
129 case "DISASM":
130 o.Disasm = val
131 case "DISASM_INTEL":
132 o.DisasmIntel = val
133 case "DISASM_ATTSV":
134 o.DisasmATTSV = val
135 case "ATTRIBUTES":
136 o.Attributes = val
137 case "UNAME":
138 o.Uname = val
139 case "CPL":
140 o.CPL = val
141 case "CATEGORY":
142 o.Category = val
143 case "EXTENSION":
144 o.Extension = val
145 case "EXCEPTIONS":
146 o.Exceptions = val
147 case "ISA_SET":
148 o.ISASet = val
149 case "FLAGS":
150 o.Flags = val
151 case "COMMENT":
152 o.Comment = val
153 case "VERSION":
154 o.Version = val
155 case "REAL_OPCODE":
156 o.RealOpcode = val
157
158 case "OPERANDS":
159 operands = append(operands, val)
160 case "PATTERN":
161 patterns = append(patterns, val)
162 case "IFORM":
163 iforms = append(iforms, val)
164
165 default:
166
167
168
169 return nil, fmt.Errorf("unknown key token: %s", key)
170 }
171 }
172
173 if len(operands) != len(patterns) {
174 return nil, fmt.Errorf("%s: OPERANDS and PATTERN lines mismatch", o.Opcode())
175 }
176
177 insts := make([]*Inst, len(operands))
178 for i := range operands {
179 insts[i] = &Inst{
180 Object: o,
181 Index: i,
182 Pattern: patterns[i],
183 Operands: operands[i],
184 }
185
186 if i < len(iforms) {
187 insts[i].Iform = iforms[i]
188 }
189 }
190 o.Insts = insts
191
192 return o, nil
193 }
194
195
196
197
198
199 func (r *Reader) scanLine() string {
200 for r.scanner.Scan() {
201 line := r.scanner.Text()
202 if line == "" {
203 continue
204 }
205 if r.joinLines {
206 return line[:len(line)-len("\\")] + r.scanLine()
207 }
208 return line
209 }
210 return ""
211 }
212
View as plain text