golang.org/x/arch@v0.17.0/s390x/s390xspec/spec.go (about) 1 // Copyright 2024 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // S390xspec reads the Principles of Operation PDF Manual 6 // to collect instruction encoding details and writes those details to standard output 7 // in CSV format. 8 // 9 // Usage: 10 // 11 // s390xspec z_Architecture_Principles_of_Operation.pdf > s390x.csv 12 // 13 // Each CSV line contains three fields: 14 // 15 // instruction 16 // The instruction heading, such as "BRANCH AND LINK". 17 // mnemonic 18 // The instruction mnemonics, such as "BAL R1,D2(X2,B2)". 19 // encoding 20 // The instruction encoding, a sequence of opcode and operands encoding in respective bit positions 21 // such as operand@bitposition each separated by | 22 // Ex: "45@0|R1@8|X2@12|B2@16|D2@20|" 23 // 24 // For more on the exact meaning of these fields, see the Principle of Operations IBM-Z Architecture PDF Manual. 25 package main 26 27 import ( 28 "bufio" 29 "fmt" 30 "log" 31 "math" 32 "os" 33 "sort" 34 "strconv" 35 "strings" 36 37 "rsc.io/pdf" 38 ) 39 40 type Inst struct { 41 Name string 42 Text string 43 Enc string 44 Flags string 45 } 46 47 var stdout *bufio.Writer 48 49 func main() { 50 log.SetFlags(0) 51 log.SetPrefix("s390xspec: ") 52 53 if len(os.Args) != 2 { 54 fmt.Fprintf(os.Stderr, "usage: s390xspec file.pdf\n") 55 os.Exit(2) 56 } 57 58 f, err := pdf.Open(os.Args[1]) 59 if err != nil { 60 log.Fatal(err) 61 } 62 63 // Split across multiple columns and pages! 64 var all = []Inst{} 65 66 // Scan document looking for instructions. 67 // Must find exactly the ones in the outline. 68 n := f.NumPage() 69 for pageNum := 1; pageNum <= n; pageNum++ { 70 page := f.Page(pageNum) 71 t1 := getPageContent(page) 72 if len(t1) > 0 && match(t1[0], "Helvetica-Bold", 13.98, "Instructions Arranged by Name") { 73 for n := pageNum; n < pageNum+24; n++ { 74 page := f.Page(n) 75 table := parsePage(n, page) 76 all = append(all, table...) 77 } 78 break 79 } else { 80 continue 81 } 82 } 83 stdout = bufio.NewWriter(os.Stdout) 84 for _, inst := range all { 85 if strings.Contains(inst.Name, "\x00I") { 86 r := rune(0x2190) 87 inst.Name = strings.Replace(inst.Name, "\x00I", string(r), -1) 88 } else if strings.Contains(inst.Name, "I\x00") { 89 r := rune(0x2192) 90 inst.Name = strings.Replace(inst.Name, "I\x00", string(r), -1) 91 } 92 fmt.Fprintf(stdout, "%q,%q,%q,%q\n", inst.Name, inst.Text, inst.Enc, inst.Flags) 93 } 94 stdout.Flush() 95 96 } 97 98 // getPageContent gets the page content of a single PDF page 99 func getPageContent(p pdf.Page) []pdf.Text { 100 var text []pdf.Text 101 102 content := p.Content() 103 for _, t := range content.Text { 104 text = append(text, t) 105 } 106 107 text = findWords(text) 108 return text 109 } 110 111 // parsePage parses single PDF page and returns the instructions content 112 func parsePage(num int, p pdf.Page) []Inst { 113 var insts []Inst 114 text := getPageContent(p) 115 116 for { 117 var heading, mnemonic, format string 118 // The float numbers below are the horizontal X-coordinate values to be parsed out of the Z-ISA PDF book. 119 for len(text) > 0 && !(match(text[0], "Helvetica-Narrow", 8, "") && (matchXCord(text[0], 73.9) || matchXCord(text[0], 55.9))) { 120 text = text[1:] 121 } 122 if len(text) == 0 { 123 break 124 } 125 heading = text[0].S 126 text = text[1:] 127 // The float numbers below are the horizontal X-coordinate values to be parsed out of the Z-ISA PDF book. 128 for !(matchXCord(text[0], 212.2) || matchXCord(text[0], 230.1) || matchXCord(text[0], 246.2) || matchXCord(text[0], 264.2)) { 129 heading += text[0].S 130 if match(text[0], "Wingdings3", 0, "") { 131 heading += text[1].S 132 text = text[1:] 133 } 134 text = text[1:] 135 } 136 if strings.Compare(heading, "DIAGNOSE") == 0 { 137 text = text[1:] 138 continue 139 } 140 heading, check, m := checkHeading(heading) 141 if check { 142 mnemonic = m 143 } else { 144 mnemonic = text[0].S 145 text = text[1:] 146 } 147 index := strings.Index(mnemonic, " ") 148 if index != -1 { 149 format = mnemonic[index+1:] 150 mnemonic = mnemonic[:index] 151 } else { 152 format = text[0].S 153 } 154 text = text[1:] 155 if strings.Compare(format, "SS") == 0 { 156 format += text[0].S 157 } 158 before, _, _ := strings.Cut(format, " ") 159 format = before 160 // The float numbers below are the horizontal X-coordinate values to be parsed out of the Z-ISA PDF book. 161 for len(text) > 0 && !(match(text[0], "Helvetica-Narrow", 8, "") && (matchXCord(text[0], 350.82) || matchXCord(text[0], 363.84) || matchXCord(text[0], 332.82) || matchXCord(text[0], 345.84))) { 162 if text[0].X > 405.48 { 163 break 164 } 165 text = text[1:] 166 } 167 flags := text[0].S 168 // The float numbers below are the horizontal X-coordinate values to be parsed out of the Z-ISA PDF book. 169 for len(text) > 0 && !(match(text[0], "Helvetica-Narrow", 8, "") && ((matchXCord(text[0], 481.7) && (!matchXCord(text[1], 496.1))) || matchXCord(text[0], 496.1) || (matchXCord(text[0], 499.6) && (!matchXCord(text[1], 514))) || (matchXCord(text[0], 514)))) { 170 text = text[1:] 171 } 172 if len(text) == 0 { 173 break 174 } 175 opcode := text[0].S 176 b1, b2, _ := strings.Cut(opcode, " ") 177 if matchXCord(text[0], 481.7) || matchXCord(text[0], 499.6) { 178 opcode = b2 179 } else { 180 opcode = b1 181 } 182 if strings.Compare(text[0].S, b1) == 0 { 183 text = text[2:] 184 } else { 185 text = text[1:] 186 } 187 mnemonic1, encoding := frameMnemonic(mnemonic, format, opcode) 188 for match(text[0], "Helvetica-Narrow", 5.1, "") { 189 text = text[1:] 190 } 191 if match(text[0], "Helvetica-Oblique", 9, "") { 192 text = text[2:] 193 insts = append(insts, Inst{heading, mnemonic1, encoding, flags}) 194 continue 195 } 196 if strings.HasPrefix(text[0].S, "(") { 197 y123 := text[0].Y 198 for text[0].Y == y123 && !matchXCord(text[0], 5.1) { 199 heading += text[0].S 200 text = text[1:] 201 } 202 } else if !(math.Abs(text[0].Y-text[1].Y) < 0.3) { 203 heading += " " + text[0].S 204 text = text[1:] 205 } 206 insts = append(insts, Inst{heading, mnemonic1, encoding, flags}) 207 if match(text[0], "Helvetica-Oblique", 9, "") { 208 break 209 } 210 } 211 return insts 212 } 213 214 func checkHeading(heading string) (string, bool, string) { 215 substr := []string{"ALSI", "ALGSI", "CHRL", "CGHRL", "CUXTR", "IEXTR", "RXSBG", "RISBLG", "VERIM", "VPSOP"} 216 b := false 217 for _, s := range substr { 218 r1 := strings.Index(heading, s) 219 if r1 != -1 { 220 heading = heading[:r1-1] 221 b = true 222 return heading, b, s 223 } 224 } 225 return heading, b, "" 226 } 227 228 func frameMnemonic(mnemonic, format, opcode string) (string, string) { 229 230 var mn, enc string 231 232 switch format { 233 case "E": 234 mn, enc = mnemonic_E(mnemonic, opcode) 235 case "I": 236 mn, enc = mnemonic_I(mnemonic, opcode) 237 case "IE": 238 mn, enc = mnemonic_IE(mnemonic, opcode) 239 case "MII": 240 mn, enc = mnemonic_MII(mnemonic, opcode) 241 case "RI-a", "RI-b", "RI-c": 242 mn, enc = mnemonic_RI(mnemonic, format, opcode) 243 case "RIE-a", "RIE-b", "RIE-c", "RIE-d", "RIE-e", "RIE-f", "RIE-g": 244 mn, enc = mnemonic_RIE(mnemonic, format, opcode) 245 case "RIL-a", "RIL-b", "RIL-c": 246 mn, enc = mnemonic_RIL(mnemonic, format, opcode) 247 case "RIS": 248 mn, enc = mnemonic_RIS(mnemonic, opcode) 249 case "RR": 250 mn, enc = mnemonic_RR(mnemonic, opcode) 251 case "RRD": 252 mn, enc = mnemonic_RRD(mnemonic, opcode) 253 case "RRE": 254 mn, enc = mnemonic_RRE(mnemonic, opcode) 255 case "RRF-a", "RRF-b", "RRF-c", "RRF-d", "RRF-e": 256 mn, enc = mnemonic_RRF(mnemonic, format, opcode) 257 case "RRS": 258 mn, enc = mnemonic_RRS(mnemonic, opcode) 259 case "RS-a", "RS-b": 260 mn, enc = mnemonic_RS(mnemonic, format, opcode) 261 case "RSI": 262 mn, enc = mnemonic_RSI(mnemonic, opcode) 263 case "RSL-a", "RSL-b": 264 mn, enc = mnemonic_RSL(mnemonic, format, opcode) 265 case "RSY-a", "RSY-b": 266 mn, enc = mnemonic_RSY(mnemonic, format, opcode) 267 case "RX-a", "RX-b": 268 mn, enc = mnemonic_RX(mnemonic, format, opcode) 269 case "RXE": 270 mn, enc = mnemonic_RXE(mnemonic, opcode) 271 case "RXF": 272 mn, enc = mnemonic_RXF(mnemonic, opcode) 273 case "RXY-a", "RXY-b": 274 mn, enc = mnemonic_RXY(mnemonic, format, opcode) 275 case "S": 276 mn, enc = mnemonic_S(mnemonic, opcode) 277 case "SI": 278 mn, enc = mnemonic_SI(mnemonic, opcode) 279 case "SIL": 280 mn, enc = mnemonic_SIL(mnemonic, opcode) 281 case "SIY": 282 mn, enc = mnemonic_SIY(mnemonic, opcode) 283 case "SMI": 284 mn, enc = mnemonic_SMI(mnemonic, opcode) 285 case "SS-a", "SS-b", "SS-c", "SS-d", "SS-e", "SS-f": 286 mn, enc = mnemonic_SS(mnemonic, format, opcode) 287 case "SSE": 288 mn, enc = mnemonic_SSE(mnemonic, opcode) 289 case "SSF": 290 mn, enc = mnemonic_SSF(mnemonic, opcode) 291 case "VRI-a", "VRI-b", "VRI-c", "VRI-d", "VRI-e", "VRI-f", "VRI-g", "VRI-h", "VRI-i": 292 mn, enc = mnemonic_VRI(mnemonic, format, opcode) 293 case "VRR-a", "VRR-b", "VRR-c", "VRR-d", "VRR-e", "VRR-f", "VRR-g", "VRR-h", "VRR-i", "VRR-j", "VRR-k": 294 mn, enc = mnemonic_VRR(mnemonic, format, opcode) 295 case "VRS-a", "VRS-b", "VRS-c", "VRS-d": 296 mn, enc = mnemonic_VRS(mnemonic, format, opcode) 297 case "VRV": 298 mn, enc = mnemonic_VRV(mnemonic, opcode) 299 case "VRX": 300 mn, enc = mnemonic_VRX(mnemonic, opcode) 301 case "VSI": 302 mn, enc = mnemonic_VSI(mnemonic, opcode) 303 default: 304 mn = mnemonic 305 } 306 return mn, enc 307 } 308 309 func mnemonic_E(mnemonic, opcode string) (string, string) { 310 var enc string 311 val, _ := strconv.ParseUint(opcode, 16, 16) 312 str := strconv.Itoa(int(val)) 313 enc = str + "@0|??@16" 314 return mnemonic, enc 315 } 316 317 func mnemonic_I(mnemonic, opcode string) (string, string) { 318 var enc string 319 mnemonic += " I" 320 val, _ := strconv.ParseUint(opcode, 16, 16) 321 str := strconv.Itoa(int(val)) 322 enc = str + "@0|I@8|??@16" 323 return mnemonic, enc 324 } 325 326 func mnemonic_IE(mnemonic, opcode string) (string, string) { 327 var enc string 328 mnemonic += " I1,I2" 329 val, _ := strconv.ParseUint(opcode, 16, 16) 330 str := strconv.Itoa(int(val)) 331 enc = str + "@0|//@16|I1@24|I2@28|??@32" 332 return mnemonic, enc 333 } 334 335 func mnemonic_MII(mnemonic, opcode string) (string, string) { 336 var enc string 337 mnemonic += " M1,RI2,RI3" 338 val, _ := strconv.ParseUint(opcode, 16, 16) 339 str := strconv.Itoa(int(val)) 340 enc = str + "@0|M1@8|RI2@12|RI3@24|??@48" 341 return mnemonic, enc 342 } 343 344 func mnemonic_RI(mnemonic, format, opcode string) (string, string) { 345 var enc string 346 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 347 str1 := strconv.Itoa(int(val1)) 348 val2, _ := strconv.ParseUint(opcode[2:3], 16, 16) 349 str2 := strconv.Itoa(int(val2)) 350 switch format { 351 case "RI-a": 352 mnemonic += " R1,I2" 353 enc = str1 + "@0|R1@8|" + str2 + "@12|I2@16|??@32" 354 case "RI-b": 355 mnemonic += " R1,RI2" 356 enc = str1 + "@0|R1@8|" + str2 + "@12|RI2@16|??@32" 357 case "RI-c": 358 mnemonic += " M1,RI2" 359 enc = str1 + "@0|M1@8|" + str2 + "@12|RI2@16|??@32" 360 } 361 return mnemonic, enc 362 } 363 364 func mnemonic_RIE(mnemonic, format, opcode string) (string, string) { 365 var enc string 366 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 367 str1 := strconv.Itoa(int(val1)) 368 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 369 str2 := strconv.Itoa(int(val2)) 370 switch format { 371 case "RIE-a": 372 mnemonic += " R1,I2,M3" 373 enc = str1 + "@0|R1@8|//@12|I2@16|M3@32|//@36|" + str2 + "@40|??@48" 374 case "RIE-b": 375 mnemonic += " R1,R2,M3,RI4" 376 enc = str1 + "@0|R1@8|R2@12|RI4@16|M3@32|//@36|" + str2 + "@40|??@48" 377 case "RIE-c": 378 mnemonic += " R1,I2,M3,RI4" 379 enc = str1 + "@0|R1@8|M3@12|RI4@16|I2@32|" + str2 + "@40|??@48" 380 case "RIE-d": 381 mnemonic += " R1,R3,I2" 382 enc = str1 + "@0|R1@8|R3@12|I2@16|//@32|" + str2 + "@40|??@48" 383 case "RIE-e": 384 mnemonic += " R1,R3,RI2" 385 enc = str1 + "@0|R1@8|R3@12|RI2@16|//@32|" + str2 + "@40|??@48" 386 case "RIE-f": 387 mnemonic += " R1,R2,I3,I4,I5" 388 enc = str1 + "@0|R1@8|R2@12|I3@16|I4@24|I5@32|" + str2 + "@40|??@48" 389 case "RIE-g": 390 mnemonic += " R1,I2,M3" 391 enc = str1 + "@0|R1@8|M3@12|I2@16|//@32|" + str2 + "@40|??@48" 392 } 393 return mnemonic, enc 394 } 395 396 func mnemonic_RIL(mnemonic, format, opcode string) (string, string) { 397 var enc string 398 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 399 str1 := strconv.Itoa(int(val1)) 400 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 401 str2 := strconv.Itoa(int(val2)) 402 switch format { 403 case "RIL-a": 404 mnemonic += " R1,I2" 405 enc = str1 + "@0|R1@8|" + str2 + "@12|I2@16|??@48" 406 case "RIL-b": 407 mnemonic += " R1,RI2" 408 enc = str1 + "@0|R1@8|" + str2 + "@12|RI2@16|??@48" 409 case "RIL-c": 410 mnemonic += " M1,RI2" 411 enc = str1 + "@0|M1@8|" + str2 + "@12|RI2@16|??@48" 412 } 413 return mnemonic, enc 414 } 415 416 func mnemonic_RIS(mnemonic, opcode string) (string, string) { 417 var enc string 418 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 419 str1 := strconv.Itoa(int(val1)) 420 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 421 str2 := strconv.Itoa(int(val2)) 422 mnemonic += " R1,I2,M3,D4(B4)" 423 enc = str1 + "@0|R1@8|M3@12|B4@16|D4@20|I2@32|" + str2 + "@40|??@48" 424 return mnemonic, enc 425 } 426 427 func mnemonic_RR(mnemonic, opcode string) (string, string) { 428 var enc string 429 val, _ := strconv.ParseUint(opcode, 16, 16) 430 str := strconv.Itoa(int(val)) 431 switch mnemonic { 432 case "BCR": 433 mnemonic += " M1,R2" 434 enc = str + "@0|M1@8|R2@12|??@16" 435 case "SPM": 436 mnemonic += " R1" 437 enc = str + "@0|R1@8|//@12|??@16" 438 default: 439 mnemonic += " R1,R2" 440 enc = str + "@0|R1@8|R2@12|??@16" 441 } 442 return mnemonic, enc 443 } 444 445 func mnemonic_RRD(mnemonic, opcode string) (string, string) { 446 var enc string 447 mnemonic += " R1,R3,R2" 448 val, _ := strconv.ParseUint(opcode, 16, 16) 449 str := strconv.Itoa(int(val)) 450 enc = str + "@0|R1@16|//@20|R3@24|R2@28|??@32" 451 return mnemonic, enc 452 } 453 454 func mnemonic_RRE(mnemonic, opcode string) (string, string) { 455 var enc string 456 val, _ := strconv.ParseUint(opcode, 16, 16) 457 str := strconv.Itoa(int(val)) 458 switch mnemonic { 459 case "LZER", "LZDR", "LZXR", "EFPC", "EPAR", "EPAIR", "ESEA", "ESAIR", "ESAR", "ETND", "IAC", "IPM", "MSTA", "PTF", "SFASR", "SFPC", "SSAR", "SSAIR": 460 mnemonic += " R1" 461 enc = str + "@0|//@16|R1@24|//@28|??@32" 462 case "NNPA", "PALB", "PCC", "PCKMO": 463 enc = str + "@0|//@16|??@32" 464 default: 465 mnemonic += " R1,R2" 466 enc = str + "@0|//@16|R1@24|R2@28|??@32" 467 } 468 return mnemonic, enc 469 } 470 471 func mnemonic_RRF(mnemonic, format, opcode string) (string, string) { 472 var enc string 473 val, _ := strconv.ParseUint(opcode, 16, 16) 474 str := strconv.Itoa(int(val)) 475 switch format { 476 case "RRF-a": 477 switch mnemonic { 478 case "SELR", "SELGR", "SELFHR", "IPTE", "AXTRA", "ADTRA", 479 "DDTRA", "DXTRA", "MDTRA", "MXTRA", "SDTRA", "SXTRA": 480 mnemonic += " R1,R2,R3,M4" 481 enc = str + "@0|R3@16|M4@20|R1@24|R2@28|??@32" 482 default: 483 mnemonic += " R1,R2,R3" 484 enc = str + "@0|R3@16|//@20|R1@24|R2@28|??@32" 485 } 486 case "RRF-b": 487 switch mnemonic { 488 case "CRDTE", "IDTE", "LPTEA", "RDP", "DIEBR", "DIDBR", 489 "QADTR", "QAXTR", "RRDTR", "RRXTR": 490 mnemonic += " R1,R3,R2,M4" 491 enc = str + "@0|R3@16|M4@20|R1@24|R2@28|??@32" 492 default: 493 mnemonic += " R1,R3,R2" 494 enc = str + "@0|R3@16|//@20|R1@24|R2@28|??@32" 495 } 496 case "RRF-c": 497 mnemonic += " R1,R2,M3" 498 enc = str + "@0|M3@16|//@20|R1@24|R2@28|??@32" 499 case "RRF-d": 500 mnemonic += " R1,R2,M4" 501 enc = str + "@0|//@16|M4@20|R1@24|R2@28|??@32" 502 case "RRF-e": 503 switch mnemonic { 504 case "CXFBRA", "CXFTR", "CDFBRA", "CDFTR", "CEFBRA", "CXGBRA", "CXGTRA", "CDGBRA", "CDGTRA", "CEGBRA", "CXLFBR", "CXLFTR", "CDLFBR", "CDLFTR", "CELFBR", 505 "CXLGBR", "CXLGTR", "CDLGBR", "CDLGTR", "CELGBR", "CFXBRA", "CGXBRA", "CFXTR", "CGXTRA", "CFDBRA", "CGDBRA", "CFDTR", "CGDTRA", "CFEBRA", "CGEBRA", 506 "CLFEBR", "CLFDBR", "CLFXBR", "CLGEBR", "CLGDBR", "CLGXBR", "CLFXTR", "CLFDTR", "CLGXTR", "CLGDTR", "FIEBRA", "FIDBRA", "FIXBRA", "FIDTR", "FIXTR", 507 "LDXBRA", "LEDBRA", "LEXBRA", "LEDTR", "LDXTR": 508 mnemonic += " R1,M3,R2,M4" 509 enc = str + "@0|M3@16|M4@20|R1@24|R2@28|??@32" 510 default: 511 mnemonic += " R1,M3,R2" 512 enc = str + "@0|M3@16|//@20|R1@24|R2@28|??@32" 513 } 514 } 515 return mnemonic, enc 516 } 517 518 func mnemonic_RRS(mnemonic, opcode string) (string, string) { 519 var enc string 520 mnemonic += " R1,R2,M3,D4(B4)" 521 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 522 str1 := strconv.Itoa(int(val1)) 523 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 524 str2 := strconv.Itoa(int(val2)) 525 enc = str1 + "@0|R1@8|R2@12|B4@16|D4@20|M3@32|//@36|" + str2 + "@40|??@48" 526 return mnemonic, enc 527 } 528 529 func mnemonic_RS(mnemonic, format, opcode string) (string, string) { 530 var enc string 531 val, _ := strconv.ParseUint(opcode, 16, 16) 532 str := strconv.Itoa(int(val)) 533 switch format { 534 case "RS-a": 535 switch mnemonic { 536 case "SLDA", "SLDL", "SLA", "SLL", "SRA", "SRDA", "SRDL", "SRL": 537 mnemonic += " R1,D2(B2)" 538 enc = str + "@0|R1@8|//@12|B2@16|D2@20|??@32" 539 default: 540 mnemonic += " R1,R3,D2(B2)" 541 enc = str + "@0|R1@8|R3@12|B2@16|D2@20|??@32" 542 } 543 case "RS-b": 544 mnemonic += " R1,M3,D2(B2)" 545 enc = str + "@0|R1@8|M3@12|B2@16|D2@20|??@32" 546 } 547 return mnemonic, enc 548 } 549 550 func mnemonic_RSI(mnemonic, opcode string) (string, string) { 551 var enc string 552 mnemonic += " R1,R3,RI2" 553 val, _ := strconv.ParseUint(opcode, 16, 16) 554 str := strconv.Itoa(int(val)) 555 enc = str + "@0|R1@8|R3@12|RI2@16|??@32" 556 return mnemonic, enc 557 } 558 559 func mnemonic_RSL(mnemonic, format, opcode string) (string, string) { 560 var enc string 561 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 562 str1 := strconv.Itoa(int(val1)) 563 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 564 str2 := strconv.Itoa(int(val2)) 565 switch format { 566 case "RSL-a": 567 mnemonic += " D1(L1,B1)" 568 enc = str1 + "@0|L1@8|//@12|B1@16|D1@20|//@32|" + str2 + "@40|??@48" 569 case "RSL-b": 570 mnemonic += " R1,D2(L2,B2),M3" 571 enc = str1 + "@0|L2@8|B2@16|D2@20|R1@32|M3@36|" + str2 + "@40|??@48" 572 } 573 return mnemonic, enc 574 } 575 576 func mnemonic_RSY(mnemonic, format, opcode string) (string, string) { 577 var enc string 578 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 579 str1 := strconv.Itoa(int(val1)) 580 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 581 str2 := strconv.Itoa(int(val2)) 582 switch format { 583 case "RSY-a": 584 mnemonic += " R1,R3,D2(B2)" 585 enc = str1 + "@0|R1@8|R3@12|B2@16|D2@20|" + str2 + "@40|??@48" 586 case "RSY-b": 587 switch mnemonic { 588 case "LOC", "LOCFH", "LOCG", "STOCFH", "STOC", "STOCG": 589 mnemonic += " R1,D2(B2),M3" 590 default: 591 mnemonic += " R1,M3,D2(B2)" 592 } 593 enc = str1 + "@0|R1@8|M3@12|B2@16|D2@20|" + str2 + "@40|??@48" 594 } 595 return mnemonic, enc 596 } 597 598 func mnemonic_RX(mnemonic, format, opcode string) (string, string) { 599 var enc string 600 val, _ := strconv.ParseInt(opcode, 16, 16) 601 str := strconv.Itoa(int(val)) 602 switch format { 603 case "RX-a": 604 mnemonic += " R1,D2(X2,B2)" 605 enc = str + "@0|R1@8|X2@12|B2@16|D2@20|??@32" 606 case "RX-b": 607 mnemonic += " M1,D2(X2,B2)" 608 enc = str + "@0|M1@8|X2@12|B2@16|D2@20|??@32" 609 } 610 return mnemonic, enc 611 } 612 613 func mnemonic_RXE(mnemonic, opcode string) (string, string) { 614 var enc string 615 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 616 str1 := strconv.Itoa(int(val1)) 617 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 618 str2 := strconv.Itoa(int(val2)) 619 switch mnemonic { 620 case "LCBB": 621 mnemonic += " R1,D2(X2,B2),M3" 622 enc = str1 + "@0|R1@8|X2@12|B2@16|D2@20|M3@32|//@36|" + str2 + "@40|??@48" 623 default: 624 mnemonic += " R1,D2(X2,B2)" 625 enc = str1 + "@0|R1@8|X2@12|B2@16|D2@20|//@32|" + str2 + "@40|??@48" 626 } 627 return mnemonic, enc 628 } 629 630 func mnemonic_RXF(mnemonic, opcode string) (string, string) { 631 var enc string 632 mnemonic += " R1,R3,D2(X2,B2)" 633 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 634 str1 := strconv.Itoa(int(val1)) 635 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 636 str2 := strconv.Itoa(int(val2)) 637 enc = str1 + "@0|R3@8|X2@12|B2@16|D2@20|R1@32|//@36|" + str2 + "@40|??@48" 638 return mnemonic, enc 639 } 640 641 func mnemonic_RXY(mnemonic, format, opcode string) (string, string) { 642 var enc string 643 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 644 str1 := strconv.Itoa(int(val1)) 645 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 646 str2 := strconv.Itoa(int(val2)) 647 switch format { 648 case "RXY-a": 649 mnemonic += " R1,D2(X2,B2)" 650 enc = str1 + "@0|R1@8|X2@12|B2@16|D2@20|" + str2 + "@40|??@48" 651 case "RXY-b": 652 mnemonic += " M1,D2(X2,B2)" 653 enc = str1 + "@0|M1@8|X2@12|B2@16|D2@20|" + str2 + "@40|??@48" 654 } 655 return mnemonic, enc 656 } 657 658 func mnemonic_S(mnemonic, opcode string) (string, string) { 659 var enc string 660 val, _ := strconv.ParseUint(opcode, 16, 16) 661 str := strconv.Itoa(int(val)) 662 switch mnemonic { 663 case "PTLB", "TEND", "XSCH", "CSCH", "HSCH", "IPK", "RCHP", "RSCH", "SAL", "SCHM": 664 enc = str + "@0|//@16|??@32" 665 default: 666 mnemonic += " D2(B2)" 667 enc = str + "@0|B2@16|D2@20|??@32" 668 } 669 return mnemonic, enc 670 } 671 672 func mnemonic_SI(mnemonic, opcode string) (string, string) { 673 var enc string 674 val, _ := strconv.ParseUint(opcode, 16, 16) 675 str := strconv.Itoa(int(val)) 676 switch mnemonic { 677 case "TS", "SSM", "LPSW": 678 mnemonic += " D1(B1)" 679 default: 680 mnemonic += " D1(B1),I2" 681 } 682 enc = str + "@0|I2@8|B1@16|D1@20|??@32" 683 return mnemonic, enc 684 } 685 686 func mnemonic_SIL(mnemonic, opcode string) (string, string) { 687 var enc string 688 mnemonic += " D1(B1),I2" 689 val, _ := strconv.ParseUint(opcode, 16, 16) 690 str := strconv.Itoa(int(val)) 691 enc = str + "@0|B1@16|D1@20|I2@32|??@48" 692 return mnemonic, enc 693 } 694 695 func mnemonic_SIY(mnemonic, opcode string) (string, string) { 696 var enc string 697 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 698 str1 := strconv.Itoa(int(val1)) 699 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 700 str2 := strconv.Itoa(int(val2)) 701 switch mnemonic { 702 case "LPSWEY": 703 mnemonic += " D1(B1)" 704 enc = str1 + "@0|//@8|B1@16|D1@20|" + str2 + "@40|??@48" 705 default: 706 mnemonic += " D1(B1),I2" 707 enc = str1 + "@0|I2@8|B1@16|D1@20|" + str2 + "@40|??@48" 708 } 709 return mnemonic, enc 710 } 711 712 func mnemonic_SMI(mnemonic, opcode string) (string, string) { 713 var enc string 714 mnemonic += " M1,RI2,D3(B3)" 715 val, _ := strconv.ParseUint(opcode, 16, 16) 716 str := strconv.Itoa(int(val)) 717 enc = str + "@0|M1@8|//@12|B3@16|D3@20|RI2@32|??@48" 718 return mnemonic, enc 719 } 720 721 func mnemonic_SS(mnemonic, format, opcode string) (string, string) { 722 var enc string 723 val, _ := strconv.ParseUint(opcode, 16, 16) 724 str := strconv.Itoa(int(val)) 725 switch format { 726 case "SS-a": 727 mnemonic += " D1(L1,B1),D2(B2)" 728 enc = str + "@0|L1@8|B1@16|D1@20|B2@32|D2@36|??@48" 729 case "SS-b": 730 mnemonic += " D1(L1,B1),D2(L2,B2)" 731 enc = str + "@0|L1@8|L2@12|B1@16|D1@20|B2@32|D2@36|??@48" 732 case "SS-c": 733 mnemonic += " D1(L1,B1),D2(B2),I3" 734 enc = str + "@0|L1@8|I3@12|B1@16|D1@20|B2@32|D2@36|??@48" 735 case "SS-d": 736 mnemonic += " D1(R1,B1),D2(B2),R3" 737 enc = str + "@0|R1@8|R3@12|B1@16|D1@20|B2@32|D2@36|??@48" 738 case "SS-e": 739 switch mnemonic { 740 case "LMD": 741 mnemonic += " R1,R3,D2(B2),D4(B4)" 742 default: 743 mnemonic += " R1,D2(B2),R3,D4(B4)" 744 } 745 enc = str + "@0|R1@8|R3@12|B2@16|D2@20|B4@32|D4@36|??@48" 746 case "SS-f": 747 mnemonic += " D1(B1),D2(L2,B2)" 748 enc = str + "@0|L2@8|B1@16|D1@20|B2@32|D2@36|??@48" 749 } 750 return mnemonic, enc 751 752 } 753 754 func mnemonic_SSE(mnemonic, opcode string) (string, string) { 755 var enc string 756 mnemonic += " D1(B1),D2(B2)" 757 val, _ := strconv.ParseUint(opcode, 16, 16) 758 str := strconv.Itoa(int(val)) 759 enc = str + "@0|B1@16|D1@20|B2@32|D2@36|??@48" 760 return mnemonic, enc 761 } 762 763 func mnemonic_SSF(mnemonic, opcode string) (string, string) { 764 var enc string 765 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 766 str1 := strconv.Itoa(int(val1)) 767 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 768 str2 := strconv.Itoa(int(val2)) 769 switch mnemonic { 770 case "LPD", "LPDG": 771 mnemonic += " R3,D1(B1),D2(B2)" 772 default: 773 mnemonic += " D1(B1),D2(B2),R3" 774 } 775 enc = str1 + "@0|R3@8|" + str2 + "@12|B1@16|D1@20|B2@32|D2@36|??@48" 776 return mnemonic, enc 777 } 778 779 func mnemonic_VRI(mnemonic, format, opcode string) (string, string) { 780 var enc string 781 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 782 str1 := strconv.Itoa(int(val1)) 783 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 784 str2 := strconv.Itoa(int(val2)) 785 switch format { 786 case "VRI-a": 787 if strings.Contains(mnemonic, "VGBM") { // Check for M3 field 788 mnemonic += " V1,I2" 789 enc = str1 + "@0|V1@8|//@12|I2@16|//@32|RXB@36|" + str2 + "@40|??@48" 790 } else { 791 mnemonic += " V1,I2,M3" 792 enc = str1 + "@0|V1@8|//@12|I2@16|M3@32|RXB@36|" + str2 + "@40|??@48" 793 } 794 case "VRI-b": 795 mnemonic += " V1,I2,I3,M4" 796 enc = str1 + "@0|V1@8|//@12|I2@16|I3@24|M4@32|RXB@36|" + str2 + "@40|??@48" 797 case "VRI-c": 798 mnemonic += " V1,V3,I2,M4" 799 enc = str1 + "@0|V1@8|V3@12|I2@16|M4@32|RXB@36|" + str2 + "@40|??@48" 800 case "VRI-d": 801 if strings.Contains(mnemonic, "VERIM") { // Check for M5 field 802 mnemonic += " V1,V2,V3,I4,M5" 803 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|I4@24|M5@32|RXB@36|" + str2 + "@40|??@48" 804 } else { 805 mnemonic += " V1,V2,V3,I4" 806 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|I4@24|//@32|RXB@36|" + str2 + "@40|??@48" 807 } 808 case "VRI-e": 809 mnemonic += " V1,V2,I3,M4,M5" 810 enc = str1 + "@0|V1@8|V2@12|I3@16|M5@28|M4@32|RXB@36|" + str2 + "@40|??@48" 811 case "VRI-f": 812 mnemonic += " V1,V2,V3,I4,M5" 813 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M5@24|I4@28|RXB@36|" + str2 + "@40|??@48" 814 case "VRI-g": 815 mnemonic += " V1,V2,I3,I4,M5" 816 enc = str1 + "@0|V1@8|V2@12|I4@16|M5@24|I3@28|RXB@36|" + str2 + "@40|??@48" 817 case "VRI-h": 818 mnemonic += " V1,I2,I3" 819 enc = str1 + "@0|V1@8|//@12|I2@16|I3@32|RXB@36|" + str2 + "@40|??@48" 820 case "VRI-i": 821 mnemonic += " V1,R2,I3,M4" 822 enc = str1 + "@0|V1@8|R2@12|//@16|M4@24|I3@28|RXB@36|" + str2 + "@40|??@48" 823 } 824 return mnemonic, enc 825 } 826 827 func mnemonic_VRR(mnemonic, format, opcode string) (string, string) { 828 var enc string 829 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 830 str1 := strconv.Itoa(int(val1)) 831 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 832 str2 := strconv.Itoa(int(val2)) 833 switch format { 834 case "VRR-a": 835 switch mnemonic { 836 case "VLR", "VTM": // V1,V2 837 mnemonic += " V1,V2" 838 enc = str1 + "@0|V1@8|V2@12|//@16|RXB@36|" + str2 + "@40|??@48" 839 840 case "VSEG", "VUPH", "VUPLH", "VUPL", "VUPLL", "VCLZ", "VCTZ", "VEC", "VECL", "VLC", "VLP", "VPOPCT": // V1,V2,M3 841 mnemonic += " V1,V2,M3" 842 enc = str1 + "@0|V1@8|V2@12|//@16|M3@32|RXB@36|" + str2 + "@40|??@48" 843 844 case "VISTR": // V1,V2,M3,M5 845 mnemonic += " V1,V2,M3,M5" 846 enc = str1 + "@0|V1@8|V2@12|//@16|M5@24|//@28|M3@32|RXB@36|" + str2 + "@40|??@48" 847 848 case "WFC", "WFK", "VFLL", "VFSQ", "VCLFNH", "VCLFNL", "VCFN", "VCNF": // V1,V2,M3,M4 849 mnemonic += " V1,V2,M3,M4" 850 enc = str1 + "@0|V1@8|V2@12|//@16|M4@28|M3@32|RXB@36|" + str2 + "@40|??@48" 851 852 case "VCFPS", "VCDG", "VCDLG", "VCGD", "VCFPL", "VCSFP", "VCLFP", "VCLGD", "VFI", "VFLR", "VFPSO": // V1,V2,M3,M4,M5 853 mnemonic += " V1,V2,M3,M4,M5" 854 enc = str1 + "@0|V1@8|V2@12|//@16|M5@24|M4@28|M3@32|RXB@36|" + str2 + "@40|??@48" 855 } 856 case "VRR-b": 857 switch mnemonic { 858 case "VSCSHP": 859 mnemonic += " V1,V2,V3" 860 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|RXB@36|" + str2 + "@40|??@48" 861 default: 862 mnemonic += " V1,V2,V3,M4,M5" 863 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M5@24|//@28|M4@32|RXB@36|" + str2 + "@40|??@48" 864 } 865 case "VRR-c": 866 switch mnemonic { 867 case "VFA", "VFD", "VFM", "VFS", "VCRNF": // V1,V2,V3,M4,M5 868 mnemonic += " V1,V2,V3,M4,M5" 869 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M5@28|M4@32|RXB@36|" + str2 + "@40|??@48" 870 871 case "VFCE", "VFCH", "VFCHE", "VFMAX", "VFMIN": // V1,V2,V3,M4,M5,M6 872 mnemonic += " V1,V2,V3,M4,M5,M6" 873 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M6@24|M5@28|M4@32|RXB@36|" + str2 + "@40|??@48" 874 875 case "VBPERM", "VN", "VNC", "VCKSM", "VX", "VNN", "VNO", "VNX", 876 "VO", "VOC", "VSL", "VSLB", "VSRA", "VSRAB", "VSRL", "VSRLB": // V1,V2,V3 877 mnemonic += " V1,V2,V3" 878 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|RXB@36|" + str2 + "@40|??@48" 879 default: // V1,V2,V3,M4 880 mnemonic += " V1,V2,V3,M4" 881 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M4@32|RXB@36|" + str2 + "@40|??@48" 882 } 883 case "VRR-d": 884 switch mnemonic { 885 case "VMSL", "VSTRC", "VSTRS": // V1,V2,V3,V4,M5,M6 886 mnemonic += " V1,V2,V3,V4,M5,M6" 887 enc = str1 + "@0|V1@8|V2@12|V3@16|M5@20|M6@24|//@28|V4@32|RXB@36|" + str2 + "@40|??@48" 888 default: 889 mnemonic += " V1,V2,V3,V4,M5" 890 enc = str1 + "@0|V1@8|V2@12|V3@16|M5@20|//@24|V4@32|RXB@36|" + str2 + "@40|??@48" 891 } 892 case "VRR-e": 893 switch mnemonic { 894 case "VPERM", "VSEL": 895 mnemonic += " V1,V2,V3,V4" 896 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|V4@32|RXB@36|" + str2 + "@40|??@48" 897 default: 898 mnemonic += " V1,V2,V3,V4,M5,M6" 899 enc = str1 + "@0|V1@8|V2@12|V3@16|M6@20|//@24|M5@28|V4@32|RXB@36|" + str2 + "@40|??@48" 900 } 901 case "VRR-f": 902 mnemonic += " V1,R2,R3" 903 enc = str1 + "@0|V1@8|R2@12|R3@16|//@20|RXB@36|" + str2 + "@40|??@48" 904 case "VRR-g": 905 mnemonic += " V1" 906 enc = str1 + "@0|//@8|V1@12|//@16|RXB@36|" + str2 + "@40|??@48" 907 case "VRR-h": 908 mnemonic += " V1,V2,M3" 909 enc = str1 + "@0|//@8|V1@12|V2@16|//@20|M3@24|//@28|RXB@36|" + str2 + "@40|??@48" 910 case "VRR-i": 911 mnemonic += " R1,V2,M3,M4" 912 enc = str1 + "@0|R1@8|V2@12|//@16|M3@24|M4@28|//@32|RXB@36|" + str2 + "@40|??@48" 913 case "VRR-j": 914 mnemonic += " V1,V2,V3,M4" 915 enc = str1 + "@0|V1@8|V2@12|V3@16|//@20|M4@24|//@28|RXB@36|" + str2 + "@40|??@48" 916 case "VRR-k": 917 mnemonic += " V1,V2,M3" 918 enc = str1 + "@0|V1@8|V2@12|//@16|M3@24|//@28|RXB@36|" + str2 + "@40|??@48" 919 } 920 return mnemonic, enc 921 } 922 923 func mnemonic_VRS(mnemonic, format, opcode string) (string, string) { 924 var enc string 925 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 926 str1 := strconv.Itoa(int(val1)) 927 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 928 str2 := strconv.Itoa(int(val2)) 929 switch format { 930 case "VRS-a": 931 mnemonic += " V1,V3,D2(B2),M4" 932 enc = str1 + "@0|V1@8|V3@12|B2@16|D2@20|M4@32|RXB@36|" + str2 + "@40|??@48" 933 case "VRS-b": 934 if strings.Contains(mnemonic, "VLVG") { 935 mnemonic += " V1,R3,D2(B2),M4" 936 enc = str1 + "@0|V1@8|R3@12|B2@16|D2@20|M4@32|RXB@36|" + str2 + "@40|??@48" 937 } else { 938 mnemonic += " V1,R3,D2(B2)" 939 enc = str1 + "@0|V1@8|R3@12|B2@16|D2@20|//@32|RXB@36|" + str2 + "@40|??@48" 940 } 941 case "VRS-c": 942 mnemonic += " R1,V3,D2(B2),M4" 943 enc = str1 + "@0|R1@8|V3@12|B2@16|D2@20|M4@32|RXB@36|" + str2 + "@40|??@48" 944 case "VRS-d": 945 mnemonic += " V1,R3,D2(B2)" 946 enc = str1 + "@0|//@8|R3@12|B2@16|D2@20|V1@32|RXB@36|" + str2 + "@40|??@48" 947 } 948 return mnemonic, enc 949 } 950 951 func mnemonic_VRV(mnemonic, opcode string) (string, string) { 952 var enc string 953 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 954 str1 := strconv.Itoa(int(val1)) 955 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 956 str2 := strconv.Itoa(int(val2)) 957 mnemonic += " V1,D2(V2,B2),M3" 958 enc = str1 + "@0|V1@8|V2@12|B2@16|D2@20|M3@32|RXB@36|" + str2 + "@40|??@48" 959 return mnemonic, enc 960 } 961 962 func mnemonic_VRX(mnemonic, opcode string) (string, string) { 963 var enc string 964 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 965 str1 := strconv.Itoa(int(val1)) 966 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 967 str2 := strconv.Itoa(int(val2)) 968 mnemonic += " V1,D2(X2,B2),M3" 969 enc = str1 + "@0|V1@8|X2@12|B2@16|D2@20|M3@32|RXB@36|" + str2 + "@40|??@48" 970 return mnemonic, enc 971 } 972 973 func mnemonic_VSI(mnemonic, opcode string) (string, string) { 974 var enc string 975 mnemonic += " V1,D2(B2),I3" 976 val1, _ := strconv.ParseUint(opcode[:2], 16, 16) 977 str1 := strconv.Itoa(int(val1)) 978 val2, _ := strconv.ParseUint(opcode[2:], 16, 16) 979 str2 := strconv.Itoa(int(val2)) 980 enc = str1 + "@0|I3@8|B2@16|D2@20|V1@32|RXB@36|" + str2 + "@40|??@48" 981 return mnemonic, enc 982 } 983 984 func matchXCord(t pdf.Text, Xcord float64) bool { 985 return math.Abs(t.X-Xcord) < 0.9 986 } 987 988 func match(t pdf.Text, font string, size float64, substr string) bool { 989 return t.Font == font && (size == 0 || math.Abs(t.FontSize-size) < 0.2) && strings.Contains(t.S, substr) 990 } 991 992 func findWords(chars []pdf.Text) (words []pdf.Text) { 993 // Sort by Y coordinate and normalize. 994 const nudge = 1.5 995 sort.Sort(pdf.TextVertical(chars)) 996 old := -100000.0 997 for i, c := range chars { 998 if c.Y != old && math.Abs(old-c.Y) < nudge { 999 chars[i].Y = old 1000 } else { 1001 old = c.Y 1002 } 1003 } 1004 1005 // Sort by Y coordinate, breaking ties with X. 1006 // This will bring letters in a single word together. 1007 sort.Sort(pdf.TextVertical(chars)) 1008 1009 // Loop over chars. 1010 for i := 0; i < len(chars); { 1011 // Find all chars on line. 1012 j := i + 1 1013 for j < len(chars) && chars[j].Y == chars[i].Y { 1014 j++ 1015 } 1016 var end float64 1017 // Split line into words (really, phrases). 1018 for k := i; k < j; { 1019 ck := &chars[k] 1020 s := ck.S 1021 end = ck.X + ck.W 1022 charSpace := ck.FontSize / 6 1023 wordSpace := ck.FontSize * 2 / 3 1024 l := k + 1 1025 for l < j { 1026 // Grow word. 1027 cl := &chars[l] 1028 if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+charSpace { 1029 s += cl.S 1030 end = cl.X + cl.W 1031 l++ 1032 continue 1033 } 1034 // Add space to phrase before next word. 1035 if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+wordSpace { 1036 s += " " + cl.S 1037 end = cl.X + cl.W 1038 l++ 1039 continue 1040 } 1041 break 1042 } 1043 f := ck.Font 1044 f = strings.TrimSuffix(f, ",Italic") 1045 f = strings.TrimSuffix(f, "-Italic") 1046 words = append(words, pdf.Text{ 1047 Font: f, 1048 FontSize: ck.FontSize, 1049 X: ck.X, 1050 Y: ck.Y, 1051 W: end - ck.X, 1052 S: s, 1053 }) 1054 k = l 1055 } 1056 i = j 1057 } 1058 return words 1059 } 1060 1061 func sameFont(f1, f2 string) bool { 1062 f1 = strings.TrimSuffix(f1, ",Italic") 1063 f1 = strings.TrimSuffix(f1, "-Italic") 1064 f2 = strings.TrimSuffix(f1, ",Italic") 1065 f2 = strings.TrimSuffix(f1, "-Italic") 1066 return strings.TrimSuffix(f1, ",Italic") == strings.TrimSuffix(f2, ",Italic") || f1 == "Symbol" || f2 == "Symbol" || f1 == "TimesNewRoman" || f2 == "TimesNewRoman" 1067 }