]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/python/contrib/Parser/parser.c
Inital import
[l4.git] / l4 / pkg / python / contrib / Parser / parser.c
1
2 /* Parser implementation */
3
4 /* For a description, see the comments at end of this file */
5
6 /* XXX To do: error recovery */
7
8 #include "Python.h"
9 #include "pgenheaders.h"
10 #include "token.h"
11 #include "grammar.h"
12 #include "node.h"
13 #include "parser.h"
14 #include "errcode.h"
15
16
17 #ifdef Py_DEBUG
18 extern int Py_DebugFlag;
19 #define D(x) if (!Py_DebugFlag); else x
20 #else
21 #define D(x)
22 #endif
23
24
25 /* STACK DATA TYPE */
26
27 static void s_reset(stack *);
28
29 static void
30 s_reset(stack *s)
31 {
32         s->s_top = &s->s_base[MAXSTACK];
33 }
34
35 #define s_empty(s) ((s)->s_top == &(s)->s_base[MAXSTACK])
36
37 static int
38 s_push(register stack *s, dfa *d, node *parent)
39 {
40         register stackentry *top;
41         if (s->s_top == s->s_base) {
42                 fprintf(stderr, "s_push: parser stack overflow\n");
43                 return E_NOMEM;
44         }
45         top = --s->s_top;
46         top->s_dfa = d;
47         top->s_parent = parent;
48         top->s_state = 0;
49         return 0;
50 }
51
52 #ifdef Py_DEBUG
53
54 static void
55 s_pop(register stack *s)
56 {
57         if (s_empty(s))
58                 Py_FatalError("s_pop: parser stack underflow -- FATAL");
59         s->s_top++;
60 }
61
62 #else /* !Py_DEBUG */
63
64 #define s_pop(s) (s)->s_top++
65
66 #endif
67
68
69 /* PARSER CREATION */
70
71 parser_state *
72 PyParser_New(grammar *g, int start)
73 {
74         parser_state *ps;
75         
76         if (!g->g_accel)
77                 PyGrammar_AddAccelerators(g);
78         ps = (parser_state *)PyMem_MALLOC(sizeof(parser_state));
79         if (ps == NULL)
80                 return NULL;
81         ps->p_grammar = g;
82 #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
83         ps->p_flags = 0;
84 #endif
85         ps->p_tree = PyNode_New(start);
86         if (ps->p_tree == NULL) {
87                 PyMem_FREE(ps);
88                 return NULL;
89         }
90         s_reset(&ps->p_stack);
91         (void) s_push(&ps->p_stack, PyGrammar_FindDFA(g, start), ps->p_tree);
92         return ps;
93 }
94
95 void
96 PyParser_Delete(parser_state *ps)
97 {
98         /* NB If you want to save the parse tree,
99            you must set p_tree to NULL before calling delparser! */
100         PyNode_Free(ps->p_tree);
101         PyMem_FREE(ps);
102 }
103
104
105 /* PARSER STACK OPERATIONS */
106
107 static int
108 shift(register stack *s, int type, char *str, int newstate, int lineno, int col_offset)
109 {
110         int err;
111         assert(!s_empty(s));
112         err = PyNode_AddChild(s->s_top->s_parent, type, str, lineno, col_offset);
113         if (err)
114                 return err;
115         s->s_top->s_state = newstate;
116         return 0;
117 }
118
119 static int
120 push(register stack *s, int type, dfa *d, int newstate, int lineno, int col_offset)
121 {
122         int err;
123         register node *n;
124         n = s->s_top->s_parent;
125         assert(!s_empty(s));
126         err = PyNode_AddChild(n, type, (char *)NULL, lineno, col_offset);
127         if (err)
128                 return err;
129         s->s_top->s_state = newstate;
130         return s_push(s, d, CHILD(n, NCH(n)-1));
131 }
132
133
134 /* PARSER PROPER */
135
136 static int
137 classify(parser_state *ps, int type, char *str)
138 {
139         grammar *g = ps->p_grammar;
140         register int n = g->g_ll.ll_nlabels;
141         
142         if (type == NAME) {
143                 register char *s = str;
144                 register label *l = g->g_ll.ll_label;
145                 register int i;
146                 for (i = n; i > 0; i--, l++) {
147                         if (l->lb_type != NAME || l->lb_str == NULL ||
148                             l->lb_str[0] != s[0] ||
149                             strcmp(l->lb_str, s) != 0)
150                                 continue;
151 #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
152                         if (ps->p_flags & CO_FUTURE_PRINT_FUNCTION &&
153                             s[0] == 'p' && strcmp(s, "print") == 0) { 
154                                 break; /* no longer a keyword */
155                         }
156 #endif
157                         D(printf("It's a keyword\n"));
158                         return n - i;
159                 }
160         }
161         
162         {
163                 register label *l = g->g_ll.ll_label;
164                 register int i;
165                 for (i = n; i > 0; i--, l++) {
166                         if (l->lb_type == type && l->lb_str == NULL) {
167                                 D(printf("It's a token we know\n"));
168                                 return n - i;
169                         }
170                 }
171         }
172         
173         D(printf("Illegal token\n"));
174         return -1;
175 }
176
177 #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
178 static void
179 future_hack(parser_state *ps)
180 {
181         node *n = ps->p_stack.s_top->s_parent;
182         node *ch, *cch;
183         int i;
184
185         /* from __future__ import ..., must have at least 4 children */
186         n = CHILD(n, 0);
187         if (NCH(n) < 4)
188                 return;
189         ch = CHILD(n, 0);
190         if (STR(ch) == NULL || strcmp(STR(ch), "from") != 0)
191                 return;
192         ch = CHILD(n, 1);
193         if (NCH(ch) == 1 && STR(CHILD(ch, 0)) &&
194             strcmp(STR(CHILD(ch, 0)), "__future__") != 0)
195                 return;
196         ch = CHILD(n, 3);
197         /* ch can be a star, a parenthesis or import_as_names */
198         if (TYPE(ch) == STAR)
199                 return;
200         if (TYPE(ch) == LPAR)
201                 ch = CHILD(n, 4);
202         
203         for (i = 0; i < NCH(ch); i += 2) {
204                 cch = CHILD(ch, i);
205                 if (NCH(cch) >= 1 && TYPE(CHILD(cch, 0)) == NAME) {
206                         char *str_ch = STR(CHILD(cch, 0));
207                         if (strcmp(str_ch, FUTURE_WITH_STATEMENT) == 0) {
208                                 ps->p_flags |= CO_FUTURE_WITH_STATEMENT;
209                         } else if (strcmp(str_ch, FUTURE_PRINT_FUNCTION) == 0) {
210                                 ps->p_flags |= CO_FUTURE_PRINT_FUNCTION;
211                         } else if (strcmp(str_ch, FUTURE_UNICODE_LITERALS) == 0) {
212                                 ps->p_flags |= CO_FUTURE_UNICODE_LITERALS;
213                         }
214                 }
215         }
216 }
217 #endif /* future keyword */
218
219 int
220 PyParser_AddToken(register parser_state *ps, register int type, char *str,
221                   int lineno, int col_offset, int *expected_ret)
222 {
223         register int ilabel;
224         int err;
225         
226         D(printf("Token %s/'%s' ... ", _PyParser_TokenNames[type], str));
227         
228         /* Find out which label this token is */
229         ilabel = classify(ps, type, str);
230         if (ilabel < 0)
231                 return E_SYNTAX;
232         
233         /* Loop until the token is shifted or an error occurred */
234         for (;;) {
235                 /* Fetch the current dfa and state */
236                 register dfa *d = ps->p_stack.s_top->s_dfa;
237                 register state *s = &d->d_state[ps->p_stack.s_top->s_state];
238                 
239                 D(printf(" DFA '%s', state %d:",
240                         d->d_name, ps->p_stack.s_top->s_state));
241                 
242                 /* Check accelerator */
243                 if (s->s_lower <= ilabel && ilabel < s->s_upper) {
244                         register int x = s->s_accel[ilabel - s->s_lower];
245                         if (x != -1) {
246                                 if (x & (1<<7)) {
247                                         /* Push non-terminal */
248                                         int nt = (x >> 8) + NT_OFFSET;
249                                         int arrow = x & ((1<<7)-1);
250                                         dfa *d1 = PyGrammar_FindDFA(
251                                                 ps->p_grammar, nt);
252                                         if ((err = push(&ps->p_stack, nt, d1,
253                                                 arrow, lineno, col_offset)) > 0) {
254                                                 D(printf(" MemError: push\n"));
255                                                 return err;
256                                         }
257                                         D(printf(" Push ...\n"));
258                                         continue;
259                                 }
260                                 
261                                 /* Shift the token */
262                                 if ((err = shift(&ps->p_stack, type, str,
263                                                 x, lineno, col_offset)) > 0) {
264                                         D(printf(" MemError: shift.\n"));
265                                         return err;
266                                 }
267                                 D(printf(" Shift.\n"));
268                                 /* Pop while we are in an accept-only state */
269                                 while (s = &d->d_state
270                                                 [ps->p_stack.s_top->s_state],
271                                         s->s_accept && s->s_narcs == 1) {
272                                         D(printf("  DFA '%s', state %d: "
273                                                  "Direct pop.\n",
274                                                  d->d_name,
275                                                  ps->p_stack.s_top->s_state));
276 #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
277                                         if (d->d_name[0] == 'i' &&
278                                             strcmp(d->d_name,
279                                                    "import_stmt") == 0)
280                                                 future_hack(ps);
281 #endif
282                                         s_pop(&ps->p_stack);
283                                         if (s_empty(&ps->p_stack)) {
284                                                 D(printf("  ACCEPT.\n"));
285                                                 return E_DONE;
286                                         }
287                                         d = ps->p_stack.s_top->s_dfa;
288                                 }
289                                 return E_OK;
290                         }
291                 }
292                 
293                 if (s->s_accept) {
294 #ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
295                         if (d->d_name[0] == 'i' &&
296                             strcmp(d->d_name, "import_stmt") == 0)
297                                 future_hack(ps);
298 #endif
299                         /* Pop this dfa and try again */
300                         s_pop(&ps->p_stack);
301                         D(printf(" Pop ...\n"));
302                         if (s_empty(&ps->p_stack)) {
303                                 D(printf(" Error: bottom of stack.\n"));
304                                 return E_SYNTAX;
305                         }
306                         continue;
307                 }
308                 
309                 /* Stuck, report syntax error */
310                 D(printf(" Error.\n"));
311                 if (expected_ret) {
312                         if (s->s_lower == s->s_upper - 1) {
313                                 /* Only one possible expected token */
314                                 *expected_ret = ps->p_grammar->
315                                     g_ll.ll_label[s->s_lower].lb_type;
316                         }
317                         else 
318                                 *expected_ret = -1;
319                 }
320                 return E_SYNTAX;
321         }
322 }
323
324
325 #ifdef Py_DEBUG
326
327 /* DEBUG OUTPUT */
328
329 void
330 dumptree(grammar *g, node *n)
331 {
332         int i;
333         
334         if (n == NULL)
335                 printf("NIL");
336         else {
337                 label l;
338                 l.lb_type = TYPE(n);
339                 l.lb_str = STR(n);
340                 printf("%s", PyGrammar_LabelRepr(&l));
341                 if (ISNONTERMINAL(TYPE(n))) {
342                         printf("(");
343                         for (i = 0; i < NCH(n); i++) {
344                                 if (i > 0)
345                                         printf(",");
346                                 dumptree(g, CHILD(n, i));
347                         }
348                         printf(")");
349                 }
350         }
351 }
352
353 void
354 showtree(grammar *g, node *n)
355 {
356         int i;
357         
358         if (n == NULL)
359                 return;
360         if (ISNONTERMINAL(TYPE(n))) {
361                 for (i = 0; i < NCH(n); i++)
362                         showtree(g, CHILD(n, i));
363         }
364         else if (ISTERMINAL(TYPE(n))) {
365                 printf("%s", _PyParser_TokenNames[TYPE(n)]);
366                 if (TYPE(n) == NUMBER || TYPE(n) == NAME)
367                         printf("(%s)", STR(n));
368                 printf(" ");
369         }
370         else
371                 printf("? ");
372 }
373
374 void
375 printtree(parser_state *ps)
376 {
377         if (Py_DebugFlag) {
378                 printf("Parse tree:\n");
379                 dumptree(ps->p_grammar, ps->p_tree);
380                 printf("\n");
381                 printf("Tokens:\n");
382                 showtree(ps->p_grammar, ps->p_tree);
383                 printf("\n");
384         }
385         printf("Listing:\n");
386         PyNode_ListTree(ps->p_tree);
387         printf("\n");
388 }
389
390 #endif /* Py_DEBUG */
391
392 /*
393
394 Description
395 -----------
396
397 The parser's interface is different than usual: the function addtoken()
398 must be called for each token in the input.  This makes it possible to
399 turn it into an incremental parsing system later.  The parsing system
400 constructs a parse tree as it goes.
401
402 A parsing rule is represented as a Deterministic Finite-state Automaton
403 (DFA).  A node in a DFA represents a state of the parser; an arc represents
404 a transition.  Transitions are either labeled with terminal symbols or
405 with non-terminals.  When the parser decides to follow an arc labeled
406 with a non-terminal, it is invoked recursively with the DFA representing
407 the parsing rule for that as its initial state; when that DFA accepts,
408 the parser that invoked it continues.  The parse tree constructed by the
409 recursively called parser is inserted as a child in the current parse tree.
410
411 The DFA's can be constructed automatically from a more conventional
412 language description.  An extended LL(1) grammar (ELL(1)) is suitable.
413 Certain restrictions make the parser's life easier: rules that can produce
414 the empty string should be outlawed (there are other ways to put loops
415 or optional parts in the language).  To avoid the need to construct
416 FIRST sets, we can require that all but the last alternative of a rule
417 (really: arc going out of a DFA's state) must begin with a terminal
418 symbol.
419
420 As an example, consider this grammar:
421
422 expr:   term (OP term)*
423 term:   CONSTANT | '(' expr ')'
424
425 The DFA corresponding to the rule for expr is:
426
427 ------->.---term-->.------->
428         ^          |
429         |          |
430         \----OP----/
431
432 The parse tree generated for the input a+b is:
433
434 (expr: (term: (NAME: a)), (OP: +), (term: (NAME: b)))
435
436 */