blob: d3c4c2844d6e499e53c3bd239b874d3d06d6bbfc [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 Ukaib36f3872015-04-10 15:06:38 +0900139 // TODO(ukai): parse expr here.
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900140 ast := &AssignAST{
141 lhs: string(bytes.TrimSpace(line[:sep])),
142 rhs: string(bytes.TrimLeft(line[esep:], " \t")),
143 op: string(line[sep:esep]),
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900144 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900145 ast.filename = p.mk.filename
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900146 ast.lineno = p.lineno
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900147 return ast
148}
149
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900150func (p *parser) parseMaybeRule(line string, semicolonIndex int) AST {
Shinichiro Hamajide829712015-03-31 18:26:56 +0900151 if len(strings.TrimSpace(line)) == 0 {
152 return nil
153 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900154
Shinichiro Hamaji486e9de2015-04-09 15:20:32 +0900155 ast := &MaybeRuleAST{
156 expr: line,
157 semicolonIndex: semicolonIndex,
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900158 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900159 ast.filename = p.mk.filename
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900160 ast.lineno = p.lineno
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900161 /*
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900162 ast.cmdLineno = p.elineno + 1
163 for {
164 line := p.readRecipeLine()
165 if len(line) == 0 {
166 break
167 } else if line[0] == '\t' {
168 ast.cmds = append(ast.cmds, string(bytes.TrimLeft(line, " \t")))
169 } else {
170 p.unreadLine(line)
171 break
172 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900173 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900174 */
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900175 return ast
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900176}
177
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900178func (p *parser) parseInclude(line string, oplen int) AST {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900179 // TODO(ukai): parse expr here
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900180 ast := &IncludeAST{
181 expr: line[oplen+1:],
182 op: line[:oplen],
183 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900184 ast.filename = p.mk.filename
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900185 ast.lineno = p.lineno
186 return ast
187}
188
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900189func (p *parser) parseIfdef(line string, oplen int) AST {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900190 // TODO(ukai): parse expr here.
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900191 ast := &IfAST{
Shinichiro Hamajiae32b782015-03-31 14:41:19 +0900192 op: line[:oplen],
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900193 lhs: line[oplen+1:],
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900194 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900195 ast.filename = p.mk.filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900196 ast.lineno = p.lineno
197 p.addStatement(ast)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900198 p.ifStack = append(p.ifStack, ifState{ast: ast, numNest: p.numIfNest})
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900199 p.outStmts = &ast.trueStmts
200 return ast
201}
202
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900203func (p *parser) parseTwoQuotes(s string, op string) ([]string, bool) {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900204 var args []string
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900205 for i := 0; i < 2; i++ {
206 s = strings.TrimSpace(s)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900207 if s == "" {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900208 return nil, false
209 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900210 quote := s[0]
211 if quote != '\'' && quote != '"' {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900212 return nil, false
213 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900214 end := strings.IndexByte(s[1:], quote) + 1
215 if end < 0 {
216 return nil, false
217 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900218 args = append(args, s[1:end])
219 s = s[end+1:]
220 }
221 if len(s) > 0 {
222 Error(p.mk.filename, p.lineno, `extraneous text after %q directive`, op)
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900223 }
224 return args, true
225}
226
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900227// parse
228// "(lhs, rhs)"
229// "lhs, rhs"
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900230func (p *parser) parseEq(s string, op string) (string, string, bool) {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900231 if s[0] == '(' && s[len(s)-1] == ')' {
232 s = s[1 : len(s)-1]
233 term := []byte{','}
234 in := []byte(s)
235 v, n, err := parseExpr(in, term)
236 if err != nil {
237 return "", "", false
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900238 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900239 lhs := v.String()
240 n++
241 n += skipSpaces(in[n:], nil)
242 v, n, err = parseExpr(in[n:], nil)
243 if err != nil {
244 return "", "", false
245 }
246 rhs := v.String()
247 return lhs, rhs, true
248 }
249 args, ok := p.parseTwoQuotes(s, op)
250 if !ok {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900251 return "", "", false
252 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900253 return args[0], args[1], true
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900254}
255
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900256func (p *parser) parseIfeq(line string, oplen int) AST {
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900257 op := line[:oplen]
258 lhs, rhs, ok := p.parseEq(strings.TrimSpace(line[oplen+1:]), op)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900259 if !ok {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900260 Error(p.mk.filename, p.lineno, `*** invalid syntax in conditional.`)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900261 }
262
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900263 ast := &IfAST{
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900264 op: op,
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900265 lhs: lhs,
266 rhs: rhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900267 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900268 ast.filename = p.mk.filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900269 ast.lineno = p.lineno
270 p.addStatement(ast)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900271 p.ifStack = append(p.ifStack, ifState{ast: ast, numNest: p.numIfNest})
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900272 p.outStmts = &ast.trueStmts
273 return ast
274}
275
276func (p *parser) checkIfStack(curKeyword string) {
277 if len(p.ifStack) == 0 {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900278 Error(p.mk.filename, p.lineno, `*** extraneous %q.`, curKeyword)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900279 }
280}
281
282func (p *parser) parseElse(line string) {
283 p.checkIfStack("else")
284 state := &p.ifStack[len(p.ifStack)-1]
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900285 if state.inElse {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900286 Error(p.mk.filename, p.lineno, `*** only one "else" per conditional.`)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900287 }
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900288 state.inElse = true
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900289 p.outStmts = &state.ast.falseStmts
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900290
291 nextIf := strings.TrimSpace(line[len("else"):])
292 if len(nextIf) == 0 {
293 return
294 }
295 var ifDirectives = map[string]func(*parser, string){
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900296 "ifdef ": ifdefDirective,
297 "ifndef ": ifndefDirective,
298 "ifeq ": ifeqDirective,
299 "ifneq ": ifneqDirective,
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900300 }
301 p.numIfNest = state.numNest + 1
302 if p.parseKeywords(nextIf, ifDirectives) {
303 p.numIfNest = 0
304 return
305 }
306 p.numIfNest = 0
307 WarnNoPrefix(p.mk.filename, p.lineno, "extraneous text after `else` directive")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900308}
309
310func (p *parser) parseEndif(line string) {
311 p.checkIfStack("endif")
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900312 state := p.ifStack[len(p.ifStack)-1]
313 for t := 0; t <= state.numNest; t++ {
314 p.ifStack = p.ifStack[0 : len(p.ifStack)-1]
315 if len(p.ifStack) == 0 {
316 p.outStmts = &p.mk.stmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900317 } else {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900318 state := p.ifStack[len(p.ifStack)-1]
319 if state.inElse {
320 p.outStmts = &state.ast.falseStmts
321 } else {
322 p.outStmts = &state.ast.trueStmts
323 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900324 }
325 }
326}
327
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900328var makeDirectives = map[string]func(*parser, string){
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900329 "include ": includeDirective,
330 "-include ": sincludeDirective,
331 "sinclude": sincludeDirective,
332 "ifdef ": ifdefDirective,
333 "ifndef ": ifndefDirective,
334 "ifeq ": ifeqDirective,
335 "ifneq ": ifneqDirective,
336 "else": elseDirective,
337 "endif": endifDirective,
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900338 "define ": defineDirective,
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900339}
340
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900341func (p *parser) parseKeywords(line string, directives map[string]func(*parser, string)) bool {
Shinichiro Hamajie3a94632015-03-31 01:12:52 +0900342 stripped := strings.TrimLeft(line, " \t")
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900343 for prefix, f := range directives {
344 if strings.HasPrefix(stripped, prefix) {
345 f(p, stripped)
346 return true
347 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900348 }
Shinichiro Hamajia66a1792015-03-31 18:04:08 +0900349 return false
350}
351
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900352func (p *parser) isDirective(line string, directives map[string]func(*parser, string)) bool {
353 stripped := strings.TrimLeft(line, " \t")
354 for prefix, _ := range directives {
355 if strings.HasPrefix(stripped, prefix) {
356 return true
357 }
358 }
359 return false
360}
361
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900362func includeDirective(p *parser, line string) {
363 p.addStatement(p.parseInclude(line, len("include")))
364}
365
366func sincludeDirective(p *parser, line string) {
367 p.addStatement(p.parseInclude(line, len("-include")))
368}
369
370func ifdefDirective(p *parser, line string) {
371 p.parseIfdef(line, len("ifdef"))
372}
373
374func ifndefDirective(p *parser, line string) {
375 p.parseIfdef(line, len("ifndef"))
376}
377
378func ifeqDirective(p *parser, line string) {
379 p.parseIfeq(line, len("ifeq"))
380}
381
382func ifneqDirective(p *parser, line string) {
383 p.parseIfeq(line, len("ifneq"))
384}
385
386func elseDirective(p *parser, line string) {
387 p.parseElse(line)
388}
389
390func endifDirective(p *parser, line string) {
391 p.parseEndif(line)
392}
393
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900394func defineDirective(p *parser, line string) {
395 p.inDef = []string{strings.TrimLeft(line[len("define "):], " \t")}
396}
397
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900398func (p *parser) parse() (mk Makefile, err error) {
399 defer func() {
400 if r := recover(); r != nil {
401 err = fmt.Errorf("panic: %v", r)
402 }
403 }()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900404 for !p.done {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900405 line := p.readLine()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900406
Shinichiro Hamaji81372e52015-04-09 11:32:09 +0900407 if len(bytes.TrimSpace(line)) == 0 {
408 continue
409 }
410
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900411 if len(p.inDef) > 0 {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900412 line = p.processMakefileLine(line)
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900413 if strings.TrimLeft(string(line), " ") == "endef" {
414 Log("multilineAssign %q", p.inDef)
415 ast := &AssignAST{
416 lhs: p.inDef[0],
417 rhs: strings.Join(p.inDef[1:], "\n"),
418 op: "=",
419 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900420 ast.filename = p.mk.filename
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900421 ast.lineno = p.lineno - len(p.inDef)
422 p.addStatement(ast)
423 p.inDef = nil
424 continue
425 }
426 p.inDef = append(p.inDef, string(line))
427 continue
428 }
429
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900430 if p.isDirective(string(line), makeDirectives) {
431 line = p.processMakefileLine(line)
432 p.parseKeywords(string(line), makeDirectives)
433 continue
434 }
435
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900436 if line[0] == '\t' {
437 ast := &CommandAST{cmd: string(p.processRecipeLine(line[1:]))}
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900438 ast.filename = p.mk.filename
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900439 ast.lineno = p.lineno
440 p.addStatement(ast)
441 continue
442 }
443
444 line = p.processMakefileLine(line)
Shinichiro Hamajia66a1792015-03-31 18:04:08 +0900445
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900446 var ast AST
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900447 var parenStack []byte
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900448 semicolonIndex := -1
449 isRule := false
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900450 for i, ch := range line {
451 switch ch {
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900452 case '(', '{':
453 parenStack = append(parenStack, ch)
454 case ')', '}':
455 if len(parenStack) == 0 {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900456 Warn(p.mk.filename, p.lineno, "Unmatched parens: %s", line)
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900457 } else {
458 parenStack = parenStack[:len(parenStack)-1]
459 }
460 }
461 if len(parenStack) > 0 {
462 continue
463 }
464
465 switch ch {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900466 case ':':
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900467 if i+1 < len(line) && line[i+1] == '=' {
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900468 ast = p.parseAssign(line, i, i+2)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900469 } else {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900470 isRule = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900471 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900472 case ';':
473 semicolonIndex = i
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900474 case '=':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900475 if !isRule {
476 ast = p.parseAssign(line, i, i+1)
477 }
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900478 case '?', '+':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900479 if !isRule && i+1 < len(line) && line[i+1] == '=' {
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900480 ast = p.parseAssign(line, i, i+2)
481 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900482 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900483 if ast != nil {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900484 p.addStatement(ast)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900485 break
486 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900487 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900488 if ast == nil {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900489 ast = p.parseMaybeRule(string(line), semicolonIndex)
Shinichiro Hamajide829712015-03-31 18:26:56 +0900490 if ast != nil {
491 p.addStatement(ast)
492 }
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900493 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900494 }
495 return p.mk, nil
496}
497
498func ParseMakefile(filename string) (Makefile, error) {
499 f, err := os.Open(filename)
500 if err != nil {
501 return Makefile{}, err
502 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900503 defer f.Close()
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900504 parser := newParser(f, filename)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900505 return parser.parse()
506}
507
508func ParseDefaultMakefile() (Makefile, error) {
509 candidates := []string{"GNUmakefile", "makefile", "Makefile"}
510 for _, filename := range candidates {
511 if exists(filename) {
512 return ParseMakefile(filename)
513 }
514 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900515 return Makefile{}, errors.New("no targets specified and no makefile found.")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900516}
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900517
Shinichiro Hamaji29ffc972015-04-06 16:13:27 +0900518func ParseMakefileString(s string, name string, lineno int) (Makefile, error) {
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900519 rd := strings.NewReader(s)
520 parser := newParser(rd, name)
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900521 parser.lineno = lineno
Shinichiro Hamaji29ffc972015-04-06 16:13:27 +0900522 parser.elineno = lineno
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900523 parser.linenoFixed = true
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900524 return parser.parse()
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900525}