PostfixExpression.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. //===-- PostfixExpression.h -------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file implements support for postfix expressions found in several symbol
  10. // file formats, and their conversion to DWARF.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLDB_SYMBOL_POSTFIXEXPRESSION_H
  14. #define LLDB_SYMBOL_POSTFIXEXPRESSION_H
  15. #include "llvm/ADT/StringRef.h"
  16. #include "llvm/Support/Allocator.h"
  17. #include "llvm/Support/Casting.h"
  18. #include <vector>
  19. namespace lldb_private {
  20. class Stream;
  21. namespace postfix {
  22. /// The base class for all nodes in the parsed postfix tree.
  23. class Node {
  24. public:
  25. enum Kind {
  26. BinaryOp,
  27. InitialValue,
  28. Integer,
  29. Register,
  30. Symbol,
  31. UnaryOp,
  32. };
  33. protected:
  34. Node(Kind kind) : m_kind(kind) {}
  35. public:
  36. Kind GetKind() const { return m_kind; }
  37. private:
  38. Kind m_kind;
  39. };
  40. /// A node representing a binary expression.
  41. class BinaryOpNode : public Node {
  42. public:
  43. enum OpType {
  44. Align, // alignDown(a, b)
  45. Minus, // a - b
  46. Plus, // a + b
  47. };
  48. BinaryOpNode(OpType op_type, Node &left, Node &right)
  49. : Node(BinaryOp), m_op_type(op_type), m_left(&left), m_right(&right) {}
  50. OpType GetOpType() const { return m_op_type; }
  51. const Node *Left() const { return m_left; }
  52. Node *&Left() { return m_left; }
  53. const Node *Right() const { return m_right; }
  54. Node *&Right() { return m_right; }
  55. static bool classof(const Node *node) { return node->GetKind() == BinaryOp; }
  56. private:
  57. OpType m_op_type;
  58. Node *m_left;
  59. Node *m_right;
  60. };
  61. /// A node representing the canonical frame address.
  62. class InitialValueNode: public Node {
  63. public:
  64. InitialValueNode() : Node(InitialValue) {}
  65. static bool classof(const Node *node) {
  66. return node->GetKind() == InitialValue;
  67. }
  68. };
  69. /// A node representing an integer literal.
  70. class IntegerNode : public Node {
  71. public:
  72. IntegerNode(int64_t value) : Node(Integer), m_value(value) {}
  73. int64_t GetValue() const { return m_value; }
  74. static bool classof(const Node *node) { return node->GetKind() == Integer; }
  75. private:
  76. int64_t m_value;
  77. };
  78. /// A node representing the value of a register with the given register number.
  79. /// The register kind (RegisterKind enum) used for the specifying the register
  80. /// number is implicit and assumed to be the same for all Register nodes in a
  81. /// given tree.
  82. class RegisterNode : public Node {
  83. public:
  84. RegisterNode(uint32_t reg_num) : Node(Register), m_reg_num(reg_num) {}
  85. uint32_t GetRegNum() const { return m_reg_num; }
  86. static bool classof(const Node *node) { return node->GetKind() == Register; }
  87. private:
  88. uint32_t m_reg_num;
  89. };
  90. /// A node representing a symbolic reference to a named entity. This may be a
  91. /// register, which hasn't yet been resolved to a RegisterNode.
  92. class SymbolNode : public Node {
  93. public:
  94. SymbolNode(llvm::StringRef name) : Node(Symbol), m_name(name) {}
  95. llvm::StringRef GetName() const { return m_name; }
  96. static bool classof(const Node *node) { return node->GetKind() == Symbol; }
  97. private:
  98. llvm::StringRef m_name;
  99. };
  100. /// A node representing a unary operation.
  101. class UnaryOpNode : public Node {
  102. public:
  103. enum OpType {
  104. Deref, // *a
  105. };
  106. UnaryOpNode(OpType op_type, Node &operand)
  107. : Node(UnaryOp), m_op_type(op_type), m_operand(&operand) {}
  108. OpType GetOpType() const { return m_op_type; }
  109. const Node *Operand() const { return m_operand; }
  110. Node *&Operand() { return m_operand; }
  111. static bool classof(const Node *node) { return node->GetKind() == UnaryOp; }
  112. private:
  113. OpType m_op_type;
  114. Node *m_operand;
  115. };
  116. /// A template class implementing a visitor pattern, but with a couple of
  117. /// twists:
  118. /// - It uses type switch instead of virtual double dispatch. This allows the
  119. // node classes to be vtable-free and trivially destructible.
  120. /// - The Visit functions get an extra Node *& parameter, which refers to the
  121. /// child pointer of the parent of the node we are currently visiting. This
  122. /// allows mutating algorithms, which replace the currently visited node with
  123. /// a different one.
  124. /// - The class is templatized on the return type of the Visit functions, which
  125. /// means it's possible to return values from them.
  126. template <typename ResultT = void> class Visitor {
  127. protected:
  128. virtual ~Visitor() = default;
  129. virtual ResultT Visit(BinaryOpNode &binary, Node *&ref) = 0;
  130. virtual ResultT Visit(InitialValueNode &val, Node *&ref) = 0;
  131. virtual ResultT Visit(IntegerNode &integer, Node *&) = 0;
  132. virtual ResultT Visit(RegisterNode &reg, Node *&) = 0;
  133. virtual ResultT Visit(SymbolNode &symbol, Node *&ref) = 0;
  134. virtual ResultT Visit(UnaryOpNode &unary, Node *&ref) = 0;
  135. /// Invoke the correct Visit function based on the dynamic type of the given
  136. /// node.
  137. ResultT Dispatch(Node *&node) {
  138. switch (node->GetKind()) {
  139. case Node::BinaryOp:
  140. return Visit(llvm::cast<BinaryOpNode>(*node), node);
  141. case Node::InitialValue:
  142. return Visit(llvm::cast<InitialValueNode>(*node), node);
  143. case Node::Integer:
  144. return Visit(llvm::cast<IntegerNode>(*node), node);
  145. case Node::Register:
  146. return Visit(llvm::cast<RegisterNode>(*node), node);
  147. case Node::Symbol:
  148. return Visit(llvm::cast<SymbolNode>(*node), node);
  149. case Node::UnaryOp:
  150. return Visit(llvm::cast<UnaryOpNode>(*node), node);
  151. }
  152. llvm_unreachable("Fully covered switch!");
  153. }
  154. };
  155. /// A utility function for "resolving" SymbolNodes. It traverses a tree and
  156. /// calls the callback function for all SymbolNodes it encountered. The
  157. /// replacement function should return the node it wished to replace the current
  158. /// SymbolNode with (this can also be the original node), or nullptr in case of
  159. /// an error. The nodes returned by the callback are inspected and replaced
  160. /// recursively, *except* for the case when the function returns the exact same
  161. /// node as the input one. It returns true if all SymbolNodes were replaced
  162. /// successfully.
  163. bool ResolveSymbols(Node *&node,
  164. llvm::function_ref<Node *(SymbolNode &symbol)> replacer);
  165. template <typename T, typename... Args>
  166. inline T *MakeNode(llvm::BumpPtrAllocator &alloc, Args &&... args) {
  167. static_assert(std::is_trivially_destructible<T>::value,
  168. "This object will not be destroyed!");
  169. return new (alloc.Allocate<T>()) T(std::forward<Args>(args)...);
  170. }
  171. /// Parse the given postfix expression. The parsed nodes are placed into the
  172. /// provided allocator.
  173. Node *ParseOneExpression(llvm::StringRef expr, llvm::BumpPtrAllocator &alloc);
  174. std::vector<std::pair<llvm::StringRef, Node *>>
  175. ParseFPOProgram(llvm::StringRef prog, llvm::BumpPtrAllocator &alloc);
  176. /// Serialize the given expression tree as DWARF. The result is written into the
  177. /// given stream. The AST should not contain any SymbolNodes. If the expression
  178. /// contains InitialValueNodes, the generated expression will assume that their
  179. /// value will be provided as the top value of the initial evaluation stack (as
  180. /// is the case with the CFA value in register eh_unwind rules).
  181. void ToDWARF(Node &node, Stream &stream);
  182. } // namespace postfix
  183. } // namespace lldb_private
  184. #endif // LLDB_SYMBOL_POSTFIXEXPRESSION_H