blob: 7660164b52c5d284b55cac4bc91a81117a2777ed [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 Hamaji370be722015-04-10 14:55:23 +090025 rd *bufio.Reader
26 mk Makefile
27 lineno int
28 elineno int // lineno == elineno unless there is trailing '\'.
29 linenoFixed bool
30 unBuf []byte
31 hasUnBuf bool
32 done bool
33 outStmts *[]AST
34 ifStack []ifState
35 inDef []string
36 numIfNest int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090037}
38
39func exists(filename string) bool {
40 f, err := os.Open(filename)
41 if err != nil {
42 return false
43 }
44 f.Close()
45 return true
46}
47
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +090048func newParser(rd io.Reader, filename string) *parser {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090049 p := &parser{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +090050 rd: bufio.NewReader(rd),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090051 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090052 p.mk.filename = filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090053 p.outStmts = &p.mk.stmts
54 return p
55}
56
Shinichiro Hamajiae32b782015-03-31 14:41:19 +090057func (p *parser) addStatement(ast AST) {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090058 *p.outStmts = append(*p.outStmts, ast)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090059}
60
Shinichiro Hamajie1841582015-03-30 17:20:33 +090061func (p *parser) readLine() []byte {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090062 if p.hasUnBuf {
63 p.hasUnBuf = false
64 return p.unBuf
Shinichiro Hamajie1841582015-03-30 17:20:33 +090065 }
66
Shinichiro Hamaji370be722015-04-10 14:55:23 +090067 if !p.linenoFixed {
68 p.lineno = p.elineno
69 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +090070 line, err := p.rd.ReadBytes('\n')
Shinichiro Hamaji370be722015-04-10 14:55:23 +090071 if !p.linenoFixed {
72 p.lineno++
73 p.elineno = p.lineno
74 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +090075 if err == io.EOF {
76 p.done = true
77 } else if err != nil {
78 panic(err)
79 }
80
Shinichiro Hamaji56c868c2015-04-09 10:17:10 +090081 line = bytes.TrimRight(line, "\r\n")
Shinichiro Hamajie1841582015-03-30 17:20:33 +090082
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +090083 return line
84}
85
86func removeComment(line []byte) []byte {
87 var parenStack []byte
88 for i, ch := range line {
89 switch ch {
90 case '(', '{':
91 parenStack = append(parenStack, ch)
92 case ')', '}':
93 if len(parenStack) > 0 {
94 parenStack = parenStack[:len(parenStack)-1]
95 }
96 case '#':
97 if len(parenStack) == 0 {
98 return line[:i]
99 }
100 }
101 }
102 return line
103}
104
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900105func (p *parser) processMakefileLine(line []byte) []byte {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900106 // TODO: Handle \\ at the end of the line?
107 for len(line) > 0 && line[len(line)-1] == '\\' {
108 line = line[:len(line)-1]
Shinichiro Hamaji3e4533d2015-04-06 14:03:58 +0900109 lineno := p.lineno
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900110 nline := p.readLine()
Shinichiro Hamaji3e4533d2015-04-06 14:03:58 +0900111 p.lineno = lineno
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900112 line = append(line, nline...)
113 }
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900114 return removeComment(line)
115}
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900116
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900117func (p *parser) processRecipeLine(line []byte) []byte {
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900118 // TODO: Handle \\ at the end of the line?
119 for len(line) > 0 && line[len(line)-1] == '\\' {
120 line = append(line, '\n')
121 lineno := p.lineno
122 nline := p.readLine()
123 p.lineno = lineno
124 line = append(line, nline...)
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900125 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900126 return line
127}
128
129func (p *parser) unreadLine(line []byte) {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900130 if p.hasUnBuf {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900131 panic("unreadLine twice!")
132 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900133 p.unBuf = line
134 p.hasUnBuf = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900135}
136
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900137func (p *parser) parseAssign(line []byte, sep, esep int) AST {
Fumitoshi Ukai8773e5e2015-04-01 11:23:18 +0900138 Log("parseAssign %q op:%q", line, line[sep:esep])
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900139 ast := &AssignAST{
140 lhs: string(bytes.TrimSpace(line[:sep])),
141 rhs: string(bytes.TrimLeft(line[esep:], " \t")),
142 op: string(line[sep:esep]),
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900143 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900144 ast.filename = p.mk.filename
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900145 ast.lineno = p.lineno
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900146 return ast
147}
148
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900149func (p *parser) parseMaybeRule(line string, semicolonIndex int) AST {
Shinichiro Hamajide829712015-03-31 18:26:56 +0900150 if len(strings.TrimSpace(line)) == 0 {
151 return nil
152 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900153
Shinichiro Hamaji486e9de2015-04-09 15:20:32 +0900154 ast := &MaybeRuleAST{
155 expr: line,
156 semicolonIndex: semicolonIndex,
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900157 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900158 ast.filename = p.mk.filename
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900159 ast.lineno = p.lineno
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900160 /*
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900161 ast.cmdLineno = p.elineno + 1
162 for {
163 line := p.readRecipeLine()
164 if len(line) == 0 {
165 break
166 } else if line[0] == '\t' {
167 ast.cmds = append(ast.cmds, string(bytes.TrimLeft(line, " \t")))
168 } else {
169 p.unreadLine(line)
170 break
171 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900172 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900173 */
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900174 return ast
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900175}
176
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900177func (p *parser) parseInclude(line string, oplen int) AST {
178 ast := &IncludeAST{
179 expr: line[oplen+1:],
180 op: line[:oplen],
181 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900182 ast.filename = p.mk.filename
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900183 ast.lineno = p.lineno
184 return ast
185}
186
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900187func (p *parser) parseIfdef(line string, oplen int) AST {
188 ast := &IfAST{
Shinichiro Hamajiae32b782015-03-31 14:41:19 +0900189 op: line[:oplen],
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900190 lhs: strings.TrimSpace(line[oplen+1:]),
191 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900192 ast.filename = p.mk.filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900193 ast.lineno = p.lineno
194 p.addStatement(ast)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900195 p.ifStack = append(p.ifStack, ifState{ast: ast, numNest: p.numIfNest})
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900196 p.outStmts = &ast.trueStmts
197 return ast
198}
199
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900200func closeParen(ch byte) (byte, error) {
201 switch ch {
202 case '(':
203 return ')', nil
204 case '{':
205 return '}', nil
206 default:
207 return 0, fmt.Errorf("unexpected paren %c", ch)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900208 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900209}
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900210
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900211// parseExpr parses s as expr.
212// The expr should starts with '(' or '{' and returns strings
213// separeted by ',' before ')' or '}' respectively, and an index for the rest.
214func parseExpr(s string) ([]string, int, error) {
215 if len(s) == 0 {
216 return nil, 0, errors.New("empty expr")
217 }
218 paren, err := closeParen(s[0])
219 if err != nil {
220 return nil, 0, err
221 }
222 parenCnt := make(map[byte]int)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900223 i := 0
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900224 ia := 1
225 var args []string
226Loop:
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900227 for {
228 i++
229 if i == len(s) {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900230 return nil, 0, errors.New("unexpected end of expr")
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900231 }
232 ch := s[i]
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900233 switch ch {
234 case '(', '{':
235 cch, err := closeParen(ch)
236 if err != nil {
237 return nil, 0, err
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900238 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900239 parenCnt[cch]++
240 case ')', '}':
241 parenCnt[ch]--
242 if ch == paren && parenCnt[ch] < 0 {
243 break Loop
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900244 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900245 case ',':
246 if parenCnt[')'] == 0 && parenCnt['}'] == 0 {
247 args = append(args, s[ia:i])
248 ia = i + 1
249 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900250 }
251 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900252 args = append(args, s[ia:i])
253 return args, i + 1, nil
254}
255
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900256func (p *parser) parseTwoQuotes(s string, op string) ([]string, bool) {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900257 var args []string
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900258 for i := 0; i < 2; i++ {
259 s = strings.TrimSpace(s)
260 if len(s) < 1 {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900261 return nil, false
262 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900263
264 quote := s[0]
265 if quote != '\'' && quote != '"' {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900266 return nil, false
267 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900268 end := strings.IndexByte(s[1:], quote) + 1
269 if end < 0 {
270 return nil, false
271 }
272
273 args = append(args, s[1:end])
274 s = s[end+1:]
275 }
276 if len(s) > 0 {
277 Error(p.mk.filename, p.lineno, `extraneous text after %q directive`, op)
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900278 }
279 return args, true
280}
281
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900282func (p *parser) parseEq(s string, op string) (string, string, bool) {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900283 args, _, err := parseExpr(s)
284 if err != nil {
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900285 args, ok := p.parseTwoQuotes(s, op)
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900286 if ok {
287 return args[0], args[1], true
288 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900289 return "", "", false
290 }
291 if len(args) != 2 {
292 return "", "", false
293 }
294 // TODO: check rest?
Shinichiro Hamajie56f2222015-04-07 05:09:00 +0900295 return args[0], strings.TrimLeft(args[1], " \t"), true
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900296}
297
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900298func (p *parser) parseIfeq(line string, oplen int) AST {
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900299 op := line[:oplen]
300 lhs, rhs, ok := p.parseEq(strings.TrimSpace(line[oplen+1:]), op)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900301 if !ok {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900302 Error(p.mk.filename, p.lineno, `*** invalid syntax in conditional.`)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900303 }
304
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900305 ast := &IfAST{
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900306 op: op,
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900307 lhs: lhs,
308 rhs: rhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900309 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900310 ast.filename = p.mk.filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900311 ast.lineno = p.lineno
312 p.addStatement(ast)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900313 p.ifStack = append(p.ifStack, ifState{ast: ast, numNest: p.numIfNest})
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900314 p.outStmts = &ast.trueStmts
315 return ast
316}
317
318func (p *parser) checkIfStack(curKeyword string) {
319 if len(p.ifStack) == 0 {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900320 Error(p.mk.filename, p.lineno, `*** extraneous %q.`, curKeyword)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900321 }
322}
323
324func (p *parser) parseElse(line string) {
325 p.checkIfStack("else")
326 state := &p.ifStack[len(p.ifStack)-1]
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900327 if state.inElse {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900328 Error(p.mk.filename, p.lineno, `*** only one "else" per conditional.`)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900329 }
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900330 state.inElse = true
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900331 p.outStmts = &state.ast.falseStmts
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900332
333 nextIf := strings.TrimSpace(line[len("else"):])
334 if len(nextIf) == 0 {
335 return
336 }
337 var ifDirectives = map[string]func(*parser, string){
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900338 "ifdef ": ifdefDirective,
339 "ifndef ": ifndefDirective,
340 "ifeq ": ifeqDirective,
341 "ifneq ": ifneqDirective,
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900342 }
343 p.numIfNest = state.numNest + 1
344 if p.parseKeywords(nextIf, ifDirectives) {
345 p.numIfNest = 0
346 return
347 }
348 p.numIfNest = 0
349 WarnNoPrefix(p.mk.filename, p.lineno, "extraneous text after `else` directive")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900350}
351
352func (p *parser) parseEndif(line string) {
353 p.checkIfStack("endif")
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900354 state := p.ifStack[len(p.ifStack)-1]
355 for t := 0; t <= state.numNest; t++ {
356 p.ifStack = p.ifStack[0 : len(p.ifStack)-1]
357 if len(p.ifStack) == 0 {
358 p.outStmts = &p.mk.stmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900359 } else {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900360 state := p.ifStack[len(p.ifStack)-1]
361 if state.inElse {
362 p.outStmts = &state.ast.falseStmts
363 } else {
364 p.outStmts = &state.ast.trueStmts
365 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900366 }
367 }
368}
369
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900370var makeDirectives = map[string]func(*parser, string){
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900371 "include ": includeDirective,
372 "-include ": sincludeDirective,
373 "sinclude": sincludeDirective,
374 "ifdef ": ifdefDirective,
375 "ifndef ": ifndefDirective,
376 "ifeq ": ifeqDirective,
377 "ifneq ": ifneqDirective,
378 "else": elseDirective,
379 "endif": endifDirective,
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900380 "define ": defineDirective,
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900381}
382
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900383func (p *parser) parseKeywords(line string, directives map[string]func(*parser, string)) bool {
Shinichiro Hamajie3a94632015-03-31 01:12:52 +0900384 stripped := strings.TrimLeft(line, " \t")
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900385 for prefix, f := range directives {
386 if strings.HasPrefix(stripped, prefix) {
387 f(p, stripped)
388 return true
389 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900390 }
Shinichiro Hamajia66a1792015-03-31 18:04:08 +0900391 return false
392}
393
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900394func (p *parser) isDirective(line string, directives map[string]func(*parser, string)) bool {
395 stripped := strings.TrimLeft(line, " \t")
396 for prefix, _ := range directives {
397 if strings.HasPrefix(stripped, prefix) {
398 return true
399 }
400 }
401 return false
402}
403
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900404func includeDirective(p *parser, line string) {
405 p.addStatement(p.parseInclude(line, len("include")))
406}
407
408func sincludeDirective(p *parser, line string) {
409 p.addStatement(p.parseInclude(line, len("-include")))
410}
411
412func ifdefDirective(p *parser, line string) {
413 p.parseIfdef(line, len("ifdef"))
414}
415
416func ifndefDirective(p *parser, line string) {
417 p.parseIfdef(line, len("ifndef"))
418}
419
420func ifeqDirective(p *parser, line string) {
421 p.parseIfeq(line, len("ifeq"))
422}
423
424func ifneqDirective(p *parser, line string) {
425 p.parseIfeq(line, len("ifneq"))
426}
427
428func elseDirective(p *parser, line string) {
429 p.parseElse(line)
430}
431
432func endifDirective(p *parser, line string) {
433 p.parseEndif(line)
434}
435
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900436func defineDirective(p *parser, line string) {
437 p.inDef = []string{strings.TrimLeft(line[len("define "):], " \t")}
438}
439
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900440func (p *parser) parse() (mk Makefile, err error) {
441 defer func() {
442 if r := recover(); r != nil {
443 err = fmt.Errorf("panic: %v", r)
444 }
445 }()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900446 for !p.done {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900447 line := p.readLine()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900448
Shinichiro Hamaji81372e52015-04-09 11:32:09 +0900449 if len(bytes.TrimSpace(line)) == 0 {
450 continue
451 }
452
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900453 if len(p.inDef) > 0 {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900454 line = p.processMakefileLine(line)
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900455 if strings.TrimLeft(string(line), " ") == "endef" {
456 Log("multilineAssign %q", p.inDef)
457 ast := &AssignAST{
458 lhs: p.inDef[0],
459 rhs: strings.Join(p.inDef[1:], "\n"),
460 op: "=",
461 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900462 ast.filename = p.mk.filename
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900463 ast.lineno = p.lineno - len(p.inDef)
464 p.addStatement(ast)
465 p.inDef = nil
466 continue
467 }
468 p.inDef = append(p.inDef, string(line))
469 continue
470 }
471
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900472 if p.isDirective(string(line), makeDirectives) {
473 line = p.processMakefileLine(line)
474 p.parseKeywords(string(line), makeDirectives)
475 continue
476 }
477
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900478 if line[0] == '\t' {
479 ast := &CommandAST{cmd: string(p.processRecipeLine(line[1:]))}
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900480 ast.filename = p.mk.filename
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900481 ast.lineno = p.lineno
482 p.addStatement(ast)
483 continue
484 }
485
486 line = p.processMakefileLine(line)
Shinichiro Hamajia66a1792015-03-31 18:04:08 +0900487
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900488 var ast AST
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900489 var parenStack []byte
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900490 semicolonIndex := -1
491 isRule := false
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900492 for i, ch := range line {
493 switch ch {
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900494 case '(', '{':
495 parenStack = append(parenStack, ch)
496 case ')', '}':
497 if len(parenStack) == 0 {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900498 Warn(p.mk.filename, p.lineno, "Unmatched parens: %s", line)
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900499 } else {
500 parenStack = parenStack[:len(parenStack)-1]
501 }
502 }
503 if len(parenStack) > 0 {
504 continue
505 }
506
507 switch ch {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900508 case ':':
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900509 if i+1 < len(line) && line[i+1] == '=' {
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900510 ast = p.parseAssign(line, i, i+2)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900511 } else {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900512 isRule = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900513 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900514 case ';':
515 semicolonIndex = i
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900516 case '=':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900517 if !isRule {
518 ast = p.parseAssign(line, i, i+1)
519 }
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900520 case '?', '+':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900521 if !isRule && i+1 < len(line) && line[i+1] == '=' {
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900522 ast = p.parseAssign(line, i, i+2)
523 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900524 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900525 if ast != nil {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900526 p.addStatement(ast)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900527 break
528 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900529 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900530 if ast == nil {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900531 ast = p.parseMaybeRule(string(line), semicolonIndex)
Shinichiro Hamajide829712015-03-31 18:26:56 +0900532 if ast != nil {
533 p.addStatement(ast)
534 }
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900535 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900536 }
537 return p.mk, nil
538}
539
540func ParseMakefile(filename string) (Makefile, error) {
541 f, err := os.Open(filename)
542 if err != nil {
543 return Makefile{}, err
544 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900545 defer f.Close()
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900546 parser := newParser(f, filename)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900547 return parser.parse()
548}
549
550func ParseDefaultMakefile() (Makefile, error) {
551 candidates := []string{"GNUmakefile", "makefile", "Makefile"}
552 for _, filename := range candidates {
553 if exists(filename) {
554 return ParseMakefile(filename)
555 }
556 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900557 return Makefile{}, errors.New("no targets specified and no makefile found.")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900558}
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900559
Shinichiro Hamaji29ffc972015-04-06 16:13:27 +0900560func ParseMakefileString(s string, name string, lineno int) (Makefile, error) {
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900561 rd := strings.NewReader(s)
562 parser := newParser(rd, name)
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900563 parser.lineno = lineno
Shinichiro Hamaji29ffc972015-04-06 16:13:27 +0900564 parser.elineno = lineno
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900565 parser.linenoFixed = true
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900566 return parser.parse()
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900567}