View Javadoc

1   /*
2   	Copyright (c) 2009 Olivier Chafik, All Rights Reserved
3   	
4   	This file is part of JNAerator (http://jnaerator.googlecode.com/).
5   	
6   	JNAerator is free software: you can redistribute it and/or modify
7   	it under the terms of the GNU Lesser General Public License as published by
8   	the Free Software Foundation, either version 3 of the License, or
9   	(at your option) any later version.
10  	
11  	JNAerator is distributed in the hope that it will be useful,
12  	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  	GNU Lesser General Public License for more details.
15  	
16  	You should have received a copy of the GNU Lesser General Public License
17  	along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
18  */
19  package com.ochafik.lang.jnaerator;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.anarres.cpp.CppReader;
29  import org.anarres.cpp.Feature;
30  import org.anarres.cpp.FileLexerSource;
31  import org.anarres.cpp.LexerException;
32  import org.anarres.cpp.Macro;
33  import org.anarres.cpp.Preprocessor;
34  import org.anarres.cpp.PreprocessorListener;
35  import org.anarres.cpp.Source;
36  import org.anarres.cpp.StringLexerSource;
37  import org.anarres.cpp.Token;
38  import org.anarres.cpp.Warning;
39  
40  import com.ochafik.io.ReadText;
41  import com.ochafik.io.WriteText;
42  import com.ochafik.lang.jnaerator.parser.Define;
43  import com.ochafik.lang.jnaerator.parser.Expression;
44  import com.ochafik.util.string.StringUtils;
45  
46  public class PreprocessorUtils {
47  	
48  	public static String preprocessSources(JNAeratorConfig config, List<Define> defines, boolean verbose, TypeConversion typeConverter) throws IOException, LexerException {
49  
50  		Preprocessor preProcessor = PreprocessorUtils.createPreProcessor(config.preprocessorConfig);
51  		for (File file : config.getFiles())
52  			preProcessor.addInput(file);
53  		
54  		for (String content : config.preprocessorConfig.includeStrings)
55  			preProcessor.addInput(new StringLexerSource(content, true));
56  		
57  		String sourceContent = ReadText.readText(new CppReader(preProcessor));
58  		preProcessor.close();
59  		
60  		Map<String, Macro> macros = preProcessor.getMacros();
61  		
62  		if (config.preprocessingOutFile != null) {
63  			if (config.verbose)
64  				System.out.println("Writing preprocessor output to '" + config.preprocessingOutFile + "'");
65  			WriteText.writeText(sourceContent, config.preprocessingOutFile);
66  		}
67  		
68  		if (config.macrosOutFile != null) {
69  			if (config.verbose)
70  				System.out.println("Writing preprocessor macros to '" + config.macrosOutFile + "'");
71  			WriteText.writeText(StringUtils.implode(macros.entrySet(), "\n"), config.macrosOutFile);
72  		}
73  		
74  		for (String k : config.preprocessorConfig.macros.keySet())
75  			macros.remove(k);
76  		
77  		PreprocessorUtils.addDefines(macros, defines, verbose, typeConverter);
78  		
79  		return sourceContent;
80  	}
81  
82  	public static Preprocessor createPreProcessor(JNAeratorConfig.PreprocessorConfig config) throws IOException, LexerException {
83  		Preprocessor preprocessor = new Preprocessor() {
84  			Set<String> pragmaOnces = new HashSet<String>();
85  			@Override
86  			protected void pragma(Token name, List<Token> value)
87  					throws IOException, LexerException {
88  				if ("once".equals(name.getText())) {
89  					if (!pragmaOnces.add(getSource().toString()))
90  						pop_source();
91  				} else
92  					super.pragma(name, value);
93  			}
94  			@Override
95  			protected void pop_source() throws IOException {
96  				if (getSource() instanceof FileLexerSource) {
97  					
98  				}
99  				super.pop_source();
100 			}
101 		};
102 		preprocessor.setProperStringTokensInLinePragmas(true);
103 		//preprocessor.addFeatures(EnumSet.allOf(Feature.class));
104 		if (config.preprocess) {
105 			preprocessor.addFeature(Feature.KEEPCOMMENTS);
106 			preprocessor.addFeature(Feature.DIGRAPHS);
107 			preprocessor.addFeature(Feature.INCLUDENEXT);
108 			preprocessor.addFeature(Feature.OBJCSYNTAX);
109 			preprocessor.addFeature(Feature.TRIGRAPHS);
110 			//preprocessor.addFeature(Feature.CSYNTAX);
111 			preprocessor.addFeature(Feature.LINEMARKERS);
112 			//preprocessor.addFeature(Feature.DEBUG);
113 			
114 	
115 			preprocessor.addWarning(Warning.IMPORT);
116 		} else {
117 			preprocessor.getFeatures().clear();
118 		}
119 		
120 		preprocessor.setListener(new PreprocessorListener() {
121 			@Override
122 			public void handleWarning(Source source, int line, int column,
123 					String msg) throws LexerException {
124 				if (msg.contains("Unnecessary escape character "))
125 					return;
126 				
127 				if (msg.contains("#pragma"))
128 					return;
129 					
130 				super.handleWarning(source, line, column, msg);
131 			}
132 		});
133 		
134 		preprocessor.getSystemIncludePath().addAll(config.includes);
135 		//preprocessor.getSystemIncludePath().addAll(Arrays.asList(DEFAULT_INCLUDE_PATH.split(":")));
136 		preprocessor.getQuoteIncludePath().addAll(config.includes);
137 		//preprocessor.getFrameworksPath().addAll(Arrays.asList(DEFAULT_FRAMEWORKS_PATH.split(":")));
138 		preprocessor.getFrameworksPath().addAll(config.frameworksPath);
139 		for (Map.Entry<String, String> e : config.macros.entrySet()) {
140 			if (e.getValue() != null)
141 				preprocessor.addMacro(e.getKey(), e.getValue());
142 			else
143 				preprocessor.addMacro(e.getKey());
144 		}
145 		return preprocessor;
146 	}
147 
148 	public static String removePreprocessorDirectives(String s) {
149 		s = s.replaceAll(";#line", ";\n#line"); /// hack !
150 		
151 		s = s.replaceAll("(?s)#\\s*(pragma|if|endif|error|ifdef|ifndef|else|elif|define|undef).*?\n", "\n");
152 		s = s.replaceAll("(?s)#\\s*(import|include).*?\n", "\n");
153 		return s;
154 	}
155 
156 	public static String removeNastyDefines(String s) {
157 		/// Mac OS X
158 		s = s.replaceAll("DEPRECATED_IN_MAC_OS_X_VERSION_[A-Z0-9_]+_AND_LATER", " ");
159 		s = s.replaceAll("AVAILABLE_MAC_OS_X_VERSION_[A-Z0-9_]+_AND_LATER(_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_[A-Z0-9_]+)?", " ");
160 		s = s.replaceAll("NS_REQUIRES_NIL_TERMINATION", " ");
161 		s = s.replaceAll("__MATH_H_ALWAYS_INLINE__", " ");
162 		s = s.replace("CSEXTERN", "extern");
163 		
164 		/// Windows
165 		s = s.replace("__inner_fallthrough_dec", " ");
166 		
167 		/// Others
168 		//s = s.replaceAll("__strong", " ");
169 		return s;
170 	}
171 
172 	//static void addDefines(Preprocessor preProcessor, List<Define> defines) {
173 	//	for (Map.Entry<String, Macro> e : preProcessor.getMacros().entrySet()) {
174 	static void addDefines(Map<String, Macro> macros, List<Define> defines, boolean verbose, TypeConversion typeConverter) {
175 		for (Map.Entry<String, Macro> e : macros.entrySet()) {
176 			Macro macro = e.getValue();
177 			if (macro.getText() == null)
178 				continue;
179 		
180 			if (macro.isFunctionLike() && macro.getArgs() > 0)
181 				continue;
182 			
183 			//if (macro.getFile() == null)
184 			//	continue;
185 			
186 			try {
187 				Expression expression = JNAeratorParser.newObjCppParser(typeConverter, macro.getText(), verbose).expression().expr;
188 				if (expression == null)
189 					continue;
190 			
191 				Define define = new Define(e.getKey(), expression);
192 				if (macro.getSource() != null)
193 					define.setElementFile(macro.getSource().getPath());
194 				defines.add(define);
195 			} catch (Exception ex) {
196 				if (verbose)
197 					System.err.println("Failed to convert define '" + e.getValue() + ":\n" + ex);
198 				//ex.printStackTrace();
199 			}
200 		}
201 	}
202 	
203 
204 }