| /* | |
| Copyright 2019 Alain Dargelas | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| /* | |
| * File: PreprocessFile.h | |
| * Author: alain | |
| * | |
| * Created on February 24, 2017, 9:37 PM | |
| */ | |
| #ifndef PREPROCESSFILE_H | |
| #define PREPROCESSFILE_H | |
| #include <string> | |
| #include <vector> | |
| #include <map> | |
| #include <set> | |
| #include <stack> | |
| #include "parser/SV3_1aPpLexer.h" | |
| #include "parser/SV3_1aPpParser.h" | |
| #include "SourceCompile/CompilationUnit.h" | |
| #include "Library/Library.h" | |
| #include "SourceCompile/LoopCheck.h" | |
| #include "SourceCompile/IncludeFileInfo.h" | |
| namespace SURELOG { | |
| class SV3_1aPpTreeShapeListener; | |
| class CompileSourceFile; | |
| #define LINE1 1 | |
| /* Can be either an include file or a macro definition being evaluated */ | |
| class PreprocessFile { | |
| public: | |
| class SpecialInstructions; | |
| class DescriptiveErrorListener; | |
| /* Constructors */ | |
| PreprocessFile(SymbolId fileId, CompileSourceFile* csf, | |
| SpecialInstructions& instructions, | |
| CompilationUnit* compilationUnit, Library* library); | |
| PreprocessFile(SymbolId fileId, PreprocessFile* includedIn, | |
| unsigned int includerLine, CompileSourceFile* csf, | |
| SpecialInstructions& instructions, | |
| CompilationUnit* compilationUnit, Library* library, | |
| std::string macroBody = "", MacroInfo* = NULL, | |
| unsigned int embeddedMacroCallLine = 0, | |
| SymbolId embeddedMacroCallFile = 0); | |
| PreprocessFile(const PreprocessFile& orig); | |
| virtual ~PreprocessFile(); | |
| /* Main function */ | |
| bool preprocess(); | |
| std::string getPreProcessedFileContent(); | |
| /* Macro manipulations */ | |
| void recordMacro(const std::string name, unsigned int line, | |
| unsigned short int column, | |
| const std::string formal_arguments, | |
| const std::vector<std::string> body); | |
| void recordMacro(const std::string name, unsigned int line, | |
| unsigned short int column, | |
| const std::vector<std::string> formal_arguments, | |
| const std::vector<std::string> body); | |
| std::string getMacro(const std::string name, | |
| std::vector<std::string>& actual_arguments, | |
| PreprocessFile* callingFile, unsigned int callingLine, | |
| LoopCheck& loopChecker, | |
| SpecialInstructions& instructions, | |
| unsigned int embeddedMacroCallLine = 0, | |
| SymbolId embeddedMacroCallFile = 0); | |
| bool deleteMacro(const std::string name, std::set<PreprocessFile*>& visited); | |
| void undefineAllMacros(std::set<PreprocessFile*>& visited); | |
| bool isMacroBody() { return (m_macroBody != ""); } | |
| std::string getMacroBody() { return m_macroBody; } | |
| MacroInfo* getMacroInfo() { return m_macroInfo; } | |
| SymbolId getMacroSignature(); | |
| const MacroStorage& getMacros() { return m_macros; } | |
| MacroInfo* getMacro(const std::string name); | |
| const std::string getFileName(unsigned int line); | |
| std::string reportIncludeInfo(); | |
| CompileSourceFile* getCompileSourceFile() { return m_compileSourceFile; } | |
| CompilationUnit* getCompilationUnit() { return m_compilationUnit; } | |
| Library* getLibrary() { return m_library; } | |
| antlr4::CommonTokenStream* getTokenStream() { | |
| return m_antlrParserHandler ? m_antlrParserHandler->m_pptokens : NULL; | |
| } | |
| SymbolId getFileId(unsigned int line); | |
| SymbolId getIncluderFileId(unsigned int line); | |
| SymbolId getRawFileId() { return m_fileId; } | |
| unsigned int getLineNb(unsigned int line); | |
| PreprocessFile* getIncluder() { return m_includer; } | |
| unsigned int getIncluderLine() { return m_includerLine; } | |
| unsigned int getLineCount() { return m_lineCount; } | |
| unsigned int getSumLineCount(); | |
| std::vector<IncludeFileInfo>& getIncludeFileInfo() { | |
| return m_includeFileInfo; | |
| } | |
| IncludeFileInfo& getIncludeFileInfo(int index) { | |
| if (index >= 0 && index < ((int)m_includeFileInfo.size())) | |
| return m_includeFileInfo[index]; | |
| else | |
| return m_badIncludeFileInfo; | |
| } | |
| unsigned int getEmbeddedMacroCallLine() { return m_embeddedMacroCallLine; } | |
| SymbolId getEmbeddedMacroCallFile() { return m_embeddedMacroCallFile; } | |
| /* Markings */ | |
| static std::string MacroNotDefined; | |
| static std::string PP__Line__Marking; | |
| static std::string PP__File__Marking; | |
| private: | |
| SymbolId m_fileId; | |
| Library* m_library; | |
| std::string m_result; | |
| std::string m_macroBody; | |
| PreprocessFile* m_includer; | |
| unsigned int m_includerLine; | |
| std::vector<PreprocessFile*> m_includes; | |
| CompileSourceFile* m_compileSourceFile; | |
| unsigned int m_lineCount; | |
| IncludeFileInfo m_badIncludeFileInfo; | |
| public: | |
| /* Instructions passed from calling scope */ | |
| class SpecialInstructions { | |
| public: | |
| enum TraceInstr : bool { Mute = true, DontMute = false }; | |
| enum EmptyMacroInstr : bool { Mark = true, DontMark = false }; | |
| enum FileLineInfoInstr : bool { Filter = true, DontFilter = false }; | |
| enum CheckLoopInstr : bool { CheckLoop = true, DontCheckLoop = false }; | |
| enum AsIsUndefinedMacroInstr : bool { | |
| AsIsUndefinedMacro = true, | |
| ComplainUndefinedMacro = false | |
| }; | |
| SpecialInstructions() | |
| : m_mute(DontMute), | |
| m_mark_empty_macro(DontMark), | |
| m_filterFileLine(DontFilter), | |
| m_check_macro_loop(DontCheckLoop), | |
| m_as_is_undefined_macro(ComplainUndefinedMacro) {} | |
| SpecialInstructions(SpecialInstructions& rhs) | |
| : m_mute(rhs.m_mute), | |
| m_mark_empty_macro(rhs.m_mark_empty_macro), | |
| m_filterFileLine(rhs.m_filterFileLine), | |
| m_check_macro_loop(rhs.m_check_macro_loop), | |
| m_as_is_undefined_macro(rhs.m_as_is_undefined_macro) {} | |
| SpecialInstructions(TraceInstr mute, EmptyMacroInstr mark_empty_macro, | |
| FileLineInfoInstr filterFileLine, | |
| CheckLoopInstr check_macro_loop, | |
| AsIsUndefinedMacroInstr as_is_undefined_macro) | |
| : m_mute(mute), | |
| m_mark_empty_macro(mark_empty_macro), | |
| m_filterFileLine(filterFileLine), | |
| m_check_macro_loop(check_macro_loop), | |
| m_as_is_undefined_macro(as_is_undefined_macro) {} | |
| void print() { | |
| std::cout << "Trace:" << (m_mute ? "Mute" : "DontMute") | |
| << ", EmptyMacro:" << (m_mark_empty_macro ? "Mark" : "DontMark") | |
| << ", FileLineInfo:" | |
| << (m_filterFileLine ? "Filter " : "DontFilter") | |
| << ", CheckLoop:" | |
| << (m_check_macro_loop ? "CheckLoop" : "DontCheckLoop") | |
| << ", AsIsUndefMacro:" | |
| << (m_as_is_undefined_macro ? "AsIsUndefinedMacro" | |
| : "ComplainUndefinedMacro") | |
| << std::endl; | |
| }; | |
| TraceInstr m_mute; | |
| EmptyMacroInstr m_mark_empty_macro; | |
| FileLineInfoInstr m_filterFileLine; | |
| CheckLoopInstr m_check_macro_loop; | |
| AsIsUndefinedMacroInstr m_as_is_undefined_macro; | |
| }; | |
| std::string evaluateMacroInstance( | |
| const std::string macro_instance, PreprocessFile* callingFile, | |
| unsigned int callingLine, | |
| SpecialInstructions::CheckLoopInstr checkMacroLoop, | |
| SpecialInstructions::AsIsUndefinedMacroInstr); | |
| /* Incoming `line handling */ | |
| class LineTranslationInfo { | |
| public: | |
| LineTranslationInfo(SymbolId pretendFileId, unsigned int originalLine, | |
| unsigned int pretendLine) | |
| : m_pretendFileId(pretendFileId), | |
| m_originalLine(originalLine), | |
| m_pretendLine(pretendLine) {} | |
| SymbolId m_pretendFileId; | |
| unsigned int m_originalLine; | |
| unsigned int m_pretendLine; | |
| }; | |
| /* `ifdef, `ifndef, `elsif, `else Stack */ | |
| class IfElseItem { | |
| public: | |
| enum Type { IFDEF, IFNDEF, ELSIF, ELSE }; | |
| std::string m_macroName; | |
| bool m_defined; | |
| Type m_type; | |
| bool m_previousActiveState; | |
| }; | |
| typedef std::vector<IfElseItem> IfElseStack; | |
| IfElseStack m_ifStack; | |
| IfElseStack& getStack(); | |
| /* Antlr parser container */ | |
| class AntlrParserHandler { | |
| public: | |
| AntlrParserHandler() | |
| : m_inputStream(NULL), | |
| m_pplexer(NULL), | |
| m_pptokens(NULL), | |
| m_ppparser(NULL), | |
| m_pptree(NULL) {} | |
| ~AntlrParserHandler(); | |
| antlr4::ANTLRInputStream* m_inputStream; | |
| SV3_1aPpLexer* m_pplexer; | |
| antlr4::CommonTokenStream* m_pptokens; | |
| SV3_1aPpParser* m_ppparser; | |
| antlr4::tree::ParseTree* m_pptree; | |
| DescriptiveErrorListener* m_errorListener; | |
| }; | |
| SV3_1aPpTreeShapeListener* m_listener; | |
| public: | |
| /* Options */ | |
| void setDebug(int level); | |
| bool m_debugPP; | |
| bool m_debugPPResult; | |
| bool m_debugPPTokens; | |
| bool m_debugPPTree; | |
| bool m_debugMacro; | |
| SpecialInstructions m_instructions; | |
| /* To create the preprocessed content */ | |
| void append(const std::string& s); | |
| void pauseAppend() { m_pauseAppend = true; } | |
| void resumeAppend() { m_pauseAppend = false; } | |
| void addLineTranslationInfo(LineTranslationInfo& info) { | |
| m_lineTranslationVec.push_back(info); | |
| } | |
| /* Shorthand for logging an error */ | |
| void addError(Error& error); | |
| /* Shorthands for symbol manipulations */ | |
| SymbolId registerSymbol(const std::string symbol); | |
| SymbolId getId(const std::string symbol); | |
| const std::string getSymbol(SymbolId id); | |
| // For recursive macro definition detection | |
| PreprocessFile* getSourceFile(); | |
| LoopCheck m_loopChecker; | |
| // For cache processing | |
| void saveCache(); | |
| void collectIncludedFiles(std::set<PreprocessFile*>& included); | |
| bool usingCachedVersion() { return m_usingCachedVersion; } | |
| private: | |
| std::pair<bool, std::string> evaluateMacro_( | |
| const std::string name, std::vector<std::string>& arguments, | |
| PreprocessFile* callingFile, unsigned int callingLine, | |
| LoopCheck& loopChecker, MacroInfo* macroInfo, | |
| SpecialInstructions& instructions, unsigned int embeddedMacroCallLine, | |
| SymbolId embeddedMacroCallFile); | |
| void checkMacroArguments_(const std::string& name, unsigned int line, | |
| unsigned short column, | |
| const std::vector<std::string>& arguments, | |
| const std::vector<std::string>& tokens); | |
| void forgetPreprocessor_(PreprocessFile*, PreprocessFile* pp); | |
| AntlrParserHandler* m_antlrParserHandler; | |
| MacroInfo* m_macroInfo; /* Only used when preprocessing a macro content */ | |
| MacroStorage m_macros; | |
| CompilationUnit* m_compilationUnit; | |
| std::vector<LineTranslationInfo> m_lineTranslationVec; | |
| bool m_pauseAppend; | |
| bool m_usingCachedVersion; | |
| std::vector<IncludeFileInfo> m_includeFileInfo; | |
| unsigned int m_embeddedMacroCallLine; | |
| SymbolId m_embeddedMacroCallFile; | |
| }; | |
| }; // namespace SURELOG | |
| #endif /* PREPROCESSFILE_H */ |