Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: 2920eada634f94f2a508cceb35289b7378caa7d4 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                                
                                                            

                                                                        
                                                           

                                            
                
                                                            
                                      
                                                                                 

                                                        
                           
                                 
                      
                    



                                 
 
                                                

                                                             
                                                     
                                                                  
                                                           
                                                                    
                                                                


                                                               
                                                             


                                                                 
                                                                     
                                                                    
                                                                  




                                                                
                                                               



                                                                
                                                                           
                                       

                                              
                                           
                                              

   



                                                            
                                                                                        
                                  
                                          




                                             
                                                     
   
 
                                                                           

                                                                                                                    
 
                                                            
                                                          
                                
                                                                              







                                                                                                                       
          




















































                                                                                  
                                                               

                              
                            
         
 
                 


                                                                    

                 

                                                                              

         
                 





                                                                                            

                                                                               
                                                                           
                                                                
                                 
 
                                                                                  
                                                                                        








                                                                                               

                 
                                                                           
                                                            
         

 
                                                                                     

                                    

                                                                                    


                                  

                                            
 

                                    



                                                                    
 






















                                                                                                
                                 
 








                                                                                
                                 
 













                                                                                                   
                                         

                                                                                                
                                 
 

















                                                                                                   
                                         

                                                                                         
                                 

                                                   
                                                             










                                                                                       

                                                 
 











                                                                                                   
                                         












                                                                                                  
                                 
 






                                                                               
                                 
 






                                                                               
 







                                                                                
 







                                                                                       
 





                                                                                              
                                                         
                                         
                                 
 








                                                                                                
                                 
 








                                                                                        
                                 
 



                                                                                 
 



                                             
                 


                                                                              

         
                                                                                     
                                         
                                                
                        


                                                                           


                 

                                                              
                                                    
                                                      
                                                            
                                                      
                                                          
                                                      
                                                           
                                                      



                            

                                                               
                                                       
                                                   
                                                           
                                                
                                                             
                                                  



                            

                                                                
                                                           
                                                      
                                                                 
                                                      
                                                                    
                                                      
                                                                  
                                                      
                                                                    
                                                      
                                                                   
                                                      
                                                                   














                                                                            



                            




                                                             

                                                    
                                                                  
                                                               
                                                                        


                                             
                 
                                                                    
                                                             
                                                                          
                                                      
                                                                             
                                                               
                                                                           
                                                             
                                                                             
                                                               
                                                                            
                                                                        
                                                                             
                                                                        
                                                                             
                                                            
                                                                                    
                                                                   
                                                                                 
                                                                
                                                                                       
                                                                    
                                                                                           
                                                                        
                                                                                            
                                                                         
                                                                                    


                                                                  







                            
          
           
                                                             













                                                                
                                                                             
                                                          
                                                                                     
                                                           
                                                                                   
                                                         
                                                                                    
                                                          
                                                                                   
                                                   







                                               
                                                     










                                                                        
                                                                                      



                                                  
                                                                             


           













                                                                                         
                                                 



                                                               
                                                                 







                                                                       
                                                                                                              





                                                                      
                                                          


                                               
                                                             

         
                                                       






                                                                
                                                
         
 
                                                                    








                                                                 
                                                                                   


                                                                  
                                                                        




















                                                                   
                                                            

                         

                                                                                           
                        
                                                                          





                                                                              
                                                                                                                                           
                                          
                                                                              




                             
                                                                           








                                                                    
                                                     




                                                        

                                                                          





                                                                             
                                                              















                                                                        
                                                     






























                                                                                 

                                                                                                 











                                                                                        
                                                                                                 
                                                    
                                                                   
                                      
                                                                   
                                        
                                                                           
                                      
                                                                         
                        
                                                                             



                          
                                                                         






                                                                            
                                                                            












                                                                                
                                                                 



                                                               
                                                         




                                                                                      
                                                                                                                                           



                                   
                                                                 






                                                       
                                                                

         
                 
                                           
                                

         
                 









                                                             



                                                          
                 


                                                 
 
/*******************************************************************************
 * Copyright (c) 2000, 2013 QNX Software Systems and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     QNX Software Systems - Initial API and implementation
 *     Wind River Systems - Bug 338936
 *******************************************************************************/
package org.eclipse.cdt.make.internal.core.makefile.gnu;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;

