001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 the ConQAT Project | 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 or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package eu.cqse.check.framework.preprocessor.c; 018 019import java.util.List; 020import java.util.Set; 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023 024import org.conqat.lib.commons.collections.Pair; 025import org.conqat.lib.commons.string.StringUtils; 026 027import eu.cqse.check.framework.scanner.ELanguage; 028import eu.cqse.check.framework.scanner.IToken; 029import eu.cqse.check.framework.scanner.ScannerUtils; 030import eu.cqse.check.framework.shallowparser.framework.ShallowEntity; 031 032/** 033 * An implementation of the C preprocessor that is adjusted to application in 034 * static analysis. For this, various options of preprocessing can be adjusted. 035 * This class adds include handling to its base classes. 036 * 037 * The design of the preprocessor uses inheritance to separate the aspects macro 038 * handling, include handling, and conditionals to separate classes. This is 039 * meant to keep the classes small and easier to understand, while still 040 * providing a final common class, that can be easily extended by subclassing 041 * and overriding certain methods, which would be hard when using 042 * delegation/composition. 043 */ 044public class CPreprocessor extends ConditionalHandlingCPreprocessorBase { 045 046 /** Patterns used for parsing include statements. */ 047 public static final Pattern INCLUDE_PATTERN = Pattern.compile("#\\s*include +[\"<](.+?)[\">]"); 048 049 /** 050 * A post processing operation that removes all tokens that have been inserted 051 * by the C++ preprocessor as result of the macro expansion. 052 * 053 * Modifies the given collection. 054 */ 055 public static void removePreprocessorTokens(List<ShallowEntity> entities) { 056 ShallowEntity.filterTokens(entities, 057 token -> token.getOriginId().equals(MacroHandlingCPreprocessorBase.MACRO_ORIGIN)); 058 ShallowEntity.collapseEmptyEntities(entities); 059 } 060 061 /** Constructor. */ 062 public CPreprocessor(IMacroProvider macroProvider) { 063 super(macroProvider); 064 } 065 066 /** {@inheritDoc} */ 067 @Override 068 protected void handleInclude(String uniformPath, IToken token, List<IToken> result, int inclusionLimit, 069 Set<String> seenPaths) { 070 if (inclusionLimit <= 0) { 071 return; 072 } 073 074 Matcher matcher = INCLUDE_PATTERN.matcher(token.getText()); 075 if (!matcher.find()) { 076 return; 077 } 078 079 String includedName = matcher.group(1); 080 IncludedTokens pathAndTokens = resolveIncludedTokens(uniformPath, includedName); 081 result.addAll(preprocess(pathAndTokens.getFirst(), pathAndTokens.getSecond(), inclusionLimit - 1, seenPaths)); 082 } 083 084 /** 085 * Returns the included tokens for a given include name. 086 * 087 * @param includingUniformPath 088 * the uniform path of the file that includes this. May be null if no 089 * information is available. 090 * @param includedName 091 * the name of the file to be included. 092 * @return the pair of the name of the resolved uniform path of the include file 093 * and the file's tokens. The resolved uniform path may be null, if it 094 * is not available. 095 */ 096 protected IncludedTokens resolveIncludedTokens(String includingUniformPath, String includedName) { 097 Pair<String, String> content = resolveIncludeContent(includingUniformPath, includedName); 098 099 return new IncludedTokens(content.getFirst(), 100 ScannerUtils.getTokens(content.getSecond(), ELanguage.CPP, includedName)); 101 } 102 103 /** 104 * Returns the resolved uniform path and content of an included file. The 105 * default implementation returns a pair of null and the empty string. 106 * 107 * @param includingUniformPath 108 * the uniform path of the file that includes this. May be null if no 109 * information is available. 110 * @param includedName 111 * the name of the file to be included. 112 * @return the pair of the name of the resolved uniform path of the include file 113 * and the file's content. The resolved uniform path may be null, if it 114 * is not available. 115 */ 116 protected Pair<String, String> resolveIncludeContent(String includingUniformPath, String includedName) { 117 return new Pair<>(null, StringUtils.EMPTY_STRING); 118 } 119 120}