[mugiwara] easier parser to read
[ozulis.git] / src / plugins / lang / mugiwara / bison-parser / parser.y
blob66da581a13efc2c9d98ba0d993d67c4b2b36dca2
1 %glr-parser
2 %pure-parser
3 %locations
4 %start file
5 %defines
6 %error-verbose
7 %name-prefix "mugiwara"
9 %lex-param {yyscan_t yyscanner}
10 %parse-param {yyscan_t yyscanner}
11 %parse-param {ozulis::ast::File *& file}
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
18 #include <iostream>
19 #include <algorithm>
21 #include <ozulis/core/assert.hh>
22 #include <ozulis/ast/ast.hh>
23 #include <ozulis/ast/node-factory.hh>
25 #include "parser.hh"
26 #include "lexer.hh"
28 static void yyerror(YYLTYPE *yyloccp,
29 yyscan_t /*yyscanner*/,
30 ozulis::ast::File *& file,
31 const char *str)
33 if (file)
34 std::cerr << file->path << ":" ;
35 std::cerr << yyloccp->first_line << "." << yyloccp->first_column << "-"
36 << yyloccp->last_line << "." << yyloccp->last_column
37 << ": " << str << std::endl;
40 #define MAKE_BINARY_EXP(Type, Out, Left, Right) \
41 do { \
42 ozulis::ast::Type * exp = new ozulis::ast::Type(); \
43 assert(Left); \
44 assert(Right); \
45 exp = new ozulis::ast::Type(); \
46 exp->left = (Left); \
47 exp->right = (Right); \
48 (Out) = exp; \
49 } while (0)
51 #define MAKE_UNARY_EXP(Type, Out, Exp) \
52 do { \
53 ozulis::ast::Type * exp = new ozulis::ast::Type(); \
54 assert(Exp); \
55 exp = new ozulis::ast::Type(); \
56 exp->exp = (Exp); \
57 (Out) = exp; \
58 } while (0)
60 static ozulis::ast::Type *
61 createType(const char * name)
63 static const struct {
64 const char * name;
65 bool isSigned;
66 int size;
67 } integerTypes[] = {
68 { "int8", true, 8 },
69 { "uint8", false, 8 },
70 { "int16", true, 16 },
71 { "uint16", false, 16 },
72 { "int32", true, 32 },
73 { "uint32", false, 32 },
74 { "int64", true, 64 },
75 { "uint64", false, 64 },
76 { "int128", true, 128 },
77 { "uint128", false, 128 },
78 { 0, false, 0 }
81 for (int i = 0; integerTypes[i].name; i++)
82 if (!strcmp(name, integerTypes[i].name))
84 ozulis::ast::IntegerType * itype = new ozulis::ast::IntegerType();
85 itype->isSigned = integerTypes[i].isSigned;
86 itype->size = integerTypes[i].size;
87 return itype;
89 if (!strcmp("bool", name))
90 return ozulis::ast::NodeFactory::createBoolType();
91 if (!strcmp("float", name))
92 return ozulis::ast::NodeFactory::createFloatType();
93 if (!strcmp("double", name))
94 return ozulis::ast::NodeFactory::createDoubleType();
95 if (!strcmp("void", name))
96 return ozulis::ast::NodeFactory::createVoidType();
97 ozulis::ast::NamedType * type = new ozulis::ast::NamedType;
98 type->name = name;
99 return type;
104 %union
106 ozulis::ast::Node * node;
107 std::vector<ozulis::ast::Node *> * nodes;
108 ozulis::ast::Function * funcDec;
109 ozulis::ast::Type * type;
110 std::vector<ozulis::ast::VarDecl *> * varDecls;
111 ozulis::ast::VarDecl * varDecl;
112 ozulis::ast::Block * block;
113 ozulis::ast::Exp * exp;
114 std::vector<ozulis::ast::Exp *> * exps;
115 ozulis::ast::NumberExp * nbExp;
117 int number;
118 char * string;
119 bool boolean;
122 %token <nbExp> NUMBER
123 %token <string> ID STRING
124 %token EQEQ "=="
125 %token NEQ "!="
126 %token LTEQ "<="
127 %token GTEQ ">="
128 %token SHL "<<"
129 %token ASHR ">>>"
130 %token LSHR ">>"
131 %token OROR "||"
132 %token ANDAND "&&"
133 %token GOTO "goto"
134 %token CONST "const"
135 %token CAST "cast"
136 %token RETURN "return"
137 %token IF "if"
138 %token ELSE "else"
139 %token WHILE "while"
140 %token DO "do"
141 %token FOR "for"
143 %type <nodes> decls
144 %type <node> decl
145 %type <type> type
146 %type <varDecls> var_decls func_params func_params_non_empty
147 %type <varDecl> var_decl
148 %type <node> func_dec
149 %type <block> block
150 %type <nodes> statements
151 %type <node> statement label_statement goto_statement
152 %type <node> if_statement else_statement while_statement
153 %type <node> do_while_statement return_statement
154 %type <node> exp_statement
155 %type <exp> exp assign_exp oror_exp andand_exp or_exp xor_exp and_exp
156 %type <exp> cmp_exp shift_exp add_exp mul_exp unary_exp
157 %type <exp> call_exp
158 %type <exps> call_exp_args call_exp_args_non_empty
162 file: decls {
163 file = new ozulis::ast::File();
164 file->decls = $1;
165 if (!file->varDecls)
166 file->varDecls = new ozulis::ast::File::varDecls_t;
167 std::reverse(file->decls->begin(), file->decls->end());
170 decls: decl decls {
171 assert($1);
172 assert($2);
173 $$ = $2;
174 $$->push_back($1);
175 } | /* epsilon */ { $$ = new std::vector<ozulis::ast::Node *> (); };
177 decl: func_dec {
178 $$ = $1;
181 func_dec: type ID '(' func_params ')' ';' {
182 ozulis::ast::FunctionDecl * func = new ozulis::ast::FunctionDecl;
183 func->returnType = $1;
184 func->name = $2;
185 func->args = $4;
186 $$ = func;
187 } | type ID '(' func_params ')' block {
188 ozulis::ast::Function * func = new ozulis::ast::Function;
189 func->returnType = $1;
190 func->name = $2;
191 func->args = $4;
192 func->block = $6;
193 $$ = func;
196 func_params: func_params_non_empty { $$ = $1; }
197 | /* epsilon */ { $$ = new std::vector<ozulis::ast::VarDecl *>(); };
199 func_params_non_empty: var_decl {
200 $$ = new std::vector<ozulis::ast::VarDecl *>();
201 $$->push_back($1);
202 } | func_params_non_empty ',' var_decl {
203 $$ = $1;
204 $$->push_back($3);
207 block: '[' var_decls statements ']' {
208 $$ = new ozulis::ast::Block();
209 $$->varDecls = $2;
210 $$->statements = $3;
213 var_decls: var_decls var_decl ';' {
214 assert($2);
215 $$ = $1 ? : new std::vector<ozulis::ast::VarDecl *> ();
216 $$->push_back($2);
217 } | /* epsilon */ { $$ = new std::vector<ozulis::ast::VarDecl *> (); };
219 var_decl: type ID {
220 $$ = new ozulis::ast::VarDecl();
221 $$->type = $1;
222 $$->name = $2;
225 statements: statements statement {
226 assert($2);
227 $$ = $1 ? : new std::vector<ozulis::ast::Node *> ();
228 $$->push_back($2);
229 } | /* epsilon */ { $$ = new std::vector<ozulis::ast::Node *> (); };
231 statement: exp_statement { $$ = $1; }
232 | label_statement { $$ = $1; }
233 | goto_statement { $$ = $1; }
234 | if_statement { $$ = $1; }
235 | while_statement { $$ = $1; }
236 | do_while_statement { $$ = $1; }
237 | return_statement { $$ = $1; }
238 | block { $$ = $1; }
239 | ';' { $$ = new ozulis::ast::EmptyStatement(); };
241 exp_statement: exp ';' {
242 assert($1);
243 $$ = $1;
246 label_statement: ID ':' {
247 ozulis::ast::Label * label = new ozulis::ast::Label();
248 label->name = $1;
249 $$ = label;
252 goto_statement: "goto" ID ';' {
253 ozulis::ast::Goto * gt = new ozulis::ast::Goto();
254 gt->label = $2;
255 $$ = gt;
258 if_statement: "if" '(' exp ')' statement else_statement {
259 ozulis::ast::If * ifStmt = new ozulis::ast::If();
260 assert($3);
261 assert($5);
262 assert($6);
263 ifStmt->branch = new ozulis::ast::ConditionalBranch;
264 ifStmt->branch->cond = $3;
265 ifStmt->trueBlock = $5;
266 ifStmt->falseBlock = $6;
267 $$ = ifStmt;
270 else_statement: "else" statement {
271 $$ = $2;
272 } | /* epsylon */ { $$ = new ozulis::ast::EmptyStatement; };
274 while_statement: "while" '(' exp ')' statement {
275 ozulis::ast::While * whileStmt = new ozulis::ast::While;
276 assert($3);
277 assert($5);
278 whileStmt->branch = new ozulis::ast::ConditionalBranch;
279 whileStmt->branch->cond = $3;
280 whileStmt->block = $5;
281 $$ = whileStmt;
284 do_while_statement: "do" statement "while" '(' exp ')' ';' {
285 ozulis::ast::DoWhile * doWhileStmt = new ozulis::ast::DoWhile;
286 assert($2);
287 assert($5);
288 doWhileStmt->branch = new ozulis::ast::ConditionalBranch;
289 doWhileStmt->branch->cond = $5;
290 doWhileStmt->block = $2;
291 $$ = doWhileStmt;
294 return_statement: "return" ';' {
295 ozulis::ast::Return * ret = new ozulis::ast::Return;
296 ret->exp = new ozulis::ast::VoidExp;
297 ret->exp->type = new ozulis::ast::VoidType;
298 $$ = ret;
299 } | "return" exp ';' {
300 ozulis::ast::Return * ret = new ozulis::ast::Return;
301 ret->exp = $2;
302 $$ = ret;
305 type: ID {
306 $$ = createType($1);
307 } | CONST type {
308 $2->isConst = true;
309 $$ = $2;
310 } | '@' type {
311 ozulis::ast::PointerType * type = new ozulis::ast::PointerType;
312 type->type = $2;
313 $$ = type;
314 } | '{' NUMBER ',' type '}' {
315 ozulis::ast::ArrayType * type = new ozulis::ast::ArrayType;
316 type->type = $4;
317 type->size = $2->number;
318 $$ = type;
321 exp: assign_exp {
322 assert($1);
323 $$ = $1;
326 assign_exp: exp '=' oror_exp {
327 ozulis::ast::AssignExp * exp = new ozulis::ast::AssignExp();
328 exp->dest = $1;
329 exp->value = $3;
330 $$ = exp;
331 } | oror_exp { assert($1); $$ = $1; };
333 oror_exp: oror_exp "||" andand_exp { MAKE_BINARY_EXP(OrOrExp, $$, $1, $3); }
334 | andand_exp { assert($1); $$ = $1; };
336 andand_exp: andand_exp "&&" or_exp { MAKE_BINARY_EXP(AndAndExp, $$, $1, $3); }
337 | or_exp { assert($1); $$ = $1; };
339 or_exp: or_exp '|' xor_exp { MAKE_BINARY_EXP(OrExp, $$, $1, $3); }
340 | xor_exp { assert($1); $$ = $1; };
342 xor_exp: xor_exp '^' and_exp { MAKE_BINARY_EXP(XorExp, $$, $1, $3); }
343 | and_exp { assert($1); $$ = $1; };
345 and_exp: and_exp '&' cmp_exp { MAKE_BINARY_EXP(AndExp, $$, $1, $3); }
346 | cmp_exp { assert($1); $$ = $1; };
348 cmp_exp: shift_exp "==" shift_exp { MAKE_BINARY_EXP(EqExp, $$, $1, $3); }
349 | shift_exp "!=" shift_exp { MAKE_BINARY_EXP(NeqExp, $$, $1, $3); }
350 | shift_exp '<' shift_exp { MAKE_BINARY_EXP(LtExp, $$, $1, $3); }
351 | shift_exp "<=" shift_exp { MAKE_BINARY_EXP(LtEqExp, $$, $1, $3); }
352 | shift_exp '>' shift_exp { MAKE_BINARY_EXP(GtExp, $$, $1, $3); }
353 | shift_exp ">=" shift_exp { MAKE_BINARY_EXP(GtEqExp, $$, $1, $3); }
354 | shift_exp { assert($1); $$ = $1; };
356 shift_exp: shift_exp "<<" add_exp { MAKE_BINARY_EXP(ShlExp, $$, $1, $3); }
357 | shift_exp ">>>" add_exp { MAKE_BINARY_EXP(AShrExp, $$, $1, $3); }
358 | shift_exp ">>" add_exp { MAKE_BINARY_EXP(LShrExp, $$, $1, $3); }
359 | add_exp { assert($1); $$ = $1; };
361 add_exp: add_exp '+' mul_exp { MAKE_BINARY_EXP(AddExp, $$, $1, $3); }
362 | add_exp '-' mul_exp { MAKE_BINARY_EXP(SubExp, $$, $1, $3); }
363 | mul_exp { assert($1); $$ = $1; };
365 mul_exp: mul_exp '*' unary_exp { MAKE_BINARY_EXP(MulExp, $$, $1, $3); }
366 | mul_exp '/' unary_exp { MAKE_BINARY_EXP(DivExp, $$, $1, $3); }
367 | mul_exp '%' unary_exp { MAKE_BINARY_EXP(ModExp, $$, $1, $3); }
368 | unary_exp { assert($1); $$ = $1; };
370 unary_exp: NUMBER { $$ = $1; }
371 | ID {
372 ozulis::ast::IdExp * exp = new ozulis::ast::IdExp;
373 exp->symbol = new ozulis::ast::Symbol;
374 exp->symbol->name = $1;
375 $$ = exp;
376 } | STRING {
377 ozulis::ast::StringExp * exp = new ozulis::ast::StringExp;
378 exp->string = $1;
379 $$ = exp;
380 } | '(' exp ')' { assert($2); $$ = $2; }
381 | '!' unary_exp { MAKE_UNARY_EXP(BangExp, $$, $2); }
382 | '~' unary_exp { MAKE_UNARY_EXP(NotExp, $$, $2); }
383 | '-' unary_exp { MAKE_UNARY_EXP(NegExp, $$, $2); }
384 | call_exp { $$ = $1; }
385 | "cast" '(' type ',' exp ')' {
386 ozulis::ast::CastExp * cast = new ozulis::ast::CastExp;
387 assert($3);
388 assert($5);
389 cast->type = $3;
390 cast->exp = $5;
391 $$ = cast;
392 } | unary_exp '$' {
393 ozulis::ast::DereferenceExp * exp = new ozulis::ast::DereferenceExp;
394 exp->exp = $1;
395 $$ = exp;
396 } | '@' unary_exp {
397 ozulis::ast::AtExp * exp = new ozulis::ast::AtExp;
398 exp->exp = $2;
399 $$ = exp;
400 } | unary_exp '{' exp '}' {
401 ozulis::ast::DereferenceByIndexExp * exp = new ozulis::ast::DereferenceByIndexExp;
402 exp->exp = $1;
403 exp->index = $3;
404 $$ = exp;
407 call_exp: ID '(' call_exp_args ')' {
408 assert($1);
409 assert($3);
411 ozulis::ast::CallExp * callExp = new ozulis::ast::CallExp;
412 callExp->id = $1;
413 callExp->args = $3;
414 $$ = callExp;
417 call_exp_args: call_exp_args_non_empty { $$ = $1; }
418 | /* empty */ { $$ = new std::vector<ozulis::ast::Exp *>(); };
420 call_exp_args_non_empty: exp {
421 assert($1);
422 $$ = new std::vector<ozulis::ast::Exp *>();
423 $$->push_back($1);
424 } | call_exp_args_non_empty ',' exp {
425 assert($1);
426 assert($3);
427 $1->push_back($3);
428 $$ = $1;