github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/internal/rsg/yacc/parse.go (about) 1 // Copyright 2011 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 licenses/BSD-golang.txt. 4 5 // Portions of this file are additionally subject to the following license 6 // and copyright. 7 // 8 // Copyright 2016 The Cockroach Authors. 9 // 10 // Use of this software is governed by the Business Source License 11 // included in the file licenses/BSL.txt. 12 // 13 // As of the Change Date specified in that file, in accordance with 14 // the Business Source License, use of this software will be governed 15 // by the Apache License, Version 2.0, included in the file 16 // licenses/APL.txt. 17 18 // Copied from Go's text/template/parse package and modified for yacc. 19 20 // Package yacc parses .y files. 21 package yacc 22 23 import ( 24 "fmt" 25 "runtime" 26 27 "github.com/cockroachdb/errors" 28 ) 29 30 // Tree is the representation of a single parsed file. 31 type Tree struct { 32 Name string // name of the template represented by the tree. 33 Productions []*ProductionNode 34 text string // text parsed to create the template (or its parent) 35 // Parsing only; cleared after parse. 36 lex *lexer 37 token [2]item // two-token lookahead for parser. 38 peekCount int 39 } 40 41 // Parse parses the yacc file text with optional name. 42 func Parse(name, text string) (t *Tree, err error) { 43 t = New(name) 44 t.text = text 45 err = t.Parse(text) 46 return 47 } 48 49 // next returns the next token. 50 func (t *Tree) next() item { 51 if t.peekCount > 0 { 52 t.peekCount-- 53 } else { 54 t.token[0] = t.lex.nextItem() 55 } 56 return t.token[t.peekCount] 57 } 58 59 // backup backs the input stream up one token. 60 func (t *Tree) backup() { 61 t.peekCount++ 62 } 63 64 // peek returns but does not consume the next token. 65 func (t *Tree) peek() item { 66 if t.peekCount > 0 { 67 return t.token[t.peekCount-1] 68 } 69 t.peekCount = 1 70 t.token[0] = t.lex.nextItem() 71 return t.token[0] 72 } 73 74 // Parsing. 75 76 // New allocates a new parse tree with the given name. 77 func New(name string) *Tree { 78 return &Tree{ 79 Name: name, 80 } 81 } 82 83 // errorf formats the error and terminates processing. 84 func (t *Tree) errorf(format string, args ...interface{}) { 85 err := fmt.Errorf(format, args...) 86 err = errors.Wrapf(err, "parse: %s:%d", t.Name, t.lex.lineNumber()) 87 panic(err) 88 } 89 90 // expect consumes the next token and guarantees it has the required type. 91 func (t *Tree) expect(expected itemType, context string) item { 92 token := t.next() 93 if token.typ != expected { 94 t.unexpected(token, context) 95 } 96 return token 97 } 98 99 // unexpected complains about the token and terminates processing. 100 func (t *Tree) unexpected(token item, context string) { 101 t.errorf("unexpected %s in %s", token, context) 102 } 103 104 // recover is the handler that turns panics into returns from the top level of Parse. 105 func (t *Tree) recover(errp *error) { 106 if e := recover(); e != nil { 107 if _, ok := e.(runtime.Error); ok { 108 panic(e) 109 } 110 if t != nil { 111 t.stopParse() 112 } 113 *errp = e.(error) 114 } 115 } 116 117 // startParse initializes the parser, using the lexer. 118 func (t *Tree) startParse(lex *lexer) { 119 t.lex = lex 120 } 121 122 // stopParse terminates parsing. 123 func (t *Tree) stopParse() { 124 t.lex = nil 125 } 126 127 // Parse parses the yacc string to construct a representation of 128 // the file for analysis. 129 func (t *Tree) Parse(text string) (err error) { 130 defer t.recover(&err) 131 t.startParse(lex(t.Name, text)) 132 t.text = text 133 t.parse() 134 t.stopParse() 135 return nil 136 } 137 138 // parse is the top-level parser for a file. 139 // It runs to EOF. 140 func (t *Tree) parse() { 141 for { 142 switch token := t.next(); token.typ { 143 case itemIdent: 144 p := newProduction(token.pos, token.val) 145 t.parseProduction(p) 146 t.Productions = append(t.Productions, p) 147 case itemEOF: 148 return 149 } 150 } 151 } 152 153 func (t *Tree) parseProduction(p *ProductionNode) { 154 const context = "production" 155 t.expect(itemColon, context) 156 if t.peek().typ == itemNL { 157 t.next() 158 } 159 expectExpr := true 160 for { 161 token := t.next() 162 switch token.typ { 163 case itemComment, itemNL: 164 // ignore 165 case itemPipe: 166 if expectExpr { 167 t.unexpected(token, context) 168 } 169 expectExpr = true 170 default: 171 t.backup() 172 if !expectExpr { 173 return 174 } 175 e := newExpression(token.pos) 176 t.parseExpression(e) 177 p.Expressions = append(p.Expressions, e) 178 expectExpr = false 179 } 180 } 181 } 182 183 func (t *Tree) parseExpression(e *ExpressionNode) { 184 const context = "expression" 185 for { 186 switch token := t.next(); token.typ { 187 case itemNL: 188 peek := t.peek().typ 189 if peek == itemPipe || peek == itemNL { 190 return 191 } 192 case itemIdent: 193 e.Items = append(e.Items, Item{token.val, TypToken}) 194 case itemLiteral: 195 e.Items = append(e.Items, Item{token.val, TypLiteral}) 196 case itemExpr: 197 e.Command = token.val 198 if t.peek().typ == itemNL { 199 t.next() 200 } 201 return 202 case itemPct, itemComment: 203 // ignore 204 default: 205 t.unexpected(token, context) 206 } 207 } 208 }