| /* |
| 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: ParseFile.cpp |
| * Author: alain |
| * |
| * Created on February 24, 2017, 10:03 PM |
| */ |
| |
| #include "SymbolTable.h" |
| #include "../CommandLine/CommandLineParser.hpp" |
| #include "../ErrorReporting/ErrorContainer.h" |
| #include "CompilationUnit.h" |
| #include "PreprocessFile.h" |
| #include "CompileSourceFile.h" |
| #include "Compiler.h" |
| #include "ParseFile.h" |
| #include "AntlrParserHandler.h" |
| #include <cstdlib> |
| #include <iostream> |
| #include "antlr4-runtime.h" |
| #include "atn/ParserATNSimulator.h" |
| |
| using namespace std; |
| using namespace antlr4; |
| using namespace SURELOG; |
| |
| #include "../parser/SV3_1aLexer.h" |
| #include "../parser/SV3_1aParser.h" |
| #include "../parser/SV3_1aParserBaseListener.h" |
| #include "SV3_1aTreeShapeListener.h" |
| #include "../API/SV3_1aPythonListener.h" |
| using namespace antlr4; |
| #include "../Utils/ParseUtils.h" |
| #include "../Utils/FileUtils.h" |
| #include "../Cache/ParseCache.h" |
| #include "AntlrParserErrorListener.h" |
| #include "../Package/Precompiled.h" |
| #include "../Utils/StringUtils.h" |
| #include "../Utils/Timer.h" |
| ParseFile::ParseFile (SymbolId fileId, SymbolTable* symbolTable, ErrorContainer* errors) : |
| m_fileId (fileId), m_ppFileId(0), m_compileSourceFile(NULL), m_compilationUnit(NULL), m_library(NULL), m_antlrParserHandler(NULL), m_listener(NULL), |
| m_usingCachedVersion(false), m_keepParserHandler(false), m_fileContent(NULL), debug_AstModel(false), m_parent(NULL), m_offsetLine(0), m_symbolTable(symbolTable), m_errors(errors) { |
| debug_AstModel = true; |
| } |
| |
| ParseFile::ParseFile (SymbolId fileId, CompileSourceFile* csf, CompilationUnit* compilationUnit, Library* library, SymbolId ppFileId, bool keepParserHandler) : |
| m_fileId (fileId), m_ppFileId(ppFileId), m_compileSourceFile(csf), m_compilationUnit(compilationUnit), m_library(library), m_antlrParserHandler(NULL), m_listener(NULL), |
| m_usingCachedVersion(false), m_keepParserHandler(keepParserHandler), m_fileContent(NULL), debug_AstModel(false), m_parent(NULL), m_offsetLine(0), m_symbolTable(NULL), m_errors(NULL) { |
| debug_AstModel = m_compileSourceFile->getCommandLineParser ()->getDebugAstModel(); |
| } |
| |
| ParseFile::ParseFile(CompileSourceFile* compileSourceFile, ParseFile* parent, SymbolId chunkFileId, unsigned int offsetLine) : m_fileId (parent->m_fileId), m_ppFileId(chunkFileId), |
| m_compileSourceFile(compileSourceFile), m_compilationUnit(parent->m_compilationUnit), m_library(parent->m_library), m_antlrParserHandler(NULL), m_listener(NULL), |
| m_usingCachedVersion(false), m_keepParserHandler(parent->m_keepParserHandler), m_fileContent(parent->m_fileContent), |
| debug_AstModel(false), m_parent(parent), m_offsetLine(offsetLine), m_symbolTable(NULL), m_errors(NULL) { |
| parent->m_children.push_back(this); |
| } |
| |
| ParseFile::~ParseFile () |
| { |
| if (!m_keepParserHandler) |
| delete m_antlrParserHandler; |
| } |
| |
| SymbolTable* ParseFile::getSymbolTable() { |
| return m_symbolTable ? m_symbolTable : m_compileSourceFile->getSymbolTable(); |
| } |
| |
| ErrorContainer* ParseFile::getErrorContainer() { |
| return m_errors ? m_errors : m_compileSourceFile->getErrorContainer(); |
| } |
| |
| SymbolId ParseFile::registerSymbol(const std::string symbol) { |
| return getCompileSourceFile()->getSymbolTable()->registerSymbol(symbol); |
| } |
| |
| SymbolId ParseFile::getId(const std::string symbol) { |
| return getCompileSourceFile()->getSymbolTable()->getId(symbol); |
| } |
| |
| const std::string ParseFile::getSymbol(SymbolId id) { |
| return getCompileSourceFile()->getSymbolTable()->getSymbol(id); |
| } |
| |
| const std::string ParseFile::getFileName(unsigned int line) { |
| return getSymbol(getFileId(line)); |
| } |
| |
| void |
| ParseFile::addError (Error& error) |
| { |
| getCompileSourceFile()->getErrorContainer ()->addError (error); |
| } |
| |
| SymbolId |
| ParseFile::getFileId (unsigned int line) |
| { |
| if (!getCompileSourceFile()) |
| return m_fileId; |
| PreprocessFile* pp = getCompileSourceFile()->getPreprocessor (); |
| auto& infos = pp->getIncludeFileInfo (); |
| if (line == 0) |
| return m_fileId; |
| if (infos.size()) |
| { |
| |
| bool inRange = false; |
| unsigned int indexOpeningRange = 0; |
| for (unsigned int i =infos.size()-1; i >= 0; i--) |
| { |
| //if (!inRange) |
| // { |
| if ((line >= infos[i].m_originalLine) && (infos[i].m_type == 2)) |
| { |
| SymbolId fileId = getSymbolTable()->registerSymbol (pp->getSymbol (infos[i].m_sectionFile)); |
| return (fileId); |
| } |
| // } |
| if (infos[i].m_type == 2) |
| { |
| if (!inRange) |
| { |
| inRange = true; |
| indexOpeningRange = infos[i].m_indexOpening; |
| } |
| } |
| else |
| { |
| if (inRange) |
| { |
| if (i == indexOpeningRange) |
| inRange = false; |
| } |
| } |
| if ((line >= infos[i].m_originalLine) && (infos[i].m_type == 1) && (line < infos[infos[i].m_indexClosing].m_originalLine)) |
| { |
| SymbolId fileId = getSymbolTable()->registerSymbol (pp->getSymbol (infos[i].m_sectionFile)); |
| return (fileId); |
| } |
| if (i == 0) |
| break; |
| } |
| return m_fileId; |
| } |
| else |
| { |
| return m_fileId; |
| } |
| } |
| |
| unsigned int |
| ParseFile::getLineNb (unsigned int line) |
| { |
| if (!getCompileSourceFile()) |
| return line; |
| PreprocessFile* pp = getCompileSourceFile()->getPreprocessor (); |
| auto& infos = pp->getIncludeFileInfo (); |
| if (line == 0) |
| return 1; |
| |
| if (infos.size()) |
| { |
| |
| bool inRange = false; |
| unsigned int indexOpeningRange = 0; |
| for (unsigned int i =infos.size()-1; i >= 0; i--) |
| { |
| // if (!inRange) |
| // { |
| if ((line >= infos[i].m_originalLine) && (infos[i].m_type == 2)) |
| { |
| return (infos[i].m_sectionStartLine + (line - infos[i].m_originalLine)); |
| } |
| // } |
| if (infos[i].m_type == 2) |
| { |
| if (!inRange) |
| { |
| inRange = true; |
| indexOpeningRange = infos[i].m_indexOpening; |
| } |
| } |
| else |
| { |
| if (inRange) |
| { |
| if (i == indexOpeningRange) |
| inRange = false; |
| } |
| } |
| if ((line >= infos[i].m_originalLine) && (infos[i].m_type == 1) && (line < infos[infos[i].m_indexClosing].m_originalLine)) |
| { |
| return (infos[i].m_sectionStartLine + (line - infos[i].m_originalLine)); |
| } |
| |
| if (i == 0) |
| break; |
| } |
| return line; |
| } |
| else |
| { |
| return line; |
| } |
| } |
| |
| |
| bool ParseFile::parseOneFile_ (std::string fileName, unsigned int lineOffset) |
| { |
| Timer tmr; |
| AntlrParserHandler* antlrParserHandler = new AntlrParserHandler (); |
| m_antlrParserHandler = antlrParserHandler; |
| std::ifstream stream; |
| stream.open (fileName); |
| if (!stream.good ()) |
| { |
| SymbolId fileId = registerSymbol (fileName); |
| Location ppfile (fileId); |
| Error err (ErrorDefinition::PA_CANNOT_OPEN_FILE, ppfile); |
| addError (err); |
| return false; |
| } |
| |
| antlrParserHandler->m_inputStream = new ANTLRInputStream (stream); |
| antlrParserHandler->m_errorListener = new AntlrParserErrorListener (this, false, lineOffset, fileName); |
| antlrParserHandler->m_lexer = new SV3_1aLexer (antlrParserHandler->m_inputStream); |
| antlrParserHandler->m_lexer->removeErrorListeners (); |
| antlrParserHandler->m_lexer->addErrorListener (antlrParserHandler->m_errorListener); |
| antlrParserHandler->m_tokens = new CommonTokenStream (antlrParserHandler->m_lexer); |
| antlrParserHandler->m_tokens->fill (); |
| |
| if (getCompileSourceFile ()->getCommandLineParser ()->profile ()) |
| { |
| //m_profileInfo += "Tokenizer: " + std::to_string (tmr.elapsed_rounded ()) + " " + fileName + "\n"; |
| tmr.reset (); |
| } |
| |
| antlrParserHandler->m_parser = new SV3_1aParser (antlrParserHandler->m_tokens); |
| |
| m_antlrParserHandler->m_parser->getInterpreter<atn::ParserATNSimulator>()->setPredictionMode (atn::PredictionMode::SLL); |
| m_antlrParserHandler->m_parser->setErrorHandler (std::make_shared<BailErrorStrategy>()); |
| m_antlrParserHandler->m_parser->removeErrorListeners (); |
| |
| try |
| { |
| m_antlrParserHandler->m_tree = m_antlrParserHandler->m_parser->top_level_rule (); |
| |
| if (getCompileSourceFile()->getCommandLineParser ()->profile ()) |
| { |
| m_profileInfo += "SSL Parsing: " + StringUtils::to_string(tmr.elapsed_rounded()) + " " + fileName + "\n"; |
| tmr.reset(); |
| } |
| } |
| catch (ParseCancellationException& pex) |
| { |
| |
| m_antlrParserHandler->m_tokens->reset (); |
| m_antlrParserHandler->m_parser->reset (); |
| |
| m_antlrParserHandler->m_parser->setErrorHandler (std::make_shared<DefaultErrorStrategy>()); |
| antlrParserHandler->m_parser->removeErrorListeners (); |
| antlrParserHandler->m_parser->addErrorListener (antlrParserHandler->m_errorListener); |
| antlrParserHandler->m_parser->getInterpreter<atn::ParserATNSimulator>()->setPredictionMode (atn::PredictionMode::LL); |
| antlrParserHandler->m_tree = antlrParserHandler->m_parser->top_level_rule (); |
| |
| if (getCompileSourceFile()->getCommandLineParser ()->profile ()) |
| { |
| m_profileInfo += "LL Parsing: " + StringUtils::to_string(tmr.elapsed_rounded()) + " " + fileName + "\n"; |
| tmr.reset(); |
| } |
| |
| } |
| stream.close (); |
| return true; |
| } |
| |
| |
| std::string ParseFile::getProfileInfo() { |
| std::string profile; |
| profile = m_profileInfo; |
| for (unsigned int i = 0; i < m_children.size (); i++) |
| profile += m_children[i]->m_profileInfo; |
| |
| return profile; |
| } |
| |
| bool ParseFile::parse() { |
| |
| Precompiled* prec = Precompiled::getSingleton (); |
| std::string root = this->getPpFileName (); |
| root = StringUtils::getRootFileName (root); |
| bool precompiled = false; |
| if (prec->isFilePrecompiled (root)) |
| precompiled = true; |
| |
| |
| if (m_children.size () == 0) |
| { |
| ParseCache cache (this); |
| |
| if (cache.restore ()) |
| { |
| m_usingCachedVersion = true; |
| if (debug_AstModel && !precompiled) |
| std::cout << m_fileContent->printObjects (); |
| return true; |
| } |
| } |
| else |
| { |
| bool ok = true; |
| for (unsigned int i = 0; i < m_children.size (); i++) |
| { |
| ParseCache cache (m_children[i]); |
| |
| if (cache.restore ()) |
| { |
| m_children[i]->m_fileContent->setParent(m_fileContent); |
| m_usingCachedVersion = true; |
| if (debug_AstModel && !precompiled) |
| std::cout << m_children[i]->m_fileContent->printObjects (); |
| } |
| else |
| { |
| ok = false; |
| } |
| |
| } |
| if (ok) |
| { |
| return true; |
| } |
| } |
| |
| // This is not a parent Parser object |
| if (m_children.size() == 0) |
| { |
| //std::cout << std::endl << "Parsing " << getSymbol(m_ppFileId) << " Line: " << m_offsetLine << std::endl << std::flush; |
| |
| parseOneFile_(getSymbol(m_ppFileId), m_offsetLine); |
| |
| //m_listener = new SV3_1aTreeShapeListener (this, m_antlrParserHandler->m_tokens, m_offsetLine); |
| //tree::ParseTreeWalker::DEFAULT.walk (m_listener, m_antlrParserHandler->m_tree); |
| //std::cout << std::endl << "End Parsing " << getSymbol(m_ppFileId) << " Line: " << m_offsetLine << std::endl << std::flush; |
| |
| } |
| |
| |
| // This is either a parent Parser object of this Parser object has no parent |
| if ((m_children.size () != 0) || (m_parent == NULL)) |
| { |
| |
| if ((m_parent == NULL) && (m_children.size () == 0)) |
| { |
| Timer tmr; |
| |
| m_listener = new SV3_1aTreeShapeListener (this, m_antlrParserHandler->m_tokens, m_offsetLine); |
| tree::ParseTreeWalker::DEFAULT.walk (m_listener, m_antlrParserHandler->m_tree); |
| |
| if (debug_AstModel && !precompiled) |
| std::cout << m_fileContent->printObjects (); |
| |
| if (getCompileSourceFile ()->getCommandLineParser ()->profile ()) |
| { |
| //m_profileInfo += "AST Walking: " + std::to_string (tmr.elapsed_rounded ()) + "\n"; |
| tmr.reset (); |
| } |
| |
| ParseCache cache (this); |
| if (!cache.save ()) |
| { |
| return false; |
| } |
| |
| } |
| |
| if (m_children.size () != 0) |
| { |
| |
| for (unsigned int i = 0; i < m_children.size (); i++) |
| { |
| if (m_children[i]->m_antlrParserHandler) |
| { |
| // Only visit the chunks that got re-parsed |
| // TODO: Incrementally regenerate the FileContent |
| m_children[i]->m_fileContent->setParent(m_fileContent); |
| m_children[i]->m_listener = new SV3_1aTreeShapeListener (m_children[i], m_children[i]->m_antlrParserHandler->m_tokens, |
| m_children[i]->m_offsetLine); |
| |
| Timer tmr; |
| tree::ParseTreeWalker::DEFAULT.walk (m_children[i]->m_listener, m_children[i]->m_antlrParserHandler->m_tree); |
| |
| if (getCompileSourceFile ()->getCommandLineParser ()->profile ()) |
| { |
| //m_profileInfo += "For file " + getSymbol (m_children[i]->m_ppFileId) + ", AST Walking took" + std::to_string (tmr.elapsed_rounded ()) + "\n"; |
| tmr.reset (); |
| } |
| |
| if (debug_AstModel && !precompiled) |
| std::cout << m_children[i]->m_fileContent->printObjects (); |
| |
| ParseCache cache (m_children[i]); |
| if (!cache.save ()) |
| { |
| return false; |
| } |
| |
| } |
| } |
| |
| } |
| } |
| return true; |
| } |
| |
| |
| |