]> git.madduck.net Git - etc/vim.git/blob - blib2to3/pgen2/grammar.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Add PyCon talk link to README (#844)
[etc/vim.git] / blib2to3 / pgen2 / grammar.py
1 # Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
2 # Licensed to PSF under a Contributor Agreement.
3
4 """This module defines the data structures used to represent a grammar.
5
6 These are a bit arcane because they are derived from the data
7 structures used by Python's 'pgen' parser generator.
8
9 There's also a table here mapping operators to their names in the
10 token module; the Python tokenize module reports all operators as the
11 fallback token code OP, but the parser needs the actual token code.
12
13 """
14
15 # Python imports
16 import os
17 import pickle
18 import tempfile
19
20 # Local imports
21 from . import token
22
23
24 class Grammar(object):
25     """Pgen parsing tables conversion class.
26
27     Once initialized, this class supplies the grammar tables for the
28     parsing engine implemented by parse.py.  The parsing engine
29     accesses the instance variables directly.  The class here does not
30     provide initialization of the tables; several subclasses exist to
31     do this (see the conv and pgen modules).
32
33     The load() method reads the tables from a pickle file, which is
34     much faster than the other ways offered by subclasses.  The pickle
35     file is written by calling dump() (after loading the grammar
36     tables using a subclass).  The report() method prints a readable
37     representation of the tables to stdout, for debugging.
38
39     The instance variables are as follows:
40
41     symbol2number -- a dict mapping symbol names to numbers.  Symbol
42                      numbers are always 256 or higher, to distinguish
43                      them from token numbers, which are between 0 and
44                      255 (inclusive).
45
46     number2symbol -- a dict mapping numbers to symbol names;
47                      these two are each other's inverse.
48
49     states        -- a list of DFAs, where each DFA is a list of
50                      states, each state is a list of arcs, and each
51                      arc is a (i, j) pair where i is a label and j is
52                      a state number.  The DFA number is the index into
53                      this list.  (This name is slightly confusing.)
54                      Final states are represented by a special arc of
55                      the form (0, j) where j is its own state number.
56
57     dfas          -- a dict mapping symbol numbers to (DFA, first)
58                      pairs, where DFA is an item from the states list
59                      above, and first is a set of tokens that can
60                      begin this grammar rule (represented by a dict
61                      whose values are always 1).
62
63     labels        -- a list of (x, y) pairs where x is either a token
64                      number or a symbol number, and y is either None
65                      or a string; the strings are keywords.  The label
66                      number is the index in this list; label numbers
67                      are used to mark state transitions (arcs) in the
68                      DFAs.
69
70     start         -- the number of the grammar's start symbol.
71
72     keywords      -- a dict mapping keyword strings to arc labels.
73
74     tokens        -- a dict mapping token numbers to arc labels.
75
76     """
77
78     def __init__(self):
79         self.symbol2number = {}
80         self.number2symbol = {}
81         self.states = []
82         self.dfas = {}
83         self.labels = [(0, "EMPTY")]
84         self.keywords = {}
85         self.tokens = {}
86         self.symbol2label = {}
87         self.start = 256
88
89     def dump(self, filename):
90         """Dump the grammar tables to a pickle file."""
91         with tempfile.NamedTemporaryFile(dir=os.path.dirname(filename), delete=False) as f:
92             pickle.dump(self.__dict__, f, pickle.HIGHEST_PROTOCOL)
93         os.replace(f.name, filename)
94
95     def load(self, filename):
96         """Load the grammar tables from a pickle file."""
97         with open(filename, "rb") as f:
98             d = pickle.load(f)
99         self.__dict__.update(d)
100
101     def loads(self, pkl):
102         """Load the grammar tables from a pickle bytes object."""
103         self.__dict__.update(pickle.loads(pkl))
104
105     def copy(self):
106         """
107         Copy the grammar.
108         """
109         new = self.__class__()
110         for dict_attr in ("symbol2number", "number2symbol", "dfas", "keywords",
111                           "tokens", "symbol2label"):
112             setattr(new, dict_attr, getattr(self, dict_attr).copy())
113         new.labels = self.labels[:]
114         new.states = self.states[:]
115         new.start = self.start
116         return new
117
118     def report(self):
119         """Dump the grammar tables to standard output, for debugging."""
120         from pprint import pprint
121         print("s2n")
122         pprint(self.symbol2number)
123         print("n2s")
124         pprint(self.number2symbol)
125         print("states")
126         pprint(self.states)
127         print("dfas")
128         pprint(self.dfas)
129         print("labels")
130         pprint(self.labels)
131         print("start", self.start)
132
133
134 # Map from operator to number (since tokenize doesn't do this)
135
136 opmap_raw = """
137 ( LPAR
138 ) RPAR
139 [ LSQB
140 ] RSQB
141 : COLON
142 , COMMA
143 ; SEMI
144 + PLUS
145 - MINUS
146 * STAR
147 / SLASH
148 | VBAR
149 & AMPER
150 < LESS
151 > GREATER
152 = EQUAL
153 . DOT
154 % PERCENT
155 ` BACKQUOTE
156 { LBRACE
157 } RBRACE
158 @ AT
159 @= ATEQUAL
160 == EQEQUAL
161 != NOTEQUAL
162 <> NOTEQUAL
163 <= LESSEQUAL
164 >= GREATEREQUAL
165 ~ TILDE
166 ^ CIRCUMFLEX
167 << LEFTSHIFT
168 >> RIGHTSHIFT
169 ** DOUBLESTAR
170 += PLUSEQUAL
171 -= MINEQUAL
172 *= STAREQUAL
173 /= SLASHEQUAL
174 %= PERCENTEQUAL
175 &= AMPEREQUAL
176 |= VBAREQUAL
177 ^= CIRCUMFLEXEQUAL
178 <<= LEFTSHIFTEQUAL
179 >>= RIGHTSHIFTEQUAL
180 **= DOUBLESTAREQUAL
181 // DOUBLESLASH
182 //= DOUBLESLASHEQUAL
183 -> RARROW
184 """
185
186 opmap = {}
187 for line in opmap_raw.splitlines():
188     if line:
189         op, name = line.split()
190         opmap[op] = getattr(token, name)