DFA.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #
  2. # Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
  3. # Use of this file is governed by the BSD 3-clause license that
  4. # can be found in the LICENSE.txt file in the project root.
  5. from antlr4.atn.ATNState import StarLoopEntryState
  6. from antlr4.atn.ATNConfigSet import ATNConfigSet
  7. from antlr4.atn.ATNState import DecisionState
  8. from antlr4.dfa.DFAState import DFAState
  9. from antlr4.error.Errors import IllegalStateException
  10. class DFA(object):
  11. __slots__ = ('atnStartState', 'decision', '_states', 's0', 'precedenceDfa')
  12. def __init__(self, atnStartState:DecisionState, decision:int=0):
  13. # From which ATN state did we create this DFA?
  14. self.atnStartState = atnStartState
  15. self.decision = decision
  16. # A set of all DFA states. Use {@link Map} so we can get old state back
  17. # ({@link Set} only allows you to see if it's there).
  18. self._states = dict()
  19. self.s0 = None
  20. # {@code true} if this DFA is for a precedence decision; otherwise,
  21. # {@code false}. This is the backing field for {@link #isPrecedenceDfa},
  22. # {@link #setPrecedenceDfa}.
  23. self.precedenceDfa = False
  24. if isinstance(atnStartState, StarLoopEntryState):
  25. if atnStartState.isPrecedenceDecision:
  26. self.precedenceDfa = True
  27. precedenceState = DFAState(configs=ATNConfigSet())
  28. precedenceState.edges = []
  29. precedenceState.isAcceptState = False
  30. precedenceState.requiresFullContext = False
  31. self.s0 = precedenceState
  32. # Get the start state for a specific precedence value.
  33. #
  34. # @param precedence The current precedence.
  35. # @return The start state corresponding to the specified precedence, or
  36. # {@code null} if no start state exists for the specified precedence.
  37. #
  38. # @throws IllegalStateException if this is not a precedence DFA.
  39. # @see #isPrecedenceDfa()
  40. def getPrecedenceStartState(self, precedence:int):
  41. if not self.precedenceDfa:
  42. raise IllegalStateException("Only precedence DFAs may contain a precedence start state.")
  43. # s0.edges is never null for a precedence DFA
  44. if precedence < 0 or precedence >= len(self.s0.edges):
  45. return None
  46. return self.s0.edges[precedence]
  47. # Set the start state for a specific precedence value.
  48. #
  49. # @param precedence The current precedence.
  50. # @param startState The start state corresponding to the specified
  51. # precedence.
  52. #
  53. # @throws IllegalStateException if this is not a precedence DFA.
  54. # @see #isPrecedenceDfa()
  55. #
  56. def setPrecedenceStartState(self, precedence:int, startState:DFAState):
  57. if not self.precedenceDfa:
  58. raise IllegalStateException("Only precedence DFAs may contain a precedence start state.")
  59. if precedence < 0:
  60. return
  61. # synchronization on s0 here is ok. when the DFA is turned into a
  62. # precedence DFA, s0 will be initialized once and not updated again
  63. # s0.edges is never null for a precedence DFA
  64. if precedence >= len(self.s0.edges):
  65. ext = [None] * (precedence + 1 - len(self.s0.edges))
  66. self.s0.edges.extend(ext)
  67. self.s0.edges[precedence] = startState
  68. #
  69. # Sets whether this is a precedence DFA. If the specified value differs
  70. # from the current DFA configuration, the following actions are taken;
  71. # otherwise no changes are made to the current DFA.
  72. #
  73. # <ul>
  74. # <li>The {@link #states} map is cleared</li>
  75. # <li>If {@code precedenceDfa} is {@code false}, the initial state
  76. # {@link #s0} is set to {@code null}; otherwise, it is initialized to a new
  77. # {@link DFAState} with an empty outgoing {@link DFAState#edges} array to
  78. # store the start states for individual precedence values.</li>
  79. # <li>The {@link #precedenceDfa} field is updated</li>
  80. # </ul>
  81. #
  82. # @param precedenceDfa {@code true} if this is a precedence DFA; otherwise,
  83. # {@code false}
  84. def setPrecedenceDfa(self, precedenceDfa:bool):
  85. if self.precedenceDfa != precedenceDfa:
  86. self._states = dict()
  87. if precedenceDfa:
  88. precedenceState = DFAState(configs=ATNConfigSet())
  89. precedenceState.edges = []
  90. precedenceState.isAcceptState = False
  91. precedenceState.requiresFullContext = False
  92. self.s0 = precedenceState
  93. else:
  94. self.s0 = None
  95. self.precedenceDfa = precedenceDfa
  96. @property
  97. def states(self):
  98. return self._states
  99. # Return a list of all states in this DFA, ordered by state number.
  100. def sortedStates(self):
  101. return sorted(self._states.keys(), key=lambda state: state.stateNumber)
  102. def __str__(self):
  103. return self.toString(None)
  104. def toString(self, literalNames:list=None, symbolicNames:list=None):
  105. if self.s0 is None:
  106. return ""
  107. from antlr4.dfa.DFASerializer import DFASerializer
  108. serializer = DFASerializer(self,literalNames,symbolicNames)
  109. return str(serializer)
  110. def toLexerString(self):
  111. if self.s0 is None:
  112. return ""
  113. from antlr4.dfa.DFASerializer import LexerDFASerializer
  114. serializer = LexerDFASerializer(self)
  115. return str(serializer)