verilog-slang.cc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include <slang/syntax/SyntaxTree.h>
  2. #include <slang/syntax/SyntaxPrinter.h>
  3. #include <slang/syntax/SyntaxVisitor.h>
  4. #include <slang/syntax/SyntaxNode.h>
  5. #include <iostream>
  6. #include <cassert>
  7. class NodePrintingVisitor {
  8. using SyntaxNode = slang::SyntaxNode;
  9. using Token = slang::Token;
  10. size_t depth = 0;
  11. public:
  12. /// Visit the provided node, of static type T.
  13. template<typename T>
  14. void visit(const T& t) {
  15. visitDefault(t);
  16. }
  17. /// The default handler invoked when no visit() method is overriden for a particular type.
  18. /// Will visit all child nodes by default.
  19. void visitDefault(const SyntaxNode& node) {
  20. if (node.kind != slang::SyntaxKind::SyntaxList &&
  21. node.kind != slang::SyntaxKind::TokenList &&
  22. node.kind != slang::SyntaxKind::SeparatedList) {
  23. std::string spaces(depth * 3, ' ');
  24. std::cout << spaces << node.kind;
  25. if (node.parent) {
  26. std::cout << "(parent: " << node.parent->kind << ")";
  27. }
  28. if (node.kind == slang::SyntaxKind::FunctionPort) {
  29. const auto &port = node.as<slang::FunctionPortSyntax>();
  30. std::cout << "(direction: " << port.direction.rawText() << ")";
  31. }
  32. if (node.kind == slang::SyntaxKind::Declarator) {
  33. const auto &decl = node.as<slang::DeclaratorSyntax>();
  34. std::cout << "(name: " << decl.name.rawText() << ")";
  35. }
  36. std::cout << std::endl;
  37. }
  38. for (uint32_t i = 0; i < node.getChildCount(); i++) {
  39. auto child = node.childNode(i);
  40. if (child) {
  41. depth++;
  42. child->visit(*this);
  43. depth--;
  44. }
  45. }
  46. }
  47. /// The default handler invoked when visiting an invalid node.
  48. void visitInvalid(const SyntaxNode&) {}
  49. private:
  50. // This is to make things compile if the derived class doesn't provide an implementation.
  51. void visitToken(Token) {}
  52. };
  53. class ScanMethodVisitor: public slang::SyntaxVisitor<ScanMethodVisitor>
  54. {
  55. using ClassMethodDeclaration = slang::ClassMethodDeclarationSyntax;
  56. public:
  57. void handle(const ClassMethodDeclaration &decl)
  58. {
  59. bool isTask;
  60. if (decl.declaration->kind == slang::SyntaxKind::TaskDeclaration) {
  61. isTask = true;
  62. } else if (decl.declaration->kind == slang::SyntaxKind::FunctionDeclaration) {
  63. isTask = false;
  64. } else {
  65. assert(false);
  66. }
  67. slang::NameSyntax *name = decl.declaration->prototype->name;
  68. if (slang::IdentifierNameSyntax::isKind(name->kind)) {
  69. slang::IdentifierNameSyntax &id = name->as<slang::IdentifierNameSyntax>();
  70. std::cout << "Class method: " << (isTask?"task ":"function ") << id.toString() << std::endl;
  71. } else {
  72. std::cout << "[Unknown class decl]" << std::endl;
  73. }
  74. if (!isTask) {
  75. auto returnType = decl.declaration->prototype->returnType;
  76. std::cout << "Return type: " << returnType->toString() << std::endl;
  77. }
  78. }
  79. };
  80. class FunctionToTaskVisitor: public slang::SyntaxRewriter<FunctionToTaskVisitor>
  81. {
  82. public:
  83. void handle(const slang::ClassMethodDeclarationSyntax &decl)
  84. {
  85. bool isTask;
  86. if (decl.declaration->kind == slang::SyntaxKind::TaskDeclaration) {
  87. isTask = true;
  88. } else if (decl.declaration->kind == slang::SyntaxKind::FunctionDeclaration) {
  89. isTask = false;
  90. } else {
  91. assert(false);
  92. }
  93. if (!isTask) {
  94. auto returnType = decl.declaration->prototype->returnType;
  95. auto retTyStr = returnType->toString();
  96. // go for ports
  97. auto &ports = decl.declaration->prototype->portList->ports;
  98. insertBefore(*ports[0], parse("output " + retTyStr + " retVal,"));
  99. decl.declaration->prototype->keyword.kind = slang::TokenKind::TaskKeyword;
  100. replace(*decl.declaration->prototype->returnType, parse(""));
  101. decl.declaration->end.kind = slang::TokenKind::EndTaskKeyword;
  102. // continue to rewrite the return statements
  103. visitDefault(decl);
  104. }
  105. }
  106. void handle(const slang::ReturnStatementSyntax &retn)
  107. {
  108. if (retn.returnValue != nullptr) {
  109. replace(retn, parse("retVal = " + retn.returnValue->toString() + ";\nreturn;"));
  110. }
  111. }
  112. };
  113. int main(int argc, char *argv[])
  114. {
  115. if (argc != 2) {
  116. std::cerr << "usage: " << argv[0] << " file" << std::endl;
  117. return 1;
  118. }
  119. auto tree = slang::SyntaxTree::fromFile(argv[1]);
  120. std::cout << "============= print node =================" << std::endl;
  121. NodePrintingVisitor visitor;
  122. tree->root().visit(visitor);
  123. std::cout << "============= scan visitor ===============" << std::endl;
  124. ScanMethodVisitor scan_method;
  125. tree->root().visit(scan_method);
  126. std::cout << "============= print file ================" << std::endl;
  127. std::string s = slang::SyntaxPrinter::printFile(*tree);
  128. std::cout << s << std::endl;
  129. std::cout << "============= rewrite ===================" << std::endl;
  130. tree = FunctionToTaskVisitor().transform(tree);
  131. std::cout << slang::SyntaxPrinter::printFile(*tree) << std::endl;
  132. }