| /* |
| 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 "SourceCompile/SymbolTable.h" |
| #include "CommandLine/CommandLineParser.h" |
| #include "ErrorReporting/ErrorContainer.h" |
| #include "SourceCompile/CompilationUnit.h" |
| #include "SourceCompile/PreprocessFile.h" |
| #include "SourceCompile/CompileSourceFile.h" |
| #include "SourceCompile/Compiler.h" |
| #include "SourceCompile/ParseFile.h" |
| #include "SourceCompile/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 "SourceCompile/SV3_1aTreeShapeListener.h" |
| #include "API/SV3_1aPythonListener.h" |
| using namespace antlr4; |
| #include "Utils/ParseUtils.h" |
| #include "Utils/FileUtils.h" |
| #include "Cache/ParseCache.h" |
| #include "SourceCompile/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 += |
| "SLL 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 (getCompileSourceFile()->getCommandLineParser()->profile()) { |
| m_profileInfo += "Cache saving: " + std::to_string(tmr.elapsed_rounded ()) + "\n"; |
| std::cout << "Cache saving: " + std::to_string(tmr.elapsed_rounded ()) + "\n" << std::flush; |
| tmr.reset(); |
| } |
| } |
| |
| 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; |
| } |