import org.eclipse.cdt.make.core.MakeCorePlugin;
import org.eclipse.cdt.make.core.makefile.IAutomaticVariable;
import org.eclipse.cdt.make.core.makefile.IBuiltinFunction;
import org.eclipse.cdt.make.core.makefile.IDirective;
import org.eclipse.cdt.make.core.makefile.IMakefileReaderProvider;
import org.eclipse.cdt.make.core.makefile.gnu.IGNUMakefile;
import org.eclipse.cdt.make.internal.core.makefile.AbstractMakefile;
import org.eclipse.cdt.make.internal.core.makefile.BadDirective;
import org.eclipse.cdt.make.internal.core.makefile.Command;
import org.eclipse.cdt.make.internal.core.makefile.Comment;
import org.eclipse.cdt.make.internal.core.makefile.DefaultRule;
import org.eclipse.cdt.make.internal.core.makefile.Directive;
import org.eclipse.cdt.make.internal.core.makefile.EmptyLine;
import org.eclipse.cdt.make.internal.core.makefile.IgnoreRule;
import org.eclipse.cdt.make.internal.core.makefile.InferenceRule;
import org.eclipse.cdt.make.internal.core.makefile.MakeFileConstants;
import org.eclipse.cdt.make.internal.core.makefile.MakefileMessages;
import org.eclipse.cdt.make.internal.core.makefile.MakefileReader;
import org.eclipse.cdt.make.internal.core.makefile.PosixRule;
import org.eclipse.cdt.make.internal.core.makefile.PreciousRule;
import org.eclipse.cdt.make.internal.core.makefile.Rule;
import org.eclipse.cdt.make.internal.core.makefile.SccsGetRule;
import org.eclipse.cdt.make.internal.core.makefile.SilentRule;
import org.eclipse.cdt.make.internal.core.makefile.SpecialRule;
import org.eclipse.cdt.make.internal.core.makefile.SuffixesRule;
import org.eclipse.cdt.make.internal.core.makefile.Target;
import org.eclipse.cdt.make.internal.core.makefile.TargetRule;
import org.eclipse.cdt.make.internal.core.makefile.Util;
import org.eclipse.cdt.make.internal.core.makefile.posix.PosixMakefileUtil;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.runtime.CoreException;

/**
 * Makefile : ( statement ) *
 * statement :   rule | macro_definition | comments | empty
 * rule :  inference_rule | target_rule
 * inference_rule : target ':' <nl> ( <tab> command <nl> ) +
 * target_rule : target [ ( target ) * ] ':' [ ( prerequisite ) * ] [ ';' command ] <nl>
                 [ ( command ) * ]
 * macro_definition : string '=' (string)*
 * comments : ('#' (string) <nl>) *
 * empty : <nl>
 * command : <tab> prefix_command string <nl>
 * target : string
 * prefix_command : '-' | '@' | '+'
 * internal_macro :  "$<" | "$*" | "$@" | "$?" | "$%"
 */

public class GNUMakefile extends AbstractMakefile implements IGNUMakefile {
	public static String PATH_SEPARATOR = System.getProperty("path.separator", ":"); //$NON-NLS-1$ //$NON-NLS-2$
	public static String FILE_SEPARATOR = System.getProperty("file.separator", "/"); //$NON-NLS-1$ //$NON-NLS-2$

	private String[] includeDirectories = new String[0];
	private IDirective[] builtins = new IDirective[0];
	@SuppressWarnings("nls")
	private IAutomaticVariable[] autoVariables = new IAutomaticVariable[]{
		new AutomaticVariable(this, "@", MakefileMessages.getString("GNUMakefile.automaticVariable.at")),
		new AutomaticVariable(this, "%", MakefileMessages.getString("GNUMakefile.automaticVariable.percent")),
		new AutomaticVariable(this, "<", MakefileMessages.getString("GNUMakefile.automaticVariable.less")),
		new AutomaticVariable(this, "?", MakefileMessages.getString("GNUMakefile.automaticVariable.question")),
		new AutomaticVariable(this, "^", MakefileMessages.getString("GNUMakefile.automaticVariable.carrot")),
		new AutomaticVariable(this, "+", MakefileMessages.getString("GNUMakefile.automaticVariable.plus")),
		new AutomaticVariable(this, "|", MakefileMessages.getString("GNUMakefile.automaticVariable.pipe")),
		new AutomaticVariable(this, "*", MakefileMessages.getString("GNUMakefile.automaticVariable.star")),
	};

