blob: 8404649d8b7e636ed81492257a5f4d192d5a9cce [file] [log] [blame]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09001package main
2
3import (
4 "bufio"
Shinichiro Hamajie1841582015-03-30 17:20:33 +09005 "bytes"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09006 "errors"
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +09007 "fmt"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09008 "io"
9 "os"
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090010 "strings"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090011)
12
13type Makefile struct {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090014 filename string
15 stmts []AST
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090016}
17
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090018type ifState struct {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +090019 ast *IfAST
20 inElse bool
21 numNest int
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090022}
23
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090024type parser struct {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +090025 rd *bufio.Reader
26 mk Makefile
27 lineno int
28 elineno int // lineno == elineno unless there is trailing '\'.
29 unBuf []byte
30 hasUnBuf bool
31 done bool
32 outStmts *[]AST
33 ifStack []ifState
34 inDef []string
Shinichiro Hamajia06760f2015-04-07 13:13:45 +090035 numIfNest int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090036}
37
38func exists(filename string) bool {
39 f, err := os.Open(filename)
40 if err != nil {
41 return false
42 }
43 f.Close()
44 return true
45}
46
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +090047func newParser(rd io.Reader, filename string) *parser {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090048 p := &parser{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +090049 rd: bufio.NewReader(rd),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090050 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090051 p.mk.filename = filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090052 p.outStmts = &p.mk.stmts
53 return p
54}
55
Shinichiro Hamajiae32b782015-03-31 14:41:19 +090056func (p *parser) addStatement(ast AST) {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090057 *p.outStmts = append(*p.outStmts, ast)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090058}
59
Shinichiro Hamajie1841582015-03-30 17:20:33 +090060func (p *parser) readLine() []byte {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090061 if p.hasUnBuf {
62 p.hasUnBuf = false
63 return p.unBuf
Shinichiro Hamajie1841582015-03-30 17:20:33 +090064 }
65
66 p.lineno = p.elineno
67 line, err := p.rd.ReadBytes('\n')
68 p.lineno++
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +090069 p.elineno = p.lineno
Shinichiro Hamajie1841582015-03-30 17:20:33 +090070 if err == io.EOF {
71 p.done = true
72 } else if err != nil {
73 panic(err)
74 }
75
Shinichiro Hamaji56c868c2015-04-09 10:17:10 +090076 line = bytes.TrimRight(line, "\r\n")
Shinichiro Hamajie1841582015-03-30 17:20:33 +090077
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +090078 return line
79}
80
81func removeComment(line []byte) []byte {
82 var parenStack []byte
83 for i, ch := range line {
84 switch ch {
85 case '(', '{':
86 parenStack = append(parenStack, ch)
87 case ')', '}':
88 if len(parenStack) > 0 {
89 parenStack = parenStack[:len(parenStack)-1]
90 }
91 case '#':
92 if len(parenStack) == 0 {
93 return line[:i]
94 }
95 }
96 }
97 return line
98}
99
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900100func (p *parser) processMakefileLine(line []byte) []byte {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900101 // TODO: Handle \\ at the end of the line?
102 for len(line) > 0 && line[len(line)-1] == '\\' {
103 line = line[:len(line)-1]
Shinichiro Hamaji3e4533d2015-04-06 14:03:58 +0900104 lineno := p.lineno
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900105 nline := p.readLine()
Shinichiro Hamaji3e4533d2015-04-06 14:03:58 +0900106 p.lineno = lineno
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900107 line = append(line, nline...)
108 }
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900109 return removeComment(line)
110}
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900111
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900112func (p *parser) processRecipeLine(line []byte) []byte {
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900113 // TODO: Handle \\ at the end of the line?
114 for len(line) > 0 && line[len(line)-1] == '\\' {
115 line = append(line, '\n')
116 lineno := p.lineno
117 nline := p.readLine()
118 p.lineno = lineno
119 line = append(line, nline...)
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900120 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900121 return line
122}
123
124func (p *parser) unreadLine(line []byte) {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900125 if p.hasUnBuf {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900126 panic("unreadLine twice!")
127 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900128 p.unBuf = line
129 p.hasUnBuf = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900130}
131
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900132func (p *parser) parseAssign(line []byte, sep, esep int) AST {
Fumitoshi Ukai8773e5e2015-04-01 11:23:18 +0900133 Log("parseAssign %q op:%q", line, line[sep:esep])
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900134 ast := &AssignAST{
135 lhs: string(bytes.TrimSpace(line[:sep])),
136 rhs: string(bytes.TrimLeft(line[esep:], " \t")),
137 op: string(line[sep:esep]),
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900138 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900139 ast.filename = p.mk.filename
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900140 ast.lineno = p.lineno
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900141 return ast
142}
143
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900144func (p *parser) parseMaybeRule(line string, semicolonIndex int) AST {
Shinichiro Hamajide829712015-03-31 18:26:56 +0900145 if len(strings.TrimSpace(line)) == 0 {
146 return nil
147 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900148
Shinichiro Hamaji19f4bf62015-04-02 04:55:57 +0900149 ast := &MaybeRuleAST{}
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900150 if i := semicolonIndex; i >= 0 {
Shinichiro Hamaji19f4bf62015-04-02 04:55:57 +0900151 ast.expr = line[:i]
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900152 ast.cmd = strings.TrimSpace(line[i+1:])
Shinichiro Hamaji19f4bf62015-04-02 04:55:57 +0900153 } else {
154 ast.expr = line
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900155 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900156 ast.filename = p.mk.filename
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900157 ast.lineno = p.lineno
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900158 /*
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900159 ast.cmdLineno = p.elineno + 1
160 for {
161 line := p.readRecipeLine()
162 if len(line) == 0 {
163 break
164 } else if line[0] == '\t' {
165 ast.cmds = append(ast.cmds, string(bytes.TrimLeft(line, " \t")))
166 } else {
167 p.unreadLine(line)
168 break
169 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900170 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900171 */
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900172 return ast
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900173}
174
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900175func (p *parser) parseInclude(line string, oplen int) AST {
176 ast := &IncludeAST{
177 expr: line[oplen+1:],
178 op: line[:oplen],
179 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900180 ast.filename = p.mk.filename
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900181 ast.lineno = p.lineno
182 return ast
183}
184
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900185func (p *parser) parseIfdef(line string, oplen int) AST {
186 ast := &IfAST{
Shinichiro Hamajiae32b782015-03-31 14:41:19 +0900187 op: line[:oplen],
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900188 lhs: strings.TrimSpace(line[oplen+1:]),
189 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900190 ast.filename = p.mk.filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900191 ast.lineno = p.lineno
192 p.addStatement(ast)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900193 p.ifStack = append(p.ifStack, ifState{ast: ast, numNest: p.numIfNest})
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900194 p.outStmts = &ast.trueStmts
195 return ast
196}
197
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900198func closeParen(ch byte) (byte, error) {
199 switch ch {
200 case '(':
201 return ')', nil
202 case '{':
203 return '}', nil
204 default:
205 return 0, fmt.Errorf("unexpected paren %c", ch)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900206 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900207}
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900208
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900209// parseExpr parses s as expr.
210// The expr should starts with '(' or '{' and returns strings
211// separeted by ',' before ')' or '}' respectively, and an index for the rest.
212func parseExpr(s string) ([]string, int, error) {
213 if len(s) == 0 {
214 return nil, 0, errors.New("empty expr")
215 }
216 paren, err := closeParen(s[0])
217 if err != nil {
218 return nil, 0, err
219 }
220 parenCnt := make(map[byte]int)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900221 i := 0
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900222 ia := 1
223 var args []string
224Loop:
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900225 for {
226 i++
227 if i == len(s) {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900228 return nil, 0, errors.New("unexpected end of expr")
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900229 }
230 ch := s[i]
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900231 switch ch {
232 case '(', '{':
233 cch, err := closeParen(ch)
234 if err != nil {
235 return nil, 0, err
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900236 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900237 parenCnt[cch]++
238 case ')', '}':
239 parenCnt[ch]--
240 if ch == paren && parenCnt[ch] < 0 {
241 break Loop
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900242 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900243 case ',':
244 if parenCnt[')'] == 0 && parenCnt['}'] == 0 {
245 args = append(args, s[ia:i])
246 ia = i + 1
247 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900248 }
249 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900250 args = append(args, s[ia:i])
251 return args, i + 1, nil
252}
253
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900254func (p *parser) parseTwoQuotes(s string, op string) ([]string, bool) {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900255 var args []string
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900256 for i := 0; i < 2; i++ {
257 s = strings.TrimSpace(s)
258 if len(s) < 1 {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900259 return nil, false
260 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900261
262 quote := s[0]
263 if quote != '\'' && quote != '"' {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900264 return nil, false
265 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900266 end := strings.IndexByte(s[1:], quote) + 1
267 if end < 0 {
268 return nil, false
269 }
270
271 args = append(args, s[1:end])
272 s = s[end+1:]
273 }
274 if len(s) > 0 {
275 Error(p.mk.filename, p.lineno, `extraneous text after %q directive`, op)
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900276 }
277 return args, true
278}
279
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900280func (p *parser) parseEq(s string, op string) (string, string, bool) {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900281 args, _, err := parseExpr(s)
282 if err != nil {
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900283 args, ok := p.parseTwoQuotes(s, op)
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900284 if ok {
285 return args[0], args[1], true
286 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900287 return "", "", false
288 }
289 if len(args) != 2 {
290 return "", "", false
291 }
292 // TODO: check rest?
Shinichiro Hamajie56f2222015-04-07 05:09:00 +0900293 return args[0], strings.TrimLeft(args[1], " \t"), true
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900294}
295
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900296func (p *parser) parseIfeq(line string, oplen int) AST {
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900297 op := line[:oplen]
298 lhs, rhs, ok := p.parseEq(strings.TrimSpace(line[oplen+1:]), op)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900299 if !ok {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900300 Error(p.mk.filename, p.lineno, `*** invalid syntax in conditional.`)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900301 }
302
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900303 ast := &IfAST{
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900304 op: op,
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900305 lhs: lhs,
306 rhs: rhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900307 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900308 ast.filename = p.mk.filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900309 ast.lineno = p.lineno
310 p.addStatement(ast)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900311 p.ifStack = append(p.ifStack, ifState{ast: ast, numNest: p.numIfNest})
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900312 p.outStmts = &ast.trueStmts
313 return ast
314}
315
316func (p *parser) checkIfStack(curKeyword string) {
317 if len(p.ifStack) == 0 {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900318 Error(p.mk.filename, p.lineno, `*** extraneous %q.`, curKeyword)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900319 }
320}
321
322func (p *parser) parseElse(line string) {
323 p.checkIfStack("else")
324 state := &p.ifStack[len(p.ifStack)-1]
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900325 if state.inElse {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900326 Error(p.mk.filename, p.lineno, `*** only one "else" per conditional.`)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900327 }
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900328 state.inElse = true
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900329 p.outStmts = &state.ast.falseStmts
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900330
331 nextIf := strings.TrimSpace(line[len("else"):])
332 if len(nextIf) == 0 {
333 return
334 }
335 var ifDirectives = map[string]func(*parser, string){
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900336 "ifdef ": ifdefDirective,
337 "ifndef ": ifndefDirective,
338 "ifeq ": ifeqDirective,
339 "ifneq ": ifneqDirective,
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900340 }
341 p.numIfNest = state.numNest + 1
342 if p.parseKeywords(nextIf, ifDirectives) {
343 p.numIfNest = 0
344 return
345 }
346 p.numIfNest = 0
347 WarnNoPrefix(p.mk.filename, p.lineno, "extraneous text after `else` directive")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900348}
349
350func (p *parser) parseEndif(line string) {
351 p.checkIfStack("endif")
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900352 state := p.ifStack[len(p.ifStack)-1]
353 for t := 0; t <= state.numNest; t++ {
354 p.ifStack = p.ifStack[0 : len(p.ifStack)-1]
355 if len(p.ifStack) == 0 {
356 p.outStmts = &p.mk.stmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900357 } else {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900358 state := p.ifStack[len(p.ifStack)-1]
359 if state.inElse {
360 p.outStmts = &state.ast.falseStmts
361 } else {
362 p.outStmts = &state.ast.trueStmts
363 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900364 }
365 }
366}
367
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900368var makeDirectives = map[string]func(*parser, string){
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900369 "include ": includeDirective,
370 "-include ": sincludeDirective,
371 "sinclude": sincludeDirective,
372 "ifdef ": ifdefDirective,
373 "ifndef ": ifndefDirective,
374 "ifeq ": ifeqDirective,
375 "ifneq ": ifneqDirective,
376 "else": elseDirective,
377 "endif": endifDirective,
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900378 "define ": defineDirective,
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900379}
380
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900381func (p *parser) parseKeywords(line string, directives map[string]func(*parser, string)) bool {
Shinichiro Hamajie3a94632015-03-31 01:12:52 +0900382 stripped := strings.TrimLeft(line, " \t")
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900383 for prefix, f := range directives {
384 if strings.HasPrefix(stripped, prefix) {
385 f(p, stripped)
386 return true
387 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900388 }
Shinichiro Hamajia66a1792015-03-31 18:04:08 +0900389 return false
390}
391
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900392func (p *parser) isDirective(line string, directives map[string]func(*parser, string)) bool {
393 stripped := strings.TrimLeft(line, " \t")
394 for prefix, _ := range directives {
395 if strings.HasPrefix(stripped, prefix) {
396 return true
397 }
398 }
399 return false
400}
401
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900402func includeDirective(p *parser, line string) {
403 p.addStatement(p.parseInclude(line, len("include")))
404}
405
406func sincludeDirective(p *parser, line string) {
407 p.addStatement(p.parseInclude(line, len("-include")))
408}
409
410func ifdefDirective(p *parser, line string) {
411 p.parseIfdef(line, len("ifdef"))
412}
413
414func ifndefDirective(p *parser, line string) {
415 p.parseIfdef(line, len("ifndef"))
416}
417
418func ifeqDirective(p *parser, line string) {
419 p.parseIfeq(line, len("ifeq"))
420}
421
422func ifneqDirective(p *parser, line string) {
423 p.parseIfeq(line, len("ifneq"))
424}
425
426func elseDirective(p *parser, line string) {
427 p.parseElse(line)
428}
429
430func endifDirective(p *parser, line string) {
431 p.parseEndif(line)
432}
433
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900434func defineDirective(p *parser, line string) {
435 p.inDef = []string{strings.TrimLeft(line[len("define "):], " \t")}
436}
437
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900438func (p *parser) parse() (mk Makefile, err error) {
439 defer func() {
440 if r := recover(); r != nil {
441 err = fmt.Errorf("panic: %v", r)
442 }
443 }()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900444 for !p.done {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900445 line := p.readLine()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900446
Shinichiro Hamaji81372e52015-04-09 11:32:09 +0900447 if len(bytes.TrimSpace(line)) == 0 {
448 continue
449 }
450
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900451 if len(p.inDef) > 0 {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900452 line = p.processMakefileLine(line)
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900453 if strings.TrimLeft(string(line), " ") == "endef" {
454 Log("multilineAssign %q", p.inDef)
455 ast := &AssignAST{
456 lhs: p.inDef[0],
457 rhs: strings.Join(p.inDef[1:], "\n"),
458 op: "=",
459 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900460 ast.filename = p.mk.filename
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900461 ast.lineno = p.lineno - len(p.inDef)
462 p.addStatement(ast)
463 p.inDef = nil
464 continue
465 }
466 p.inDef = append(p.inDef, string(line))
467 continue
468 }
469
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900470 if p.isDirective(string(line), makeDirectives) {
471 line = p.processMakefileLine(line)
472 p.parseKeywords(string(line), makeDirectives)
473 continue
474 }
475
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900476 if line[0] == '\t' {
477 ast := &CommandAST{cmd: string(p.processRecipeLine(line[1:]))}
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900478 ast.filename = p.mk.filename
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900479 ast.lineno = p.lineno
480 p.addStatement(ast)
481 continue
482 }
483
484 line = p.processMakefileLine(line)
Shinichiro Hamajia66a1792015-03-31 18:04:08 +0900485
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900486 var ast AST
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900487 var parenStack []byte
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900488 semicolonIndex := -1
489 isRule := false
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900490 for i, ch := range line {
491 switch ch {
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900492 case '(', '{':
493 parenStack = append(parenStack, ch)
494 case ')', '}':
495 if len(parenStack) == 0 {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900496 Warn(p.mk.filename, p.lineno, "Unmatched parens: %s", line)
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900497 } else {
498 parenStack = parenStack[:len(parenStack)-1]
499 }
500 }
501 if len(parenStack) > 0 {
502 continue
503 }
504
505 switch ch {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900506 case ':':
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900507 if i+1 < len(line) && line[i+1] == '=' {
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900508 ast = p.parseAssign(line, i, i+2)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900509 } else {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900510 isRule = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900511 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900512 case ';':
513 semicolonIndex = i
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900514 case '=':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900515 if !isRule {
516 ast = p.parseAssign(line, i, i+1)
517 }
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900518 case '?', '+':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900519 if !isRule && i+1 < len(line) && line[i+1] == '=' {
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900520 ast = p.parseAssign(line, i, i+2)
521 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900522 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900523 if ast != nil {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900524 p.addStatement(ast)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900525 break
526 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900527 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900528 if ast == nil {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900529 ast = p.parseMaybeRule(string(line), semicolonIndex)
Shinichiro Hamajide829712015-03-31 18:26:56 +0900530 if ast != nil {
531 p.addStatement(ast)
532 }
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900533 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900534 }
535 return p.mk, nil
536}
537
538func ParseMakefile(filename string) (Makefile, error) {
539 f, err := os.Open(filename)
540 if err != nil {
541 return Makefile{}, err
542 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900543 defer f.Close()
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900544 parser := newParser(f, filename)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900545 return parser.parse()
546}
547
548func ParseDefaultMakefile() (Makefile, error) {
549 candidates := []string{"GNUmakefile", "makefile", "Makefile"}
550 for _, filename := range candidates {
551 if exists(filename) {
552 return ParseMakefile(filename)
553 }
554 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900555 return Makefile{}, errors.New("no targets specified and no makefile found.")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900556}
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900557
Shinichiro Hamaji29ffc972015-04-06 16:13:27 +0900558func ParseMakefileString(s string, name string, lineno int) (Makefile, error) {
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900559 rd := strings.NewReader(s)
560 parser := newParser(rd, name)
Shinichiro Hamaji29ffc972015-04-06 16:13:27 +0900561 parser.lineno = lineno - 1
562 parser.elineno = lineno
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900563 return parser.parse()
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900564}