Line data Source code
1 :
2 : /* Parser-tokenizer link implementation */
3 :
4 : #include "pgenheaders.h"
5 : #include "tokenizer.h"
6 : #include "node.h"
7 : #include "grammar.h"
8 : #include "parser.h"
9 : #include "parsetok.h"
10 : #include "errcode.h"
11 : #include "graminit.h"
12 :
13 :
14 : /* Forward */
15 : static node *parsetok(struct tok_state *, grammar *, int, perrdetail *, int *);
16 : static int initerr(perrdetail *err_ret, const char* filename);
17 :
18 : /* Parse input coming from a string. Return error code, print some errors. */
19 : node *
20 0 : PyParser_ParseString(const char *s, grammar *g, int start, perrdetail *err_ret)
21 : {
22 0 : return PyParser_ParseStringFlagsFilename(s, NULL, g, start, err_ret, 0);
23 : }
24 :
25 : node *
26 0 : PyParser_ParseStringFlags(const char *s, grammar *g, int start,
27 : perrdetail *err_ret, int flags)
28 : {
29 0 : return PyParser_ParseStringFlagsFilename(s, NULL,
30 : g, start, err_ret, flags);
31 : }
32 :
33 : node *
34 0 : PyParser_ParseStringFlagsFilename(const char *s, const char *filename,
35 : grammar *g, int start,
36 : perrdetail *err_ret, int flags)
37 : {
38 0 : int iflags = flags;
39 0 : return PyParser_ParseStringFlagsFilenameEx(s, filename, g, start,
40 : err_ret, &iflags);
41 : }
42 :
43 : node *
44 3 : PyParser_ParseStringFlagsFilenameEx(const char *s, const char *filename,
45 : grammar *g, int start,
46 : perrdetail *err_ret, int *flags)
47 : {
48 : struct tok_state *tok;
49 3 : int exec_input = start == file_input;
50 :
51 3 : if (initerr(err_ret, filename) < 0)
52 0 : return NULL;
53 :
54 3 : if (*flags & PyPARSE_IGNORE_COOKIE)
55 3 : tok = PyTokenizer_FromUTF8(s, exec_input);
56 : else
57 0 : tok = PyTokenizer_FromString(s, exec_input);
58 3 : if (tok == NULL) {
59 0 : err_ret->error = PyErr_Occurred() ? E_DECODE : E_NOMEM;
60 0 : return NULL;
61 : }
62 :
63 : #ifndef PGEN
64 3 : Py_INCREF(err_ret->filename);
65 3 : tok->filename = err_ret->filename;
66 : #endif
67 3 : return parsetok(tok, g, start, err_ret, flags);
68 : }
69 :
70 : /* Parse input coming from a file. Return error code, print some errors. */
71 :
72 : node *
73 0 : PyParser_ParseFile(FILE *fp, const char *filename, grammar *g, int start,
74 : char *ps1, char *ps2, perrdetail *err_ret)
75 : {
76 0 : return PyParser_ParseFileFlags(fp, filename, NULL,
77 : g, start, ps1, ps2, err_ret, 0);
78 : }
79 :
80 : node *
81 0 : PyParser_ParseFileFlags(FILE *fp, const char *filename, const char *enc,
82 : grammar *g, int start,
83 : char *ps1, char *ps2, perrdetail *err_ret, int flags)
84 : {
85 0 : int iflags = flags;
86 0 : return PyParser_ParseFileFlagsEx(fp, filename, enc, g, start, ps1,
87 : ps2, err_ret, &iflags);
88 : }
89 :
90 : node *
91 0 : PyParser_ParseFileFlagsEx(FILE *fp, const char *filename,
92 : const char *enc, grammar *g, int start,
93 : char *ps1, char *ps2, perrdetail *err_ret, int *flags)
94 : {
95 : struct tok_state *tok;
96 :
97 0 : if (initerr(err_ret, filename) < 0)
98 0 : return NULL;
99 :
100 0 : if ((tok = PyTokenizer_FromFile(fp, (char *)enc, ps1, ps2)) == NULL) {
101 0 : err_ret->error = E_NOMEM;
102 0 : return NULL;
103 : }
104 : #ifndef PGEN
105 0 : Py_INCREF(err_ret->filename);
106 0 : tok->filename = err_ret->filename;
107 : #endif
108 0 : return parsetok(tok, g, start, err_ret, flags);
109 : }
110 :
111 : #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
112 : #if 0
113 : static char with_msg[] =
114 : "%s:%d: Warning: 'with' will become a reserved keyword in Python 2.6\n";
115 :
116 : static char as_msg[] =
117 : "%s:%d: Warning: 'as' will become a reserved keyword in Python 2.6\n";
118 :
119 : static void
120 : warn(const char *msg, const char *filename, int lineno)
121 : {
122 : if (filename == NULL)
123 : filename = "<string>";
124 : PySys_WriteStderr(msg, filename, lineno);
125 : }
126 : #endif
127 : #endif
128 :
129 : /* Parse input coming from the given tokenizer structure.
130 : Return error code. */
131 :
132 : static node *
133 3 : parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
134 : int *flags)
135 : {
136 : parser_state *ps;
137 : node *n;
138 3 : int started = 0;
139 :
140 3 : if ((ps = PyParser_New(g, start)) == NULL) {
141 0 : fprintf(stderr, "no mem for new parser\n");
142 0 : err_ret->error = E_NOMEM;
143 0 : PyTokenizer_Free(tok);
144 0 : return NULL;
145 : }
146 : #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
147 3 : if (*flags & PyPARSE_BARRY_AS_BDFL)
148 0 : ps->p_flags |= CO_FUTURE_BARRY_AS_BDFL;
149 : #endif
150 :
151 : for (;;) {
152 : char *a, *b;
153 : int type;
154 : size_t len;
155 : char *str;
156 : int col_offset;
157 :
158 1823 : type = PyTokenizer_Get(tok, &a, &b);
159 1823 : if (type == ERRORTOKEN) {
160 0 : err_ret->error = tok->done;
161 : break;
162 : }
163 1823 : if (type == ENDMARKER && started) {
164 3 : type = NEWLINE; /* Add an extra newline */
165 3 : started = 0;
166 : /* Add the right number of dedent tokens,
167 : except if a certain flag is given --
168 : codeop.py uses this. */
169 6 : if (tok->indent &&
170 0 : !(*flags & PyPARSE_DONT_IMPLY_DEDENT))
171 : {
172 0 : tok->pendin = -tok->indent;
173 0 : tok->indent = 0;
174 : }
175 : }
176 : else
177 1820 : started = 1;
178 1823 : len = b - a; /* XXX this may compute NULL - NULL */
179 1823 : str = (char *) PyObject_MALLOC(len + 1);
180 1823 : if (str == NULL) {
181 0 : fprintf(stderr, "no mem for next token\n");
182 0 : err_ret->error = E_NOMEM;
183 : break;
184 : }
185 1823 : if (len > 0)
186 1511 : strncpy(str, a, len);
187 1823 : str[len] = '\0';
188 :
189 : #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
190 1823 : if (type == NOTEQUAL) {
191 6 : if (!(ps->p_flags & CO_FUTURE_BARRY_AS_BDFL) &&
192 3 : strcmp(str, "!=")) {
193 0 : PyObject_FREE(str);
194 0 : err_ret->error = E_SYNTAX;
195 : break;
196 : }
197 3 : else if ((ps->p_flags & CO_FUTURE_BARRY_AS_BDFL) &&
198 0 : strcmp(str, "<>")) {
199 0 : PyObject_FREE(str);
200 0 : err_ret->text = "with Barry as BDFL, use '<>' "
201 : "instead of '!='";
202 0 : err_ret->error = E_SYNTAX;
203 : break;
204 : }
205 : }
206 : #endif
207 1823 : if (a >= tok->line_start)
208 1705 : col_offset = a - tok->line_start;
209 : else
210 118 : col_offset = -1;
211 :
212 1823 : if ((err_ret->error =
213 1823 : PyParser_AddToken(ps, (int)type, str,
214 : tok->lineno, col_offset,
215 : &(err_ret->expected))) != E_OK) {
216 3 : if (err_ret->error != E_DONE) {
217 0 : PyObject_FREE(str);
218 0 : err_ret->token = type;
219 : }
220 : break;
221 : }
222 1820 : }
223 :
224 3 : if (err_ret->error == E_DONE) {
225 3 : n = ps->p_tree;
226 3 : ps->p_tree = NULL;
227 :
228 : #ifndef PGEN
229 : /* Check that the source for a single input statement really
230 : is a single statement by looking at what is left in the
231 : buffer after parsing. Trailing whitespace and comments
232 : are OK. */
233 3 : if (start == single_input) {
234 0 : char *cur = tok->cur;
235 0 : char c = *tok->cur;
236 :
237 : for (;;) {
238 0 : while (c == ' ' || c == '\t' || c == '\n' || c == '\014')
239 0 : c = *++cur;
240 :
241 0 : if (!c)
242 0 : break;
243 :
244 0 : if (c != '#') {
245 0 : err_ret->error = E_BADSINGLE;
246 0 : PyNode_Free(n);
247 0 : n = NULL;
248 0 : break;
249 : }
250 :
251 : /* Suck up comment. */
252 0 : while (c && c != '\n')
253 0 : c = *++cur;
254 0 : }
255 : }
256 : #endif
257 : }
258 : else
259 0 : n = NULL;
260 :
261 : #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
262 3 : *flags = ps->p_flags;
263 : #endif
264 3 : PyParser_Delete(ps);
265 :
266 3 : if (n == NULL) {
267 0 : if (tok->done == E_EOF)
268 0 : err_ret->error = E_EOF;
269 0 : err_ret->lineno = tok->lineno;
270 0 : if (tok->buf != NULL) {
271 : size_t len;
272 : assert(tok->cur - tok->buf < INT_MAX);
273 0 : err_ret->offset = (int)(tok->cur - tok->buf);
274 0 : len = tok->inp - tok->buf;
275 0 : err_ret->text = (char *) PyObject_MALLOC(len + 1);
276 0 : if (err_ret->text != NULL) {
277 0 : if (len > 0)
278 0 : strncpy(err_ret->text, tok->buf, len);
279 0 : err_ret->text[len] = '\0';
280 : }
281 : }
282 3 : } else if (tok->encoding != NULL) {
283 : /* 'nodes->n_str' uses PyObject_*, while 'tok->encoding' was
284 : * allocated using PyMem_
285 : */
286 3 : node* r = PyNode_New(encoding_decl);
287 3 : if (r)
288 3 : r->n_str = PyObject_MALLOC(strlen(tok->encoding)+1);
289 3 : if (!r || !r->n_str) {
290 0 : err_ret->error = E_NOMEM;
291 0 : if (r)
292 0 : PyObject_FREE(r);
293 0 : n = NULL;
294 0 : goto done;
295 : }
296 3 : strcpy(r->n_str, tok->encoding);
297 3 : PyMem_FREE(tok->encoding);
298 3 : tok->encoding = NULL;
299 3 : r->n_nchildren = 1;
300 3 : r->n_child = n;
301 3 : n = r;
302 : }
303 :
304 : done:
305 3 : PyTokenizer_Free(tok);
306 :
307 3 : return n;
308 : }
309 :
310 : static int
311 3 : initerr(perrdetail *err_ret, const char *filename)
312 : {
313 3 : err_ret->error = E_OK;
314 3 : err_ret->lineno = 0;
315 3 : err_ret->offset = 0;
316 3 : err_ret->text = NULL;
317 3 : err_ret->token = -1;
318 3 : err_ret->expected = -1;
319 : #ifndef PGEN
320 3 : if (filename)
321 3 : err_ret->filename = PyUnicode_DecodeFSDefault(filename);
322 : else
323 0 : err_ret->filename = PyUnicode_FromString("<string>");
324 3 : if (err_ret->filename == NULL) {
325 0 : err_ret->error = E_ERROR;
326 0 : return -1;
327 : }
328 : #endif
329 3 : return 0;
330 : }
|