1 #include <msp/strings/format.h>
2 #include <msp/strings/regex.h>
3 #include "programparser.h"
10 using namespace ProgramSyntax;
12 ProgramParser::Operator ProgramParser::operators[] =
14 { "[", 2, BINARY, LEFT_TO_RIGHT },
15 { "(", 2, BINARY, LEFT_TO_RIGHT },
16 { ".", 2, BINARY, LEFT_TO_RIGHT },
17 { "++", 2, POSTFIX, LEFT_TO_RIGHT },
18 { "--", 2, POSTFIX, LEFT_TO_RIGHT },
19 { "++", 3, PREFIX, RIGHT_TO_LEFT },
20 { "--", 3, PREFIX, RIGHT_TO_LEFT },
21 { "+", 3, PREFIX, RIGHT_TO_LEFT },
22 { "-", 3, PREFIX, RIGHT_TO_LEFT },
23 { "~", 3, PREFIX, RIGHT_TO_LEFT },
24 { "!", 3, PREFIX, RIGHT_TO_LEFT },
25 { "*", 4, BINARY, LEFT_TO_RIGHT },
26 { "/", 4, BINARY, LEFT_TO_RIGHT },
27 { "%", 4, BINARY, LEFT_TO_RIGHT },
28 { "+", 5, BINARY, LEFT_TO_RIGHT },
29 { "-", 5, BINARY, LEFT_TO_RIGHT },
30 { "<<", 6, BINARY, LEFT_TO_RIGHT },
31 { ">>", 6, BINARY, LEFT_TO_RIGHT },
32 { "<", 7, BINARY, LEFT_TO_RIGHT },
33 { ">", 7, BINARY, LEFT_TO_RIGHT },
34 { "<=", 7, BINARY, LEFT_TO_RIGHT },
35 { ">=", 7, BINARY, LEFT_TO_RIGHT },
36 { "==", 8, BINARY, LEFT_TO_RIGHT },
37 { "!=", 8, BINARY, LEFT_TO_RIGHT },
38 { "&", 9, BINARY, LEFT_TO_RIGHT },
39 { "^", 10, BINARY, LEFT_TO_RIGHT },
40 { "|", 11, BINARY, LEFT_TO_RIGHT },
41 { "&&", 12, BINARY, LEFT_TO_RIGHT },
42 { "^^", 13, BINARY, LEFT_TO_RIGHT },
43 { "||", 14, BINARY, LEFT_TO_RIGHT },
44 { "?", 15, BINARY, RIGHT_TO_LEFT },
45 { ":", 15, BINARY, RIGHT_TO_LEFT },
46 { "=", 16, BINARY, RIGHT_TO_LEFT },
47 { "+=", 16, BINARY, RIGHT_TO_LEFT },
48 { "-=", 16, BINARY, RIGHT_TO_LEFT },
49 { "*=", 16, BINARY, RIGHT_TO_LEFT },
50 { "/=", 16, BINARY, RIGHT_TO_LEFT },
51 { "%=", 16, BINARY, RIGHT_TO_LEFT },
52 { "<<=", 16, BINARY, RIGHT_TO_LEFT },
53 { ">>=", 16, BINARY, RIGHT_TO_LEFT },
54 { "&=", 16, BINARY, RIGHT_TO_LEFT },
55 { "^=", 16, BINARY, RIGHT_TO_LEFT },
56 { "|=", 16, BINARY, RIGHT_TO_LEFT },
57 { ",", 17, BINARY, LEFT_TO_RIGHT },
58 { { 0 }, 18, NO_OPERATOR, LEFT_TO_RIGHT }
61 Module &ProgramParser::parse(const string &s)
64 parse_source(main_module);
68 Module &ProgramParser::parse(IO::Base &io)
74 unsigned len = io.read(buffer, sizeof(buffer));
75 source.append(buffer, len);
77 parse_source(main_module);
81 void ProgramParser::parse_source(Module &module)
84 cur_stage = &module.shared;
85 iter = source.begin();
88 while(Node *statement = parse_global_declaration())
89 cur_stage->content.body.push_back(statement);
90 cur_stage->present = !cur_stage->content.body.empty();
92 Stage *prev_stage = cur_stage;
94 string token = parse_token();
97 else if(token=="global")
98 cur_stage = &module.shared;
99 else if(token=="vertex")
100 cur_stage = &module.vertex_stage;
101 else if(token=="geometry")
102 cur_stage = &module.geometry_stage;
103 else if(token=="fragment")
104 cur_stage = &module.fragment_stage;
106 throw runtime_error(format("Parse error at '%s': expected stage identifier", token));
107 cur_stage->previous = prev_stage;
109 for(; (iter!=source.end() && *iter!='\n'); ++iter) ;
113 const string &ProgramParser::peek_token(unsigned index)
115 while(next_tokens.size()<=index)
116 next_tokens.push_back(parse_token_());
117 return next_tokens[index];
120 string ProgramParser::parse_token()
122 if(!next_tokens.empty())
124 string token = next_tokens.front();
125 next_tokens.pop_front();
129 return parse_token_();
132 string ProgramParser::parse_token_()
134 if(!skip_comment_and_whitespace())
137 if(isalpha(*iter) || *iter=='_')
138 return parse_identifier();
139 else if(isdigit(*iter))
140 return parse_number();
142 return parse_other();
145 string ProgramParser::parse_identifier()
148 while(iter!=source.end())
150 if(isalnum(*iter) || *iter=='_')
159 string ProgramParser::parse_number()
161 bool accept_sign = false;
163 while(iter!=source.end())
165 if(isdigit(*iter) || *iter=='.')
167 else if(*iter=='e' || *iter=='E')
172 else if(accept_sign && (*iter=='+' || *iter=='-'))
181 string ProgramParser::parse_other()
183 if(iter==source.end())
186 string token(1, *iter++);
187 for(unsigned i=1; (i<3 && iter!=source.end()); ++i)
189 bool matched = false;
190 for(const Operator *j=operators; (!matched && j->type); ++j)
192 matched = (j->token[i]==*iter);
193 for(unsigned k=0; (matched && k<i && j->token[k]); ++k)
194 matched = (j->token[k]==token[k]);
206 bool ProgramParser::skip_comment_and_whitespace()
208 unsigned comment = 0;
209 unsigned slashes = 0;
210 while(iter!=source.end())
212 //IO::print("%d '%c'\n", comment, *iter);
217 else if(!isspace(*iter))
242 else if(!isspace(*iter) && slashes>=6)
245 else if(comment==3 && *iter=='*')
258 return iter!=source.end();
261 void ProgramParser::expect(const string &token)
263 string parsed = parse_token();
265 throw runtime_error(format("Parse error at '%s': expected '%s'", parsed, token));
268 string ProgramParser::expect_type()
270 string token = parse_token();
272 throw runtime_error(format("Parse error at '%s': expected a type", token));
276 string ProgramParser::expect_identifier()
278 string token = parse_token();
279 if(!is_identifier(token))
280 throw runtime_error(format("Parse error at '%s': expected an identifier", token));
284 bool ProgramParser::check(const string &token)
286 bool result = (peek_token()==token);
292 bool ProgramParser::is_interface_qualifier(const string &token)
294 return (token=="uniform" || token=="in" || token=="out");
297 bool ProgramParser::is_sampling_qualifier(const string &token)
299 return token=="centroid";
302 bool ProgramParser::is_qualifier(const string &token)
304 return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token));
307 bool ProgramParser::is_builtin_type(const string &token)
309 static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D)(Array)?(Shadow)?|Cube(Shadow)?|3D))$");
310 return re.match(token);
313 bool ProgramParser::is_type(const string &token)
315 return is_builtin_type(token) || declared_types.count(token);
318 bool ProgramParser::is_identifier(const string &token)
320 static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
321 return re.match(token);
324 Node *ProgramParser::parse_global_declaration()
326 string token = peek_token();
328 return parse_layout();
329 else if(token=="struct")
330 return parse_struct_declaration();
331 else if(is_sampling_qualifier(token) || token=="const")
332 return parse_variable_declaration();
333 else if(is_interface_qualifier(token))
335 if(is_type(peek_token(1)))
336 return parse_variable_declaration();
338 return parse_interface_block();
340 else if(is_type(token))
342 if(peek_token(2)=="(")
343 return parse_function_declaration();
345 return parse_variable_declaration();
347 else if(token.empty())
350 throw runtime_error(format("Syntax error at '%s': expected a global declaration", token));
353 Node *ProgramParser::parse_statement()
355 string token = peek_token();
357 return parse_conditional();
358 else if(token=="for")
359 return parse_iteration();
360 else if(token=="passthrough")
361 return parse_passthrough();
362 else if(token=="return")
363 return parse_return();
364 else if(is_qualifier(token) || is_type(token))
365 return parse_variable_declaration();
366 else if(!token.empty())
368 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
369 expr->expression = parse_expression();
372 return expr.release();
375 throw runtime_error(format("Syntax error at '%s': expected a statement", token));
378 Layout *ProgramParser::parse_layout()
382 RefPtr<Layout> layout = new Layout;
385 string token = parse_token();
387 throw runtime_error(format("Parse error at '%s': expected layout qualifier id", token));
389 layout->qualifiers.push_back(Layout::Qualifier());
390 Layout::Qualifier &qual = layout->qualifiers.back();
391 qual.identifier = token;
394 qual.value = parse_token();
396 if(peek_token()==")")
402 layout->interface = parse_token();
405 return layout.release();
408 void ProgramParser::parse_block(Block &block, bool require_braces)
410 bool have_braces = (require_braces || peek_token()=="{");
416 while(peek_token()!="}")
417 block.body.push_back(parse_statement());
420 block.body.push_back(parse_statement());
422 block.use_braces = (require_braces || block.body.size()!=1);
428 Expression *ProgramParser::parse_expression(unsigned precedence)
430 RefPtr<Expression> left;
431 VariableReference *left_var = 0;
434 string token = peek_token();
436 const Operator *oper = 0;
437 for(Operator *i=operators; (!oper && i->type); ++i)
438 if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX))
441 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
444 return left.release();
446 throw runtime_error(format("Parse error at '%s': expected an expression", token));
453 throw runtime_error(format("Parse error at '%s': function name must be an identifier", token));
454 left = parse_function_call(left_var);
458 RefPtr<MemberAccess> memacc = new MemberAccess;
459 memacc->left = left.release();
461 memacc->member = expect_identifier();
464 else if(oper && oper->type==POSTFIX)
466 RefPtr<UnaryExpression> unary = new UnaryExpression;
467 unary->oper = parse_token();
468 unary->prefix = false;
469 unary->expression = left.release();
472 else if(oper && oper->type==BINARY)
473 left = parse_binary(left.release(), oper);
475 throw runtime_error(format("Parse error at '%s': expected an operator", token));
483 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
484 parexpr->expression = parse_expression();
488 else if(is_identifier(token))
490 RefPtr<VariableReference> var = new VariableReference;
491 var->name = expect_identifier();
493 left_var = var.get();
495 else if(oper && oper->type==PREFIX)
497 RefPtr<UnaryExpression> unary = new UnaryExpression;
498 unary->oper = parse_token();
499 unary->prefix = true;
500 unary->expression = parse_expression(oper->precedence);
503 else if(isdigit(token[0]))
505 RefPtr<Literal> literal = new Literal;
506 literal->token = parse_token();
510 throw runtime_error(format("Parse error at '%s': expected an expression", token));
515 BinaryExpression *ProgramParser::parse_binary(Expression *left, const Operator *oper)
517 RefPtr<BinaryExpression> binary = new BinaryExpression;
519 binary->oper = parse_token();
520 if(binary->oper=="[")
522 binary->right = parse_expression();
527 binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT));
528 binary->assignment = (oper->precedence==16);
529 return binary.release();
532 FunctionCall *ProgramParser::parse_function_call(VariableReference *var)
534 RefPtr<FunctionCall> call = new FunctionCall;
535 call->name = var->name;
536 call->constructor = is_type(call->name);
538 while(peek_token()!=")")
540 if(!call->arguments.empty())
542 call->arguments.push_back(parse_expression());
545 return call.release();
548 StructDeclaration *ProgramParser::parse_struct_declaration()
551 RefPtr<StructDeclaration> strct = new StructDeclaration;
553 strct->name = expect_identifier();
554 parse_block(strct->members, true);
557 declared_types.insert(strct->name);
558 return strct.release();
561 VariableDeclaration *ProgramParser::parse_variable_declaration()
563 RefPtr<VariableDeclaration> var = new VariableDeclaration;
565 string token = peek_token();
566 if(is_sampling_qualifier(token))
568 var->sampling = parse_token();
569 token = peek_token();
570 if(!is_interface_qualifier(token))
571 throw runtime_error(format("Parse error at '%s': expected an interface qualifier", token));
574 if(is_interface_qualifier(token))
575 var->interface = parse_token();
576 else if(token=="const")
578 var->constant = true;
582 var->type = expect_type();
583 var->name = expect_identifier();
590 var->array_size = parse_expression();
596 var->init_expression = parse_expression();
599 return var.release();
602 FunctionDeclaration *ProgramParser::parse_function_declaration()
604 RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
606 func->return_type = expect_type();
607 func->name = expect_identifier();
608 parse_function_parameter_list(*func);
610 string token = peek_token();
613 func->definition = true;
614 parse_block(func->body, true);
619 throw runtime_error(format("Parse error at '%s': expected '{' or ';'", token));
621 return func.release();
624 void ProgramParser::parse_function_parameter_list(FunctionDeclaration &func)
627 while(peek_token()!=")")
629 if(!func.parameters.empty())
632 RefPtr<VariableDeclaration> var = new VariableDeclaration;
633 var->type = expect_type();
634 var->name = expect_identifier();
635 func.parameters.push_back(var.release());
640 InterfaceBlock *ProgramParser::parse_interface_block()
642 RefPtr<InterfaceBlock> iface = new InterfaceBlock;
644 iface->interface = parse_token();
645 if(!is_interface_qualifier(iface->interface))
646 throw runtime_error(format("Parse error at '%s': expected an interface qualifier", iface->interface));
648 iface->name = expect_identifier();
649 parse_block(iface->members, true);
652 return iface.release();
655 Conditional *ProgramParser::parse_conditional()
659 RefPtr<Conditional> cond = new Conditional;
660 cond->condition = parse_expression();
663 parse_block(cond->body, false);
665 string token = peek_token();
669 parse_block(cond->else_body, false);
672 return cond.release();
675 Iteration *ProgramParser::parse_iteration()
679 RefPtr<Iteration> loop = new Iteration;
680 string token = peek_token();
682 loop->init_statement = parse_statement();
685 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
686 expr->expression = parse_expression();
688 loop->init_statement = expr.release();
690 loop->condition = parse_expression();
692 loop->loop_expression = parse_expression();
695 parse_block(loop->body, false);
697 return loop.release();
700 Passthrough *ProgramParser::parse_passthrough()
702 expect("passthrough");
703 RefPtr<Passthrough> pass = new Passthrough;
704 if(cur_stage->type==GEOMETRY)
707 pass->subscript = parse_expression();
711 return pass.release();
714 Return *ProgramParser::parse_return()
717 RefPtr<Return> ret = new Return;
718 ret->expression = parse_expression();
720 return ret.release();