首先需要在 token.go 中添加对应的定义:
1 2 3 4 5 6 7 8 const ( ...... STRINGS ARRAY TYPE STRUCT ...... )
1 2 3 4 5 6 7 8 var tokens = [...]string { ...... STRINGS: "STRINGS" , ARRAY: "ARRAY" , TYPE: "type" , STRUCT: "struct" , ...... }
字符串处理 在词法分析阶段,只需要添加对 “双引号” 的处理即可:
1 2 3 4 5 6 7 case r == '"' : for { if r := p.src.Read(); r == '"' { p.emit(token.STRINGS) break } }
在语法分析阶段,字符串 AST 结点的结构可以仿造 Number:
1 2 3 4 5 6 7 type Strings struct { ValuePos int ValueEnd int Value string ValueLen int }
字符串通常会作为表达式出现,因此需要在 parseExpr_primary 中添加与字符串有关的处理:
1 2 3 4 5 6 7 case token.STRINGS: tokStrings := p.MustAcceptToken(token.STRINGS) return &ast.Strings{ ValuePos: tokStrings.Pos + 1 , ValueEnd: tokStrings.Pos + int (len (tokStrings.Literal)) - 1 , Value: tokStrings.Literal[1 : len (tokStrings.Literal)-1 ], }
数组处理 数组的处理分为数组定义和数组使用这两个过程,首先需要定义 “[]” 的符号:
1 2 3 4 5 6 const ( ...... LSB RSB ...... )
1 2 3 4 5 6 var tokens = [...]string { ...... LSB: "[" , RSB: "]" , ...... }
然后在语法分析中添加对 “[]” 的识别:
1 2 3 4 case r == '[' : p.emit(token.LSB) case r == ']' : p.emit(token.RSB)
另外还需要修改变量的 AST 结点结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type VarSpec struct { VarPos int Name *IdentArr Type *Ident Value Expr } type IdentArr struct { NamePos int Name string Offset Expr }
其实就是在变量的基础上添加了一个 Expr 用于记录数组偏移
数组定义的格式如下:
1 var arrName [arrLen]arrType
对比于普通变量的定义多了 [arrLen]arrType
,因此直接对 parseStmt_var 函数进行修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 func (p *Parser) parseStmt_var () *ast .VarSpec { tokVar := p.MustAcceptToken(token.VAR) tokIdent := p.MustAcceptToken(token.IDENT) var varSpec = &ast.VarSpec{ VarPos: tokVar.Pos, } varSpec.Name = &ast.IdentArr{ NamePos: tokIdent.Pos, Name: tokIdent.Literal, Offset: nil , } if typ, ok := p.AcceptToken(token.IDENT); ok { varSpec.Type = &ast.Ident{ NamePos: typ.Pos, Name: typ.Literal, } } if _, ok := p.AcceptToken(token.LSB); ok { varSpec.Name.Offset = p.parseExpr() p.AcceptToken(token.RSB) typ, _ := p.AcceptToken(token.IDENT) varSpec.Type = &ast.Ident{ NamePos: typ.Pos, Name: typ.Literal, } } if _, ok := p.AcceptToken(token.ASSIGN); ok { varSpec.Value = p.parseExpr() } p.AcceptToken(token.SEMICOLON) return varSpec }
数组多用于表达式中,需要在 parseExpr_primary 添加对于数组的处理:
1 2 3 4 5 6 7 8 9 10 11 case token.IDENT: p.MustAcceptToken(token.IDENT) asti := &ast.IdentArr{ NamePos: tok.Pos, Name: tok.Literal, } if _, ok := p.AcceptToken(token.LSB); ok { asti.Offset = p.parseExpr() p.AcceptToken(token.RSB) } return asti
为了与赋值语句匹配,最后需要修改 parseStmt 和 parseStmt_block 的部分代码:
1 2 3 4 5 6 7 8 9 10 var assignStmt = &ast.AssignStmt{ Target: make ([]*ast.IdentArr, len (exprList)), OpPos: tok.Pos, Op: tok.Type, Value: make ([]ast.Expr, len (exprList)), } for i, target := range exprList { assignStmt.Target[i] = target.(*ast.IdentArr) assignStmt.Value[i] = exprValueList[i] }
结构体处理 在词法分析阶段,需要添加对 “type” 和 “struct” 这两个关键词的匹配:
1 2 3 4 5 6 var tokens = [...]string { ..... TYPE: "type" , STRUCT: "struct" , ..... }
另外需要将它们添加入关键词列表中:
1 2 3 4 5 6 var keywords = map [string ]TokenType{ ...... "type" : TYPE, "struct" : STRUCT, ...... }
结构体的 AST 结点结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 type TypeSpec struct { Name *Ident Type *Ident } type StructType struct { TypePos int Name *Ident Types []*TypeSpec }
结构体定义发生在全局,需要先修改 parseFile 函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 func (p *Parser) parseFile () { p.file = &ast.File{ Filename: p.Filename(), Source: p.Source(), } p.file.Pkg = p.parsePackage() for { switch tok := p.PeekToken(); tok.Type { case token.EOF: return case token.ERROR: panic (tok) case token.SEMICOLON: p.AcceptTokenList(token.SEMICOLON) case token.FUNC: p.file.Funcs = append (p.file.Funcs, p.parseFunc()) case token.VAR: p.file.Globals = append (p.file.Globals, p.parseStmt_var()) case token.TYPE: p.file.Types = append (p.file.Types, p.parseStmt_type()) default : p.errorf(tok.Pos, "unknown token: %v" , tok) } } }
核心函数 parseStmt_type 如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 func (p *Parser) parseStmt_type () *ast .StructType { tokpos := p.MustAcceptToken(token.TYPE) tokIdent := p.MustAcceptToken(token.IDENT) var StructType = &ast.StructType{ TypePos: tokpos.Pos, } StructType.Name = &ast.Ident{ NamePos: tokIdent.Pos, Name: tokIdent.Literal, } switch tok := p.PeekToken(); tok.Type { case token.IDENT: tokty := p.MustAcceptToken(token.IDENT) StructType.Types = append (StructType.Types, &ast.TypeSpec{ Name: nil , Type: &ast.Ident{ NamePos: tokty.Pos, Name: tokty.Literal, }, }) case token.STRUCT: if _, ok := p.AcceptToken(token.STRUCT); ok { p.AcceptToken(token.LBRACE) for { if _, ok := p.AcceptToken(token.RBRACE); ok { break } if toks, ok := p.AcceptTokenList(token.IDENT); ok { StructType.Types = append (StructType.Types, &ast.TypeSpec{ Name: &ast.Ident{ NamePos: toks[0 ].Pos, Name: toks[0 ].Literal, }, Type: &ast.Ident{ NamePos: toks[1 ].Pos, Name: toks[1 ].Literal, }, }) } p.ReadToken() } } else { panic ("Grammatical parsing errors" ) } default : p.errorf(tok.Pos, "unknown tok: type=%v, lit=%q" , tok.Type, tok.Literal) } p.AcceptToken(token.SEMICOLON) return StructType }
结构体多用于表达式中,需要在 parseExpr_primary 添加对于结构体的处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 case token.IDENT: p.MustAcceptToken(token.IDENT) asti := &ast.IdentArr{ NamePos: tok.Pos, Name: tok.Literal, } if _, ok := p.AcceptToken(token.LSB); ok { asti.Offset = p.parseExpr() p.AcceptToken(token.RSB) } if _, ok := p.AcceptToken(token.DOT); ok { asti.Offset = p.parseExpr() } return asti