	@SuppressWarnings("nls")
	private final static String[] functions = {
		"subst", "patsubst", "strip", "findstring",
		"filter", "filter-out", "sort",
		"word", "words", "wordlist", "firstword", "lastword",
		"dir", "notdir",
		"suffix", "basename", "addsuffix", "addprefix",
		"join", "wildcard", "realpath", "abspath",
		"if", "or", "and", "foreach",
		"call", "value", "eval", "origin", "flavor",
		"shell", "error", "warning", "info",
	};

	@SuppressWarnings("nls")
	private IBuiltinFunction[] builtinFunctions = new IBuiltinFunction[]{
		new BuiltinFunction(this, "$(subst from,to,text)"),
		new BuiltinFunction(this, "$(patsubst pattern,replacement,text)"),
		new BuiltinFunction(this, "$(strip string)"),
		new BuiltinFunction(this, "$(findstring find,in)"),
		new BuiltinFunction(this, "$(filter pattern,text)"),
		new BuiltinFunction(this, "$(filter-out pattern,text)"),
		new BuiltinFunction(this, "$(sort list)"),
		new BuiltinFunction(this, "$(word n,text)"),
		new BuiltinFunction(this, "$(words text)"),
		new BuiltinFunction(this, "$(wordlist s,e,text)"),
		new BuiltinFunction(this, "$(firstword names)"),
		new BuiltinFunction(this, "$(lastword names)"),
		new BuiltinFunction(this, "$(dir names)"),
		new BuiltinFunction(this, "$(notdir names)"),
		new BuiltinFunction(this, "$(suffix names)"),
		new BuiltinFunction(this, "$(basename names)"),
		new BuiltinFunction(this, "$(addsuffix suffix,names)"),
		new BuiltinFunction(this, "$(addprefix prefix,names)"),
		new BuiltinFunction(this, "$(join list1,list2)"),
		new BuiltinFunction(this, "$(wildcard pattern)"),
		new BuiltinFunction(this, "$(realpath names)"),
		new BuiltinFunction(this, "$(abspath names)"),
		new BuiltinFunction(this, "$(if condition,then-part,else-part)"),
		new BuiltinFunction(this, "$(or condition1,condition2,...)"),
		new BuiltinFunction(this, "$(and condition1,condition2,...)"),
		new BuiltinFunction(this, "$(foreach var,list,text)"),
		new BuiltinFunction(this, "$(call variable,param,...)"),
		new BuiltinFunction(this, "$(value variable)"),
		new BuiltinFunction(this, "$(eval expression)"),
		new BuiltinFunction(this, "$(origin variable)"),
		new BuiltinFunction(this, "$(flavor variable)"),
		new BuiltinFunction(this, "$(shell command)"),
		new BuiltinFunction(this, "$(error error: text)"),
		new BuiltinFunction(this, "$(warning warning: text)"),
		new BuiltinFunction(this, "$(info info: text)"),
	};

	private IMakefileReaderProvider makefileReaderProvider;

	public GNUMakefile() {
		super(null);
	}

	@Override
	public IMakefileReaderProvider getMakefileReaderProvider() {
		return makefileReaderProvider;
	}

	@Override
	public void parse(String filePath, Reader reader) throws IOException {
		parse(URIUtil.toURI(filePath), new MakefileReader(reader));
	}

	@Override
	public void parse(URI fileURI,
			IMakefileReaderProvider makefileReaderProvider) throws IOException {
		this.makefileReaderProvider = makefileReaderProvider;
		MakefileReader reader;
		if (makefileReaderProvider == null) {
			try {
				final IFileStore store = EFS.getStore(fileURI);
				final IFileInfo info = store.fetchInfo();
				if (!info.exists() || info.isDirectory()) {
					throw new IOException();
				}

				reader = new MakefileReader(new InputStreamReader(
						store.openInputStream(EFS.NONE, null)));
			} catch (CoreException e) {
				MakeCorePlugin.log(e);
				throw new IOException(e.getMessage());
			}
		} else {
			reader = new MakefileReader(makefileReaderProvider.getReader(fileURI));
		}
		parse(fileURI, reader);
	}

	@Override
	public void parse(URI filePath, Reader reader) throws IOException {
		parse(filePath, new MakefileReader(reader));
	}


