blob: b32168c63d95737994f836d7dfa0d09814521859 [file] [log] [blame]
/*
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
};
enum EvaluateInstr : bool { Evaluate = true, DontEvaluate = false };
SpecialInstructions()
: m_mute(DontMute),
m_mark_empty_macro(DontMark),
m_filterFileLine(DontFilter),
m_check_macro_loop(DontCheckLoop),
m_as_is_undefined_macro(ComplainUndefinedMacro),
m_evaluate(Evaluate){}
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),
m_evaluate(rhs.m_evaluate) {}
SpecialInstructions(TraceInstr mute, EmptyMacroInstr mark_empty_macro,
FileLineInfoInstr filterFileLine,
CheckLoopInstr check_macro_loop,
AsIsUndefinedMacroInstr as_is_undefined_macro,
EvaluateInstr evalaute = Evaluate)
: 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),
m_evaluate(evalaute) {}
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")
<< ", Evaluate:"
<< (m_evaluate ? "Evaluate" : "DontEvaluate")
<< std::endl;
};
TraceInstr m_mute;
EmptyMacroInstr m_mark_empty_macro;
FileLineInfoInstr m_filterFileLine;
CheckLoopInstr m_check_macro_loop;
AsIsUndefinedMacroInstr m_as_is_undefined_macro;
EvaluateInstr m_evaluate;
};
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; }
std::string getProfileInfo() { return m_profileInfo; }
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;
std::string m_profileInfo;
};
}; // namespace SURELOG
#endif /* PREPROCESSFILE_H */