1/* Grammar from Python 2.2.2 Grammar/Grammar, converted to dparser */
2
3{
4#include "dparse_tables.h"
5typedef struct PythonGlobals {
6  int indent_stack[1024];
7  int *current_indent;
8  int implicit_line_joining;
9} PythonGlobals;
10#define D_ParseNode_Globals PythonGlobals
11int python_indent(PythonGlobals **p_globals);
12int python_dedent(PythonGlobals **p_globals);
13void python_whitespace(struct D_Parser *p, d_loc_t *loc, void **p_globals);
14}
15
16${declare longest_match}
17${declare subparser single_input}
18${declare subparser eval_input}
19${declare whitespace python_whitespace}
20
21file_input: (NEWLINE | stmt)*;
22single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE;
23eval_input: testlist NEWLINE*;
24
25funcdef: 'def' NAME parameters ':' suite;
26parameters: LP varargslist? RP;
27varargslist: (fpdef ('=' test)? ',')* ('*' NAME (',' '**' NAME) | '**' NAME) | fpdef ('=' test)? (',' fpdef ('=' test)?)* ','?;
28fpdef: NAME | LP fplist RP;
29fplist: fpdef (',' fpdef)* ','?;
30
31stmt: simple_stmt | compound_stmt;
32simple_stmt: small_stmt (';' small_stmt)* ';'? NEWLINE;
33small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt;
34expr_stmt: testlist (augassign testlist | ('=' testlist)*);
35augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=';
36/* For normal assignments, additional restrictions enforced by the interpreter */
37print_stmt: 'print' ( ( test (',' test)* ','? )? | '>>' test ( (',' test)+ ','? )? );
38del_stmt: 'del' exprlist;
39pass_stmt: 'pass';
40flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt;
41break_stmt: 'break';
42continue_stmt: 'continue';
43return_stmt: 'return' testlist?;
44yield_stmt: 'yield' testlist;
45raise_stmt: 'raise' (test (',' test (',' test)?)?)?;
46import_stmt: 'import' dotted_as_name (',' dotted_as_name)* | 'from' dotted_name 'import' ('*' | import_as_name (',' import_as_name)*);
47import_as_name: NAME (NAME NAME)?;
48dotted_as_name: dotted_name (NAME NAME)?;
49dotted_name: NAME ('.' NAME)*;
50global_stmt: 'global' NAME (',' NAME)*;
51exec_stmt: 'exec' expr ('in' test (',' test)?)?;
52assert_stmt: 'assert' test (',' test)?;
53
54compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef;
55if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ('else' ':' suite)?;
56while_stmt: 'while' test ':' suite ('else' ':' suite)?;
57for_stmt: 'for' exprlist 'in' testlist ':' suite ('else' ':' suite)?;
58try_stmt: ('try' ':' suite (except_clause ':' suite)+
59           ('else' ':' suite)? | 'try' ':' suite 'finally' ':' suite);
60// NB compile.c makes sure that the default except clause is last
61except_clause: 'except' (test (',' test)?)?;
62suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT;
63
64test: and_test ('or' and_test)* | lambdef;
65and_test: not_test ('and' not_test)*;
66not_test: 'not' not_test | comparison;
67comparison: expr (comp_op expr)*;
68comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not';
69expr: xor_expr ('|' xor_expr)*;
70xor_expr: and_expr ('^' and_expr)*;
71and_expr: shift_expr ('&' shift_expr)*;
72shift_expr: arith_expr (('<<'|'>>') arith_expr)*;
73arith_expr: term (('+'|'-') term)*;
74term: factor (('*'|'/'|'%'|'//') factor)*;
75factor: ('+'|'-'|'~') factor | power;
76power: atom trailer* ('**' factor)*;
77atom: LP testlist? RP | LB listmaker? RB | LC dictmaker? RC | '`' testlist '`' | NAME | NUMBER | STRING+;
78listmaker: test ( list_for | (',' test)* ','? );
79lambdef: 'lambda' varargslist? ':' test;
80trailer: LP arglist? RP | LB subscriptlist RB | '.' NAME;
81subscriptlist: subscript (',' subscript)* ','?;
82subscript: '.' '.' '.' | test | test? ':' test? sliceop?;
83sliceop: ':' test?;
84exprlist: expr (',' expr)* ','?;
85testlist: test (',' test)* ','?;
86testlist_safe: test ((',' test)+ ','?)?;
87dictmaker: test ':' test (',' test ':' test)* ','?;
88
89classdef: 'class' NAME (LP testlist RP)? ':' suite;
90
91arglist: (argument ',')* (argument ','?| '*' test (',' '**' test)? | '**' test);
92argument: (NAME '=')? test;
93
94list_iter: list_for | list_if;
95list_for: 'for' exprlist 'in' testlist_safe list_iter?;
96list_if: 'if' test list_iter?;
97
98/* additional material from http://www.python.org/doc/current/ref/grammar.txt */
99
100NEWLINE: '\n';
101INDENT: [ if (!python_indent(&$g)) return -1; ] ;
102DEDENT: [ if (!python_dedent(&$g)) return -1; ] ;
103NAME ::= (letter|'_') (letter | digit | '_')*;
104letter ::= "[a-zA-Z]";
105digit ::= "[0-9]";
106STRING ::= stringprefix?(shortstring | longstring);
107shortstring ::= "'" shortstringsingleitem* "'"
108              | '"' shortstringdoubleitem* '"';
109longstring ::= "'''" longstringitem* "'''"
110             | '"""' longstringitem* '"""';
111shortstringsingleitem ::= shortstringsinglechar | escapeseq;
112shortstringdoubleitem ::= shortstringdoublechar | escapeseq;
113longstringitem ::= longstringchar | escapeseq;
114shortstringsinglechar ::= "[^\\\n\']";
115shortstringdoublechar ::= "[^\\\n\"]";
116longstringchar ::= "[^\\]";
117stringprefix ::= 'r' | 'u' | 'ur' | 'R' | 'U' | 'UR' | 'Ur' | 'uR';
118escapeseq ::= "\\[^]";
119NUMBER ::= integer | longinteger | floatnumber | imagnumber;
120integer ::= decimalinteger | octinteger | hexinteger;
121decimalinteger ::= nonzerodigit digit* | '0';
122octinteger ::= '0' octdigit+;
123hexinteger ::= '0' ('x' | 'X') hexdigit+;
124floatnumber ::= pointfloat | exponentfloat;
125pointfloat ::= intpart? fraction | intpart '.';
126exponentfloat ::= (intpart | pointfloat) exponent;
127intpart ::= digit+;
128fraction ::= "." digit+;
129exponent ::= ("e" | "E") ("+" | "-")? digit+;
130imagnumber ::= (floatnumber | intpart) ("j" | "J");
131longinteger ::= integer ("l" | "L");
132nonzerodigit ::= "[1-9]";
133digit ::= "[0-9]";
134octdigit ::= "[0-7]";
135hexdigit ::= digit | "[a-fA-F]";
136
137LP ::= '(' [ $g->implicit_line_joining++; ];
138RP ::= ')' [ $g->implicit_line_joining--; ];
139LB ::= '[' [ $g->implicit_line_joining++; ];
140RB ::= ']' [ $g->implicit_line_joining--; ];
141LC ::= '{' [ $g->implicit_line_joining++; ];
142RC ::= '}' [ $g->implicit_line_joining--; ];
143
144{
145
146#include "dparse.h"
147#include <stdlib.h>
148#include <stdio.h>
149#include <string.h>
150
151void print_pg(PythonGlobals *pg, char *s) {
152  int i, n;
153  n = pg->current_indent - pg->indent_stack;
154  for (i = 0; i < n; i++)
155    printf("%d ", pg->indent_stack[i]);
156  printf("%s\n", s);
157}
158
159void python_whitespace(struct D_Parser *parser, d_loc_t *loc, void **p_globals) {
160  char *p = loc->s;
161  PythonGlobals *pg = *p_globals;
162  int i;
163  if (!pg) {
164    *p_globals = (void**)(pg = (PythonGlobals*)malloc(sizeof(PythonGlobals)));
165    memset(pg, 0, sizeof(*pg));
166    pg->current_indent = &pg->indent_stack[2];
167  }
168  if (parser->loc.s == p)
169    i = 0;
170  else
171    i = p[-1] == '\n' ? 0 : -1;
172  while (1) {
173    switch (*p) {
174      case '#': p++; while (*p && *p != '\n') p++; break;
175      case ' ': p++; if (i >= 0) i++; break;
176      case '\t': p++; if (i >= 0) i = (i + 7) & ~7; break;
177      case '\n': if (i >= 0 || pg->implicit_line_joining) { loc->line++; p++; i = 0; break; }
178        /* else fall through */
179      default: goto Ldone;
180    }
181  }
182 Ldone:;
183  if (i >= 0 && !pg->implicit_line_joining && *p != '\n')
184    if (i != pg->current_indent[-1]) /* || i != pg->current_indent[-2]) */ {
185      *pg->current_indent++ = i;
186      /* print_pg(pg, "-"); */
187    }
188  loc->s = p;
189}
190
191int python_indent(PythonGlobals **p_globals) {
192  PythonGlobals *pg = *p_globals;
193  if (pg) {
194    if (pg->current_indent[-1] > pg->current_indent[-2])
195      return 1;
196    if (pg->current_indent[-1] && pg->current_indent[-1] == pg->current_indent[-2] &&
197        pg->current_indent[-2] > pg->current_indent[-3]) {
198      pg->current_indent--;
199      /* print_pg(pg, ">"); */
200      return 1;
201    }
202  }
203  return 0;
204}
205
206int python_dedent(PythonGlobals **p_globals) {
207  int x;
208  PythonGlobals *pg = *p_globals;
209  if (pg && pg->current_indent[-1] < pg->current_indent[-2]) {
210    pg->current_indent--;
211    x = pg->current_indent[-1] = pg->current_indent[0];
212    while (x == pg->current_indent[-2]) pg->current_indent--;
213    /* print_pg(pg, "<"); */
214    return 1;
215  }
216  return 0;
217}
218
219}
220
221