diff options
Diffstat (limited to 'pkg/ast')
| -rw-r--r-- | pkg/ast/ast.go | 9 | ||||
| -rw-r--r-- | pkg/ast/clone.go | 2 | ||||
| -rw-r--r-- | pkg/ast/format.go | 15 | ||||
| -rw-r--r-- | pkg/ast/parser.go | 19 | ||||
| -rw-r--r-- | pkg/ast/scanner.go | 59 | ||||
| -rw-r--r-- | pkg/ast/testdata/all.txt | 7 |
6 files changed, 70 insertions, 41 deletions
diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go index 13ff2b40e..f1f74e61b 100644 --- a/pkg/ast/ast.go +++ b/pkg/ast/ast.go @@ -163,6 +163,7 @@ func (n *Ident) Info() (Pos, string, string) { type String struct { Pos Pos Value string + Fmt StrFmt } func (n *String) Info() (Pos, string, string) { @@ -178,6 +179,13 @@ const ( IntFmtChar ) +type StrFmt int + +const ( + StrFmtRaw StrFmt = iota + StrFmtHex +) + type Int struct { Pos Pos // Only one of Value, Ident, CExpr is filled. @@ -198,6 +206,7 @@ type Type struct { ValueFmt IntFmt Ident string String string + StringFmt StrFmt HasString bool // Parts after COLON (for ranges and bitfields). Colon []*Type diff --git a/pkg/ast/clone.go b/pkg/ast/clone.go index a594e41f6..54bf8250c 100644 --- a/pkg/ast/clone.go +++ b/pkg/ast/clone.go @@ -134,6 +134,7 @@ func (n *String) Clone() Node { return &String{ Pos: n.Pos, Value: n.Value, + Fmt: n.Fmt, } } @@ -154,6 +155,7 @@ func (n *Type) Clone() Node { ValueFmt: n.ValueFmt, Ident: n.Ident, String: n.String, + StringFmt: n.StringFmt, HasString: n.HasString, Colon: cloneTypes(n.Colon), Args: cloneTypes(n.Args), diff --git a/pkg/ast/format.go b/pkg/ast/format.go index c3d931706..a2ead06f2 100644 --- a/pkg/ast/format.go +++ b/pkg/ast/format.go @@ -50,6 +50,17 @@ func FormatInt(v uint64, format IntFmt) string { } } +func FormatStr(v string, format StrFmt) string { + switch format { + case StrFmtRaw: + return fmt.Sprintf(`"%v"`, v) + case StrFmtHex: + return fmt.Sprintf("`%x`", v) + default: + panic(fmt.Sprintf("unknown str format %v", format)) + } +} + type serializer interface { serialize(w io.Writer) } @@ -153,7 +164,7 @@ func (flags *IntFlags) serialize(w io.Writer) { func (flags *StrFlags) serialize(w io.Writer) { fmt.Fprintf(w, "%v = ", flags.Name.Name) for i, v := range flags.Values { - fmt.Fprintf(w, "%v\"%v\"", comma(i, ""), v.Value) + fmt.Fprintf(w, "%v%v", comma(i, ""), FormatStr(v.Value, v.Fmt)) } fmt.Fprintf(w, "\n") } @@ -172,7 +183,7 @@ func fmtType(t *Type) string { case t.Ident != "": v = t.Ident case t.HasString: - v = fmt.Sprintf("\"%v\"", t.String) + v = FormatStr(t.String, t.StringFmt) default: v = FormatInt(t.Value, t.ValueFmt) } diff --git a/pkg/ast/parser.go b/pkg/ast/parser.go index b8d22fd88..7b46f6611 100644 --- a/pkg/ast/parser.go +++ b/pkg/ast/parser.go @@ -314,7 +314,7 @@ func (p *parser) parseFlags(name *Ident) Node { switch p.tok { case tokInt, tokIdent: return p.parseIntFlags(name) - case tokString: + case tokString, tokStringHex: return p.parseStrFlags(name) default: p.expect(tokInt, tokIdent, tokString) @@ -417,9 +417,10 @@ func (p *parser) parseType() *Type { case tokIdent: allowColon = true arg.Ident = p.lit - case tokString: + case tokString, tokStringHex: arg.String = p.lit arg.HasString = true + arg.StringFmt = strTokToFmt(p.tok) default: p.expect(tokInt, tokIdent, tokString) } @@ -468,15 +469,27 @@ func (p *parser) parseIdent() *Ident { } func (p *parser) parseString() *String { - p.expect(tokString) + p.expect(tokString, tokStringHex) str := &String{ Pos: p.pos, Value: p.lit, + Fmt: strTokToFmt(p.tok), } p.next() return str } +func strTokToFmt(tok token) StrFmt { + switch tok { + case tokString: + return StrFmtRaw + case tokStringHex: + return StrFmtHex + default: + panic("bad string token") + } +} + func (p *parser) parseInt() *Int { i := &Int{ Pos: p.pos, diff --git a/pkg/ast/scanner.go b/pkg/ast/scanner.go index a9448b34f..3a6ba9d98 100644 --- a/pkg/ast/scanner.go +++ b/pkg/ast/scanner.go @@ -4,6 +4,7 @@ package ast import ( + "encoding/hex" "fmt" "os" "strconv" @@ -20,6 +21,7 @@ const ( tokDefine tokResource tokString + tokStringHex tokCExpr tokInt @@ -51,18 +53,19 @@ var punctuation = [256]token{ } var tok2str = [...]string{ - tokIllegal: "ILLEGAL", - tokComment: "comment", - tokIdent: "identifier", - tokInclude: "include", - tokIncdir: "incdir", - tokDefine: "define", - tokResource: "resource", - tokString: "string", - tokCExpr: "CEXPR", - tokInt: "int", - tokNewLine: "NEWLINE", - tokEOF: "EOF", + tokIllegal: "ILLEGAL", + tokComment: "comment", + tokIdent: "identifier", + tokInclude: "include", + tokIncdir: "incdir", + tokDefine: "define", + tokResource: "resource", + tokString: "string", + tokStringHex: "hex string", + tokCExpr: "CEXPR", + tokInt: "int", + tokNewLine: "NEWLINE", + tokEOF: "EOF", } func init() { @@ -132,12 +135,7 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) { case s.ch == 0: tok = tokEOF s.next() - case s.ch == '`': - tok = tokCExpr - lit = s.scanCExpr(pos) case s.prev2 == tokDefine && s.prev1 == tokIdent: - // Note: the old form for C expressions, not really lexable. - // TODO(dvyukov): get rid of this eventually. tok = tokCExpr for ; s.ch != '\n'; s.next() { } @@ -150,6 +148,9 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) { case s.ch == '"' || s.ch == '<': tok = tokString lit = s.scanStr(pos) + case s.ch == '`': + tok = tokStringHex + lit = s.scanStr(pos) case s.ch >= '0' && s.ch <= '9' || s.ch == '-': tok = tokInt lit = s.scanInt(pos) @@ -170,21 +171,9 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) { return } -func (s *scanner) scanCExpr(pos Pos) string { - for s.next(); s.ch != '`' && s.ch != '\n'; s.next() { - } - if s.ch == '\n' { - s.Error(pos, "C expression is not terminated") - return "" - } - lit := string(s.data[pos.Off+1 : s.off]) - s.next() - return lit -} - func (s *scanner) scanStr(pos Pos) string { // TODO(dvyukov): get rid of <...> strings, that's only includes - closing := byte('"') + closing := s.ch if s.ch == '<' { closing = '>' } @@ -196,7 +185,6 @@ func (s *scanner) scanStr(pos Pos) string { } lit := string(s.data[pos.Off+1 : s.off]) for i := 0; i < len(lit); i++ { - //lit[i] if lit[i] < 0x20 || lit[i] >= 0x80 { pos1 := pos pos1.Col += i + 1 @@ -206,7 +194,14 @@ func (s *scanner) scanStr(pos Pos) string { } } s.next() - return lit + if closing != '`' { + return lit + } + decoded, err := hex.DecodeString(lit) + if err != nil { + s.Error(pos, "bad hex string literal: %v", err) + } + return string(decoded) } func (s *scanner) scanInt(pos Pos) string { diff --git a/pkg/ast/testdata/all.txt b/pkg/ast/testdata/all.txt index 392796254..122fa514b 100644 --- a/pkg/ast/testdata/all.txt +++ b/pkg/ast/testdata/all.txt @@ -17,15 +17,14 @@ int_flags4 = 1, -2- ### bad integer "-2-" str_flags0 = "foo", "bar" str_flags1 = "non terminated ### string literal is not terminated str_flags2 = "bad chars здесь" ### illegal character U+00D0 'Ð' in string literal -str_flags3 = "string", not a string ### unexpected identifier, expecting string -str_flags4 = "string", 42 ### unexpected int, expecting string +str_flags3 = "string", not a string ### unexpected identifier, expecting string, hex string +str_flags4 = "string", 42 ### unexpected int, expecting string, hex string call(foo ,int32 , bar int32) ### unexpected ',', expecting int, identifier, string call(foo int32:"bar") ### unexpected string, expecting int, identifier call(a int32, b len[a:"bar"]) ### unexpected string, expecting int, identifier -define FOO `bar` -define FOO `bar ### C expression is not terminated +define FOO bar foo(x int32[1:2:3, opt]) foo2(x int32[1[2]:2]) ### unexpected ':', expecting ']' |
