• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Parser-tokenizer link implementation.
3 
4   Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials are licensed and made available under
6   the terms and conditions of the BSD License that accompanies this distribution.
7   The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php.
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13 #include "pgenheaders.h"
14 #include "tokenizer.h"
15 #include "node.h"
16 #include "grammar.h"
17 #include "parser.h"
18 #include "parsetok.h"
19 #include "errcode.h"
20 #include "graminit.h"
21 
22 int Py_TabcheckFlag;
23 
24 
25 /* Forward */
26 static node *parsetok(struct tok_state *, grammar *, int, perrdetail *, int *);
27 static void initerr(perrdetail *err_ret, const char* filename);
28 
29 /* Parse input coming from a string.  Return error code, print some errors. */
30 node *
PyParser_ParseString(const char * s,grammar * g,int start,perrdetail * err_ret)31 PyParser_ParseString(const char *s, grammar *g, int start, perrdetail *err_ret)
32 {
33     return PyParser_ParseStringFlagsFilename(s, NULL, g, start, err_ret, 0);
34 }
35 
36 node *
PyParser_ParseStringFlags(const char * s,grammar * g,int start,perrdetail * err_ret,int flags)37 PyParser_ParseStringFlags(const char *s, grammar *g, int start,
38                           perrdetail *err_ret, int flags)
39 {
40     return PyParser_ParseStringFlagsFilename(s, NULL,
41                                              g, start, err_ret, flags);
42 }
43 
44 node *
PyParser_ParseStringFlagsFilename(const char * s,const char * filename,grammar * g,int start,perrdetail * err_ret,int flags)45 PyParser_ParseStringFlagsFilename(const char *s, const char *filename,
46                           grammar *g, int start,
47                           perrdetail *err_ret, int flags)
48 {
49     int iflags = flags;
50     return PyParser_ParseStringFlagsFilenameEx(s, filename, g, start,
51                                                err_ret, &iflags);
52 }
53 
54 node *
PyParser_ParseStringFlagsFilenameEx(const char * s,const char * filename,grammar * g,int start,perrdetail * err_ret,int * flags)55 PyParser_ParseStringFlagsFilenameEx(const char *s, const char *filename,
56                           grammar *g, int start,
57                           perrdetail *err_ret, int *flags)
58 {
59     struct tok_state *tok;
60 
61     initerr(err_ret, filename);
62 
63     if ((tok = PyTokenizer_FromString(s, start == file_input)) == NULL) {
64         err_ret->error = PyErr_Occurred() ? E_DECODE : E_NOMEM;
65         return NULL;
66     }
67 
68     tok->filename = filename ? filename : "<string>";
69     if (Py_TabcheckFlag || Py_VerboseFlag) {
70         tok->altwarning = (tok->filename != NULL);
71         if (Py_TabcheckFlag >= 2)
72             tok->alterror++;
73     }
74 
75     return parsetok(tok, g, start, err_ret, flags);
76 }
77 
78 /* Parse input coming from a file.  Return error code, print some errors. */
79 
80 node *
PyParser_ParseFile(FILE * fp,const char * filename,grammar * g,int start,char * ps1,char * ps2,perrdetail * err_ret)81 PyParser_ParseFile(FILE *fp, const char *filename, grammar *g, int start,
82                    char *ps1, char *ps2, perrdetail *err_ret)
83 {
84     return PyParser_ParseFileFlags(fp, filename, g, start, ps1, ps2,
85                                    err_ret, 0);
86 }
87 
88 node *
PyParser_ParseFileFlags(FILE * fp,const char * filename,grammar * g,int start,char * ps1,char * ps2,perrdetail * err_ret,int flags)89 PyParser_ParseFileFlags(FILE *fp, const char *filename, grammar *g, int start,
90                         char *ps1, char *ps2, perrdetail *err_ret, int flags)
91 {
92     int iflags = flags;
93     return PyParser_ParseFileFlagsEx(fp, filename, g, start, ps1, ps2, err_ret, &iflags);
94 }
95 
96 node *
PyParser_ParseFileFlagsEx(FILE * fp,const char * filename,grammar * g,int start,char * ps1,char * ps2,perrdetail * err_ret,int * flags)97 PyParser_ParseFileFlagsEx(FILE *fp, const char *filename, grammar *g, int start,
98                           char *ps1, char *ps2, perrdetail *err_ret, int *flags)
99 {
100     struct tok_state *tok;
101 
102     initerr(err_ret, filename);
103 
104     if ((tok = PyTokenizer_FromFile(fp, ps1, ps2)) == NULL) {
105         err_ret->error = E_NOMEM;
106         return NULL;
107     }
108     tok->filename = filename;
109     if (Py_TabcheckFlag || Py_VerboseFlag) {
110         tok->altwarning = (filename != NULL);
111         if (Py_TabcheckFlag >= 2)
112             tok->alterror++;
113     }
114 
115     return parsetok(tok, g, start, err_ret, flags);
116 }
117 
118 #if 0
119 static char with_msg[] =
120 "%s:%d: Warning: 'with' will become a reserved keyword in Python 2.6\n";
121 
122 static char as_msg[] =
123 "%s:%d: Warning: 'as' will become a reserved keyword in Python 2.6\n";
124 
125 static void
126 warn(const char *msg, const char *filename, int lineno)
127 {
128     if (filename == NULL)
129         filename = "<string>";
130     PySys_WriteStderr(msg, filename, lineno);
131 }
132 #endif
133 
134 /* Parse input coming from the given tokenizer structure.
135    Return error code. */
136 
137 static node *
parsetok(struct tok_state * tok,grammar * g,int start,perrdetail * err_ret,int * flags)138 parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
139          int *flags)
140 {
141     parser_state *ps;
142     node *n;
143     int started = 0;
144     //int handling_import = 0;
145     //int handling_with = 0;
146 
147     if ((ps = PyParser_New(g, start)) == NULL) {
148         fprintf(stderr, "no mem for new parser\n");
149         err_ret->error = E_NOMEM;
150         PyTokenizer_Free(tok);
151         return NULL;
152     }
153 #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
154     if (*flags & PyPARSE_PRINT_IS_FUNCTION) {
155         ps->p_flags |= CO_FUTURE_PRINT_FUNCTION;
156     }
157     if (*flags & PyPARSE_UNICODE_LITERALS) {
158         ps->p_flags |= CO_FUTURE_UNICODE_LITERALS;
159     }
160 
161 #endif
162 
163     for (;;) {
164         char *a, *b;
165         int type;
166         size_t len;
167         char *str;
168         int col_offset;
169 
170         type = PyTokenizer_Get(tok, &a, &b);
171         if (type == ERRORTOKEN) {
172             err_ret->error = tok->done;
173             break;
174         }
175         if (type == ENDMARKER && started) {
176             type = NEWLINE; /* Add an extra newline */
177             //handling_with = 0;
178             //handling_import = 0;
179             started = 0;
180             /* Add the right number of dedent tokens,
181                except if a certain flag is given --
182                codeop.py uses this. */
183             if (tok->indent &&
184                 !(*flags & PyPARSE_DONT_IMPLY_DEDENT))
185             {
186                 tok->pendin = -tok->indent;
187                 tok->indent = 0;
188             }
189         }
190         else
191             started = 1;
192         len = b - a; /* XXX this may compute NULL - NULL */
193         str = (char *) PyObject_MALLOC(len + 1);
194         if (str == NULL) {
195             fprintf(stderr, "no mem for next token\n");
196             err_ret->error = E_NOMEM;
197             break;
198         }
199         if (len > 0)
200             strncpy(str, a, len);
201         str[len] = '\0';
202 
203 #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
204 #endif
205         if (a >= tok->line_start)
206             col_offset = a - tok->line_start;
207         else
208             col_offset = -1;
209 
210         if ((err_ret->error =
211              PyParser_AddToken(ps, (int)type, str, tok->lineno, col_offset,
212                                &(err_ret->expected))) != E_OK) {
213             if (err_ret->error != E_DONE) {
214                 PyObject_FREE(str);
215                 err_ret->token = type;
216             }
217             break;
218         }
219     }
220 
221     if (err_ret->error == E_DONE) {
222         n = ps->p_tree;
223         ps->p_tree = NULL;
224     }
225     else
226         n = NULL;
227 
228 #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
229     *flags = ps->p_flags;
230 #endif
231     PyParser_Delete(ps);
232 
233     if (n == NULL) {
234         if (tok->lineno <= 1 && tok->done == E_EOF)
235             err_ret->error = E_EOF;
236         err_ret->lineno = tok->lineno;
237         if (tok->buf != NULL) {
238             char *text = NULL;
239             size_t len;
240             assert(tok->cur - tok->buf < INT_MAX);
241             err_ret->offset = (int)(tok->cur - tok->buf);
242             len = tok->inp - tok->buf;
243 #ifdef Py_USING_UNICODE
244             text = PyTokenizer_RestoreEncoding(tok, len, &err_ret->offset);
245 
246 #endif
247             if (text == NULL) {
248                 text = (char *) PyObject_MALLOC(len + 1);
249                 if (text != NULL) {
250                     if (len > 0)
251                         strncpy(text, tok->buf, len);
252                     text[len] = '\0';
253                 }
254             }
255             err_ret->text = text;
256         }
257     } else if (tok->encoding != NULL) {
258         /* 'nodes->n_str' uses PyObject_*, while 'tok->encoding' was
259          * allocated using PyMem_
260          */
261         node* r = PyNode_New(encoding_decl);
262         if (r)
263             r->n_str = PyObject_MALLOC(strlen(tok->encoding)+1);
264         if (!r || !r->n_str) {
265             err_ret->error = E_NOMEM;
266             if (r)
267                 PyObject_FREE(r);
268             n = NULL;
269             goto done;
270         }
271         strcpy(r->n_str, tok->encoding);
272         PyMem_FREE(tok->encoding);
273         tok->encoding = NULL;
274         r->n_nchildren = 1;
275         r->n_child = n;
276         n = r;
277     }
278 
279 done:
280     PyTokenizer_Free(tok);
281 
282     return n;
283 }
284 
285 static void
initerr(perrdetail * err_ret,const char * filename)286 initerr(perrdetail *err_ret, const char *filename)
287 {
288     err_ret->error = E_OK;
289     err_ret->filename = filename;
290     err_ret->lineno = 0;
291     err_ret->offset = 0;
292     err_ret->text = NULL;
293     err_ret->token = -1;
294     err_ret->expected = -1;
295 }
296