func argCount(log lex8.Logger, ops []*lex8.Token, n int) bool { if len(ops) == n+1 { return true } log.Errorf(ops[0].Pos, "%q needs %d arguments", ops[0].Lit, n) return false }
func checkTypeAll(p lex8.Logger, toks []*lex8.Token, typ int) bool { for _, t := range toks { if t.Type != typ { p.Errorf(t.Pos, "expect operand, got %s", parse.TypeStr(t.Type)) return false } } return true }
func (rs instResolvers) resolve(log lex8.Logger, ops []*lex8.Token) *inst { for _, r := range rs { if i, hit := r(log, ops); hit { return i } } op0 := ops[0] log.Errorf(op0.Pos, "invalid asm instruction %q", op0.Lit) return nil }
func resolveReg(p lex8.Logger, op *lex8.Token) uint32 { if op.Type != parse.Operand { panic("not an operand") } ret, found := regNameMap[op.Lit] if !found { p.Errorf(op.Pos, "invalid register name %q", op.Lit) return 0 } return ret }
// parseImm parses an unsigned 16-bit immediate func parseImm(p lex8.Logger, op *lex8.Token) uint32 { ret, e := strconv.ParseInt(op.Lit, 0, 32) if e != nil { p.Errorf(op.Pos, "invalid signed immediate %q: %s", op.Lit, e) return 0 } if ret > 0xffff || ret < -0x8000 { p.Errorf(op.Pos, "immediate out of 16-bit range: %s", op.Lit) return 0 } return uint32(ret) & 0xffff }
func parseShift(p lex8.Logger, op *lex8.Token) uint32 { ret, e := strconv.ParseUint(op.Lit, 0, 32) if e != nil { p.Errorf(op.Pos, "invalid shift %q: %s", op.Lit, e) return 0 } if (ret & 0x1f) != ret { p.Errorf(op.Pos, "shift too large: %s", op.Lit) return 0 } return uint32(ret) }
// parseImu parses an unsigned 16-bit immediate func parseImu(p lex8.Logger, op *lex8.Token) uint32 { ret, e := strconv.ParseUint(op.Lit, 0, 32) if e != nil { p.Errorf(op.Pos, "invalid unsigned immediate %q: %s", op.Lit, e) return 0 } if (ret & 0xffff) != ret { p.Errorf(op.Pos, "immediate too large: %s", op.Lit) return 0 } return uint32(ret) }
func checkLabel(log lex8.Logger, t *lex8.Token) bool { if t.Type != parse.Operand { panic("not an operand") } lab := t.Lit if !isLabelStart(lab) { return false } if !isLabel(lab) { log.Errorf(t.Pos, "invalid label: %q", lab) } return true }
func parseDataNums(p lex8.Logger, args []*lex8.Token, mode int) ( []byte, uint32, ) { if !checkTypeAll(p, args, parse.Operand) { return nil, 0 } var ui uint32 nbit := 8 if mode&modeWord != 0 { nbit = 32 } var e error buf := new(bytes.Buffer) for _, arg := range args { if mode&modeFloat != 0 { var f float64 f, e = strconv.ParseFloat(arg.Lit, 32) ui = math.Float32bits(float32(f)) } else if mode&modeSigned != 0 { var i int64 i, e = strconv.ParseInt(arg.Lit, 0, nbit) ui = uint32(i) } else { var ui64 uint64 ui64, e = strconv.ParseUint(arg.Lit, 0, nbit) ui = uint32(ui64) } if e != nil { p.Errorf(arg.Pos, "%s", e) return nil, 0 } if nbit == 8 { buf.WriteByte(byte(ui)) } else if nbit == 32 { var bs [4]byte arch8.Endian.PutUint32(bs[:], ui) buf.Write(bs[:]) } } return buf.Bytes(), nbitAlign(nbit) }
func resolveFuncStmt(log lex8.Logger, s *ast.FuncStmt) *funcStmt { ops := s.Ops op0 := ops[0] lead := op0.Lit if lead == "" { panic("empty operand") } if checkLabel(log, op0) { if len(ops) > 1 { log.Errorf(op0.Pos, "label should take the entire line") return nil } return &funcStmt{label: lead, FuncStmt: s} } return &funcStmt{inst: resolveInst(log, ops), FuncStmt: s} }
func parseDataHex(p lex8.Logger, args []*lex8.Token) ([]byte, uint32) { if !checkTypeAll(p, args, parse.Operand) { return nil, 0 } buf := new(bytes.Buffer) for _, arg := range args { b, e := strconv.ParseUint(arg.Lit, 16, 8) if e != nil { p.Errorf(arg.Pos, "%s", e) return nil, 0 } buf.WriteByte(byte(b)) } return buf.Bytes(), 0 }
func parseSym(p lex8.Logger, t *lex8.Token) (pack, sym string) { if t.Type != parse.Operand { panic("symbol not an operand") } sym = t.Lit dot := strings.Index(sym, ".") if dot >= 0 { pack, sym = sym[:dot], sym[dot+1:] } if dot >= 0 && !lex8.IsPkgName(pack) { p.Errorf(t.Pos, "invalid package name: %q", pack) } else if !parse.IsIdent(sym) { p.Errorf(t.Pos, "invalid symbol: %q", t.Lit) } return pack, sym }
func resolveImportDecl(log lex8.Logger, imp *ast.Import) *importDecl { ret := new(importDecl) ret.Import = imp ret.stmts = make(map[string]*importStmt) ret.paths = make(map[string]struct{}) for _, stmt := range imp.Stmts { r := resolveImportStmt(log, stmt) if other, found := ret.stmts[r.as]; found { log.Errorf(r.As.Pos, "%s already imported", r.as) log.Errorf(other.As.Pos, " previously imported here", other.as) continue } ret.stmts[r.as] = r ret.paths[r.path] = struct{}{} } return ret }
func resolveImportStmt(log lex8.Logger, imp *ast.ImportStmt) *importStmt { ret := new(importStmt) ret.ImportStmt = imp s, e := strconv.Unquote(imp.Path.Lit) if e != nil { log.Errorf(imp.Path.Pos, "invalid string %s", imp.Path.Lit) return nil } ret.path = s if imp.As != nil { ret.as = imp.As.Lit } else { ret.as = path.Base(ret.path) } return ret }
func parseDataStr(p lex8.Logger, args []*lex8.Token) ([]byte, uint32) { if !checkTypeAll(p, args, parse.String) { return nil, 0 } buf := new(bytes.Buffer) for _, arg := range args { if arg.Lit[0] != '"' { p.Errorf(arg.Pos, "expect string for string data") return nil, 0 } s, e := strconv.Unquote(arg.Lit) if e != nil { p.Errorf(arg.Pos, "invalid string %s", arg.Lit) return nil, 0 } buf.Write([]byte(s)) } return buf.Bytes(), 0 }
func resolveData(p lex8.Logger, t *lex8.Token, args []*lex8.Token) ( []byte, uint32, ) { switch t.Lit { case "str": return parseDataStr(p, args) case "x": return parseDataHex(p, args) case "u32": return parseDataNums(p, args, modeWord) case "i32": return parseDataNums(p, args, modeWord|modeSigned) case "u8", "byte": return parseDataNums(p, args, 0) case "i8": return parseDataNums(p, args, modeSigned) case "f32": return parseDataNums(p, args, modeWord|modeFloat) default: p.Errorf(t.Pos, "unknown data type %q", t.Lit) return nil, 0 } }
func resolveInstBr(p lex8.Logger, ops []*lex8.Token) (*inst, bool) { op0 := ops[0] opName := op0.Lit args := ops[1:] var ( op, s1, s2 uint32 lab string symTok *lex8.Token found bool ) if op, found = opBrMap[opName]; found { // op reg reg label if argCount(p, ops, 3) { s1 = resolveReg(p, args[0]) s2 = resolveReg(p, args[1]) symTok = args[2] if checkLabel(p, symTok) { lab = symTok.Lit } else { p.Errorf(symTok.Pos, "expects a label for %s", opName) } } } else { return nil, false } ret := makeInstBr(op, s1, s2) ret.sym = lab ret.fill = fillLabel ret.symTok = symTok return ret, true }