1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
111 preprocessor.addFeature(Feature.LINEMARKERS);
112
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
136 preprocessor.getQuoteIncludePath().addAll(config.includes);
137
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");
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
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
165 s = s.replace("__inner_fallthrough_dec", " ");
166
167
168
169 return s;
170 }
171
172
173
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
184
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
199 }
200 }
201 }
202
203
204 }