From 29d94d9ca6e830e79208de8d2e868fe9f7eef789 Mon Sep 17 00:00:00 2001 From: HS Date: Thu, 28 Mar 2024 00:33:54 -0700 Subject: [PATCH] Implement directives --- CMakeLists.txt | 10 +- grammar/SV3_1aLexer.g4 | 7 +- grammar/SV3_1aParser.g4 | 15 +- grammar/SV3_1aPpParser.g4 | 7 +- .../Surelog/CommandLine/CommandLineParser.h | 3 + include/Surelog/Design/FileContent.h | 20 +- .../SourceCompile/CommonListenerHelper.h | 19 +- .../ParseTreeListener.template.hpp | 12 +- .../SourceCompile/SV3_1aParseTreeListener.h | 98 ++ .../SourceCompile/SV3_1aPpParseTreeListener.h | 137 +++ scripts/generate_parser_listener.py | 35 +- src/API/Surelog.cpp | 24 +- src/CommandLine/CommandLineParser.cpp | 11 + src/Common/PlatformFileSystem.cpp | 1 + src/Design/FileContent.cpp | 189 +++- src/Design/VObject.cpp | 2 +- src/Library/SVLibShapeListener.cpp | 2 +- src/SourceCompile/CommonListenerHelper.cpp | 14 +- src/SourceCompile/ParseFile.cpp | 45 +- .../ParseTreeListener.template.cxx | 114 +-- src/SourceCompile/PreprocessFile.cpp | 22 +- .../SV3_1aParseTreeListener.template.cxx | 575 +++++++++++ .../SV3_1aPpParseTreeListener.template.cxx | 923 ++++++++++++++++++ .../SV3_1aPpTreeShapeListener.cpp | 93 +- src/SourceCompile/SV3_1aTreeShapeHelper.cpp | 6 + src/SourceCompile/SV3_1aTreeShapeListener.cpp | 43 +- src/Utils/ParseUtils.cpp | 30 +- third_party/UHDM | 2 +- third_party/antlr4 | 2 +- 29 files changed, 2160 insertions(+), 301 deletions(-) create mode 100644 include/Surelog/SourceCompile/SV3_1aParseTreeListener.h create mode 100644 include/Surelog/SourceCompile/SV3_1aPpParseTreeListener.h create mode 100644 src/SourceCompile/SV3_1aParseTreeListener.template.cxx create mode 100644 src/SourceCompile/SV3_1aPpParseTreeListener.template.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index b4d470cea8..9d3b6a9f33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -343,6 +343,8 @@ add_custom_command( ${GENDIR}/include/Surelog/SourceCompile/SV3_1aTreeShapeListener.h ${GENDIR}/include/Surelog/SourceCompile/VObjectTypes.h ${GENDIR}/src/SourceCompile/ParseTreeListener.cpp + ${GENDIR}/src/SourceCompile/SV3_1aParseTreeListener.cpp + ${GENDIR}/src/SourceCompile/SV3_1aPpParseTreeListener.cpp ${GENDIR}/src/SourceCompile/VObjectTypes.cpp DEPENDS ${GENDIR}/src/parser/generated-parsers.tstamp ${surelog_grammars-GENERATED_SRC} @@ -350,6 +352,8 @@ add_custom_command( ${PROJECT_SOURCE_DIR}/include/Surelog/SourceCompile/ParseTreeTraceListener.template.hpp ${PROJECT_SOURCE_DIR}/scripts/generate_parser_listener.py ${PROJECT_SOURCE_DIR}/src/SourceCompile/ParseTreeListener.template.cxx + ${PROJECT_SOURCE_DIR}/src/SourceCompile/SV3_1aParseTreeListener.template.cxx + ${PROJECT_SOURCE_DIR}/src/SourceCompile/SV3_1aPpParseTreeListener.template.cxx ${PROJECT_SOURCE_DIR}/src/SourceCompile/SV3_1aPpTreeShapeListener.cpp ${PROJECT_SOURCE_DIR}/src/SourceCompile/SV3_1aTreeShapeListener.cpp WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} @@ -367,6 +371,8 @@ add_custom_target(GenerateParserListeners DEPENDS ${GENDIR}/include/Surelog/SourceCompile/SV3_1aTreeShapeListener.h ${GENDIR}/include/Surelog/SourceCompile/VObjectTypes.h ${GENDIR}/src/SourceCompile/ParseTreeListener.cpp + ${GENDIR}/src/SourceCompile/SV3_1aParseTreeListener.cpp + ${GENDIR}/src/SourceCompile/SV3_1aPpParseTreeListener.cpp ${GENDIR}/src/SourceCompile/VObjectTypes.cpp) if (SURELOG_WITH_PYTHON) @@ -534,7 +540,9 @@ set(surelog_generated_SRC # Derived from parser generation. ${GENDIR}/src/SourceCompile/VObjectTypes.cpp - ${GENDIR}/src/SourceCompile/ParseTreeListener.cpp) + ${GENDIR}/src/SourceCompile/ParseTreeListener.cpp + ${GENDIR}/src/SourceCompile/SV3_1aParseTreeListener.cpp + ${GENDIR}/src/SourceCompile/SV3_1aPpParseTreeListener.cpp) foreach(gen_src ${surelog_generated_SRC}) set_source_files_properties(${gen_src} PROPERTIES GENERATED TRUE) diff --git a/grammar/SV3_1aLexer.g4 b/grammar/SV3_1aLexer.g4 index 0088f45fa8..964161f58f 100644 --- a/grammar/SV3_1aLexer.g4 +++ b/grammar/SV3_1aLexer.g4 @@ -27,9 +27,13 @@ lexer grammar SV3_1aLexer; channels { WHITESPACES, - COMMENTS + COMMENTS, + PREPROC } +PREPROC_BEGIN: '{!< ' Decimal_digit+ ' !}' -> channel(PREPROC); +PREPROC_END: '{! ' Decimal_digit+ ' >!}' -> channel(PREPROC); + QMARK: '?'; TICK_b0: '\'b0'; @@ -916,6 +920,7 @@ NETTYPE: 'nettype'; //Escaped_identifier : '^^^' [\\|+a-zA-Z0-9_$:,-/*{}()`~!=;'"<>?.]* '^^^' ; Escaped_identifier: '#~@' .*? '#~@'; +Preproc_identifier: '@~#' Decimal_digit+; TILDA: '~'; diff --git a/grammar/SV3_1aParser.g4 b/grammar/SV3_1aParser.g4 index d8946d8d72..76e31e5121 100644 --- a/grammar/SV3_1aParser.g4 +++ b/grammar/SV3_1aParser.g4 @@ -146,9 +146,8 @@ include_statement: INCLUDE file_path_spec SEMICOLON; source_text: timeunits_declaration? description*; -null_rule - : - ; // Placeholder rule that create the "0" VObject, DO NOT REMOVE +// Placeholder rule that create the "0" VObject, DO NOT REMOVE +null_rule: ; description : module_declaration @@ -308,7 +307,10 @@ parameter_port_declaration | TYPE list_of_type_assignments ; -list_of_ports: OPEN_PARENS port (COMMA port)* CLOSE_PARENS; +list_of_ports + : OPEN_PARENS CLOSE_PARENS + | OPEN_PARENS port (COMMA port)* CLOSE_PARENS + ; list_of_port_declarations : OPEN_PARENS ( @@ -384,7 +386,10 @@ module_common_item | system_task ; -module_item: port_declaration SEMICOLON | non_port_module_item; +module_item + : port_declaration SEMICOLON + | non_port_module_item + ; module_or_generate_item : attribute_instance* ( diff --git a/grammar/SV3_1aPpParser.g4 b/grammar/SV3_1aPpParser.g4 index 4c31016450..f6ff608e7f 100644 --- a/grammar/SV3_1aPpParser.g4 +++ b/grammar/SV3_1aPpParser.g4 @@ -104,7 +104,7 @@ description escaped_identifier: ESCAPED_IDENTIFIER; macro_instance - : (Macro_identifier | Macro_Escaped_identifier) Spaces* OPEN_PARENS macro_actual_args CLOSE_PARENS + : (Macro_identifier | Macro_Escaped_identifier) Spaces* OPEN_PARENS macro_actual_args CLOSE_PARENS # MacroInstanceWithArgs | (Macro_identifier | Macro_Escaped_identifier) # MacroInstanceNoArgs ; @@ -352,10 +352,7 @@ multiline_args_macro_definition simple_no_args_macro_definition : TICK_DEFINE Spaces (Simple_identifier | ESCAPED_IDENTIFIER) Spaces simple_macro_definition_body - ( - CR - | One_line_comment - ) + (CR | One_line_comment) | TICK_DEFINE Spaces (Simple_identifier | ESCAPED_IDENTIFIER) Spaces* CR ; diff --git a/include/Surelog/CommandLine/CommandLineParser.h b/include/Surelog/CommandLine/CommandLineParser.h index 70b4c50ac3..19ace93fda 100644 --- a/include/Surelog/CommandLine/CommandLineParser.h +++ b/include/Surelog/CommandLine/CommandLineParser.h @@ -150,7 +150,9 @@ class CommandLineParser final { bool sepComp() const { return m_sepComp; } bool link() const { return m_link; } bool gc() const { return m_gc; } + bool parseTree() const { return m_parseTree; } void setParse(bool val) { m_parse = val; } + void setParseTree(bool val) { m_parseTree = val; } void setParseOnly(bool val) { m_parseOnly = val; } void setLowMem(bool val) { m_lowMem = val; } void setCompile(bool val) { m_compile = val; } @@ -311,6 +313,7 @@ class CommandLineParser final { bool m_parametersubstitution; bool m_letexprsubstitution; bool m_diffCompMode; + bool m_parseTree; bool m_help; bool m_cacheAllowed; bool m_writeCache; diff --git a/include/Surelog/Design/FileContent.h b/include/Surelog/Design/FileContent.h index 748ca9cbd2..f40ca9ea07 100644 --- a/include/Surelog/Design/FileContent.h +++ b/include/Surelog/Design/FileContent.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -101,12 +102,6 @@ class FileContent : public DesignComponent { bool isInstance() const override { return false; } std::string_view getName() const override; NodeId getRootNode() const; - std::string printObjects() const; // The whole file content - std::string printSubTree( - NodeId parentIndex) const; // Print subtree from parent - std::string printObject(NodeId noedId) const; // Only print that object - std::vector collectSubTree( - NodeId uniqueId) const; // Helper function SymbolTable* getSymbolTable() const { return m_symbolTable; } void setSymbolTable(SymbolTable* table) { m_symbolTable = table; } PathId getFileId(NodeId id) const; @@ -215,6 +210,19 @@ class FileContent : public DesignComponent { void populateCoreMembers(NodeId startIndex, NodeId endIndex, UHDM::any* instance) const; + void sortTree(); + bool validate() const; + + std::string printObjects() const; // The whole file content + std::string printObject(NodeId nodeId) const; // Only print that object + + void printTree(std::ostream& strm) const; + void printTree(std::ostream& strm, NodeId id, size_t indent = 0) const; + + private: + void sortTree(NodeId parentId); + bool validate(NodeId parentId) const; + protected: std::vector m_elements; std::map m_elementMap; diff --git a/include/Surelog/SourceCompile/CommonListenerHelper.h b/include/Surelog/SourceCompile/CommonListenerHelper.h index 85596c15c1..91fa113699 100644 --- a/include/Surelog/SourceCompile/CommonListenerHelper.h +++ b/include/Surelog/SourceCompile/CommonListenerHelper.h @@ -30,6 +30,7 @@ #include #include +#include #include namespace antlr4 { @@ -46,7 +47,13 @@ namespace SURELOG { class FileContent; class VObject; -static constexpr char EscapeSequence[] = "#~@"; +static constexpr char kEscapeSequence[] = "#~@"; + +static constexpr std::string_view kPreprocBeginPrefix = "{!< "; +static constexpr std::string_view kPreprocBeginSuffix = " !}"; + +static constexpr std::string_view kPreprocEndPrefix = "{! "; +static constexpr std::string_view kPreprocEndSuffix = " >!}"; class CommonListenerHelper { public: @@ -54,6 +61,7 @@ class CommonListenerHelper { public: FileContent* getFileContent() { return m_fileContent; } + const FileContent* getFileContent() const { return m_fileContent; } protected: virtual SymbolId registerSymbol(std::string_view symbol) = 0; @@ -85,8 +93,7 @@ class CommonListenerHelper { NodeId getObjectId(antlr4::ParserRuleContext* ctx) const; - virtual std::tuple + virtual std::tuple getFileLine(antlr4::ParserRuleContext* ctx, antlr4::Token* token) const = 0; NodeId& MutableChild(NodeId index); @@ -95,8 +102,7 @@ class CommonListenerHelper { protected: CommonListenerHelper(FileContent* file_content, - antlr4::CommonTokenStream* tokens) - : m_fileContent(file_content), m_tokens(tokens) {} + antlr4::CommonTokenStream* tokens); // These should be *const, but they are still set in some places. // TODO: fix these places. @@ -105,6 +111,9 @@ class CommonListenerHelper { typedef std::map ContextToObjectMap; ContextToObjectMap m_contextToObjectMap; + + const std::regex m_escSeqReplaceRegex; + const std::regex m_escSeqSearchRegex; }; } // namespace SURELOG diff --git a/include/Surelog/SourceCompile/ParseTreeListener.template.hpp b/include/Surelog/SourceCompile/ParseTreeListener.template.hpp index b58d3195ec..2acb53e747 100644 --- a/include/Surelog/SourceCompile/ParseTreeListener.template.hpp +++ b/include/Surelog/SourceCompile/ParseTreeListener.template.hpp @@ -32,6 +32,8 @@ #include #include +#include +#include #include #include #include @@ -98,6 +100,7 @@ class ParseTreeListener { ParseTreeListener() = default; virtual ~ParseTreeListener() = default; + virtual bool shouldWalkSourceFile(PathId fileId) { return true; } virtual void enterSourceFile(PathId fileId) {} virtual void leaveSourceFile(PathId fileId) {} @@ -114,8 +117,8 @@ class ParseTreeListener { // clang-format on void listen(const ParseTreeNode& node); - void listenChildren(const ParseTreeNode& node, bool ordered); - void listenSiblings(const ParseTreeNode& node, bool ordered); + void listenChildren(const ParseTreeNode& node); + void listenSiblings(const ParseTreeNode& node); void listen(PathId fileId, const VObject* objects, size_t count, const SymbolTable* symbolTable); @@ -123,6 +126,7 @@ class ParseTreeListener { VObjectType getNodeType(const ParseTreeNode& node) const; ParseTreeNode getRootNode() const; bool getNodeText(const ParseTreeNode& node, std::string& text) const; + bool getNodeText(const ParseTreeNode& node, std::string_view& text) const; bool getNodeFileId(const ParseTreeNode& node, PathId& fileId) const; bool getNodeStartLocation(const ParseTreeNode& node, int32_t& line, int32_t& column) const; @@ -134,9 +138,9 @@ class ParseTreeListener { ParseTreeNode getNodeParent(const ParseTreeNode& node) const; ParseTreeNode getNodePrevSibling(const ParseTreeNode& node) const; ParseTreeNode getNodeNextSibling(const ParseTreeNode& node) const; - bool getNodeChildren(const ParseTreeNode& node, bool ordered, + bool getNodeChildren(const ParseTreeNode& node, parsetreenode_vector_t& children) const; - bool getNodeSiblings(const ParseTreeNode& node, bool ordered, + bool getNodeSiblings(const ParseTreeNode& node, parsetreenode_vector_t& siblings) const; private: diff --git a/include/Surelog/SourceCompile/SV3_1aParseTreeListener.h b/include/Surelog/SourceCompile/SV3_1aParseTreeListener.h new file mode 100644 index 0000000000..b46ee4b836 --- /dev/null +++ b/include/Surelog/SourceCompile/SV3_1aParseTreeListener.h @@ -0,0 +1,98 @@ +/* + 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: SV3_1aParseTreeListener.h + * Author: hs + * + * Created on January 31, 2023, 12:00 PM + */ + +#ifndef SURELOG_SV3_1APARSETREELISTENER_H +#define SURELOG_SV3_1APARSETREELISTENER_H +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace SURELOG { +class SV3_1aParseTreeListener final : public SV3_1aParserBaseListener, + public SV3_1aTreeShapeHelper { + typedef std::vector vobjects_t; + + typedef std::vector rule_callstack_t; + typedef std::set visited_tokens_t; + typedef std::multimap orphan_objects_t; + typedef std::vector preproc_begin_statck_t; + + typedef std::tuple column_offset_t; + typedef std::multimap offsets_t; + + public: + SV3_1aParseTreeListener(ParseFile* pf, antlr4::CommonTokenStream* tokens, + uint32_t lineOffset, FileContent* ppFileContent); + ~SV3_1aParseTreeListener() final = default; + + void enterString_value(SV3_1aParser::String_valueContext* ctx) final; + + void enterEveryRule(antlr4::ParserRuleContext* ctx) final; + void exitEveryRule(antlr4::ParserRuleContext* ctx) final; + void visitTerminal(antlr4::tree::TerminalNode* node) final; + void visitErrorNode(antlr4::tree::ErrorNode* node) final; + + private: + using SV3_1aTreeShapeHelper::addVObject; + NodeId addVObject(antlr4::ParserRuleContext* ctx, antlr4::Token* token, + VObjectType objectType); + NodeId addVObject(antlr4::tree::TerminalNode* node, VObjectType objectType); + + NodeId mergeObjectTree(NodeId ppNodeId); + std::optional isUnaryOperator( + const antlr4::tree::TerminalNode* node) const; + + void sortChildren(vobjects_t& objects, NodeId id) const; + void applyLocationOffsets(); + void visitPreprocBegin(antlr4::Token* token); + void visitPreprocEnd(antlr4::Token* token, NodeId ppNodeId); + void processPendingTokens(antlr4::ParserRuleContext* ctx, + size_t endTokenIndex); + void processOrphanObjects(antlr4::ParserRuleContext* ctx, NodeId parentId); + + typedef std::map> line_ends_t; + void collectLineRanges(NodeId ppParentId, line_ends_t &ends) const; + void collectLineRanges(const antlr4::Token* begin, const antlr4::Token* end, + line_ends_t& ends) const; + + private: + FileContent* const m_ppFileContent = nullptr; + offsets_t m_offsets; + + rule_callstack_t m_ruleCallstack; + visited_tokens_t m_visitedTokens; + orphan_objects_t m_orphanObjects; + preproc_begin_statck_t m_preprocBeginStack; + + size_t m_lastVisitedTokenIndex = 0; + int32_t m_paused = 0; +}; +} // namespace SURELOG +#endif // SURELOG_SV3_1APARSETREELISTENER_H diff --git a/include/Surelog/SourceCompile/SV3_1aPpParseTreeListener.h b/include/Surelog/SourceCompile/SV3_1aPpParseTreeListener.h new file mode 100644 index 0000000000..3b26e0608e --- /dev/null +++ b/include/Surelog/SourceCompile/SV3_1aPpParseTreeListener.h @@ -0,0 +1,137 @@ +/* + 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: SV3_1aPpParseTreeListener.h + * Author: hs + * + * Created on January 31, 2023, 12:00 PM + */ + +#ifndef SURELOG_SV3_1APPPARSETREELISTENER_H +#define SURELOG_SV3_1APPPARSETREELISTENER_H +#pragma once + +#include +#include + +namespace SURELOG { +class PreprocessFile; +class SV3_1aPpParseTreeListener final : public SV3_1aPpParserBaseListener, + public SV3_1aPpTreeListenerHelper { + public: + typedef std::vector callstack_t; + typedef std::set visited_rules_t; + + public: + SV3_1aPpParseTreeListener(PreprocessFile* pp, + antlr4::CommonTokenStream* tokens, + PreprocessFile::SpecialInstructions& instructions); + ~SV3_1aPpParseTreeListener() final = default; + + void enterText_blob(SV3_1aPpParser::Text_blobContext* ctx) final; + + void enterEscaped_identifier( + SV3_1aPpParser::Escaped_identifierContext* ctx) final; + + void enterIfdef_directive(SV3_1aPpParser::Ifdef_directiveContext* ctx) final; + void exitIfdef_directive(SV3_1aPpParser::Ifdef_directiveContext* ctx) final; + + void enterIfndef_directive( + SV3_1aPpParser::Ifndef_directiveContext* ctx) final; + void exitIfndef_directive(SV3_1aPpParser::Ifndef_directiveContext* ctx) final; + + void enterUndef_directive(SV3_1aPpParser::Undef_directiveContext* ctx) final; + void exitUndef_directive(SV3_1aPpParser::Undef_directiveContext* ctx) final; + + void enterElsif_directive(SV3_1aPpParser::Elsif_directiveContext* ctx) final; + void exitElsif_directive(SV3_1aPpParser::Elsif_directiveContext* ctx) final; + + void enterElse_directive(SV3_1aPpParser::Else_directiveContext* ctx) final; + void exitElse_directive(SV3_1aPpParser::Else_directiveContext* ctx) final; + + void enterElseif_directive( + SV3_1aPpParser::Elseif_directiveContext* ctx) final; + void exitElseif_directive(SV3_1aPpParser::Elseif_directiveContext* ctx) final; + + void enterEndif_directive(SV3_1aPpParser::Endif_directiveContext* ctx) final; + void exitEndif_directive(SV3_1aPpParser::Endif_directiveContext* ctx) final; + + void enterInclude_directive( + SV3_1aPpParser::Include_directiveContext* ctx) final; + void exitInclude_directive( + SV3_1aPpParser::Include_directiveContext* ctx) final; + + void enterLine_directive(SV3_1aPpParser::Line_directiveContext* ctx) final; + void exitLine_directive(SV3_1aPpParser::Line_directiveContext* ctx) final; + + void enterSv_file_directive( + SV3_1aPpParser::Sv_file_directiveContext* ctx) final; + void exitSv_file_directive( + SV3_1aPpParser::Sv_file_directiveContext* ctx) final; + + void enterSv_line_directive( + SV3_1aPpParser::Sv_line_directiveContext* ctx) final; + void exitSv_line_directive( + SV3_1aPpParser::Sv_line_directiveContext* ctx) final; + + void enterMacroInstanceWithArgs( + SV3_1aPpParser::MacroInstanceWithArgsContext* ctx) final; + void exitMacroInstanceWithArgs( + SV3_1aPpParser::MacroInstanceWithArgsContext* ctx) final; + + void enterMacroInstanceNoArgs( + SV3_1aPpParser::MacroInstanceNoArgsContext* ctx) final; + void exitMacroInstanceNoArgs( + SV3_1aPpParser::MacroInstanceNoArgsContext* ctx) final; + + void enterMacro_definition( + SV3_1aPpParser::Macro_definitionContext* ctx) final; + void exitMacro_definition(SV3_1aPpParser::Macro_definitionContext* ctx) final; + + void exitSimple_macro_definition_body( + SV3_1aPpParser::Simple_macro_definition_bodyContext* ctx) final; + void exitEscaped_macro_definition_body( + SV3_1aPpParser::Escaped_macro_definition_bodyContext* ctx) final; + void exitMacro_arg(SV3_1aPpParser::Macro_argContext* ctx) final; + + void enterEveryRule(antlr4::ParserRuleContext* ctx) final; + void exitEveryRule(antlr4::ParserRuleContext* ctx) final; + void visitTerminal(antlr4::tree::TerminalNode* node) final; + + private: + using SV3_1aPpTreeListenerHelper::addVObject; + NodeId addVObject(antlr4::tree::TerminalNode* node, VObjectType objectType); + + bool isOnCallStack(size_t ruleIndex) const; + bool isAnyOnCallStack(const std::unordered_set& ruleIndicies) const; + + void appendPreprocBegin(); + void appendPreprocEnd(antlr4::ParserRuleContext *ctx, VObjectType type); + + void recordMacro(std::string_view name, std::string_view arguments, + antlr4::tree::TerminalNode* identifier, + antlr4::ParserRuleContext* body); + + private: + visited_rules_t m_visitedRules; + callstack_t m_callstack; + size_t m_pendingCRs = 0; + int32_t m_paused = 0; +}; +} // namespace SURELOG + +#endif // SURELOG_SV3_1APPPARSETREELISTENER_H \ No newline at end of file diff --git a/scripts/generate_parser_listener.py b/scripts/generate_parser_listener.py index da030efedc..4009e5fe57 100644 --- a/scripts/generate_parser_listener.py +++ b/scripts/generate_parser_listener.py @@ -31,7 +31,7 @@ 'Ps_identifier', ]) -_forced_pa_typenames = set([ +_forced_pa_rules = set([ 'TimeUnitsDecl_TimeUnitDiv', 'TimeUnitsDecl_TimeUnit', 'TimeUnitsDecl_TimePrecision', @@ -168,7 +168,10 @@ 'BinModOp_BitwOr', 'BinModOp_BitwXor', 'BinModOp_ReductXnor1', - 'BinModOp_ReductXnor2', + 'BinModOp_ReductXnor2' +]) + +_forced_pa_tokens = set([ # Forced ones '0', @@ -318,6 +321,8 @@ 'NonBlockingTriggerEvent', ]) +_forced_pa_typenames = set.union(_forced_pa_rules, _forced_pa_tokens) + _blacklisted_typenames = set([ 'ErrorNode', 'EveryRule', @@ -446,7 +451,7 @@ def _generate_XXXTreeShapeListener_h(listener: str, antlr_definition_filepath: s '', ' public:', ' SV3_1aTreeShapeListener(ParseFile* pf, antlr4::CommonTokenStream* tokens, uint32_t lineOffset);', - ' virtual ~SV3_1aTreeShapeListener() override;', + ' ~SV3_1aTreeShapeListener() override;', '' ]) else: @@ -759,7 +764,7 @@ def _generate_VObjectTypes_py_h(pp_typenames: list, pa_typenames: list, filepath def _generate_SV3_1aPpParseTreeListener_cpp(tokens: list, rules: list, template_filepath: str, output_filepath: str): rule_case_statements = [f' case SV3_1aPpParser::Rule{rule}: addVObject(ctx, VObjectType::pp{rule}); break;' for rule in rules] visit_case_statements = [ - f' case SV3_1aPpParser::{token}: addVObject((antlr4::ParserRuleContext *)node, node->getText(), VObjectType::pp{token}); break;' + f' case SV3_1aPpParser::{token}: addVObject(node, VObjectType::pp{token}); break;' for token in tokens ] @@ -772,8 +777,8 @@ def _generate_SV3_1aPpParseTreeListener_cpp(tokens: list, rules: list, template_ def _generate_SV3_1aParseTreeListener_cpp(tokens: list, rules: list, template_filepath: str, output_filepath: str): rule_case_statements = [f' case SV3_1aParser::Rule{rule}: nodeId = addVObject(ctx, VObjectType::pa{rule}); break;' for rule in rules] visit_case_statements = [ - f' case SV3_1aParser::{token}: nodeId = addVObject((antlr4::ParserRuleContext *)node, node->getText(), VObjectType::pa{token}); break;' - for token in tokens if token not in ['Escaped_identifier'] + f' case SV3_1aParser::{token}: nodeId = addVObject(node, VObjectType::pa{token}); break;' + for token in tokens if token not in ['Escaped_identifier', 'PREPROC_BEGIN', 'PREPROC_END'] ] content = open(template_filepath, 'rt').read() @@ -817,7 +822,7 @@ def _generate_ParseTreeListener_cpp(pp_tokens: list, pp_rules: list, pa_tokens: private_listen_implementations.extend([ f'void ParseTreeListener::listen{prefix}_{rule}(const ParseTreeNode& node) {{', f' enter{prefix}_{rule}(node);', - ' listenChildren(node, true);', + ' listenChildren(node);', f' leave{prefix}_{rule}(node);', '}', '' @@ -932,6 +937,22 @@ def _main(): pp_typenames, pa_typenames, os.path.join(args.output_dirpath, 'include', 'Surelog', 'API', 'VObjectTypes_py.h')) + _generate_SV3_1aPpParseTreeListener_cpp( + pp_tokens, pp_rules, + os.path.join(args.input_dirpath, 'src', 'SourceCompile', 'SV3_1aPpParseTreeListener.template.cxx'), + os.path.join(args.output_dirpath, 'src', 'SourceCompile', 'SV3_1aPpParseTreeListener.cpp')) + + _generate_SV3_1aParseTreeListener_cpp( + pa_tokens, pa_rules, + os.path.join(args.input_dirpath, 'src', 'SourceCompile', 'SV3_1aParseTreeListener.template.cxx'), + os.path.join(args.output_dirpath, 'src', 'SourceCompile', 'SV3_1aParseTreeListener.cpp')) + + pa_rules = set.union(set(pa_rules), _forced_pa_rules) + pa_rules = sorted(pa_rules) + + pa_tokens = set.union(set(pa_tokens), _forced_pa_tokens) + pa_tokens = sorted(pa_tokens) + _generate_ParseTreeListener_h( pp_tokens, pp_rules, pa_tokens, pa_rules, os.path.join(args.input_dirpath, 'include', 'Surelog', 'SourceCompile', 'ParseTreeListener.template.hpp'), diff --git a/src/API/Surelog.cpp b/src/API/Surelog.cpp index f48c8b594e..c6586bb1c4 100644 --- a/src/API/Surelog.cpp +++ b/src/API/Surelog.cpp @@ -63,10 +63,26 @@ void walk_parsetree(scompiler* compiler, ParseTreeListener* listener) { Compiler* the_compiler = (Compiler*)compiler; for (const CompileSourceFile* csf : the_compiler->getCompileSourceFiles()) { const FileContent* const fC = csf->getParser()->getFileContent(); - const std::vector& objects = fC->getVObjects(); - const SymbolTable* const symbolTable = fC->getSymbolTable(); - listener->listen(fC->getFileId(), objects.data(), objects.size(), - symbolTable); + if (listener->shouldWalkSourceFile(fC->getFileId())) { + const std::vector& objects = fC->getVObjects(); + const SymbolTable* const symbolTable = fC->getSymbolTable(); + listener->listen(fC->getFileId(), objects.data(), objects.size(), + symbolTable); + } + } +} + +void walk_ast(scompiler* compiler, ParseTreeListener* listener) { + if (!compiler || !listener) return; + Compiler* the_compiler = (Compiler*)compiler; + for (const CompileSourceFile* csf : the_compiler->getCompileSourceFiles()) { + const FileContent* const fC = csf->getParser()->getFileContent(); + if (listener->shouldWalkSourceFile(fC->getFileId())) { + const std::vector& objects = fC->getVObjects(); + const SymbolTable* const symbolTable = fC->getSymbolTable(); + listener->listen(fC->getFileId(), objects.data(), objects.size(), + symbolTable); + } } } diff --git a/src/CommandLine/CommandLineParser.cpp b/src/CommandLine/CommandLineParser.cpp index 383ed810b4..b880b65b61 100644 --- a/src/CommandLine/CommandLineParser.cpp +++ b/src/CommandLine/CommandLineParser.cpp @@ -132,6 +132,10 @@ static const std::initializer_list helpText = { " separate compilation units to perform diffs", " -parse Parse/Compile/Elaborate the files after", " pre-processing step", + " -parsetree Collect all possible tokens and rules in the", + " parse tree. This includes spaces, newlines, and", + " other bracketing information which is excluded", + " for Surelog AST. Good for uses like Linting.", " -noparse Turns off Parsing & Compilation & Elaboration", " -nocomp Turns off Compilation & Elaboration", " -noelab Turns off Elaboration", @@ -364,6 +368,7 @@ CommandLineParser::CommandLineParser(ErrorContainer* errors, m_parametersubstitution(true), m_letexprsubstitution(true), m_diffCompMode(diffCompMode), + m_parseTree(false), m_help(false), m_cacheAllowed(true), m_writeCache(true), @@ -1278,6 +1283,12 @@ bool CommandLineParser::parseCommandLine(int32_t argc, const char** argv) { m_parse = true; m_compile = true; m_elaborate = true; + } else if (all_arguments[i] == "-parsetree") { + m_parseTree = true; + m_parse = true; + m_parseOnly = false; + m_compile = false; + m_elaborate = false; } else if (all_arguments[i] == "-parseonly") { m_writePpOutput = true; m_parse = true; diff --git a/src/Common/PlatformFileSystem.cpp b/src/Common/PlatformFileSystem.cpp index 1433e4752a..2c7c44e9a9 100644 --- a/src/Common/PlatformFileSystem.cpp +++ b/src/Common/PlatformFileSystem.cpp @@ -430,6 +430,7 @@ PathId PlatformFileSystem::getPrecompiledDir(PathId programId, const std::filesystem::path programPath = programFile.parent_path(); const std::vector search_paths = { programPath, // Build path + programPath / ".." / "share" / "surelog", // Install path programPath / ".." / ".." / "share" / "surelog", // Install path }; diff --git a/src/Design/FileContent.cpp b/src/Design/FileContent.cpp index 4a302e9e40..c02f5b78b5 100644 --- a/src/Design/FileContent.cpp +++ b/src/Design/FileContent.cpp @@ -69,7 +69,17 @@ std::string_view FileContent::SymName(NodeId index) const { } NodeId FileContent::getRootNode() const { - return m_objects.empty() ? InvalidNodeId : m_objects[1].m_sibling; + if (m_objects.empty()) return InvalidNodeId; + + int32_t index = static_cast(m_objects.size()); + while (--index >= 0) { + if ((m_objects[index].m_type == VObjectType::ppTop_level_rule) || + (m_objects[index].m_type == VObjectType::paTop_level_rule) || + (m_objects[index].m_type == VObjectType::paTop_level_library_rule)) { + return NodeId(index); + } + } + return InvalidNodeId; } PathId FileContent::getFileId(NodeId id) const { @@ -80,19 +90,35 @@ PathId* FileContent::getMutableFileId(NodeId id) { return &m_objects[id].m_fileId; } +void FileContent::printTree(std::ostream& strm, NodeId id, + size_t indent /* = 0 */) const { + if (!id) return; + + strm << std::string(indent * 2, ' ') + << m_objects[id].print(m_symbolTable, id, GetDefinitionFile(id), + m_fileId) + << std::endl; + for (NodeId childId = m_objects[id].m_child; childId; + childId = m_objects[childId].m_sibling) { + printTree(strm, childId, indent + 1); + } +} + +void FileContent::printTree(std::ostream& strm) const { + strm << "AST_DEBUG_BEGIN" << std::endl; + if (m_library) strm << "LIB: " << m_library->getName() << std::endl; + strm << "FILE: " << FileSystem::getInstance()->toPath(m_fileId) << std::endl; + printTree(strm, getRootNode(), 0); + strm << "AST_DEBUG_END" << std::endl; +} + std::string FileContent::printObjects() const { std::string text; - NodeId index(0); - StrAppend(&text, "AST_DEBUG_BEGIN\n"); if (m_library) StrAppend(&text, "LIB: ", m_library->getName(), "\n"); StrAppend(&text, "FILE: ", FileSystem::getInstance()->toPath(m_fileId), "\n"); - for (const auto& object : m_objects) { - StrAppend( - &text, - object.print(m_symbolTable, index, GetDefinitionFile(index), m_fileId), - "\n"); - index++; + for (size_t i = 0, ni = m_objects.size(); i < ni; ++i) { + StrAppend(&text, printObject(NodeId(i)), "\n"); } StrAppend(&text, "AST_DEBUG_END\n"); return text; @@ -104,25 +130,14 @@ std::string FileContent::printObject(NodeId nodeId) const { GetDefinitionFile(nodeId), m_fileId); } -std::string FileContent::printSubTree(NodeId nodeId) const { - if (!nodeId || (nodeId >= m_objects.size())) return ""; - std::string text; - for (const auto& s : collectSubTree(nodeId)) { - text += s + "\n"; - } - return text; -} - void FileContent::insertObjectLookup(std::string_view name, NodeId id, ErrorContainer* errors) { - NameIdMap::iterator itr = m_objectLookup.find(name); - if (itr == m_objectLookup.end()) { - m_objectLookup.emplace(name, id); - } else { + std::pair itr = m_objectLookup.emplace(name, id); + if (!itr.second) { Location loc(getFileId(id), Line(id), Column(id), errors->getSymbolTable()->registerSymbol(name)); - Location loc2(getFileId(itr->second), Line(itr->second), - Column(itr->second)); + Location loc2(getFileId(itr.first->second), Line(itr.first->second), + Column(itr.first->second)); Error err(ErrorDefinition::COMP_MULTIPLY_DEFINED_DESIGN_UNIT, loc, loc2); errors->addError(err); } @@ -180,27 +195,6 @@ const ClassDefinition* FileContent::getClassDefinition( } } -std::vector FileContent::collectSubTree(NodeId index) const { - std::vector text; - - text.push_back(m_objects[index].print(m_symbolTable, index, - GetDefinitionFile(index), m_fileId)); - - if (m_objects[index].m_child) { - for (const auto& s : collectSubTree(m_objects[index].m_child)) { - text.push_back(" " + s); - } - } - - if (m_objects[index].m_sibling) { - for (const auto& s : collectSubTree(m_objects[index].m_sibling)) { - text.push_back(s); - } - } - - return text; -} - void FileContent::SetDefinitionFile(NodeId index, PathId def) { m_definitionFiles.emplace(index, def); } @@ -719,4 +713,109 @@ void FileContent::populateCoreMembers(NodeId startIndex, NodeId endIndex, instance->VpiFile(FileSystem::getInstance()->toPath(fileId)); } } + +void FileContent::sortTree(NodeId parentId) { + VObject& object = m_objects[(RawNodeId)parentId]; + if (!object.m_child) return; + + std::vector indicies; + + NodeId childId = object.m_child; + while (childId) { + sortTree(childId); + + indicies.emplace_back(childId); + childId = m_objects[(RawNodeId)childId].m_sibling; + } + std::sort(indicies.begin(), indicies.end()); + for (size_t i = 1, ni = indicies.size(); i < ni; ++i) { + m_objects[(RawNodeId)indicies[i - 1]].m_sibling = indicies[i]; + } + m_objects[(RawNodeId)indicies.back()].m_sibling = InvalidNodeId; + object.m_child = indicies[0]; +} + +void FileContent::sortTree() { sortTree(getRootNode()); } + +bool FileContent::validate(NodeId parentId) const { + const VObject& parentObject = m_objects[(RawNodeId)parentId]; + if (parentObject.m_line == parentObject.m_endLine) { + if (parentObject.m_column > parentObject.m_endColumn) { + return false; + } + } else if (parentObject.m_line > parentObject.m_endLine) { + return false; + } + + if (!parentObject.m_child) return true; + + uint32_t minLine = parentObject.m_line; + uint16_t minColumn = parentObject.m_column; + + uint32_t maxLine = parentObject.m_endLine; + uint16_t maxColumn = parentObject.m_endColumn; + + NodeId childId1 = parentObject.m_child; + NodeId childId0; + while (childId1) { + if (!validate(childId1)) { + return false; + } + + const VObject& child1Object = m_objects[(RawNodeId)childId1]; + + if (childId0) { + const VObject& child0Object = m_objects[(RawNodeId)childId0]; + + if (child0Object.m_line == child1Object.m_line) { + if (child1Object.m_column < child0Object.m_endColumn) { + return false; + } + } else if (child1Object.m_line < child0Object.m_line) { + return false; + } else if (child1Object.m_endLine < child0Object.m_endLine) { + return false; + } + } + + if (child1Object.m_line < minLine) { + minLine = child1Object.m_line; + minColumn = child1Object.m_column; + } else if ((minLine == child1Object.m_line) && + (minColumn > child1Object.m_column)) { + minColumn = child1Object.m_column; + } + + if (child1Object.m_endLine > maxLine) { + maxLine = child1Object.m_endLine; + maxColumn = child1Object.m_endColumn; + } else if ((maxLine == child1Object.m_endLine) && + (maxColumn < child1Object.m_endColumn)) { + maxColumn = child1Object.m_endColumn; + } + + childId0 = childId1; + childId1 = m_objects[(RawNodeId)childId1].m_sibling; + } + + if (minLine > maxLine) { + return false; + } else if ((minLine == maxLine) && (minColumn > maxColumn)) { + return false; + } + + if (minLine != parentObject.m_line) { + return false; + } else if (maxLine != parentObject.m_endLine) { + return false; + } else if (minColumn != parentObject.m_column) { + return false; + } else if (maxColumn != parentObject.m_endColumn) { + return false; + } + + return true; +} + +bool FileContent::validate() const { return validate(getRootNode()); } } // namespace SURELOG diff --git a/src/Design/VObject.cpp b/src/Design/VObject.cpp index c83841be87..15cf0d4453 100644 --- a/src/Design/VObject.cpp +++ b/src/Design/VObject.cpp @@ -34,7 +34,7 @@ std::string VObject::print(SymbolTable* symbols, NodeId uniqueId, if (symbol == SymbolTable::getBadSymbol()) { StrAppend(&text, "n<>"); } else { - StrAppend(&text, "n<", symbol, ">"); + StrAppend(&text, "n<", StringUtils::replaceAll(symbol, "\n", "\\n"), ">"); } StrAppend(&text, " u<", uniqueId, "> "); StrAppend(&text, "t<", getTypeName(m_type).substr(2), ">"); diff --git a/src/Library/SVLibShapeListener.cpp b/src/Library/SVLibShapeListener.cpp index 1ea6936830..97345e6202 100644 --- a/src/Library/SVLibShapeListener.cpp +++ b/src/Library/SVLibShapeListener.cpp @@ -185,7 +185,7 @@ void SVLibShapeListener::exitHierarchical_identifier( childCtx = (antlr4::ParserRuleContext *)ctx->children[0]; ident = ctx->getText(); - ident = std::regex_replace(ident, std::regex(EscapeSequence), ""); + ident = std::regex_replace(ident, m_escSeqReplaceRegex, ""); addVObject(childCtx, ident, VObjectType::slStringConst); addVObject(ctx, VObjectType::paHierarchical_identifier); diff --git a/src/SourceCompile/CommonListenerHelper.cpp b/src/SourceCompile/CommonListenerHelper.cpp index 89ce50a149..41197e1630 100644 --- a/src/SourceCompile/CommonListenerHelper.cpp +++ b/src/SourceCompile/CommonListenerHelper.cpp @@ -24,12 +24,20 @@ #include #include #include +#include #include namespace SURELOG { using antlr4::ParserRuleContext; +CommonListenerHelper::CommonListenerHelper(FileContent* file_content, + antlr4::CommonTokenStream* tokens) + : m_fileContent(file_content), + m_tokens(tokens), + m_escSeqReplaceRegex(kEscapeSequence), + m_escSeqSearchRegex(StrCat(kEscapeSequence, "(.*?)", kEscapeSequence)) {} + NodeId CommonListenerHelper::NodeIdFromContext( const antlr4::tree::ParseTree* ctx) const { auto found = m_contextToObjectMap.find(ctx); @@ -137,11 +145,7 @@ void CommonListenerHelper::addParentChildRelations(NodeId indexParent, NodeId CommonListenerHelper::getObjectId(ParserRuleContext* ctx) const { auto itr = m_contextToObjectMap.find(ctx); - if (itr == m_contextToObjectMap.end()) { - return InvalidNodeId; - } else { - return (*itr).second; - } + return (itr == m_contextToObjectMap.end()) ? InvalidNodeId : itr->second; } } // namespace SURELOG diff --git a/src/SourceCompile/ParseFile.cpp b/src/SourceCompile/ParseFile.cpp index 462b01c526..8cf6bce7f7 100644 --- a/src/SourceCompile/ParseFile.cpp +++ b/src/SourceCompile/ParseFile.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -374,7 +375,7 @@ bool ParseFile::parseOneFile_(PathId fileId, uint32_t lineOffset) { tmr.reset(); profileParser(); } - } catch (antlr4::ParseCancellationException& pex) { + } catch (antlr4::ParseCancellationException&) { m_antlrParserHandler->m_tokens->reset(); m_antlrParserHandler->m_parser->reset(); m_antlrParserHandler->m_parser->removeErrorListeners(); @@ -458,8 +459,8 @@ bool ParseFile::parse() { if (cache.restore()) { m_usingCachedVersion = true; - if (debug_AstModel && !precompiled) - std::cout << m_fileContent->printObjects(); + if (debug_AstModel && !precompiled && m_fileId) + m_fileContent->printTree(std::cout); if (clp->debugCache()) { std::cout << "PARSER CACHE USED FOR: " << fileSystem->toPath(getFileId(0)) << std::endl; @@ -474,8 +475,8 @@ bool ParseFile::parse() { if (cache.restore()) { child->m_fileContent->setParent(m_fileContent); m_usingCachedVersion = true; - if (debug_AstModel && !precompiled) - std::cout << child->m_fileContent->printObjects(); + if (debug_AstModel && !precompiled && m_fileId) + child->m_fileContent->printTree(std::cout); } else { ok = false; } @@ -509,13 +510,20 @@ bool ParseFile::parse() { if ((m_parent == nullptr) && (m_children.empty())) { Timer tmr; - m_listener = new SV3_1aTreeShapeListener( - this, m_antlrParserHandler->m_tokens, m_offsetLine); + if (clp->parseTree()) { + FileContent* const ppFileContent = + getCompileSourceFile()->getPreprocessor()->getFileContent(); + m_listener = new SV3_1aParseTreeListener( + this, m_antlrParserHandler->m_tokens, m_offsetLine, ppFileContent); + } else { + m_listener = new SV3_1aTreeShapeListener( + this, m_antlrParserHandler->m_tokens, m_offsetLine); + } antlr4::tree::ParseTreeWalker::DEFAULT.walk(m_listener, m_antlrParserHandler->m_tree); - if (debug_AstModel && !precompiled) - std::cout << m_fileContent->printObjects(); + if (debug_AstModel && !precompiled && m_fileId) + m_fileContent->printTree(std::cout); if (clp->profile()) { // m_profileInfo += "AST Walking: " + std::to_string @@ -545,9 +553,18 @@ bool ParseFile::parse() { // Only visit the chunks that got re-parsed // TODO: Incrementally regenerate the FileContent child->m_fileContent->setParent(m_fileContent); - child->m_listener = new SV3_1aTreeShapeListener( - child, child->m_antlrParserHandler->m_tokens, - child->m_offsetLine); + if (clp->parseTree()) { + FileContent* const ppFileContent = child->getCompileSourceFile() + ->getPreprocessor() + ->getFileContent(); + child->m_listener = new SV3_1aParseTreeListener( + child, child->m_antlrParserHandler->m_tokens, + child->m_offsetLine, ppFileContent); + } else { + child->m_listener = new SV3_1aTreeShapeListener( + child, child->m_antlrParserHandler->m_tokens, + child->m_offsetLine); + } Timer tmr; antlr4::tree::ParseTreeWalker::DEFAULT.walk( @@ -560,8 +577,8 @@ bool ParseFile::parse() { tmr.reset(); } - if (debug_AstModel && !precompiled) - std::cout << child->m_fileContent->printObjects(); + if (debug_AstModel && !precompiled && m_fileId) + child->m_fileContent->printTree(std::cout); ParseCache cache(child); if (clp->link()) return true; diff --git a/src/SourceCompile/ParseTreeListener.template.cxx b/src/SourceCompile/ParseTreeListener.template.cxx index c9cbcc7c95..f8bac7f53f 100644 --- a/src/SourceCompile/ParseTreeListener.template.cxx +++ b/src/SourceCompile/ParseTreeListener.template.cxx @@ -31,39 +31,6 @@ #include namespace SURELOG { -namespace { -struct VObjectComparer final { - bool operator()(const VObject& lhs, const VObject& rhs) const { - // Sort top to bottom, left to right, outer to inner. - // The first two conditions apply primarily to the start line/column - // The last, outer to inner, applies to the end line/column - // i.e. if two tokens share the same start line/column sort the outer - // token ahead of the inner one. - if (lhs.m_line != rhs.m_line) { - return lhs.m_line < rhs.m_line; - } - if (lhs.m_column != rhs.m_column) { - return lhs.m_column < rhs.m_column; - } - if (lhs.m_endLine != rhs.m_endLine) { - return lhs.m_endLine > rhs.m_endLine; - } - if (lhs.m_endColumn != rhs.m_endColumn) { - return lhs.m_endColumn > rhs.m_endColumn; - } - return false; - } - - bool operator()(const NodeId& lhs, const NodeId& rhs) const { - if (lhs == rhs) return false; - return operator()(m_objects[(RawNodeId)lhs], m_objects[(RawNodeId)rhs]); - } - - const VObject* const m_objects = nullptr; - explicit VObjectComparer(const VObject* const objects) : m_objects(objects) {} -}; -} // namespace - VObjectType ParseTreeListener::getNodeType(const ParseTreeNode& node) const { return node ? node.m_object->m_type : VObjectType::sl_INVALID_; } @@ -87,6 +54,15 @@ bool ParseTreeListener::getNodeText(const ParseTreeNode& node, return false; } +bool ParseTreeListener::getNodeText(const ParseTreeNode& node, + std::string_view& text) const { + if (node && node.m_object->m_name) { + text = m_symbolTable->getSymbol(node.m_object->m_name); + return true; + } + return false; +} + bool ParseTreeListener::getNodeFileId(const ParseTreeNode& node, PathId& fileId) const { if (node) { @@ -134,25 +110,13 @@ ParseTreeNode ParseTreeListener::getNodeParent( } bool ParseTreeListener::getNodeChildren( - const ParseTreeNode& node, bool ordered, - parsetreenode_vector_t& children) const { + const ParseTreeNode& node, parsetreenode_vector_t& children) const { if (!node) return false; if (!node.m_object->m_child) return true; - std::vector indexes; - indexes.reserve(16); for (NodeId id = node.m_object->m_child; id; id = m_objects[(RawNodeId)id].m_sibling) { - indexes.emplace_back(id); - } - - if (ordered) { - std::sort(indexes.begin(), indexes.end(), VObjectComparer(m_objects)); - } - - children.reserve(children.size() + indexes.size()); - for (const NodeId& index : indexes) { - children.emplace_back(index, &m_objects[(RawNodeId)index]); + children.emplace_back(id, &m_objects[(RawNodeId)id]); } return true; @@ -162,7 +126,7 @@ ParseTreeNode ParseTreeListener::getNodePrevSibling( const ParseTreeNode& node) const { if (const ParseTreeNode parent = getNodeParent(node)) { parsetreenode_vector_t children; - if (getNodeChildren(parent, true, children)) { + if (getNodeChildren(parent, children)) { for (size_t i = 1, ni = children.size(); i < ni; ++i) { if (children[i].m_index == node.m_index) { return children[i - 1]; @@ -177,7 +141,7 @@ ParseTreeNode ParseTreeListener::getNodeNextSibling( const ParseTreeNode& node) const { if (const ParseTreeNode parent = getNodeParent(node)) { parsetreenode_vector_t children; - if (getNodeChildren(parent, true, children)) { + if (getNodeChildren(parent, children)) { for (size_t i = 0, ni = children.size() - 1; i < ni; ++i) { if (children[i].m_index == node.m_index) { return children[i + 1]; @@ -189,27 +153,17 @@ ParseTreeNode ParseTreeListener::getNodeNextSibling( } bool ParseTreeListener::getNodeSiblings( - const ParseTreeNode& node, bool ordered, - parsetreenode_vector_t& siblings) const { + const ParseTreeNode& node, parsetreenode_vector_t& siblings) const { if (!node) return false; if (!node.m_object->m_parent) return true; const VObject& parent = m_objects[(RawNodeId)node.m_object->m_parent]; - std::vector indexes; - indexes.reserve(16); for (NodeId id = parent.m_child; id; id = m_objects[(RawNodeId)id].m_sibling) { - if (id != node.m_index) indexes.emplace_back(id); - } - - if (ordered) { - std::sort(indexes.begin(), indexes.end(), VObjectComparer(m_objects)); - } - - siblings.reserve(siblings.size() + indexes.size()); - for (const NodeId& index : indexes) { - siblings.emplace_back(index, &m_objects[(RawNodeId)index]); + if (id != node.m_index) { + siblings.emplace_back(id, &m_objects[(RawNodeId)id]); + } } return true; @@ -226,47 +180,27 @@ void ParseTreeListener::listen(PathId fileId, const VObject* objects, leaveSourceFile(fileId); } -void ParseTreeListener::listenChildren(const ParseTreeNode& node, - bool ordered) { +void ParseTreeListener::listenChildren(const ParseTreeNode& node) { if (!node || !node.m_object->m_child) return; - std::vector indexes; - indexes.reserve(16); for (NodeId id = node.m_object->m_child; id; id = m_objects[(RawNodeId)id].m_sibling) { - indexes.emplace_back(id); - } - - if (ordered) { - std::sort(indexes.begin(), indexes.end(), VObjectComparer(m_objects)); - } - - for (const NodeId& index : indexes) { - const ParseTreeNode childNode(index, &m_objects[(RawNodeId)index]); + const ParseTreeNode childNode(id, &m_objects[(RawNodeId)id]); listen(childNode); } } -void ParseTreeListener::listenSiblings(const ParseTreeNode& node, - bool ordered) { +void ParseTreeListener::listenSiblings(const ParseTreeNode& node) { if (!node || !node.m_object->m_parent) return; const VObject& parent = m_objects[(RawNodeId)node.m_object->m_parent]; - std::vector indexes; - indexes.reserve(16); for (NodeId id = parent.m_child; id; id = m_objects[(RawNodeId)id].m_sibling) { - if (id != node.m_index) indexes.emplace_back(id); - } - - if (ordered) { - std::sort(indexes.begin(), indexes.end(), VObjectComparer(m_objects)); - } - - for (const NodeId& index : indexes) { - const ParseTreeNode siblingNode(index, &m_objects[(RawNodeId)index]); - listen(siblingNode); + if (id != node.m_index) { + const ParseTreeNode siblingNode(id, &m_objects[(RawNodeId)id]); + listen(siblingNode); + } } } diff --git a/src/SourceCompile/PreprocessFile.cpp b/src/SourceCompile/PreprocessFile.cpp index 03a95914cd..55cbdfc15a 100644 --- a/src/SourceCompile/PreprocessFile.cpp +++ b/src/SourceCompile/PreprocessFile.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -341,8 +342,8 @@ bool PreprocessFile::preprocess() { if (cache.restore(clp->lowMem() || clp->noCacheHash())) { m_usingCachedVersion = true; getCompilationUnit()->setCurrentTimeInfo(getFileId(0)); - if (m_debugAstModel && !precompiled) - std::cout << m_fileContent->printObjects(); + if (m_debugAstModel && !precompiled && m_fileId) + m_fileContent->printTree(std::cout); if (precompiled || clp->noCacheHash()) { if (clp->debugCache()) { std::cout << "PP CACHE USED FOR: " << PathIdPP(m_fileId) << std::endl; @@ -500,7 +501,7 @@ bool PreprocessFile::preprocess() { fileSystem->toPath(m_fileId), "\n"); tmr.reset(); } - } catch (antlr4::ParseCancellationException& pex) { + } catch (antlr4::ParseCancellationException&) { m_antlrParserHandler->m_pptokens->reset(); m_antlrParserHandler->m_ppparser->reset(); m_antlrParserHandler->m_ppparser->addErrorListener( @@ -540,13 +541,20 @@ bool PreprocessFile::preprocess() { m_result.clear(); m_lineCount = 0; delete m_listener; - m_listener = new SV3_1aPpTreeShapeListener( - this, m_antlrParserHandler->m_pptokens, m_instructions); + + if (clp->parseTree()) { + m_listener = new SV3_1aPpParseTreeListener( + this, m_antlrParserHandler->m_pptokens, m_instructions); + } else { + m_listener = new SV3_1aPpTreeShapeListener( + this, m_antlrParserHandler->m_pptokens, m_instructions); + } + // TODO: this leaks antlr4::tree::ParseTreeWalker::DEFAULT.walk(m_listener, m_antlrParserHandler->m_pptree); - if (m_debugAstModel && !precompiled) - std::cout << m_fileContent->printObjects(); + if (m_debugAstModel && !precompiled && m_fileId) + m_fileContent->printTree(std::cout); m_lineCount = LinesCount(m_result); return true; } diff --git a/src/SourceCompile/SV3_1aParseTreeListener.template.cxx b/src/SourceCompile/SV3_1aParseTreeListener.template.cxx new file mode 100644 index 0000000000..0f1794c462 --- /dev/null +++ b/src/SourceCompile/SV3_1aParseTreeListener.template.cxx @@ -0,0 +1,575 @@ +/* + 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: SV3_1aParseTreeListener.cpp + * Author: hs + * + * Created on January 31, 2023, 12:00 PM + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace SURELOG { +static constexpr std::pair kMinMaxRange( + static_cast(~0), 0); + +SV3_1aParseTreeListener::SV3_1aParseTreeListener( + ParseFile *pf, antlr4::CommonTokenStream *tokens, uint32_t lineOffset, + FileContent *ppFileContent) + : SV3_1aTreeShapeHelper(pf, tokens, lineOffset), + m_ppFileContent(ppFileContent) { + if (m_pf->getFileContent() == nullptr) { + m_fileContent = new FileContent( + m_pf->getFileId(0), m_pf->getLibrary(), + m_pf->getCompileSourceFile()->getSymbolTable(), + m_pf->getCompileSourceFile()->getErrorContainer(), nullptr, BadPathId); + m_pf->setFileContent(m_fileContent); + // m_pf->getCompileSourceFile()->getCompiler()->getDesign()->addFileContent( + // m_pf->getFileId(0), m_fileContent); + } else { + m_fileContent = m_pf->getFileContent(); + } +} + +NodeId SV3_1aParseTreeListener::addVObject(antlr4::ParserRuleContext *ctx, + antlr4::Token *token, + VObjectType objectType) { + if (m_paused != 0) return InvalidNodeId; + if (!m_visitedTokens.emplace(token).second) return InvalidNodeId; + + auto [fileId, line, column, endLine, endColumn] = getFileLine(nullptr, token); + const std::string text = token->getText(); + + NodeId childIndex = + m_fileContent->addObject(registerSymbol(text), fileId, objectType, line, + column, endLine, endColumn); + + NodeId parentIndex = NodeIdFromContext(ctx); + + VObject *const childObject = m_fileContent->MutableObject(childIndex); + VObject *const parentObject = m_fileContent->MutableObject(parentIndex); + + childObject->m_parent = parentIndex; + childObject->m_sibling = parentObject->m_child; + parentObject->m_child = childIndex; + + return childIndex; +} + +NodeId SV3_1aParseTreeListener::addVObject(antlr4::tree::TerminalNode *node, + VObjectType objectType) { + return (m_paused == 0) ? addVObject((antlr4::ParserRuleContext *)node, + node->getText(), objectType) + : InvalidNodeId; +} + +NodeId SV3_1aParseTreeListener::mergeObjectTree(NodeId ppNodeId) { + const std::vector &ppObjects = m_ppFileContent->getVObjects(); + const VObject &ppObject = ppObjects[ppNodeId]; + + std::vector &objects = *m_fileContent->mutableVObjects(); + + NodeId firstChildId; + NodeId lastChildId; + NodeId ppChildId = ppObject.m_child; + while (ppChildId) { + NodeId childId = mergeObjectTree(ppChildId); + if (firstChildId) { + objects[lastChildId].m_sibling = childId; + } else { + firstChildId = childId; + } + lastChildId = childId; + ppChildId = ppObjects[ppChildId].m_sibling; + } + + NodeId nodeId = m_fileContent->addObject( + ppObject.m_name, ppObject.m_fileId, ppObject.m_type, ppObject.m_line, + ppObject.m_column, ppObject.m_endLine, ppObject.m_endColumn); + + if (firstChildId) { + VObject &object = objects[nodeId]; + object.m_child = firstChildId; + + NodeId childId = firstChildId; + while (childId) { + objects[childId].m_parent = nodeId; + childId = objects[childId].m_sibling; + } + } + + return nodeId; +} + +std::optional SV3_1aParseTreeListener::isUnaryOperator( + const antlr4::tree::TerminalNode *node) const { + switch (((antlr4::ParserRuleContext *)node->parent)->getRuleIndex()) { + case SV3_1aParser::RuleExpression: { + SV3_1aParser::ExpressionContext *ctx = + (SV3_1aParser::ExpressionContext *)node->parent; + return std::optional(ctx->expression().size() == 1); + } break; + + case SV3_1aParser::RuleConstant_expression: { + SV3_1aParser::Constant_expressionContext *ctx = + (SV3_1aParser::Constant_expressionContext *)node->parent; + return std::optional(ctx->constant_primary() != nullptr); + } break; + + default: + break; + } + + return std::optional(); +} + +void SV3_1aParseTreeListener::enterString_value( + SV3_1aParser::String_valueContext *ctx) { + if (m_paused != 0) return; + + std::string text = ctx->String()->getText(); + + std::smatch match; + while (std::regex_search(text, match, m_escSeqSearchRegex)) { + std::string var = "\\" + match[1].str(); + text = text.replace(match.position(0), match.length(0), var); + } + + addVObject(ctx, text, VObjectType::paString_value); + m_visitedTokens.emplace(ctx->String()->getSymbol()); + + if (text.size() > SV_MAX_STRING_SIZE) { + logError(ErrorDefinition::PA_MAX_LENGTH_IDENTIFIER, ctx, text); + } +} + +void SV3_1aParseTreeListener::applyLocationOffsets() { + // std::cout << "ParseTreeListener::ColumnOffsets:" << std::endl; + // for (const auto &entry : m_offsets) { + // std::cout << std::setfill(' ') << std::setw(4) << entry.first + // << std::setfill(' ') << std::setw(4) << std::get<0>(entry.second) + // << std::setfill(' ') << std::setw(4) << std::get<1>(entry.second) + // << std::endl; + // } + // std::cout << std::endl; + + m_fileContent->sortTree(); + // m_fileContent->printTree(std::cout); + + vobjects_t &vobjects = *m_fileContent->mutableVObjects(); + for (vobjects_t::reference object : vobjects) { + if (static_cast(object.m_type) < + static_cast(VObjectType::paIndexBegin)) { + continue; // Don't apply offsets to ppXXXX types + } + + if (object.m_type == VObjectType::paTop_level_rule) { + // HACK(HS): For some unknown reason, the top level rule doesn't start + // at the top of the file and instead starts at where the module (or + // whatever is in channel 0). Force it to start at 1, 1 so the + // validation check can pass. + object.m_line = 1; + object.m_column = 1; + } + + uint16_t sc = object.m_column; + std::pair slItBounds = + m_offsets.equal_range(object.m_line); + for (offsets_t::const_iterator it = slItBounds.first; + it != slItBounds.second; ++it) { + if (object.m_column > std::get<0>(it->second)) { + sc += std::get<1>(it->second); + } + } + object.m_column = sc; + + uint16_t ec = object.m_endColumn; + std::pair elItBounds = + m_offsets.equal_range(object.m_endLine); + for (offsets_t::const_iterator it = elItBounds.first; + it != elItBounds.second; ++it) { + if (object.m_endColumn > std::get<0>(it->second)) { + ec += std::get<1>(it->second); + } + } + object.m_endColumn = ec; + } + + // if (!m_fileContent->validate()) { + // std::cerr << "Failed to validate generated tree" << std::endl; + // } +} + +void SV3_1aParseTreeListener::collectLineRanges(NodeId ppParentId, + line_ends_t &ends) const { + const std::vector &ppObjects = m_ppFileContent->getVObjects(); + const VObject &ppObject = ppObjects[ppParentId]; + + line_ends_t::iterator sit = ends.emplace(ppObject.m_line, kMinMaxRange).first; + sit->second = std::make_pair(std::min(sit->second.first, ppObject.m_column), + std::max(sit->second.second, ppObject.m_column)); + + line_ends_t::iterator eit = + ends.emplace(ppObject.m_endLine, kMinMaxRange).first; + eit->second = + std::make_pair(std::min(eit->second.first, ppObject.m_endColumn), + std::max(eit->second.second, ppObject.m_endColumn)); + + NodeId ppChildId = ppObjects[ppParentId].m_child; + while (ppChildId) { + collectLineRanges(ppChildId, ends); + ppChildId = ppObjects[ppChildId].m_sibling; + } +} + +void SV3_1aParseTreeListener::collectLineRanges(const antlr4::Token *begin, + const antlr4::Token *end, + line_ends_t &ends) const { + for (size_t i = begin->getTokenIndex() + 1, ni = end->getTokenIndex(); i < ni; + ++i) { + antlr4::Token *const token = m_tokens->get(i); + auto [fileId, sl, sc, el, ec] = getFileLine(nullptr, token); + + line_ends_t::iterator sit = ends.emplace(sl, kMinMaxRange).first; + sit->second = std::make_pair(std::min(sit->second.first, sc), + std::max(sit->second.second, sc)); + + line_ends_t::iterator eit = ends.emplace(el, kMinMaxRange).first; + eit->second = std::make_pair(std::min(eit->second.first, ec), + std::max(eit->second.second, ec)); + } +} + +void SV3_1aParseTreeListener::visitPreprocBegin(antlr4::Token *token) { + m_preprocBeginStack.emplace_back(token); + ++m_paused; +} + +void SV3_1aParseTreeListener::visitPreprocEnd(antlr4::Token *token, + NodeId ppNodeId) { + antlr4::Token *const endToken = token; + antlr4::Token *const beginToken = m_preprocBeginStack.back(); + m_preprocBeginStack.pop_back(); + + line_ends_t ppEnds; + collectLineRanges(ppNodeId, ppEnds); + + const VObject &object = m_ppFileContent->getVObjects()[(RawNodeId)ppNodeId]; + + switch (object.m_type) { + case VObjectType::ppInclude_directive: + case VObjectType::ppMacro_definition: { + auto [fileIdBegin, slBegin, scBegin, elBegin, ecBegin] = + getFileLine(nullptr, beginToken); + auto [fileIdEnd, slEnd, scEnd, elEnd, ecEnd] = + getFileLine(nullptr, endToken); + + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slBegin), + std::forward_as_tuple(scBegin, scBegin - ecBegin)); + + line_ends_t::const_iterator ppIt = ppEnds.find(slBegin); + if ((ppIt != ppEnds.end()) && + (ppIt->second.first != ppIt->second.second)) { + m_offsets.emplace( + std::piecewise_construct, std::forward_as_tuple(slBegin), + std::forward_as_tuple(ecBegin, + ppIt->second.second - ppIt->second.first)); + } + + m_offsets.emplace(std::piecewise_construct, std::forward_as_tuple(elEnd), + std::forward_as_tuple(scEnd, scEnd - ecEnd)); + } break; + + case VObjectType::ppMacro_instance: { + const ParseUtils::LineColumn slcBegin = + ParseUtils::getLineColumn(beginToken); + const ParseUtils::LineColumn slcEnd = ParseUtils::getLineColumn(endToken); + + if (slcBegin.first == slcEnd.first) { + auto [fileIdBegin, slBegin, scBegin, elBegin, ecBegin] = + getFileLine(nullptr, beginToken); + auto [fileIdEnd, slEnd, scEnd, elEnd, ecEnd] = + getFileLine(nullptr, endToken); + + line_ends_t ends; + collectLineRanges(beginToken, endToken, ends); + + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slBegin), + std::forward_as_tuple(scBegin, scBegin - ecBegin)); + + line_ends_t::const_iterator ppIt = ppEnds.find(slBegin); + if ((ppIt != ppEnds.end()) && + (ppIt->second.first != ppIt->second.second)) { + m_offsets.emplace( + std::piecewise_construct, std::forward_as_tuple(slBegin), + std::forward_as_tuple(ecBegin, + ppIt->second.second - ppIt->second.first)); + } + + line_ends_t::const_iterator it = ends.find(slBegin); + if ((it != ends.end()) && (it->second.first != it->second.second)) { + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slBegin), + std::forward_as_tuple( + ecBegin, it->second.first - it->second.second)); + } + + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(elEnd), + std::forward_as_tuple(scEnd, scEnd - ecEnd)); + } else { + const ParseUtils::LineColumn elcBegin = + ParseUtils::getEndLineColumn(beginToken); + const ParseUtils::LineColumn elcEnd = + ParseUtils::getEndLineColumn(endToken); + std::pair + ppMinMaxIt = + std::minmax_element(ppEnds.begin(), ppEnds.end(), + [](line_ends_t::const_reference lhs, + line_ends_t::const_reference rhs) { + return lhs.first < rhs.first; + }); + // const uint32_t slBegin = slcBegin.first; + const uint16_t scBegin = slcBegin.second; + // const uint32_t elBegin = elcBegin.first; + const uint16_t ecBegin = elcBegin.second; + + // const uint32_t slEnd = slcEnd.first; + const uint16_t scEnd = slcEnd.second; + // const uint32_t elEnd = elcEnd.first; + const uint16_t ecEnd = elcEnd.second; + + const uint32_t slTop = ppMinMaxIt.first->first; + const uint16_t scTop = ppMinMaxIt.first->second.first; + const uint16_t ecTop = ppMinMaxIt.first->second.second; + const uint32_t slBottom = ppMinMaxIt.second->first; + const uint16_t scBottom = ppMinMaxIt.second->second.first; + const uint16_t ecBottom = ppMinMaxIt.second->second.second; + + if (slTop == slBottom) { + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slTop), + std::forward_as_tuple(scBottom, scEnd - ecEnd)); + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slTop), + std::forward_as_tuple(scBottom, ecBottom - 1)); + } else { + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slTop), + std::forward_as_tuple(scBegin, scBegin - ecBegin)); + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slTop), + std::forward_as_tuple(scTop, ecTop - scTop)); + + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slBottom), + std::forward_as_tuple(scBottom, scEnd - ecEnd)); + m_offsets.emplace( + std::piecewise_construct, std::forward_as_tuple(slBottom), + std::forward_as_tuple(scBottom, ecBottom - scBottom)); + } + } + } break; + + default: { + auto [fileIdBegin, slBegin, scBegin, elBegin, ecBegin] = + getFileLine(nullptr, beginToken); + auto [fileIdEnd, slEnd, scEnd, elEnd, ecEnd] = + getFileLine(nullptr, endToken); + + m_offsets.emplace(std::piecewise_construct, + std::forward_as_tuple(slBegin), + std::forward_as_tuple(scBegin, scBegin - ecBegin)); + m_offsets.emplace(std::piecewise_construct, std::forward_as_tuple(elEnd), + std::forward_as_tuple(scEnd, scEnd - ecEnd)); + } break; + } + --m_paused; +} + +void SV3_1aParseTreeListener::processPendingTokens( + antlr4::ParserRuleContext *ctx, size_t endTokenIndex) { + while (m_lastVisitedTokenIndex < endTokenIndex) { + antlr4::Token *const lastToken = m_tokens->get(m_lastVisitedTokenIndex); + + NodeId nodeId; + switch (lastToken->getType()) { + case SV3_1aParser::PREPROC_BEGIN: { + visitPreprocBegin(lastToken); + } break; + + case SV3_1aParser::PREPROC_END: { + antlr4::Token *const endToken = lastToken; + const std::string endText = endToken->getText(); + std::string_view svtext = endText; + svtext.remove_prefix(kPreprocEndPrefix.length()); + + uint32_t index = 0; + if (NumUtils::parseUint32(svtext, &index)) { + const NodeId ppNodeId(index); + nodeId = mergeObjectTree(ppNodeId); + visitPreprocEnd(lastToken, ppNodeId); + } + } break; + + case SV3_1aParser::One_line_comment: { + nodeId = addVObject(ctx, lastToken, VObjectType::paOne_line_comment); + } break; + + case SV3_1aParser::Block_comment: { + nodeId = addVObject(ctx, lastToken, VObjectType::paBlock_comment); + } break; + + case SV3_1aParser::White_space: { + nodeId = addVObject(ctx, lastToken, VObjectType::paWhite_space); + } break; + + default: { + nodeId = InvalidNodeId; + } break; + } + + if (nodeId) m_orphanObjects.emplace(ctx, nodeId); + ++m_lastVisitedTokenIndex; + } +} + +void SV3_1aParseTreeListener::processOrphanObjects( + antlr4::ParserRuleContext *ctx, NodeId parentId) { + std::pair + bounds = m_orphanObjects.equal_range(ctx); + if (bounds.first == bounds.second) return; + + VObject *const parent = m_fileContent->MutableObject(parentId); + for (orphan_objects_t::const_iterator it = bounds.first; it != bounds.second; + ++it) { + const NodeId &orphanId = it->second; + VObject *const orphan = m_fileContent->MutableObject(orphanId); + + orphan->m_parent = parentId; + orphan->m_sibling = parent->m_child; + parent->m_child = orphanId; + } + + m_orphanObjects.erase(bounds.first, bounds.second); +} + +void SV3_1aParseTreeListener::enterEveryRule(antlr4::ParserRuleContext *ctx) { + if (const antlr4::Token *const startToken = ctx->getStart()) { + if (!m_ruleCallstack.empty()) { + processPendingTokens(m_ruleCallstack.back(), startToken->getTokenIndex()); + } + } + m_ruleCallstack.emplace_back(ctx); +} + +void SV3_1aParseTreeListener::exitEveryRule(antlr4::ParserRuleContext *ctx) { + if (!m_ruleCallstack.empty() && (m_ruleCallstack.back() == ctx)) { + m_ruleCallstack.pop_back(); + } + + if (const antlr4::Token *const stopToken = ctx->getStop()) { + processPendingTokens(ctx, stopToken->getTokenIndex()); + } + + NodeId nodeId; + + // clang-format off + switch (ctx->getRuleIndex()) { + + default: break; + } + // clang-format on + + processOrphanObjects(ctx, nodeId); + + if (ctx->getRuleIndex() == SV3_1aParser::RuleTop_level_rule) { + applyLocationOffsets(); + } +} + +void SV3_1aParseTreeListener::visitTerminal(antlr4::tree::TerminalNode *node) { + // Skip any tokens that are already handled as part of enterXXX/exitXXX rules + const antlr4::Token *const token = node->getSymbol(); + if (token->getType() == antlr4::Token::EOF) return; + if (!m_visitedTokens.emplace(token).second) return; + + if (!m_ruleCallstack.empty()) { + processPendingTokens(m_ruleCallstack.back(), token->getTokenIndex()); + } + + NodeId nodeId; + + // clang-format off + switch (token->getType()) { + case SV3_1aParser::Escaped_identifier: { + std::string text = node->getText(); + std::smatch match; + while (std::regex_search(text, match, m_escSeqSearchRegex)) { + std::string var = "\\" + match[1].str(); + text = text.replace(match.position(0), match.length(0), var); + } + nodeId = addVObject((antlr4::ParserRuleContext *)node, text, VObjectType::paEscaped_identifier); + } break; + + + default: break; + } + // clang-format on + + if (nodeId) { + VObject *const object = m_fileContent->MutableObject(nodeId); + + const std::optional isUnary = isUnaryOperator(node); + if (isUnary) { + // clang-format off + switch (token->getType()) { + case SV3_1aParser::BITW_AND: object->m_type = isUnary.value() ? VObjectType::paUnary_BitwAnd : VObjectType::paBinOp_BitwAnd; break; + case SV3_1aParser::BITW_OR: object->m_type = isUnary.value() ? VObjectType::paUnary_BitwOr : VObjectType::paBinOp_BitwOr; break; + case SV3_1aParser::BITW_XOR: object->m_type = isUnary.value() ? VObjectType::paUnary_BitwXor : VObjectType::paBinOp_BitwXor; break; + case SV3_1aParser::MINUS: object->m_type = isUnary.value() ? VObjectType::paUnary_Minus : VObjectType::paBinOp_Minus; break; + case SV3_1aParser::PLUS: object->m_type = isUnary.value() ? VObjectType::paUnary_Plus : VObjectType::paBinOp_Plus; break; + case SV3_1aParser::REDUCTION_NAND: object->m_type = isUnary.value() ? VObjectType::paUnary_ReductNand : VObjectType::paBinOp_ReductNand; break; + case SV3_1aParser::REDUCTION_XNOR1: object->m_type = isUnary.value() ? VObjectType::paUnary_ReductXnor1 : VObjectType::paBinOp_ReductXnor1; break; + case SV3_1aParser::REDUCTION_XNOR2: object->m_type = isUnary.value() ? VObjectType::paUnary_ReductXnor2 : VObjectType::paBinOp_ReductXnor2; break; + case SV3_1aParser::STAR: object->m_type = VObjectType::paBinOp_Mult; break; + default: break; + } + // clang-format on + } + } +} + +void SV3_1aParseTreeListener::visitErrorNode(antlr4::tree::ErrorNode *node) { + if (node->getText().find(" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace SURELOG { +SV3_1aPpParseTreeListener::SV3_1aPpParseTreeListener( + PreprocessFile *pp, antlr4::CommonTokenStream *tokens, + PreprocessFile::SpecialInstructions &instructions) + : SV3_1aPpTreeListenerHelper(pp, instructions, tokens) { + if (m_pp->getFileContent() == nullptr) { + m_fileContent = new FileContent( + m_pp->getFileId(0), m_pp->getLibrary(), + m_pp->getCompileSourceFile()->getSymbolTable(), + m_pp->getCompileSourceFile()->getErrorContainer(), nullptr, BadPathId); + m_pp->setFileContent(m_fileContent); + } else { + m_fileContent = m_pp->getFileContent(); + } + + if (PreprocessFile *includer = pp->getIncluder()) { + m_paused = ((SV3_1aPpParseTreeListener *)includer->m_listener)->m_paused; + } +} + +NodeId SV3_1aPpParseTreeListener::addVObject(antlr4::tree::TerminalNode *node, + VObjectType objectType) { + return addVObject((antlr4::ParserRuleContext *)node, node->getText(), + objectType); +} + +bool SV3_1aPpParseTreeListener::isOnCallStack(size_t ruleIndex) const { + return std::find(m_callstack.crbegin(), m_callstack.crend(), ruleIndex) != + m_callstack.crend(); +} + +bool SV3_1aPpParseTreeListener::isAnyOnCallStack( + const std::unordered_set &ruleIndicies) const { + for (callstack_t::const_reverse_iterator it = m_callstack.crbegin(), + end = m_callstack.crend(); + it != end; ++it) { + if (ruleIndicies.find(*it) != ruleIndicies.end()) { + return true; + } + } + return false; +} + +void SV3_1aPpParseTreeListener::appendPreprocBegin() { + const size_t index = m_fileContent->getVObjects().size(); + m_pp->append(StrCat(kPreprocBeginPrefix, index, kPreprocBeginSuffix, + std::string(m_pendingCRs, '\n'))); + m_pendingCRs = 0; +} + +void SV3_1aPpParseTreeListener::appendPreprocEnd(antlr4::ParserRuleContext *ctx, + VObjectType type) { + const size_t index = (RawNodeId)addVObject(ctx, type); + m_pp->append(StrCat(std::string(m_pendingCRs, '\n'), kPreprocEndPrefix, index, + kPreprocEndSuffix)); + m_visitedRules.emplace(ctx); + m_pendingCRs = 0; +} + +void SV3_1aPpParseTreeListener::enterText_blob( + SV3_1aPpParser::Text_blobContext *ctx) { + if (m_paused != 0) return; + + if (m_inActiveBranch && isOnCallStack(SV3_1aPpParser::RuleMacro_instance)) { + m_pp->append(ctx->getText()); + } +} + +void SV3_1aPpParseTreeListener::enterEscaped_identifier( + SV3_1aPpParser::Escaped_identifierContext *ctx) { + if (m_paused != 0) return; + + if (m_inActiveBranch && !m_inMacroDefinitionParsing) { + const std::string text = ctx->getText(); + + std::string sequence = kEscapeSequence; + sequence.append(++text.cbegin(), text.cend()); + sequence.append(kEscapeSequence); + + m_pp->append(sequence); + } +} + +void SV3_1aPpParseTreeListener::enterIfdef_directive( + SV3_1aPpParser::Ifdef_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); + + std::string macroName; + ParseUtils::LineColumn lc = + ParseUtils::getLineColumn(m_pp->getTokenStream(), ctx); + if (antlr4::tree::TerminalNode *const simpleIdentifierNode = + ctx->Simple_identifier()) { + lc = ParseUtils::getLineColumn(simpleIdentifierNode); + macroName = simpleIdentifierNode->getText(); + } else if (antlr4::tree::TerminalNode *const escapedIdentifierNode = + ctx->ESCAPED_IDENTIFIER()) { + lc = ParseUtils::getLineColumn(escapedIdentifierNode); + macroName = escapedIdentifierNode->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + } else if (SV3_1aPpParser::Macro_instanceContext *const macroInstanceNode = + ctx->macro_instance()) { + lc = ParseUtils::getLineColumn(m_pp->getTokenStream(), macroInstanceNode); + macroName = m_pp->evaluateMacroInstance( + macroInstanceNode->getText(), m_pp, lc.first, + PreprocessFile::SpecialInstructions::CheckLoop, + PreprocessFile::SpecialInstructions::ComplainUndefinedMacro); + } + + if (!m_pp->isMacroBody()) { + m_pp->getSourceFile()->m_loopChecker.clear(); + } + + std::vector args; + PreprocessFile::SpecialInstructions instr = m_pp->m_instructions; + instr.m_evaluate = PreprocessFile::SpecialInstructions::DontEvaluate; + const std::string macroBody = m_pp->getMacro( + macroName, args, m_pp, 0, m_pp->getSourceFile()->m_loopChecker, instr); + + PreprocessFile::IfElseItem &item = m_pp->getStack().emplace_back(); + item.m_macroName = macroName; + item.m_defined = (macroBody != PreprocessFile::MacroNotDefined); + item.m_type = PreprocessFile::IfElseItem::IFDEF; + item.m_previousActiveState = m_inActiveBranch; + setCurrentBranchActivity(lc.first); +} + +void SV3_1aPpParseTreeListener::exitIfdef_directive( + SV3_1aPpParser::Ifdef_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppIfdef_directive); +} + +void SV3_1aPpParseTreeListener::enterIfndef_directive( + SV3_1aPpParser::Ifndef_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); +} + +void SV3_1aPpParseTreeListener::exitIfndef_directive( + SV3_1aPpParser::Ifndef_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppIfndef_directive); +} + +void SV3_1aPpParseTreeListener::enterUndef_directive( + SV3_1aPpParser::Undef_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); +} + +void SV3_1aPpParseTreeListener::exitUndef_directive( + SV3_1aPpParser::Undef_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppUndef_directive); +} + +void SV3_1aPpParseTreeListener::enterElsif_directive( + SV3_1aPpParser::Elsif_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); + + std::string macroName; + ParseUtils::LineColumn lc = + ParseUtils::getLineColumn(m_pp->getTokenStream(), ctx); + if (antlr4::tree::TerminalNode *const simpleIdentifierNode = + ctx->Simple_identifier()) { + lc = ParseUtils::getLineColumn(simpleIdentifierNode); + macroName = simpleIdentifierNode->getText(); + } else if (antlr4::tree::TerminalNode *const escapedIdentifierNode = + ctx->ESCAPED_IDENTIFIER()) { + lc = ParseUtils::getLineColumn(escapedIdentifierNode); + macroName = escapedIdentifierNode->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + } else if (SV3_1aPpParser::Macro_instanceContext *const macroInstanceNode = + ctx->macro_instance()) { + lc = ParseUtils::getLineColumn(m_pp->getTokenStream(), macroInstanceNode); + macroName = m_pp->evaluateMacroInstance( + macroInstanceNode->getText(), m_pp, lc.first, + PreprocessFile::SpecialInstructions::CheckLoop, + PreprocessFile::SpecialInstructions::ComplainUndefinedMacro); + } + + if (!m_pp->isMacroBody()) { + m_pp->getSourceFile()->m_loopChecker.clear(); + } + + std::vector args; + PreprocessFile::SpecialInstructions instr = m_pp->m_instructions; + instr.m_evaluate = PreprocessFile::SpecialInstructions::DontEvaluate; + const std::string macroBody = m_pp->getMacro( + macroName, args, m_pp, 0, m_pp->getSourceFile()->m_loopChecker, instr); + + const bool previousBranchActive = isPreviousBranchActive(); + PreprocessFile::IfElseItem &item = m_pp->getStack().emplace_back(); + item.m_macroName = macroName; + item.m_defined = + (macroBody != PreprocessFile::MacroNotDefined) && !previousBranchActive; + item.m_type = PreprocessFile::IfElseItem::ELSIF; + setCurrentBranchActivity(lc.first); +} + +void SV3_1aPpParseTreeListener::exitElsif_directive( + SV3_1aPpParser::Elsif_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppElsif_directive); +} + +void SV3_1aPpParseTreeListener::enterElse_directive( + SV3_1aPpParser::Else_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); + + const bool previousBranchActive = isPreviousBranchActive(); + PreprocessFile::IfElseItem &item = m_pp->getStack().emplace_back(); + ParseUtils::LineColumn lc = + ParseUtils::getLineColumn(m_pp->getTokenStream(), ctx); + item.m_defined = !previousBranchActive; + item.m_type = PreprocessFile::IfElseItem::ELSE; + setCurrentBranchActivity(lc.first); +} + +void SV3_1aPpParseTreeListener::exitElse_directive( + SV3_1aPpParser::Else_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppElse_directive); +} + +void SV3_1aPpParseTreeListener::enterElseif_directive( + SV3_1aPpParser::Elseif_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); +} + +void SV3_1aPpParseTreeListener::exitElseif_directive( + SV3_1aPpParser::Elseif_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppElseif_directive); +} + +void SV3_1aPpParseTreeListener::enterEndif_directive( + SV3_1aPpParser::Endif_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); + + PreprocessFile::IfElseStack &stack = m_pp->getStack(); + ParseUtils::LineColumn lc = + ParseUtils::getLineColumn(m_pp->getTokenStream(), ctx); + if (!stack.empty()) { + bool unroll = true; + // if (ctx->One_line_comment()) { + // addLineFiller(ctx); + // } + while (unroll && (!stack.empty())) { + PreprocessFile::IfElseItem &item = stack.back(); + switch (item.m_type) { + case PreprocessFile::IfElseItem::IFDEF: + case PreprocessFile::IfElseItem::IFNDEF: + m_inActiveBranch = item.m_previousActiveState; + stack.pop_back(); + unroll = false; + break; + case PreprocessFile::IfElseItem::ELSIF: + case PreprocessFile::IfElseItem::ELSE: + stack.pop_back(); + break; + default: + unroll = false; + break; + } + } + } + setCurrentBranchActivity(lc.first); +} + +void SV3_1aPpParseTreeListener::exitEndif_directive( + SV3_1aPpParser::Endif_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppEndif_directive); +} + +void SV3_1aPpParseTreeListener::enterInclude_directive( + SV3_1aPpParser::Include_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); + + if (!(m_inActiveBranch && (!m_inMacroDefinitionParsing))) { + return; + } + + FileSystem *const fileSystem = FileSystem::getInstance(); + + ParseUtils::LineColumn slc = + ParseUtils::getLineColumn(m_pp->getTokenStream(), ctx); + ParseUtils::LineColumn elc = + ParseUtils::getEndLineColumn(m_pp->getTokenStream(), ctx); + int32_t openingIndex = -1; + std::string fileName; + if (antlr4::tree::TerminalNode *const stringNode = ctx->STRING()) { + fileName = stringNode->getText(); + slc = ParseUtils::getLineColumn(stringNode); + elc = ParseUtils::getEndLineColumn(stringNode); + } else if (SV3_1aPpParser::Macro_instanceContext *const macroInstanceNode = + ctx->macro_instance()) { + slc = ParseUtils::getLineColumn(m_pp->getTokenStream(), macroInstanceNode); + elc = + ParseUtils::getEndLineColumn(m_pp->getTokenStream(), macroInstanceNode); + fileName = m_pp->evaluateMacroInstance( + macroInstanceNode->getText(), m_pp, slc.first, + PreprocessFile::SpecialInstructions::CheckLoop, + PreprocessFile::SpecialInstructions::ComplainUndefinedMacro); + } else { + Location loc(m_pp->getFileId(slc.first), m_pp->getLineNb(slc.first), + slc.second); + logError(ErrorDefinition::PP_INVALID_INCLUDE_FILENAME, loc); + return; + } + + fileName = StringUtils::unquoted(StringUtils::trim(fileName)); + + PathId fileId = fileSystem->locate( + fileName, + m_pp->getCompileSourceFile()->getCommandLineParser()->getIncludePaths(), + getSymbolTable()); + if (!fileId) { + // If failed to locate, then assume the same folder as the includer file + // and let it fail down the stream. + fileId = fileSystem->getSibling(m_pp->getCompileSourceFile()->getFileId(), + fileName, getSymbolTable()); + } + + const SymbolId symbolId = getSymbolTable()->registerSymbol(fileName); + + if (m_pp->getCompileSourceFile()->getCommandLineParser()->verbose()) { + Location loc(fileId); + logError(ErrorDefinition::PP_PROCESSING_INCLUDE_FILE, loc, true); + } + + // Detect include loop + PreprocessFile *tmp = m_pp; + while (tmp) { + if (tmp->getFileId(0) == fileId) { + Location loc(m_pp->getFileId(slc.first), slc.first, slc.second, + (SymbolId)fileId); + logError(ErrorDefinition::PP_RECURSIVE_INCLUDE_DIRECTIVE, loc, true); + return; + } + tmp = tmp->getIncluder(); + } + + uint32_t lineSum = m_pp->getSumLineCount() + 1; + openingIndex = m_pp->getSourceFile()->addIncludeFileInfo( + IncludeFileInfo::Context::INCLUDE, // context + 1, // sectionStartLine + symbolId, // sectionSymbolId + fileId, // sectionFileId + lineSum, // originalStartLine + slc.second, // originalStartColumn + lineSum + (elc.first - slc.first), // originalEndLine + elc.second, // originalEndColumn + IncludeFileInfo::Action::PUSH // action + ); + + PreprocessFile *pp = new PreprocessFile( + fileId, m_pp->getCompileSourceFile(), m_instructions, + m_pp->getCompilationUnit(), m_pp->getLibrary(), m_pp, slc.first); + m_pp->getCompileSourceFile()->registerPP(pp); + if (!pp->preprocess()) { + return; + } + + if (ctx->macro_instance()) { + m_append_paused_context = ctx; + m_pp->pauseAppend(); + } + + lineSum = m_pp->getSumLineCount() + 1; + int32_t closingIndex = m_pp->getSourceFile()->addIncludeFileInfo( + IncludeFileInfo::Context::INCLUDE, // context + slc.first, // sectionStartLine + BadSymbolId, // sectionSymbolId + m_pp->getFileId(slc.first), // sectionFileId + lineSum, // originalStartLine + slc.second, // originalStartColumn + lineSum + (elc.first - slc.first), // originalEndLine + elc.second, // originalEndColumn + IncludeFileInfo::Action::POP, // action + openingIndex, // indexOpening + 0 // indexClosing + ); + if (openingIndex >= 0) { + m_pp->getSourceFile()->getIncludeFileInfo(openingIndex).m_indexClosing = + closingIndex; + } +} + +void SV3_1aPpParseTreeListener::exitInclude_directive( + SV3_1aPpParser::Include_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppInclude_directive); + + if (m_append_paused_context == ctx) { + m_append_paused_context = nullptr; + m_pp->resumeAppend(); + } + + if (antlr4::tree::TerminalNode *const escapedIdentifier = + ctx->ESCAPED_IDENTIFIER()) { + addVObject(escapedIdentifier, VObjectType::ppEscaped_identifier); + } else if (antlr4::tree::TerminalNode *const simpleIdentifier = + ctx->Simple_identifier()) { + addVObject(simpleIdentifier, VObjectType::ppPs_identifier); + } else if (antlr4::tree::TerminalNode *const stringNode = ctx->STRING()) { + addVObject(stringNode, VObjectType::ppString); + } + addVObject(ctx, VObjectType::ppInclude_directive); +} + +void SV3_1aPpParseTreeListener::enterLine_directive( + SV3_1aPpParser::Line_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); +} + +void SV3_1aPpParseTreeListener::exitLine_directive( + SV3_1aPpParser::Line_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppLine_directive); +} + +void SV3_1aPpParseTreeListener::enterSv_file_directive( + SV3_1aPpParser::Sv_file_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); +} + +void SV3_1aPpParseTreeListener::exitSv_file_directive( + SV3_1aPpParser::Sv_file_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppSv_file_directive); +} + +void SV3_1aPpParseTreeListener::enterSv_line_directive( + SV3_1aPpParser::Sv_line_directiveContext *ctx) { + if (m_paused == 0) appendPreprocBegin(); +} + +void SV3_1aPpParseTreeListener::exitSv_line_directive( + SV3_1aPpParser::Sv_line_directiveContext *ctx) { + if (m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppSv_line_directive); +} + +void SV3_1aPpParseTreeListener::enterMacroInstanceWithArgs( + SV3_1aPpParser::MacroInstanceWithArgsContext *ctx) { + if (m_paused++ == 0) appendPreprocBegin(); + if (m_inMacroDefinitionParsing) return; + + if (m_inActiveBranch) { + ParseUtils::LineColumn slc = + ParseUtils::getLineColumn(m_pp->getTokenStream(), ctx); + ParseUtils::LineColumn elc = + ParseUtils::getEndLineColumn(m_pp->getTokenStream(), ctx); + + std::string macroName; + if (antlr4::tree::TerminalNode *const identifier = + ctx->Macro_identifier()) { + macroName = identifier->getText(); + slc = ParseUtils::getLineColumn(identifier); + elc = ParseUtils::getEndLineColumn(identifier); + } else if (antlr4::tree::TerminalNode *escapedIdentifier = + ctx->Macro_Escaped_identifier()) { + macroName = escapedIdentifier->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + slc = ParseUtils::getLineColumn(escapedIdentifier); + elc = ParseUtils::getEndLineColumn(escapedIdentifier); + } + + std::vector tokens = + ParseUtils::getTopTokenList(ctx->macro_actual_args()); + std::vector actualArgs; + ParseUtils::tokenizeAtComma(actualArgs, tokens); + macroName.erase(macroName.begin()); + + int32_t openingIndex = -1; + if (!m_pp->isMacroBody()) { + m_pp->getSourceFile()->m_loopChecker.clear(); + } + + std::string macroBody; + MacroInfo *const macroInfo = m_pp->getMacro(macroName); + if (macroInfo != nullptr) { + uint32_t lineSum = m_pp->getSumLineCount() + 1; + openingIndex = m_pp->getSourceFile()->addIncludeFileInfo( + IncludeFileInfo::Context::MACRO, // context + macroInfo->m_startLine, // sectionStartLine + BadSymbolId, // sectionSymbolId + macroInfo->m_fileId, // sectionFileId + lineSum, // originalStartLine + slc.second, // originalStartColumn + lineSum + (elc.first - slc.first), // originalEndLine + elc.second, // originalEndColumn + IncludeFileInfo::Action::PUSH // action + ); + macroBody = m_pp->getMacro(macroName, actualArgs, m_pp, slc.first, + m_pp->getSourceFile()->m_loopChecker, + m_pp->m_instructions, macroInfo->m_startLine, + macroInfo->m_fileId); + } else { + macroBody = m_pp->getMacro(macroName, actualArgs, m_pp, slc.first, + m_pp->getSourceFile()->m_loopChecker, + m_pp->m_instructions); + } + + const std::string macroArgs = ctx->macro_actual_args()->getText(); + int32_t nbCRinArgs = std::count(macroArgs.begin(), macroArgs.end(), '\n'); + + bool emptyMacroBody = false; + if (macroBody.empty()) { + emptyMacroBody = true; + macroBody.append(nbCRinArgs, '\n'); + } + + m_pp->append(macroBody); + + if (openingIndex >= 0) { + PathId fileId; + uint32_t line = 0; + if (m_pp->getEmbeddedMacroCallFile()) { + fileId = m_pp->getEmbeddedMacroCallFile(); + line = m_pp->getEmbeddedMacroCallLine() + slc.first; + } else { + fileId = m_pp->getFileId(slc.first); + line = slc.first; + } + uint32_t lineSum = m_pp->getSumLineCount() + 1; + int32_t closingIndex = -1; + if (emptyMacroBody) { + if (nbCRinArgs) lineSum -= nbCRinArgs; + + closingIndex = m_pp->getSourceFile()->addIncludeFileInfo( + IncludeFileInfo::Context::MACRO, // context + line, // sectionStartLine + BadSymbolId, // sectionSymbolId + fileId, // sectionFileId + lineSum, // originalStartLine + slc.second, // originalStartColumn + lineSum + (elc.first - slc.first), // originalEndLine + elc.second, // originalEndColumn + IncludeFileInfo::Action::POP, // action + openingIndex, // indexOpening + 0 // indexClosing + ); + } else { + closingIndex = m_pp->getSourceFile()->addIncludeFileInfo( + IncludeFileInfo::Context::MACRO, // context + line + nbCRinArgs, // sectionStartLine + BadSymbolId, // sectionSymbolId + fileId, // sectionFileId + lineSum, // originalStartLine + slc.second, // originalStartColumn + lineSum + (elc.first - slc.first), // originalEndLine + elc.second, // originalEndColumn + IncludeFileInfo::Action::POP, // action + openingIndex, // indexOpening + 0 // indexClosing + ); + } + if (openingIndex >= 0) { + m_pp->getSourceFile()->getIncludeFileInfo(openingIndex).m_indexClosing = + closingIndex; + } + } + } else { + const std::string macroArgs = ctx->macro_actual_args()->getText(); + int32_t nbCRinArgs = std::count(macroArgs.begin(), macroArgs.end(), '\n'); + m_pp->append(std::string(nbCRinArgs, '\n')); + } +} + +void SV3_1aPpParseTreeListener::exitMacroInstanceWithArgs( + SV3_1aPpParser::MacroInstanceWithArgsContext *ctx) { + if (--m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppMacro_instance); +} + +void SV3_1aPpParseTreeListener::enterMacroInstanceNoArgs( + SV3_1aPpParser::MacroInstanceNoArgsContext *ctx) { + if (m_paused++ == 0) appendPreprocBegin(); + if (!(m_inActiveBranch && !m_inMacroDefinitionParsing)) return; + + ParseUtils::LineColumn slc = + ParseUtils::getLineColumn(m_pp->getTokenStream(), ctx); + ParseUtils::LineColumn elc = + ParseUtils::getEndLineColumn(m_pp->getTokenStream(), ctx); + + std::string macroName; + if (antlr4::tree::TerminalNode *const macroIdentifierNode = + ctx->Macro_identifier()) { + macroName = macroIdentifierNode->getText(); + slc = ParseUtils::getLineColumn(macroIdentifierNode); + elc = ParseUtils::getEndLineColumn(macroIdentifierNode); + } else if (antlr4::tree::TerminalNode *const macroEscapedIdentifierNode = + ctx->Macro_Escaped_identifier()) { + macroName = macroEscapedIdentifierNode->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + slc = ParseUtils::getLineColumn(macroEscapedIdentifierNode); + elc = ParseUtils::getEndLineColumn(macroEscapedIdentifierNode); + } + macroName.erase(macroName.begin()); + + if (!m_pp->isMacroBody()) { + m_pp->getSourceFile()->m_loopChecker.clear(); + } + + std::string macroBody; + int32_t openingIndex = -1; + std::vector args; + MacroInfo *const macroInfo = m_pp->getMacro(macroName); + if (macroInfo != nullptr) { + if (macroInfo->m_type == MacroInfo::WITH_ARGS) { + Location loc(m_pp->getFileId(slc.first), m_pp->getLineNb(slc.first), + slc.second, getSymbolTable()->getId(macroName)); + Location extraLoc(macroInfo->m_fileId, macroInfo->m_startLine, + macroInfo->m_startColumn); + logError(ErrorDefinition::PP_MACRO_PARENTHESIS_NEEDED, loc, extraLoc); + } + + uint32_t lineSum = m_pp->getSumLineCount() + 1; + openingIndex = m_pp->getSourceFile()->addIncludeFileInfo( + IncludeFileInfo::Context::MACRO, // context + macroInfo->m_startLine, // sectionStartLine + BadSymbolId, // sectionSymbolId + macroInfo->m_fileId, // sectionFileId + lineSum, // originalStartLine + slc.second, // originalStartColumn + lineSum + (elc.first - slc.first), // originalEndLine + elc.second, // originalEndColumn + IncludeFileInfo::Action::PUSH // action + ); + macroBody = m_pp->getMacro( + macroName, args, m_pp, slc.first, m_pp->getSourceFile()->m_loopChecker, + m_pp->m_instructions, macroInfo->m_startLine, macroInfo->m_fileId); + } else { + macroBody = m_pp->getMacro(macroName, args, m_pp, slc.first, + m_pp->getSourceFile()->m_loopChecker, + m_pp->m_instructions); + } + if (macroBody.empty() && m_instructions.m_mark_empty_macro) { + macroBody = SymbolTable::getEmptyMacroMarker(); + } + + m_pp->append(macroBody); + + if (openingIndex >= 0) { + PathId fileId; + uint32_t line = 0; + if (m_pp->getEmbeddedMacroCallFile()) { + fileId = m_pp->getEmbeddedMacroCallFile(); + line = m_pp->getEmbeddedMacroCallLine() + slc.first; + } else { + fileId = m_pp->getFileId(slc.first); + line = slc.first; + } + if (macroBody.find('\n') != std::string::npos) { + uint32_t lineSum = m_pp->getSumLineCount() + 1; + int32_t closingIndex = m_pp->getSourceFile()->addIncludeFileInfo( + IncludeFileInfo::Context::MACRO, // context + line, // sectionStartLine + BadSymbolId, // sectionSymbolId + fileId, // sectionFileId + lineSum, // originalStartLine + slc.second, // originalStartColumn + lineSum + (elc.first - slc.first), // originalEndLine + elc.second, // originalEndColumn + IncludeFileInfo::Action::POP, // action + openingIndex, // indexOpening + 0 // indexClosing + ); + if (openingIndex >= 0) { + m_pp->getSourceFile()->getIncludeFileInfo(openingIndex).m_indexClosing = + closingIndex; + } + } + } +} + +void SV3_1aPpParseTreeListener::exitMacroInstanceNoArgs( + SV3_1aPpParser::MacroInstanceNoArgsContext *ctx) { + if (--m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppMacro_instance); +} + +void SV3_1aPpParseTreeListener::recordMacro( + std::string_view name, std::string_view arguments, + antlr4::tree::TerminalNode *identifier, antlr4::ParserRuleContext *body) { + ParseUtils::LineColumn slc = ParseUtils::getLineColumn(identifier); + ParseUtils::LineColumn elc = ParseUtils::getEndLineColumn(identifier); + + std::vector bodyTokens; + if (body != nullptr) { + std::vector tokens = ParseUtils::getFlatTokenList(body); + bodyTokens.reserve(tokens.size()); + for (antlr4::Token *token : tokens) { + bodyTokens.emplace_back(token->getText()); + } + } + + m_pp->recordMacro(name, m_pp->getLineNb(slc.first), slc.second, + m_pp->getLineNb(slc.first) + (elc.first - slc.first), + elc.second, arguments, bodyTokens); +} + +void SV3_1aPpParseTreeListener::enterMacro_definition( + SV3_1aPpParser::Macro_definitionContext *ctx) { + if (m_paused++ == 0) appendPreprocBegin(); + if (!m_inActiveBranch) return; + + std::string macroName; + std::string arguments; + antlr4::tree::TerminalNode *identifier = nullptr; + antlr4::ParserRuleContext *body = nullptr; + + if (SV3_1aPpParser::Simple_no_args_macro_definitionContext *const + simpleNoArgsDefinition = ctx->simple_no_args_macro_definition()) { + if ((identifier = simpleNoArgsDefinition->Simple_identifier())) + macroName = identifier->getText(); + else if ((identifier = simpleNoArgsDefinition->ESCAPED_IDENTIFIER())) { + macroName = identifier->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + } + + body = simpleNoArgsDefinition->simple_macro_definition_body(); + } else if (SV3_1aPpParser::Simple_args_macro_definitionContext *const + simpleArgsDefinition = ctx->simple_args_macro_definition()) { + if ((identifier = simpleArgsDefinition->Simple_identifier())) + macroName = identifier->getText(); + else if ((identifier = simpleArgsDefinition->ESCAPED_IDENTIFIER())) { + macroName = identifier->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + } + + arguments = simpleArgsDefinition->macro_arguments()->getText(); + body = simpleArgsDefinition->simple_macro_definition_body(); + } else if (SV3_1aPpParser::Multiline_no_args_macro_definitionContext + *const multiNoArgsDefinition = + ctx->multiline_no_args_macro_definition()) { + if ((identifier = multiNoArgsDefinition->Simple_identifier())) + macroName = identifier->getText(); + else if ((identifier = multiNoArgsDefinition->ESCAPED_IDENTIFIER())) { + macroName = identifier->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + } + + body = multiNoArgsDefinition->escaped_macro_definition_body(); + } else if (SV3_1aPpParser::Multiline_args_macro_definitionContext *const + multiArgsDefinition = ctx->multiline_args_macro_definition()) { + if ((identifier = multiArgsDefinition->Simple_identifier())) + macroName = identifier->getText(); + else if ((identifier = multiArgsDefinition->ESCAPED_IDENTIFIER())) { + macroName = identifier->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + } + + arguments = multiArgsDefinition->macro_arguments()->getText(); + body = multiArgsDefinition->escaped_macro_definition_body(); + } else if (SV3_1aPpParser::Define_directiveContext *const defineDirective = + ctx->define_directive()) { + if ((identifier = defineDirective->Simple_identifier())) + macroName = identifier->getText(); + else if ((identifier = defineDirective->ESCAPED_IDENTIFIER())) { + macroName = identifier->getText(); + std::string_view svname = macroName; + svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + } + } + + std::string_view svname = macroName; + if (macroName[0] == '\\') svname.remove_prefix(1); + macroName = StringUtils::rtrim(svname); + + recordMacro(macroName, arguments, identifier, body); + m_inMacroDefinitionParsing = true; +} + +void SV3_1aPpParseTreeListener::exitMacro_definition( + SV3_1aPpParser::Macro_definitionContext *ctx) { + if (--m_paused == 0) appendPreprocEnd(ctx, VObjectType::ppMacro_definition); + if (!m_inActiveBranch) return; + + if ((ctx->multiline_args_macro_definition() != nullptr) || + (ctx->multiline_no_args_macro_definition() != nullptr)) { + const std::string text = ctx->getText(); + m_pendingCRs += std::count(text.begin(), text.end(), '\n'); + } + m_inMacroDefinitionParsing = false; +} + +void SV3_1aPpParseTreeListener::exitSimple_macro_definition_body( + SV3_1aPpParser::Simple_macro_definition_bodyContext *ctx) { + addVObject(ctx, ctx->getText(), VObjectType::ppSimple_macro_definition_body); +} + +void SV3_1aPpParseTreeListener::exitEscaped_macro_definition_body( + SV3_1aPpParser::Escaped_macro_definition_bodyContext *ctx) { + addVObject(ctx, ctx->getText(), VObjectType::ppEscaped_macro_definition_body); +} + +void SV3_1aPpParseTreeListener::exitMacro_arg( + SV3_1aPpParser::Macro_argContext *ctx) { + addVObject(ctx, ctx->getText(), VObjectType::ppMacro_arg); +} + +void SV3_1aPpParseTreeListener::enterEveryRule(antlr4::ParserRuleContext *ctx) { + m_callstack.emplace_back(ctx->getRuleIndex()); +} + +void SV3_1aPpParseTreeListener::exitEveryRule(antlr4::ParserRuleContext *ctx) { + if (!m_callstack.empty() && (m_callstack.back() == ctx->getRuleIndex())) { + m_callstack.pop_back(); + } + + if (!m_visitedRules.emplace(ctx).second) return; + + if (isAnyOnCallStack({SV3_1aPpParser::RuleEscaped_macro_definition_body, + SV3_1aPpParser::RuleSimple_macro_definition_body, + SV3_1aPpParser::RuleMacro_arg, + SV3_1aPpParser::RuleIfdef_directive_in_macro_body, + SV3_1aPpParser::RuleIfndef_directive_in_macro_body, + SV3_1aPpParser::RuleElsif_directive_in_macro_body, + SV3_1aPpParser::RuleElseif_directive_in_macro_body})) { + return; + } + + // clang-format off + switch (ctx->getRuleIndex()) { + + default: break; + } + // clang-format on +} + +void SV3_1aPpParseTreeListener::visitTerminal( + antlr4::tree::TerminalNode *node) { + const antlr4::Token *const token = node->getSymbol(); + if (token->getType() == antlr4::Token::EOF) return; + + if (isAnyOnCallStack({SV3_1aPpParser::RuleEscaped_macro_definition_body, + SV3_1aPpParser::RuleSimple_macro_definition_body, + SV3_1aPpParser::RuleMacro_arg, + SV3_1aPpParser::RuleIfdef_directive_in_macro_body, + SV3_1aPpParser::RuleIfndef_directive_in_macro_body, + SV3_1aPpParser::RuleElsif_directive_in_macro_body, + SV3_1aPpParser::RuleElseif_directive_in_macro_body})) { + return; + } + + const bool directiveOnCallstack = isAnyOnCallStack( + {SV3_1aPpParser::RuleElse_directive, SV3_1aPpParser::RuleElseif_directive, + SV3_1aPpParser::RuleElsif_directive, SV3_1aPpParser::RuleEndif_directive, + SV3_1aPpParser::RuleIfdef_directive, + SV3_1aPpParser::RuleIfndef_directive, + SV3_1aPpParser::RuleInclude_directive, + SV3_1aPpParser::RuleLine_directive, SV3_1aPpParser::RuleMacro_definition, + SV3_1aPpParser::RuleMacro_instance, + SV3_1aPpParser::RuleSv_file_directive, + SV3_1aPpParser::RuleSv_line_directive, + SV3_1aPpParser::RuleUndef_directive}); + + if (!m_inActiveBranch && !m_pp->getRawFileId()) { + const std::string text = node->getText(); + m_pendingCRs += std::count(text.begin(), text.end(), '\n'); + if (m_pendingCRs > 0) { + m_pp->append(std::string(m_pendingCRs, '\n')); + m_pendingCRs = 0; + } + return; + } else if (!directiveOnCallstack) { + if (token->getType() != SV3_1aPpParser::ESCAPED_IDENTIFIER) { + m_pp->append(node->getText()); + } + } else if ((token->getType() == SV3_1aPpParser::CR) || + (token->getType() == SV3_1aPpParser::ESCAPED_CR)) { + ++m_pendingCRs; + } + + // clang-format off + switch (token->getType()) { + + default: break; + } + // clang-format on +} +} // namespace SURELOG diff --git a/src/SourceCompile/SV3_1aPpTreeShapeListener.cpp b/src/SourceCompile/SV3_1aPpTreeShapeListener.cpp index 534012cf8b..d2c6312911 100644 --- a/src/SourceCompile/SV3_1aPpTreeShapeListener.cpp +++ b/src/SourceCompile/SV3_1aPpTreeShapeListener.cpp @@ -468,12 +468,13 @@ void SV3_1aPpTreeShapeListener::enterMacroInstanceWithArgs( std::vector actualArgs; ParseUtils::tokenizeAtComma(actualArgs, tokens); macroName.erase(macroName.begin()); - std::string macroBody; + int32_t openingIndex = -1; if (!m_pp->isMacroBody()) { m_pp->getSourceFile()->m_loopChecker.clear(); } + std::string macroBody; MacroInfo *macroInf = m_pp->getMacro(macroName); if (macroInf) { uint32_t lineSum = m_pp->getSumLineCount() + 1; @@ -496,32 +497,24 @@ void SV3_1aPpTreeShapeListener::enterMacroInstanceWithArgs( << " BODY: |" << macroBody << "|" << std::endl; if (macroBody == PreprocessFile::MacroNotDefined) { macroBody += ":" + macroName + "!!! "; + macroBody.append(nbCRinArgs, '\n'); logError(ErrorDefinition::PP_UNKOWN_MACRO, ctx, macroName, true); } std::string pre; std::string post; - if (macroInf) { - if (!m_pp->m_instructions.m_filterFileLine) { - if (startLineCol.second == 0) { - pre = StrCat("`line ", macroInf->m_startLine, " \"", - fileSystem->toPath(macroInf->m_fileId), "\" 0"); - post = StrCat("`line ", startLineCol.first + 1, " \"", - fileSystem->toPath(m_pp->getFileId(startLineCol.first)), - "\" 0"); - if (m_pp->getCompileSourceFile() - ->getCommandLineParser() - ->lineOffsetsAsComments()) { - pre = "/* " + pre + "*/"; - post = "/* " + post + "*/"; - } else { - // Don't insert as parser does not know how to process this - // directive in this lexical context - pre = ""; - post = ""; - } - } - } + if ((macroInf != nullptr) && !m_pp->m_instructions.m_filterFileLine && + (startLineCol.second == 0) && + m_pp->getCompileSourceFile() + ->getCommandLineParser() + ->lineOffsetsAsComments()) { + // Don't insert as parser does not know how to process this + // directive in this lexical context + pre = StrCat("/* `line ", macroInf->m_startLine, " \"", + fileSystem->toPath(macroInf->m_fileId), "\" 0 */"); + post = StrCat("/* `line ", startLineCol.first + 1, " \"", + fileSystem->toPath(m_pp->getFileId(startLineCol.first)), + "\" 0 */"); } bool emptyMacroBody = false; if (macroBody.empty()) { @@ -547,19 +540,18 @@ void SV3_1aPpTreeShapeListener::enterMacroInstanceWithArgs( line = startLineCol.first; } uint32_t lineSum = m_pp->getSumLineCount() + 1; - int32_t origLine = line; int32_t closingIndex = -1; if (emptyMacroBody) { if (nbCRinArgs) lineSum -= nbCRinArgs; closingIndex = m_pp->getSourceFile()->addIncludeFileInfo( - IncludeFileInfo::Context::MACRO, origLine, BadSymbolId, fileId, - lineSum, startLineCol.second, + IncludeFileInfo::Context::MACRO, line, BadSymbolId, fileId, lineSum, + startLineCol.second, lineSum + (endLineCol.first - startLineCol.first), endLineCol.second, IncludeFileInfo::Action::POP, openingIndex, 0); } else { closingIndex = m_pp->getSourceFile()->addIncludeFileInfo( - IncludeFileInfo::Context::MACRO, origLine + nbCRinArgs, BadSymbolId, + IncludeFileInfo::Context::MACRO, line + nbCRinArgs, BadSymbolId, fileId, lineSum, startLineCol.second, lineSum + (endLineCol.first - startLineCol.first), endLineCol.second, IncludeFileInfo::Action::POP, openingIndex, 0); @@ -660,28 +652,20 @@ void SV3_1aPpTreeShapeListener::enterMacroInstanceNoArgs( std::string pre; std::string post; - if (macroInf) { - if (!m_pp->m_instructions.m_filterFileLine) { - if (startLineCol.second == 0) { - if (macroInf->m_fileId) - pre = StrCat("`line ", macroInf->m_startLine, " \"", - fileSystem->toPath(macroInf->m_fileId), "\" 0"); - post = StrCat("`line ", startLineCol.first + 1, " \"", - fileSystem->toPath(m_pp->getFileId(startLineCol.first)), - "\" 0"); - if (m_pp->getCompileSourceFile() - ->getCommandLineParser() - ->lineOffsetsAsComments()) { - pre = "/* " + pre + "*/"; - post = "/* " + post + "*/"; - } else { - // Don't insert as parser does not know how to process this - // directive in this lexical context - pre = ""; - post = ""; - } - } + if (macroInf && !m_pp->m_instructions.m_filterFileLine && + (startLineCol.second == 0) && + m_pp->getCompileSourceFile() + ->getCommandLineParser() + ->lineOffsetsAsComments()) { + // Don't insert as parser does not know how to process this + // directive in this lexical context + if (macroInf->m_fileId) { + pre = StrCat("/* `line ", macroInf->m_startLine, " \"", + fileSystem->toPath(macroInf->m_fileId), "\" 0 */"); } + post = StrCat("/* `line ", startLineCol.first + 1, " \"", + fileSystem->toPath(m_pp->getFileId(startLineCol.first)), + "\" 0 */"); } m_pp->append(pre + macroBody + post); @@ -695,13 +679,11 @@ void SV3_1aPpTreeShapeListener::enterMacroInstanceNoArgs( fileId = m_pp->getFileId(startLineCol.first); line = startLineCol.first; } - int32_t nbCRinMacroBody = - std::count(macroBody.begin(), macroBody.end(), '\n'); - if (nbCRinMacroBody) { + if (macroBody.find('\n') != std::string::npos) { uint32_t lineSum = m_pp->getSumLineCount() + 1; int32_t closingIndex = m_pp->getSourceFile()->addIncludeFileInfo( IncludeFileInfo::Context::MACRO, line, BadSymbolId, fileId, lineSum, - startLineCol.first, + startLineCol.second, lineSum + (endLineCol.first - startLineCol.first), endLineCol.second, IncludeFileInfo::Action::POP, openingIndex, 0); if (openingIndex >= 0) { @@ -958,10 +940,11 @@ void SV3_1aPpTreeShapeListener::enterEscaped_identifier( if (m_inActiveBranch && (!(m_filterProtectedRegions && m_inProtectedRegion))) { if (!m_inMacroDefinitionParsing) { - std::string text = ctx->getText(); - std::string trunc; - for (uint32_t i = 1; i < text.size() - 1; i++) trunc += text[i]; - m_pp->append(EscapeSequence + trunc + EscapeSequence); + const std::string text = ctx->getText(); + std::string_view trunc = text; + trunc.remove_prefix(1); + trunc.remove_suffix(1); + m_pp->append(StrCat(kEscapeSequence, trunc, kEscapeSequence)); } } } diff --git a/src/SourceCompile/SV3_1aTreeShapeHelper.cpp b/src/SourceCompile/SV3_1aTreeShapeHelper.cpp index 2ca68ed36f..70be0f66d9 100644 --- a/src/SourceCompile/SV3_1aTreeShapeHelper.cpp +++ b/src/SourceCompile/SV3_1aTreeShapeHelper.cpp @@ -165,6 +165,12 @@ SV3_1aTreeShapeHelper::getFileLine(antlr4::ParserRuleContext* ctx, column = lineCol.second; endLine = endLineCol.first; endColumn = endLineCol.second; + } else if (token != nullptr) { + fileId = m_pf->getFileId(lineCol.first + m_lineOffset); + line = m_pf->getLineNb(lineCol.first + m_lineOffset); + column = lineCol.second; + endLine = line + (endLineCol.first - lineCol.first); + endColumn = endLineCol.second; } else { fileId = m_pf->getFileId(lineCol.first + m_lineOffset); line = m_pf->getLineNb(lineCol.first + m_lineOffset); diff --git a/src/SourceCompile/SV3_1aTreeShapeListener.cpp b/src/SourceCompile/SV3_1aTreeShapeListener.cpp index a51ea9e8ac..1dddd31435 100644 --- a/src/SourceCompile/SV3_1aTreeShapeListener.cpp +++ b/src/SourceCompile/SV3_1aTreeShapeListener.cpp @@ -80,7 +80,7 @@ void SV3_1aTreeShapeListener::enterModule_declaration( else ident = "MODULE NAME UNKNOWN"; } - ident = std::regex_replace(ident, std::regex(EscapeSequence), ""); + ident = std::regex_replace(ident, m_escSeqReplaceRegex, ""); addNestedDesignElement(ctx, ident, DesignElement::Module, VObjectType::paMODULE); } @@ -252,7 +252,7 @@ void SV3_1aTreeShapeListener::enterInterface_declaration( VObjectType::paINTERFACE); } } - ident = std::regex_replace(ident, std::regex(EscapeSequence), ""); + ident = std::regex_replace(ident, m_escSeqReplaceRegex, ""); addNestedDesignElement(ctx, ident, DesignElement::Interface, VObjectType::paINTERFACE); } @@ -622,7 +622,7 @@ void SV3_1aTreeShapeListener::enterProgram_declaration( VObjectType::paPROGRAM); } } - ident = std::regex_replace(ident, std::regex(EscapeSequence), ""); + ident = std::regex_replace(ident, m_escSeqReplaceRegex, ""); addDesignElement(ctx, ident, DesignElement::Program, VObjectType::paPROGRAM); } @@ -631,7 +631,7 @@ void SV3_1aTreeShapeListener::enterClass_declaration( std::string ident; if (ctx->identifier(0)) { ident = ctx->identifier(0)->getText(); - ident = std::regex_replace(ident, std::regex(EscapeSequence), ""); + ident = std::regex_replace(ident, m_escSeqReplaceRegex, ""); addDesignElement(ctx, ident, DesignElement::Class, VObjectType::paCLASS); } else addDesignElement(ctx, "UNNAMED_CLASS", DesignElement::Class, @@ -651,7 +651,7 @@ void SV3_1aTreeShapeListener::enterPackage_declaration( VObjectType::paPACKAGE); } std::string ident = ctx->identifier(0)->getText(); - ident = std::regex_replace(ident, std::regex(EscapeSequence), ""); + ident = std::regex_replace(ident, m_escSeqReplaceRegex, ""); addDesignElement(ctx, ident, DesignElement::Package, VObjectType::paPACKAGE); } @@ -818,7 +818,7 @@ void SV3_1aTreeShapeListener::enterUdp_declaration( VObjectType::paPRIMITIVE); } } - ident = std::regex_replace(ident, std::regex(EscapeSequence), ""); + ident = std::regex_replace(ident, m_escSeqReplaceRegex, ""); addDesignElement(ctx, ident, DesignElement::Primitive, VObjectType::paPRIMITIVE); } @@ -857,23 +857,6 @@ void SV3_1aTreeShapeListener::exitUnbased_unsized_literal( addVObject(ctx, s, type); } -/* -void -SV3_1aTreeShapeListener::exitComment_OneLine -(SV3_1aParser::Comment_OneLineContext *ctx) -{ - addVObject (ctx, ctx->One_line_comment ()->getText (), -VObjectType::paComments); -} - -void -SV3_1aTreeShapeListener::exitComment_Block (SV3_1aParser::Comment_BlockContext -*ctx) -{ - addVObject (ctx, ctx->Block_comment ()->getText (), VObjectType::paComments); -} -*/ - void SV3_1aTreeShapeListener::exitPound_delay_value( SV3_1aParser::Pound_delay_valueContext *ctx) { if (ctx->Pound_delay()) { @@ -906,10 +889,8 @@ void SV3_1aTreeShapeListener::exitString_value( ident = ctx->String()->getText(); - std::regex escaped(std::string(EscapeSequence) + std::string("(.*?)") + - EscapeSequence); std::smatch match; - while (std::regex_search(ident, match, escaped)) { + while (std::regex_search(ident, match, m_escSeqSearchRegex)) { std::string var = "\\" + match[1].str() + " "; ident = ident.replace(match.position(0), match.length(0), var); } @@ -1062,7 +1043,7 @@ void SV3_1aTreeShapeListener::exitHierarchical_identifier( if (symbol->getType() == SV3_1aParser::Simple_identifier || symbol->getType() == SV3_1aParser::Escaped_identifier) { ident = tnode->getText(); - ident = std::regex_replace(ident, std::regex(EscapeSequence), ""); + ident = std::regex_replace(ident, m_escSeqReplaceRegex, ""); addVObject((antlr4::ParserRuleContext *)tnode, ident, VObjectType::slStringConst); } else if (symbol->getType() == SV3_1aParser::THIS || @@ -1269,10 +1250,8 @@ void SV3_1aTreeShapeListener::exitPackage_scope( } else if (ctx->Escaped_identifier()) { childCtx = (antlr4::ParserRuleContext *)ctx->Escaped_identifier(); ident = ctx->Escaped_identifier()->getText(); - std::regex escaped(std::string(EscapeSequence) + std::string("(.*?)") + - EscapeSequence); std::smatch match; - while (std::regex_search(ident, match, escaped)) { + while (std::regex_search(ident, match, m_escSeqSearchRegex)) { std::string var = match[1].str(); ident = ident.replace(match.position(0), match.length(0), var); } @@ -1310,10 +1289,8 @@ void SV3_1aTreeShapeListener::exitPs_identifier( } else if (!ctx->Escaped_identifier().empty()) { childCtx = (antlr4::ParserRuleContext *)ctx->Escaped_identifier()[0]; ident = ctx->Escaped_identifier()[0]->getText(); - std::regex escaped(std::string(EscapeSequence) + std::string("(.*?)") + - EscapeSequence); std::smatch match; - while (std::regex_search(ident, match, escaped)) { + while (std::regex_search(ident, match, m_escSeqSearchRegex)) { std::string var = match[1].str(); ident = ident.replace(match.position(0), match.length(0), var); } diff --git a/src/Utils/ParseUtils.cpp b/src/Utils/ParseUtils.cpp index 4c4f0d0ae3..eed0927514 100644 --- a/src/Utils/ParseUtils.cpp +++ b/src/Utils/ParseUtils.cpp @@ -30,15 +30,24 @@ ParseUtils::LineColumn ParseUtils::getLineColumn(antlr4::Token* token) { const uint32_t lineNb = static_cast(token->getLine()); const uint16_t columnNb = static_cast(token->getCharPositionInLine() + 1); - return std::make_pair(lineNb, columnNb); + return ParseUtils::LineColumn(lineNb, columnNb); } ParseUtils::LineColumn ParseUtils::getEndLineColumn(antlr4::Token* token) { - const uint32_t lineNb = static_cast(token->getLine()); - const uint16_t columnNb = static_cast( - token->getCharPositionInLine() + token->getStopIndex() - - token->getStartIndex() + 1 + 1); - return std::make_pair(lineNb, columnNb); + const std::string text = token->getText(); + const size_t pos = text.rfind('\n'); + if (pos == std::string::npos) { + const uint32_t lineNb = static_cast(token->getLine()); + const uint16_t columnNb = static_cast( + token->getCharPositionInLine() + token->getStopIndex() - + token->getStartIndex() + 1 + 1); + return ParseUtils::LineColumn(lineNb, columnNb); + } else { + const uint32_t lineNb = static_cast(token->getLine()) + + std::count(text.begin(), text.end(), '\n'); + const uint16_t columnNb = static_cast(text.length() - pos); + return ParseUtils::LineColumn(lineNb, columnNb); + } } ParseUtils::LineColumn ParseUtils::getLineColumn( @@ -54,15 +63,16 @@ ParseUtils::LineColumn ParseUtils::getEndLineColumn( ParseUtils::LineColumn ParseUtils::getLineColumn( antlr4::CommonTokenStream* stream, antlr4::ParserRuleContext* context) { const antlr4::misc::Interval sourceInterval = context->getSourceInterval(); - if (sourceInterval.a == -1) return std::make_pair(0, 0); - return getLineColumn(stream->get(sourceInterval.a)); + return (sourceInterval.a < 0) ? ParseUtils::LineColumn(0, 0) + : getLineColumn(stream->get(sourceInterval.a)); } ParseUtils::LineColumn ParseUtils::getEndLineColumn( antlr4::CommonTokenStream* stream, antlr4::ParserRuleContext* context) { const antlr4::misc::Interval sourceInterval = context->getSourceInterval(); - if (sourceInterval.b == -1) return std::make_pair(0, 0); - return getEndLineColumn(stream->get(sourceInterval.b)); + return (sourceInterval.b < 0) + ? ParseUtils::LineColumn(0, 0) + : getEndLineColumn(stream->get(sourceInterval.b)); } const std::vector& ParseUtils::getTopTokenList( diff --git a/third_party/UHDM b/third_party/UHDM index 677a4e4093..4e26376832 160000 --- a/third_party/UHDM +++ b/third_party/UHDM @@ -1 +1 @@ -Subproject commit 677a4e409303553b2a28337359b321e4a2edb438 +Subproject commit 4e26376832644191648787221cfd54fdc5e0a56c diff --git a/third_party/antlr4 b/third_party/antlr4 index 734bd758d1..0d30259c67 160000 --- a/third_party/antlr4 +++ b/third_party/antlr4 @@ -1 +1 @@ -Subproject commit 734bd758d1811b945de044e73725689e0e7fe6e3 +Subproject commit 0d30259c67f10011c33818175fca56d6108c58f5