	protected void parse(URI fileURI, MakefileReader reader) throws IOException {
		String line;
		Rule[] rules = null;
		Stack<Directive> conditions = new Stack<Directive>();
		Stack<VariableDefinition> defines = new Stack<VariableDefinition>();
		int startLine = 0;
		int endLine = 0;

		// Clear any old directives.
		clearDirectives();

		setFileURI(fileURI);

		try {
			while ((line = reader.readLine()) != null) {
				startLine = endLine + 1;
				endLine = reader.getLineNumber();

				// Check if we enter in "define"
				if (GNUMakefileUtil.isEndef(line)) {
					// We should have a "define" for a "endef".
					if (!defines.empty()) {
						VariableDefinition def = defines.pop();
						def.setEndLine(endLine);
					}
					Endef endef = new Endef(this);
					endef.setLines(startLine, endLine);
					addDirective(conditions, endef);
					continue;
				} else if (GNUMakefileUtil.isDefine(line)) {
					VariableDefinition def = parseVariableDefinition(line);
					def.setLines(startLine, endLine);
					addDirective(conditions, def);
					defines.push(def);
					continue;
				} else if (GNUMakefileUtil.isOverrideDefine(line)) {
					VariableDefinition oDef = parseVariableDefinition(line);
					oDef.setLines(startLine, endLine);
					addDirective(conditions, oDef);
					defines.push(oDef);
					continue;
				}

				// We still in a define.
				if (!defines.empty()) {
					VariableDefinition def = defines.peek();
					StringBuffer sb = def.getValue();
					if (sb.length() > 0) {
						sb.append('\n');
					}
					sb.append(line);
					continue;
				}

				// 1- Try command first, since we can not strip '#' in command line
				if (PosixMakefileUtil.isCommand(line)) {
					Command cmd = new Command(this, line);
					cmd.setLines(startLine, endLine);
					if (!conditions.empty()) {
						addDirective(conditions, cmd);
						continue;
					} else if (rules != null) {
						// The command is added to the rules
						for (Rule rule : rules) {
							rule.addDirective(cmd);
							rule.setEndLine(endLine);
						}
						continue;
					}
					// If we have no rules/condition for the command,
					// give the other directives a chance by falling through
				}

				// 2- Strip away any comments.
				int pound = Util.indexOfComment(line);
				if (pound != -1) {
					Comment cmt = new Comment(this, line.substring(pound + 1));
					cmt.setLines(startLine, endLine);
					if (rules != null) {
						// The comment is added to the rules.
						for (Rule rule : rules) {
							rule.addDirective(cmt);
							rule.setEndLine(endLine);
						}
					} else {
						addDirective(conditions, cmt);
					}
					line = line.substring(0, pound);
					// If all we have left are spaces continue
					if (Util.isEmptyLine(line)) {
						continue;
					}
					// The rest of the line maybe a valid directives.
					// keep on trying by falling through.
				}

				// 3- Empty lines ?
				if (Util.isEmptyLine(line)) {
					Directive empty = new EmptyLine(this);
					empty.setLines(startLine, endLine);
					if (rules != null) {
						// The EmptyLine is added to the rules.
						for (Rule rule : rules) {
							rule.addDirective(empty);
							rule.setEndLine(endLine);
						}
					} else {
						addDirective(conditions, empty);
					}
					continue;
				}

				// 4- reset the rules to null
				// The first non empty line that does not begin with a <TAB> or '#'
				// shall begin a new entry.
				rules = null;

				if (GNUMakefileUtil.isElse(line)) {
					Conditional elseDirective = parseConditional(line);
					elseDirective.setLines(startLine, endLine);
					// Are we missing a if condition ?
					if (!conditions.empty()) {
						Conditional cond = (Conditional) conditions.pop();
						cond.setEndLine(endLine - 1);
					}
					addDirective(conditions, elseDirective);
					conditions.push(elseDirective);
					continue;
				} else if (GNUMakefileUtil.isEndif(line)) {
					Endif endif = new Endif(this);
					endif.setLines(startLine, endLine);
					// Are we missing a if/else condition ?
					if (!conditions.empty()) {
						Conditional cond = (Conditional) conditions.pop();
						cond.setEndLine(endLine);
					}
					addDirective(conditions, endif);
					continue;
				}

				// 5- Check for the conditionnals.
				Directive directive = processConditions(line);
				if (directive != null) {
					directive.setLines(startLine, endLine);
					addDirective(conditions, directive);
					conditions.push(directive);
					continue;
				}

				// 6- Check for other special gnu directives.
				directive = processGNUDirectives(line);
				if (directive != null) {
					directive.setLines(startLine, endLine);
					addDirective(conditions, directive);
					continue;
				}

				// 7- Check for GNU special rules.
				SpecialRule special = processSpecialRules(line);
				if (special != null) {
					rules = new Rule[] { special };
					special.setLines(startLine, endLine);
					addDirective(conditions, special);
					continue;
				}

				// - Check for inference rule.
				if (PosixMakefileUtil.isInferenceRule(line)) {
					InferenceRule irule = parseInferenceRule(line);
					irule.setLines(startLine, endLine);
					addDirective(conditions, irule);
					rules = new Rule[] { irule };
					continue;
				}

				// - Variable Definiton ?
				if (GNUMakefileUtil.isVariableDefinition(line)) {
					VariableDefinition vd = parseVariableDefinition(line);
					vd.setLines(startLine, endLine);
					addDirective(conditions, vd);
					if (!vd.isTargetSpecific()) {
						continue;
					}
				}

				// - GNU Static Target rule ?
				if (GNUMakefileUtil.isStaticTargetRule(line)) {
					StaticTargetRule[] srules = parseStaticTargetRule(line);
					for (StaticTargetRule srule : srules) {
						srule.setLines(startLine, endLine);
						addDirective(conditions, srule);
					}
					rules = srules;
					continue;
				}

				// - Target Rule ?
				if (GNUMakefileUtil.isGNUTargetRule(line)) {
					TargetRule[] trules = parseGNUTargetRules(line);
					for (TargetRule trule : trules) {
						trule.setLines(startLine, endLine);
						addDirective(conditions, trule);
					}
					rules = trules;
					continue;
				}

				// XXX ?? Should not be here.
				BadDirective stmt = new BadDirective(this, line);
				stmt.setLines(startLine, endLine);
				addDirective(conditions, stmt);

			}
			setLines(1, endLine);
		} finally {
			reader.close();
		}
		// TEST please remove.
		//GNUMakefileValidator validator = new GNUMakefileValidator();
		//validator.validateDirectives(null, getDirectives());
	}

