-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathminipython.grammar
More file actions
287 lines (245 loc) · 10.1 KB
/
minipython.grammar
File metadata and controls
287 lines (245 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/*
Αλέξιος Μανδελιάς 3190106
Δημήτριος Τσίρμπας 3190205
Αναστάσιος Πασχαλίδης 3190166
*/
Package minipython;
Helpers
digit = ['0' .. '9'];
letter = ['a' .. 'z']|['A' .. 'Z']|'_'|'$';
cr = 13;
lf = 10;
all = [0..127];
eol = lf | cr | cr lf ;
not_eol = [all - [cr + lf]];
str_literal = [not_eol - '"'];
str_literal_s = [not_eol - 39];
Tokens
tab = 9;
/* Comparison Operators */
great_eq = '>=';
less_eq = '<=';
not_eq = '!=';
eq = '==';
sub_assign = '-=';
div_assign = '/=';
less_than = '<';
greater_than = '>';
/* Mathematical Operators */
op_add = '+';
op_sub = '-';
op_exp = '**';
op_mul = '*';
op_div = '/';
op_mod = '%';
assign = '=';
/* Other Symbols */
l_par = '(';
r_par = ')';
l_br = '[';
r_br = ']';
comma =',';
dot = '.';
colon = ':';
double_quote = '"';
single_quote = 39;
/* Keywords */
true = 'true';
false = 'false';
def = 'def';
if = 'if';
for = 'for';
in = 'in';
while = 'while';
print = 'print';
return = 'return';
assert = 'assert';
length = 'len';
max = 'max';
min = 'min';
import = 'import';
as = 'as';
from = 'from';
logical_and = 'and';
logical_or = 'or';
logical_not = 'not';
none = 'None';
/* Other Tokens */
eoltoken = eol;
blank = (' ' | lf | cr);
line_comment = '#' not_eol* eol;
num = digit+ | (digit+ '.' digit+);
id = letter (letter | digit)*;
string_double_quotes = 34 str_literal* 34;
string_single_quotes = 39 str_literal_s* 39;
Ignored Tokens
blank, line_comment;
Productions
/* Goal */
goal = {commands} command more_commands* {-> New goal([command more_commands.command])};
command =
{function} function {-> New command.function(function)}
| {statement} statement {-> New command.statement(statement)}
| {empty_line} tab* {-> New command.empty()};
more_commands {-> command} = {more_commands} eoltoken command {-> command};
/* Function + Argument */
function = {func_def} def identifier l_par argument? r_par colon eoltoken statement {-> New function(identifier, [argument], statement) };
argument = {argument} identifier default_value? argument_list* {-> New argument.complex(identifier, default_value.value,[argument_list.argument])};
default_value {-> value} = {default_value} assign value {-> New value.val(value)};
argument_list {-> argument} = {argument_list} comma identifier default_value? {-> New argument.simple(identifier, default_value.value)};
/* Statement */
statement = {if} tab* if comparison colon eoltoken statement {-> New statement.if(comparison, statement)}
| {while} tab* while comparison colon eoltoken statement {-> New statement.while(comparison, statement)}
| {for} tab* for [id1]:identifier in [id2]:identifier colon eoltoken statement {-> New statement.for(id1, id2, statement)}
| {return} tab* return expression {-> New statement.return(expression.expr)}
| {print} tab* print expression expression_list* {-> New statement.print([expression.expr expression_list.expr])}
| {assign_var} tab* identifier operate_assign expression {-> New statement.assign_var(identifier, operate_assign, expression.expr)}
| {assign_array} tab* identifier l_br [ex1]:expression r_br assign [ex2]:expression {-> New statement.assign_array(identifier, ex1.expr, ex2.expr)}
| {assertion} tab* assert expression expression_list? {-> New statement.assertion([expression.expr expression_list.expr])}
| {func_call} tab* function_call {-> New statement.func_call(function_call)};
/* Note that the Import Statement is NOT included in BNF */
/* | {import_statement} tab* import_statement {-> import_statement.statement}*/
operate_assign =
{assign} assign {-> New operate_assign.assign(assign)}
| {sub_assign} sub_assign {-> New operate_assign.sub_assign(sub_assign)}
| {div_assign} div_assign {-> New operate_assign.div_assign(div_assign)};
/* Expression */
/* First the lowest priority (addition and subtraction) */
expression {-> expr} = {res2} res2 {-> res2.expr}
| {addition} expression op_add res2 {-> New expr.add(expression.expr, res2.expr)}
| {subtraction} expression op_sub res2 {-> New expr.sub(expression.expr, res2.expr)};
/* Then second lowest (multiplication, division and modulo) */
res2 {-> expr} = {res3} res3 {-> res3.expr }
| {multiplication} res2 op_mul res3 {-> New expr.mul(res2.expr, res3.expr) }
| {division} res2 op_div res3 {-> New expr.div(res2.expr, res3.expr) }
| {modulo} res2 op_mod res3 {-> New expr.mod(res2.expr, res3.expr) };
/* Then the highest (exponentiation) */
res3 {-> expr} = {other_expr} other_expr {-> other_expr.expr}
| {exponentiation} other_expr op_exp res3 {-> New expr.exp(other_expr.expr, res3.expr)};
/* Lastly, each of the above expressions can be one of the following */
other_expr {-> expr} = {id_bracket} identifier l_br expression r_br {-> New expr.id_bracket(identifier, expression.expr)}
| {func_call} function_call {-> New expr.func_call(function_call)}
| {value} value {-> New expr.value(value)}
| {id} identifier {-> New expr.id(identifier)}
| {length_expr} length l_par expression r_par {-> expression.expr}
| {minimax} minimax l_par value value_list* r_par {-> New expr.minimax([value value_list.value])}
| {ls_def} l_br expression expression_list* r_br {-> New expr.ls_def([expression.expr expression_list.expr])};
minimax = {max} max {->New minimax.max()} | {min} min {-> New minimax.min()};
value_list {->value} = {value_list} comma value {-> value};
/*[*/
/*
Import
import_statement{->statement} =
{import_module} import module import_as? module_list* {-> New statement.import_module([module.identifier import_as.identifier module_list.identifier])}
| {from_module_import} from module import identifier import_as? identifier_list* {-> New statement.from_import_statement(module, [identifier import_as.identifier identifier_list.identifier])};
Module
module {-> identifier*} = {module} id_dot* identifier {-> New identifier.identifier([id_dot.identifier identifier])};
import_as {-> identifier} = {import_as} as identifier {-> New identifier(identifier)};
module_list {-> identifier*} = {module_list} comma module import_as? {-> New identifier([identifier import_as])};
id_dot {->identifier} = {id_dot} identifier dot;
identifier_list {->identifier} = {identifier_list} comma identifier import_as? ;
*/
/* Comparison */
/* First the lowest priority (and, or) */
comparison =
{negation} negation {-> negation.comparison}
| {and_comparison} comparison logical_and negation {-> New comparison.and(comparison, negation.comparison)}
| {or_comparison} comparison logical_or negation {-> New comparison.or(comparison, negation.comparison)};
/* Then the highest (not) */
negation {-> comparison} =
{logical_value} logical_value {-> logical_value.comparison}
| {negation} logical_not logical_value {-> New comparison.neg(logical_value.comparison)};
/* Lastly, boolean literals and simple comparison expressions */
logical_value {-> comparison} =
{true} true {-> New comparison.true()}
| {false} false {-> New comparison.false()}
| {expr_compare} [ex1]:expression single_comparison [ex2]:expression {-> New comparison.single(ex1.expr, single_comparison, ex2.expr)};
single_comparison =
{gt} greater_than {-> New single_comparison.gt()}
| {lt} less_than {-> New single_comparison.lt()}
| {ge} great_eq {-> New single_comparison.ge()}
| {le} less_eq {-> New single_comparison.le()}
| {ne} not_eq {-> New single_comparison.ne()}
| {eq} eq {-> New single_comparison.eq()};
/* Function Call + Arglist */
function_call = {func_call} identifier l_par arglist? r_par {-> New function_call.fc(identifier, [arglist.expr])};
arglist {-> expr*} = {arg_list} expression expression_list* {-> [expression.expr expression_list.expr]};
/* Value */
value =
{id_func} identifier dot function_call {-> New value.id_func_call(identifier, function_call)}
| {number} number {-> number.value}
| {str_double} string_double_quotes{-> New value.string1(string_double_quotes)}
| {str_single} string_single_quotes{-> New value.string2(string_single_quotes)}
| {none} none {-> New value.none()};
/* Number + Identifier */
number {-> value} = {num} num {-> New value.number(num)};
identifier = {identifier} id {-> New identifier.id(id)};
/* Leftover production that used at many places */
expression_list {-> expr} = {expression_list} comma expression {-> expression.expr};
/*#*/
Abstract Syntax Tree
/* Goal */
goal = command*;
command = {function} function | {statement} statement |{empty};
/* Function + Argument */
function = identifier argument* statement;
argument = {simple}identifier value
| {complex} identifier value argument*;
/* Statement */
statement = {if} comparison statement
| {while} comparison statement
| {for} [id1]:identifier [id2]:identifier statement
| {return} expr
| {print} expr*
| {assign_var} identifier operate_assign expr
| {assign_array} identifier [ex1]:expr [ex2]:expr
| {assertion} expr*
| {func_call} function_call;
/* Note that the Import Statement is NOT included in BNF */
/* | {import_module} moduleas*
| {from_import_statement} module identifier_as**/
/*]*/
operate_assign =
{assign} assign
| {sub_assign} sub_assign
| {div_assign} div_assign;
expr =
{add} [ex1]:expr [ex2]:expr
| {sub} [ex1]:expr [ex2]:expr
| {mul} [ex1]:expr [ex2]:expr
| {div} [ex1]:expr [ex2]:expr
| {mod} [ex1]:expr [ex2]:expr
| {exp} [base]:expr [power]:expr
| {id_bracket} identifier expr
| {value} value
| {id} identifier
| {minimax} value*
| {ls_def} expr*
| {func_call} function_call;
/*
module = {module} identifier*;
moduleas = module identifier*;
identifier_as = [id1]:identifier [id2]:identifier*;
*/
function_call = {fc} identifier expr*;
value = {val} value
| {number} num
| {none}
| {id_func_call} identifier function_call
| {string1} string_double_quotes
| {string2} string_single_quotes;
minimax = {min} | {max};
identifier = {id} id;
single_comparison =
{gt}
| {lt}
| {ge}
| {le}
| {ne}
| {eq};
comparison = {neg} comparison
| {and} [comp1]:comparison [comp2]:comparison
| {or} [comp1]:comparison [comp2]:comparison
| {single} [ex1]:expr single_comparison [ex2]:expr
| {true}
| {false};