001/* 002 * Anarres C Preprocessor 003 * Copyright (c) 2007-2015, Shevek 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 014 * or implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.anarres.cpp; 018 019import java.io.File; 020import java.io.PrintStream; 021import java.util.Arrays; 022import java.util.EnumSet; 023import java.util.List; 024import javax.annotation.Nonnull; 025import joptsimple.OptionParser; 026import joptsimple.OptionSet; 027import joptsimple.OptionSpec; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * (Currently a simple test class). 033 */ 034public class Main { 035 036 private static final Logger LOG = LoggerFactory.getLogger(Main.class); 037 038 @Nonnull 039 private static CharSequence getWarnings() { 040 StringBuilder buf = new StringBuilder(); 041 for (Warning w : Warning.values()) { 042 if (buf.length() > 0) 043 buf.append(", "); 044 String name = w.name().toLowerCase(); 045 buf.append(name.replace('_', '-')); 046 } 047 return buf; 048 } 049 050 public static void main(String[] args) throws Exception { 051 (new Main()).run(args); 052 } 053 054 public void run(String[] args) throws Exception { 055 056 OptionParser parser = new OptionParser(); 057 OptionSpec<?> helpOption = parser.accepts("help", 058 "Displays command-line help.") 059 .forHelp(); 060 OptionSpec<?> versionOption = parser.acceptsAll(Arrays.asList("version"), 061 "Displays the product version (" + BuildMetadata.getInstance().getVersion() + ") and exits.") 062 .forHelp(); 063 064 OptionSpec<?> debugOption = parser.acceptsAll(Arrays.asList("debug"), 065 "Enables debug output."); 066 067 OptionSpec<String> defineOption = parser.acceptsAll(Arrays.asList("define", "D"), 068 "Defines the given macro.") 069 .withRequiredArg().ofType(String.class).describedAs("name[=definition]"); 070 OptionSpec<String> undefineOption = parser.acceptsAll(Arrays.asList("undefine", "U"), 071 "Undefines the given macro, previously either builtin or defined using -D.") 072 .withRequiredArg().describedAs("name"); 073 OptionSpec<File> includeOption = parser.accepts("include", 074 "Process file as if \"#" + "include \"file\"\" appeared as the first line of the primary source file.") 075 .withRequiredArg().ofType(File.class).describedAs("file"); 076 OptionSpec<File> incdirOption = parser.acceptsAll(Arrays.asList("incdir", "I"), 077 "Adds the directory dir to the list of directories to be searched for header files.") 078 .withRequiredArg().ofType(File.class).describedAs("dir"); 079 OptionSpec<File> iquoteOption = parser.acceptsAll(Arrays.asList("iquote"), 080 "Adds the directory dir to the list of directories to be searched for header files included using \"\".") 081 .withRequiredArg().ofType(File.class).describedAs("dir"); 082 OptionSpec<String> warningOption = parser.acceptsAll(Arrays.asList("warning", "W"), 083 "Enables the named warning class (" + getWarnings() + ").") 084 .withRequiredArg().ofType(String.class).describedAs("warning"); 085 OptionSpec<Void> noWarningOption = parser.acceptsAll(Arrays.asList("no-warnings", "w"), 086 "Disables ALL warnings."); 087 OptionSpec<File> inputsOption = parser.nonOptions() 088 .ofType(File.class).describedAs("Files to process."); 089 090 OptionSet options = parser.parse(args); 091 092 if (options.has(helpOption)) { 093 parser.printHelpOn(System.out); 094 return; 095 } 096 097 if (options.has(versionOption)) { 098 version(System.out); 099 return; 100 } 101 102 Preprocessor pp = new Preprocessor(); 103 pp.addFeature(Feature.DIGRAPHS); 104 pp.addFeature(Feature.TRIGRAPHS); 105 pp.addFeature(Feature.LINEMARKERS); 106 pp.addWarning(Warning.IMPORT); 107 pp.setListener(new DefaultPreprocessorListener()); 108 pp.addMacro("__JCPP__"); 109 pp.getSystemIncludePath().add("/usr/local/include"); 110 pp.getSystemIncludePath().add("/usr/include"); 111 pp.getFrameworksPath().add("/System/Library/Frameworks"); 112 pp.getFrameworksPath().add("/Library/Frameworks"); 113 pp.getFrameworksPath().add("/Local/Library/Frameworks"); 114 115 if (options.has(debugOption)) 116 pp.addFeature(Feature.DEBUG); 117 118 if (options.has(noWarningOption)) 119 pp.getWarnings().clear(); 120 121 for (String warning : options.valuesOf(warningOption)) { 122 warning = warning.toUpperCase(); 123 warning = warning.replace('-', '_'); 124 if (warning.equals("ALL")) 125 pp.addWarnings(EnumSet.allOf(Warning.class)); 126 else 127 pp.addWarning(Enum.valueOf(Warning.class, warning)); 128 } 129 130 for (String arg : options.valuesOf(defineOption)) { 131 int idx = arg.indexOf('='); 132 if (idx == -1) 133 pp.addMacro(arg); 134 else 135 pp.addMacro(arg.substring(0, idx), arg.substring(idx + 1)); 136 } 137 for (String arg : options.valuesOf(undefineOption)) { 138 pp.getMacros().remove(arg); 139 } 140 141 for (File dir : options.valuesOf(incdirOption)) 142 pp.getSystemIncludePath().add(dir.getAbsolutePath()); 143 for (File dir : options.valuesOf(iquoteOption)) 144 pp.getQuoteIncludePath().add(dir.getAbsolutePath()); 145 for (File file : options.valuesOf(includeOption)) 146 // Comply exactly with spec. 147 pp.addInput(new StringLexerSource("#" + "include \"" + file + "\"\n")); 148 149 List<File> inputs = options.valuesOf(inputsOption); 150 if (inputs.isEmpty()) { 151 pp.addInput(new InputLexerSource(System.in)); 152 } else { 153 for (File input : inputs) 154 pp.addInput(new FileLexerSource(input)); 155 } 156 157 if (pp.getFeature(Feature.DEBUG)) { 158 LOG.info("#" + "include \"...\" search starts here:"); 159 for (String dir : pp.getQuoteIncludePath()) 160 LOG.info(" " + dir); 161 LOG.info("#" + "include <...> search starts here:"); 162 for (String dir : pp.getSystemIncludePath()) 163 LOG.info(" " + dir); 164 LOG.info("End of search list."); 165 } 166 167 try { 168 for (;;) { 169 Token tok = pp.token(); 170 if (tok == null) 171 break; 172 if (tok.getType() == Token.EOF) 173 break; 174 System.out.print(tok.getText()); 175 } 176 } catch (Exception e) { 177 StringBuilder buf = new StringBuilder("Preprocessor failed:\n"); 178 Source s = pp.getSource(); 179 while (s != null) { 180 buf.append(" -> ").append(s).append("\n"); 181 s = s.getParent(); 182 } 183 LOG.error(buf.toString(), e); 184 } 185 186 } 187 188 private static void version(@Nonnull PrintStream out) { 189 BuildMetadata metadata = BuildMetadata.getInstance(); 190 out.println("Anarres Java C Preprocessor version " + metadata.getVersion() + " change-id " + metadata.getChangeId()); 191 out.println("Copyright (C) 2007-2015 Shevek (http://www.anarres.org/)."); 192 out.println("This is free software; see the source for copying conditions. There is NO"); 193 out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); 194 } 195}