	private void addDirective(Stack<Directive> conditions, Directive directive) {
		if (conditions.empty()) {
			addDirective(directive);
		} else {
			Conditional cond = (Conditional) conditions.peek();
			cond.addDirective(directive);
			cond.setEndLine(directive.getEndLine());
		}
	}

	protected Conditional processConditions(String line) {
		Conditional stmt = null;
		if (GNUMakefileUtil.isIfdef(line)) {
			stmt = parseConditional(line);
		} else if (GNUMakefileUtil.isIfndef(line)) {
			stmt = parseConditional(line);
		} else if (GNUMakefileUtil.isIfeq(line)) {
			stmt = parseConditional(line);
		} else if (GNUMakefileUtil.isIfneq(line)) {
			stmt = parseConditional(line);
		}
		return stmt;
	}

	protected Directive processGNUDirectives(String line) {
		Directive stmt = null;
		if (GNUMakefileUtil.isUnExport(line)) {
			stmt = parseUnExport(line);
		} else if (GNUMakefileUtil.isVPath(line)) {
			stmt = parseVPath(line);
		} else if (GNUMakefileUtil.isInclude(line)) {
			stmt = parseInclude(line);
		}
		return stmt;
	}

	protected SpecialRule processSpecialRules(String line) {
		SpecialRule stmt = null;
		if (PosixMakefileUtil.isIgnoreRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (PosixMakefileUtil.isPosixRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (PosixMakefileUtil.isPreciousRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (PosixMakefileUtil.isSilentRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (PosixMakefileUtil.isSuffixesRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (PosixMakefileUtil.isDefaultRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (PosixMakefileUtil.isSccsGetRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (GNUMakefileUtil.isPhonyRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (GNUMakefileUtil.isIntermediateRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (GNUMakefileUtil.isSecondaryRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (GNUMakefileUtil.isDeleteOnErrorRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (GNUMakefileUtil.isLowResolutionTimeRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (GNUMakefileUtil.isExportAllVariablesRule(line)) {
			stmt = parseSpecialRule(line);
		} else if (GNUMakefileUtil.isNotParallelRule(line)) {
			stmt = parseSpecialRule(line);
		}
		return stmt;
	}

	protected SpecialRule parseSpecialRule(String line) {
		line = line.trim();
		String keyword =  null;
		String[] reqs = null;
		SpecialRule special = null;
		int index = Util.indexOf(line, ':');
		if (index != -1) {
			keyword = line.substring(0, index).trim();
			String req = line.substring(index + 1);
			reqs = PosixMakefileUtil.findPrerequisites(req);
		} else {
			keyword = line;
			reqs = new String[0];
		}
		if (keyword.equals(MakeFileConstants.RULE_IGNORE)) {
			special = new IgnoreRule(this, reqs);
		} else if (keyword.equals(MakeFileConstants.RULE_POSIX)) {
			special = new PosixRule(this);
		} else if (keyword.equals(MakeFileConstants.RULE_PRECIOUS)) {
			special = new PreciousRule(this, reqs);
		} else if (keyword.equals(MakeFileConstants.RULE_SILENT)) {
			special = new SilentRule(this, reqs);
		} else if (keyword.equals(MakeFileConstants.RULE_SUFFIXES)) {
			special = new SuffixesRule(this, reqs);
		} else if (keyword.equals(MakeFileConstants.RULE_DEFAULT)) {
			special = new DefaultRule(this, new Command[0]);
		} else if (keyword.equals(MakeFileConstants.RULE_SCCS_GET)) {
			special = new SccsGetRule(this, new Command[0]);
		} else if (keyword.equals(GNUMakefileConstants.RULE_PHONY)) {
			special = new PhonyRule(this, reqs);
		} else if (keyword.equals(GNUMakefileConstants.RULE_INTERMEDIATE)) {
			special = new IntermediateRule(this, reqs);
		} else if (keyword.equals(GNUMakefileConstants.RULE_SECONDARY)) {
			special = new SecondaryRule(this, reqs);
		} else if (keyword.equals(GNUMakefileConstants.RULE_DELETE_ON_ERROR)) {
			special = new DeleteOnErrorRule(this, reqs);
		} else if (keyword.equals(GNUMakefileConstants.RULE_LOW_RESOLUTION_TIME)) {
			special = new LowResolutionTimeRule(this, reqs);
		} else if (keyword.equals(GNUMakefileConstants.RULE_EXPORT_ALL_VARIABLES)) {
			special = new ExportAllVariablesRule(this, reqs);
		} else if (keyword.equals(GNUMakefileConstants.RULE_NOT_PARALLEL)) {
			special = new NotParallelRule(this, reqs);
		}
		return special;
	}

	/**
	 *
	 * ifdef CONDITIONAL
	 * ifeq CONDITIONAL
	 * ifneq CONDITIONAL
	 * else
	 *
	 */
	protected Conditional parseConditional(String line) {
		Conditional condition = null;
		line = line.trim();
		String keyword = null;
		// Move pass the keyword
		for (int i = 0; i < line.length(); i++) {
			if (Util.isSpace(line.charAt(i))) {
				keyword = line.substring(0, i);
				line = line.substring(i).trim();
				break;
			}
		}
		if (keyword == null) {
			keyword = line;
		}
		if (keyword.equals(GNUMakefileConstants.CONDITIONAL_IFDEF)) {
			condition = new Ifdef(this, line);
		} else if (keyword.equals(GNUMakefileConstants.CONDITIONAL_IFNDEF)) {
			condition = new Ifndef(this, line);
		} else if (keyword.equals(GNUMakefileConstants.CONDITIONAL_IFEQ)) {
			condition = new Ifeq(this, line);
		} else if (keyword.equals(GNUMakefileConstants.CONDITIONAL_IFNEQ)) {
			condition = new Ifneq(this, line);
		} else if (keyword.equals(GNUMakefileConstants.CONDITIONAL_ELSE)) {
			condition = new Else(this);
		}
		return condition;
	}

	/**
	 *  Format of the include directive:
	 *      include filename1 filename2 ...
	 */
	protected Include parseInclude(String line) {
		String[] filenames;
		StringTokenizer st = new StringTokenizer(line);
		int count = st.countTokens();
		if (count > 0) {
			filenames = new String[count - 1];
			for (int i = 0; i < count; i++) {
				if (i == 0) {
					st.nextToken();
					// ignore the "include" keyword.
					continue;
				}
				filenames[i - 1] = expandString(st.nextToken(), true);
			}
		} else {
			filenames = new String[0];
		}
		return new Include(this, filenames, getIncludeDirectories());
	}

	/**
	 * There are three forms of the "vpath" directive:
	 *      "vpath PATTERN DIRECTORIES"
	 * Specify the search path DIRECTORIES for file names that match PATTERN.
	 *
	 * The search path, DIRECTORIES, is a list of directories to be
	 * searched, separated by colons (semi-colons on MS-DOS and
	 * MS-Windows) or blanks, just like the search path used in the `VPATH' variable.
	 *
	 *      "vpath PATTERN"
	 * Clear out the search path associated with PATTERN.
	 *
	 *      "vpath"
	 * Clear all search paths previously specified with `vpath' directives.
	 */
	protected VPath parseVPath(String line) {
		String pattern = null;
		String[] directories;
		StringTokenizer st = new StringTokenizer(line);
		int count = st.countTokens();
		List<String> dirs = new ArrayList<String>(count);
		if (count > 0) {
			for (int i = 0; i < count; i++) {
				if (count == 0) {
					// ignore the "vpath" directive
					st.nextToken();
				} else if (count == 1) {
					pattern = st.nextToken();
				} else if (count == 3) {
					String delim = " \t\n\r\f" + GNUMakefile.PATH_SEPARATOR; //$NON-NLS-1$
					dirs.add(st.nextToken(delim));
				} else {
					dirs.add(st.nextToken());
				}
			}
		}
		directories = dirs.toArray(new String[0]);
		if (pattern == null) {
			pattern = new String();
		}
		return new VPath(this, pattern, directories);
	}

	protected UnExport parseUnExport(String line) {
		// Pass over "unexport"
		for (int i = 0; i < line.length(); i++) {
			if (Util.isSpace(line.charAt(i))) {
				line = line.substring(i).trim();
				break;
			}
		}
		return new UnExport(this, line);
	}

	protected GNUTargetRule[] parseGNUTargetRules(String line) {
		String[] targetNames;
		String[] normalReqs;
		String[] orderReqs;
		String cmd = null;
		boolean doubleColon = false;
		int index = Util.indexOf(line, ':');
		if (index != -1) {
			// Break the targets
			String target = line.substring(0, index);
			targetNames = PosixMakefileUtil.findTargets(target.trim());

			// Some TargetRule have "::" for separator
			String req = line.substring(index + 1);
			doubleColon = req.startsWith(":"); //$NON-NLS-1$
			if (doubleColon) {
				// move pass the second ':'
				req = req.substring(1);
			}

			// Check for command
			int semicolon = Util.indexOf(req, ';');
			if (semicolon != -1) {
				cmd = req.substring(semicolon + 1);
				req = req.substring(0, semicolon);
			}

			// Check for Normal and order prerequisites
			String normalReq = null;
			String orderReq = null;
			int pipe = Util.indexOf(req, '|');
			if (pipe != -1) {
				normalReq = req.substring(0, pipe);
				orderReq = req.substring(pipe + 1);
			} else {
				normalReq = req;
				orderReq = ""; //$NON-NLS-1$
			}

			normalReqs = PosixMakefileUtil.findPrerequisites(normalReq.trim());
			orderReqs = PosixMakefileUtil.findPrerequisites(orderReq.trim());
		} else {
			targetNames = PosixMakefileUtil.findTargets(line);
			normalReqs = new String[0];
			orderReqs = new String[0];
		}

		GNUTargetRule[] rules = new GNUTargetRule[targetNames.length];
		for (int i = 0; i < targetNames.length; i++) {
			rules[i] = new GNUTargetRule(this, new Target(targetNames[i]), doubleColon, normalReqs, orderReqs, new Command[0]);
			if (cmd != null) {
				rules[i].addDirective(new Command(this, cmd));
			}
		}
		return rules;
	}

	protected VariableDefinition parseVariableDefinition(String line) {
		line = line.trim();
		VariableDefinition vd;

		// the default type.
		int type = VariableDefinition.TYPE_RECURSIVE_EXPAND;
		boolean isDefine = false;
		boolean isOverride = false;
		boolean isTargetVariable = false;
		boolean isExport = false;
		String targetName = ""; //$NON-NLS-1$

		String name;
		StringBuffer value = new StringBuffer();

		// Check for Target: Variable-assignment
		isTargetVariable = GNUMakefileUtil.isTargetVariable(line);
		if (isTargetVariable) {
			// move to the first ':'
			int colon = Util.indexOf(line, ':');
			if (colon != -1) {
				targetName = line.substring(0, colon).trim();
				line = line.substring(colon + 1).trim();
			} else {
				targetName = ""; //$NON-NLS-1$
			}
		}

		// Check for Override condition.
		if (GNUMakefileUtil.isOverride(line)) {
			isOverride = true;
			// Move pass the keyword override.
			for (int i = 0; i < line.length(); i++) {
				if (Util.isSpace(line.charAt(i))) {
					line = line.substring(i).trim();
					break;
				}
			}
		}

		// Check for "define"
		if (GNUMakefileUtil.isDefine(line)) {
			isDefine = true;
			// Move pass the keyword define.
			for (int i = 0; i < line.length(); i++) {
				if (Util.isSpace(line.charAt(i))) {
					line = line.substring(i).trim();
					break;
				}
			}
		}

		// Check for Override condition.
		if (GNUMakefileUtil.isExport(line)) {
			isExport = true;
			// Move pass the keyword export.
			for (int i = 0; i < line.length(); i++) {
				if (Util.isSpace(line.charAt(i))) {
					line = line.substring(i).trim();
					break;
				}
			}
		}

		// Check for Target-variable

		int index = line.indexOf('=');
		if (index != -1) {
			int separator = index;
			// Check for "+=",  ":=", "?="
			if (index > 0) {
				type = line.charAt(index - 1);
				if (type == VariableDefinition.TYPE_SIMPLE_EXPAND
						|| type == VariableDefinition.TYPE_APPEND
						|| type == VariableDefinition.TYPE_CONDITIONAL) {
					separator = index - 1;
				} else {
					type = VariableDefinition.TYPE_RECURSIVE_EXPAND;
				}
			}
			name = line.substring(0, separator).trim();
			value.append(line.substring(index + 1).trim());
		} else {
			name = line;
		}

		if (isTargetVariable) {
			vd = new TargetVariable(this, targetName, name, value, isOverride, type);
		} else if (isOverride && isDefine) {
			vd = new OverrideDefine(this, name, value);
		} else if (isDefine) {
			vd = new DefineVariable(this, name, value);
		} else if (isOverride) {
			vd = new OverrideVariable(this, name, value, type);
		} else if (isExport) {
			vd = new ExportVariable(this, name, value, type);
		} else {
			vd = new VariableDefinition(this, name, value, type);
		}
		return vd;
	}

	protected StaticTargetRule[] parseStaticTargetRule(String line) {
		// first colon: the Targets
		String targetPattern;
		String[] prereqPatterns;
		String[] targets;
		int colon = Util.indexOf(line, ':');
		if (colon > 1) {
			String targetLine = line.substring(0, colon).trim();
			targets = PosixMakefileUtil.findTargets(targetLine);
			// second colon: Target-Pattern
			line = line.substring(colon + 1);
			colon = Util.indexOf(line, ':');
			if (colon != -1) {
				targetPattern = line.substring(0, colon).trim();
				line = line.substring(colon + 1);
				StringTokenizer st = new StringTokenizer(line);
				int count = st.countTokens();
				prereqPatterns = new String[count];
				for (int i = 0; i < count; i++) {
					prereqPatterns[i] = st.nextToken();
				}
			} else {
				targetPattern = ""; //$NON-NLS-1$
				prereqPatterns = new String[0];
			}
		} else {
			targets = new String[0];
			targetPattern = ""; //$NON-NLS-1$
			prereqPatterns = new String[0];
		}

		StaticTargetRule[] staticRules = new StaticTargetRule[targets.length];
		for (int i = 0; i < targets.length; i++) {
			staticRules[i] = new StaticTargetRule(this, new Target(targets[i]), targetPattern, prereqPatterns, new Command[0]);
		}
		return staticRules;
	}

	protected InferenceRule parseInferenceRule(String line) {
		String tgt;
		int index = Util.indexOf(line, ':');
		if (index != -1) {
			tgt = line.substring(0, index);
		} else {
			tgt = line;
		}
		return new InferenceRule(this, new Target(tgt));
	}

	@Override
	public IDirective[] getBuiltins() {
		return builtins;
	}

	@Override
	public IAutomaticVariable[] getAutomaticVariables() {
		return autoVariables;
	}
	
	@Override
	public IBuiltinFunction[] getBuiltinFunctions() {
		return builtinFunctions;
	}
	
	@Override
	public void setIncludeDirectories(String[] dirs) {
		includeDirectories = dirs;
	}

	@Override
	public String[] getIncludeDirectories() {
		return includeDirectories;
	}
}

Back to the top