1 #include <msp/core/raii.h>
2 #include <msp/strings/format.h>
3 #include <msp/strings/regex.h>
14 Parser::Operator Parser::operators[] =
16 { "[", 2, BINARY, LEFT_TO_RIGHT },
17 { "(", 2, BINARY, LEFT_TO_RIGHT },
18 { ".", 2, BINARY, LEFT_TO_RIGHT },
19 { "++", 2, POSTFIX, LEFT_TO_RIGHT },
20 { "--", 2, POSTFIX, LEFT_TO_RIGHT },
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 { "~", 3, PREFIX, RIGHT_TO_LEFT },
26 { "!", 3, PREFIX, RIGHT_TO_LEFT },
27 { "*", 4, BINARY, LEFT_TO_RIGHT },
28 { "/", 4, BINARY, LEFT_TO_RIGHT },
29 { "%", 4, BINARY, LEFT_TO_RIGHT },
30 { "+", 5, BINARY, LEFT_TO_RIGHT },
31 { "-", 5, BINARY, LEFT_TO_RIGHT },
32 { "<<", 6, BINARY, LEFT_TO_RIGHT },
33 { ">>", 6, BINARY, LEFT_TO_RIGHT },
34 { "<", 7, BINARY, LEFT_TO_RIGHT },
35 { ">", 7, BINARY, LEFT_TO_RIGHT },
36 { "<=", 7, BINARY, LEFT_TO_RIGHT },
37 { ">=", 7, BINARY, LEFT_TO_RIGHT },
38 { "==", 8, BINARY, LEFT_TO_RIGHT },
39 { "!=", 8, BINARY, LEFT_TO_RIGHT },
40 { "&", 9, BINARY, LEFT_TO_RIGHT },
41 { "^", 10, BINARY, LEFT_TO_RIGHT },
42 { "|", 11, BINARY, LEFT_TO_RIGHT },
43 { "&&", 12, BINARY, LEFT_TO_RIGHT },
44 { "^^", 13, BINARY, LEFT_TO_RIGHT },
45 { "||", 14, BINARY, LEFT_TO_RIGHT },
46 { "?", 15, BINARY, RIGHT_TO_LEFT },
47 { ":", 15, 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 { "^=", 16, BINARY, RIGHT_TO_LEFT },
58 { "|=", 16, BINARY, RIGHT_TO_LEFT },
59 { ",", 17, BINARY, LEFT_TO_RIGHT },
60 { { 0 }, 18, NO_OPERATOR, LEFT_TO_RIGHT }
72 Module &Parser::parse(const string &s, const string &n, unsigned i)
81 Module &Parser::parse(IO::Base &io, const string &n, unsigned i)
89 unsigned len = io.read(buffer, sizeof(buffer));
90 source.append(buffer, len);
96 void Parser::parse_source()
100 string::size_type slashes = source.find("//////");
101 if(slashes==string::npos)
104 string::size_type newline = source.find('\n', slashes);
105 string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6));
106 source.replace(slashes, newline-slashes, pragma);
111 cur_stage = &module->shared;
112 iter = source.begin();
113 source_end = source.end();
115 allow_preprocess = true;
116 while(RefPtr<Statement> statement = parse_global_declaration())
117 cur_stage->content.body.push_back(statement);
120 string Parser::format_error(const std::string &message)
122 string location = format("%s:%d: ", source_name, current_line);
123 return location+message;
126 string Parser::format_syntax_error(const std::string &expected)
128 return format_error(format("Syntax error at '%s': expected %s", last_token, expected));
131 const string &Parser::peek_token(unsigned index)
133 while(next_tokens.size()<=index)
134 next_tokens.push_back(parse_token_());
135 return (last_token = next_tokens[index]);
138 const string &Parser::parse_token()
140 if(!next_tokens.empty())
142 last_token = next_tokens.front();
143 next_tokens.pop_front();
147 return (last_token = parse_token_());
150 string Parser::parse_token_()
154 skip_comment_and_whitespace();
157 else if(allow_preprocess && *iter=='#')
159 allow_preprocess = false;
160 SetForScope<deque<string> > clear_tokens(next_tokens, deque<string>());
163 else if(isalpha(*iter) || *iter=='_')
164 return parse_identifier();
165 else if(isdigit(*iter))
166 return parse_number();
168 return parse_other();
172 string Parser::parse_identifier()
175 while(iter!=source_end)
177 if(isalnum(*iter) || *iter=='_')
186 string Parser::parse_number()
188 bool accept_sign = false;
190 while(iter!=source_end)
192 if(isdigit(*iter) || *iter=='.')
194 else if(*iter=='e' || *iter=='E')
199 else if(accept_sign && (*iter=='+' || *iter=='-'))
208 string Parser::parse_other()
213 string token(1, *iter++);
214 for(unsigned i=1; (i<3 && iter!=source_end); ++i)
216 bool matched = false;
217 for(const Operator *j=operators; (!matched && j->type); ++j)
219 matched = (j->token[i]==*iter);
220 for(unsigned k=0; (matched && k<i && j->token[k]); ++k)
221 matched = (j->token[k]==token[k]);
233 void Parser::skip_comment_and_whitespace()
235 unsigned comment = 0;
236 while(iter!=source_end)
242 else if(!isspace(*iter))
263 else if(comment==3 && *iter=='*')
276 allow_preprocess = (comment<3);
283 void Parser::expect(const string &token)
285 string parsed = parse_token();
287 throw runtime_error(format_syntax_error(format("'%s'", token)));
290 string Parser::expect_type()
292 string token = parse_token();
294 throw runtime_error(format_syntax_error("a type"));
298 string Parser::expect_identifier()
300 string token = parse_token();
301 if(!is_identifier(token))
302 throw runtime_error(format_syntax_error("an identifier"));
306 bool Parser::check(const string &token)
308 bool result = (peek_token()==token);
314 bool Parser::is_interface_qualifier(const string &token)
316 return (token=="uniform" || token=="in" || token=="out");
319 bool Parser::is_sampling_qualifier(const string &token)
321 return (token=="centroid" || token=="sample");
324 bool Parser::is_interpolation_qualifier(const string &token)
326 return (token=="smooth" || token=="flat" || token=="noperspective");
329 bool Parser::is_precision_qualifier(const string &token)
331 return (token=="highp" || token=="mediump" || token=="lowp");
334 bool Parser::is_qualifier(const string &token)
336 return (token=="const" ||
337 is_interface_qualifier(token) ||
338 is_sampling_qualifier(token) ||
339 is_interpolation_qualifier(token) ||
340 is_precision_qualifier(token));
343 bool Parser::is_builtin_type(const string &token)
345 static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D|Cube)(Array)?(Shadow)?|3D))$");
346 return re.match(token);
349 bool Parser::is_type(const string &token)
351 return is_builtin_type(token) || declared_types.count(token);
354 bool Parser::is_identifier(const string &token)
356 static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
357 return re.match(token);
360 void Parser::preprocess()
364 string::const_iterator line_end = iter;
365 for(; (line_end!=source_end && *line_end!='\n'); ++line_end) ;
366 SetForScope<string::const_iterator> stop_at_line_end(source_end, line_end);
368 string token = peek_token();
371 else if(token=="version")
372 preprocess_version();
373 else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" ||
374 token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="line")
375 throw runtime_error(format_error(format("Unsupported preprocessor directive '%s'", token)));
376 else if(!token.empty())
377 throw runtime_error(format_syntax_error("a preprocessor directive"));
382 void Parser::preprocess_version()
385 string token = parse_token();
386 unsigned version = lexical_cast<unsigned>(token);
387 cur_stage->required_version = Version(version/100, version%100);
389 token = parse_token();
391 throw runtime_error(format_syntax_error("end of line"));
394 void Parser::preprocess_pragma()
397 string token = parse_token();
399 preprocess_pragma_msp();
402 void Parser::preprocess_pragma_msp()
404 string token = peek_token();
408 throw runtime_error(format_error(format("Unrecognized MSP pragma '%s'", token)));
410 token = parse_token();
412 throw runtime_error(format_syntax_error("end of line"));
415 void Parser::preprocess_stage()
417 if(!allow_stage_change)
418 throw runtime_error(format_error("Changing stage not allowed here"));
422 string token = expect_identifier();
423 StageType stage = SHARED;
426 else if(token=="geometry")
428 else if(token=="fragment")
431 throw runtime_error(format_syntax_error("stage identifier"));
434 if(stage<=cur_stage->type)
435 throw runtime_error(format_error(format("Stage '%s' not allowed here", token)));
437 module->stages.push_back(stage);
439 if(cur_stage->type!=SHARED)
440 module->stages.back().previous = cur_stage;
441 cur_stage = &module->stages.back();
444 RefPtr<Statement> Parser::parse_global_declaration()
446 allow_stage_change = true;
447 string token = peek_token();
448 allow_stage_change = false;
451 return parse_import();
452 else if(token=="precision")
453 return parse_precision();
454 else if(token=="layout")
456 RefPtr<Layout> layout = parse_layout();
457 token = peek_token();
458 if(is_interface_qualifier(token) && peek_token(1)==";")
460 RefPtr<InterfaceLayout> iface_lo = new InterfaceLayout;
461 iface_lo->source = source_index;
462 iface_lo->line = current_line;
463 iface_lo->layout.qualifiers = layout->qualifiers;
464 iface_lo->interface = parse_token();
470 RefPtr<VariableDeclaration> var = parse_variable_declaration();
471 var->layout = layout;
475 else if(token=="struct")
476 return parse_struct_declaration();
477 else if(is_interface_qualifier(token))
479 string next = peek_token(1);
480 if(is_type(next) || is_qualifier(next))
481 return parse_variable_declaration();
483 return parse_interface_block();
485 else if(is_qualifier(token))
486 return parse_variable_declaration();
487 else if(is_type(token))
489 if(peek_token(2)=="(")
490 return parse_function_declaration();
492 return parse_variable_declaration();
494 else if(token.empty())
497 throw runtime_error(format_syntax_error("a global declaration"));
500 RefPtr<Statement> Parser::parse_statement()
502 string token = peek_token();
504 return parse_conditional();
505 else if(token=="for")
507 else if(token=="while")
508 return parse_while();
509 else if(token=="passthrough")
510 return parse_passthrough();
511 else if(token=="return")
512 return parse_return();
513 else if(token=="break" || token=="continue" || token=="discard")
515 RefPtr<Jump> jump = new Jump;
516 jump->source = source_index;
517 jump->line = current_line;
518 jump->keyword = parse_token();
523 else if(is_qualifier(token) || is_type(token))
524 return parse_variable_declaration();
525 else if(!token.empty())
527 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
528 expr->source = source_index;
529 expr->line = current_line;
530 expr->expression = parse_expression();
536 throw runtime_error(format_syntax_error("a statement"));
539 RefPtr<Import> Parser::parse_import()
541 if(cur_stage->type!=SHARED)
542 throw runtime_error(format_error("Imports are only allowed in the shared section"));
545 RefPtr<Import> import = new Import;
546 import->source = source_index;
547 import->line = current_line;
548 import->module = expect_identifier();
553 RefPtr<Precision> Parser::parse_precision()
556 RefPtr<Precision> precision = new Precision;
557 precision->source = source_index;
558 precision->line = current_line;
560 precision->precision = parse_token();
561 if(!is_precision_qualifier(precision->precision))
562 throw runtime_error(format_syntax_error("a precision qualifier"));
564 precision->type = parse_token();
565 // Not entirely accurate; only float, int and sampler types are allowed
566 if(!is_builtin_type(precision->type))
567 throw runtime_error(format_syntax_error("a builtin type"));
574 RefPtr<Layout> Parser::parse_layout()
578 RefPtr<Layout> layout = new Layout;
581 string token = parse_token();
583 throw runtime_error(format_syntax_error("a layout qualifier name"));
585 layout->qualifiers.push_back(Layout::Qualifier());
586 Layout::Qualifier &qual = layout->qualifiers.back();
587 qual.identifier = token;
590 qual.value = parse_token();
592 if(peek_token()==")")
602 void Parser::parse_block(Block &block, bool require_braces)
604 bool have_braces = (require_braces || peek_token()=="{");
610 while(peek_token()!="}")
611 block.body.push_back(parse_statement());
614 block.body.push_back(parse_statement());
616 block.use_braces = (require_braces || block.body.size()!=1);
622 RefPtr<Expression> Parser::parse_expression(unsigned precedence)
624 RefPtr<Expression> left;
625 VariableReference *left_var = 0;
628 string token = peek_token();
630 const Operator *oper = 0;
631 for(Operator *i=operators; (!oper && i->type); ++i)
632 if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX))
635 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
640 throw runtime_error(format_syntax_error("an expression"));
647 throw runtime_error(format_error("Syntax error before '(': function name must be an identifier"));
648 left = parse_function_call(*left_var);
652 RefPtr<MemberAccess> memacc = new MemberAccess;
655 memacc->member = expect_identifier();
658 else if(oper && oper->type==POSTFIX)
660 RefPtr<UnaryExpression> unary = new UnaryExpression;
661 unary->oper = parse_token();
662 unary->prefix = false;
663 unary->expression = left;
666 else if(oper && oper->type==BINARY)
667 left = parse_binary(left, oper);
669 throw runtime_error(format_syntax_error("an operator"));
677 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
678 parexpr->expression = parse_expression();
682 else if(isdigit(token[0]) || token=="true" || token=="false")
684 RefPtr<Literal> literal = new Literal;
685 literal->token = parse_token();
688 else if(is_identifier(token))
690 RefPtr<VariableReference> var = new VariableReference;
691 var->name = expect_identifier();
693 left_var = var.get();
695 else if(oper && oper->type==PREFIX)
697 RefPtr<UnaryExpression> unary = new UnaryExpression;
698 unary->oper = parse_token();
699 unary->prefix = true;
700 unary->expression = parse_expression(oper->precedence);
704 throw runtime_error(format_syntax_error("an expression"));
709 RefPtr<BinaryExpression> Parser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
711 RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
713 binary->oper = parse_token();
714 if(binary->oper=="[")
716 binary->right = parse_expression();
721 binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT));
725 RefPtr<FunctionCall> Parser::parse_function_call(const VariableReference &var)
727 RefPtr<FunctionCall> call = new FunctionCall;
728 call->name = var.name;
729 call->constructor = is_type(call->name);
731 while(peek_token()!=")")
733 if(!call->arguments.empty())
735 call->arguments.push_back(parse_expression());
741 RefPtr<StructDeclaration> Parser::parse_struct_declaration()
744 RefPtr<StructDeclaration> strct = new StructDeclaration;
745 strct->source = source_index;
746 strct->line = current_line;
748 strct->name = expect_identifier();
749 parse_block(strct->members, true);
752 declared_types.insert(strct->name);
756 RefPtr<VariableDeclaration> Parser::parse_variable_declaration()
758 RefPtr<VariableDeclaration> var = new VariableDeclaration;
759 var->source = source_index;
760 var->line = current_line;
762 string token = peek_token();
763 while(is_qualifier(token))
766 if(is_interface_qualifier(token))
767 var->interface = token;
768 else if(is_sampling_qualifier(token))
769 var->sampling = token;
770 else if(is_interpolation_qualifier(token))
771 var->interpolation = token;
772 else if(is_precision_qualifier(token))
773 var->precision = token;
774 else if(token=="const")
775 var->constant = true;
776 token = peek_token();
779 var->type = expect_type();
780 var->name = expect_identifier();
787 var->array_size = parse_expression();
793 var->init_expression = parse_expression();
799 RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
801 RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
802 func->source = source_index;
803 func->line = current_line;
805 func->return_type = expect_type();
806 func->name = expect_identifier();
808 while(peek_token()!=")")
810 if(!func->parameters.empty())
813 RefPtr<VariableDeclaration> var = new VariableDeclaration;
814 string token = peek_token();
815 if(token=="in" || token=="out" || token=="inout")
816 var->interface = parse_token();
817 var->type = expect_type();
818 var->name = expect_identifier();
819 func->parameters.push_back(var);
823 string token = peek_token();
826 func->definition = func.get();
827 parse_block(func->body, true);
832 throw runtime_error(format_syntax_error("'{' or ';'"));
837 RefPtr<InterfaceBlock> Parser::parse_interface_block()
839 RefPtr<InterfaceBlock> iface = new InterfaceBlock;
840 iface->source = source_index;
841 iface->line = current_line;
843 iface->interface = parse_token();
844 if(!is_interface_qualifier(iface->interface))
845 throw runtime_error(format_syntax_error("an interface qualifier"));
847 iface->name = expect_identifier();
848 parse_block(iface->members, true);
851 iface->instance_name = expect_identifier();
863 RefPtr<Conditional> Parser::parse_conditional()
866 RefPtr<Conditional> cond = new Conditional;
867 cond->source = source_index;
868 cond->line = current_line;
870 cond->condition = parse_expression();
873 parse_block(cond->body, false);
875 string token = peek_token();
879 parse_block(cond->else_body, false);
885 RefPtr<Iteration> Parser::parse_for()
888 RefPtr<Iteration> loop = new Iteration;
889 loop->source = source_index;
890 loop->line = current_line;
892 string token = peek_token();
894 loop->init_statement = parse_statement();
899 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
900 expr->expression = parse_expression();
901 loop->init_statement = expr;
905 if(peek_token()!=";")
906 loop->condition = parse_expression();
908 if(peek_token()!=")")
909 loop->loop_expression = parse_expression();
912 parse_block(loop->body, false);
917 RefPtr<Iteration> Parser::parse_while()
920 RefPtr<Iteration> loop = new Iteration;
921 loop->source = source_index;
922 loop->line = current_line;
924 loop->condition = parse_expression();
927 parse_block(loop->body, false);
932 RefPtr<Passthrough> Parser::parse_passthrough()
934 expect("passthrough");
935 RefPtr<Passthrough> pass = new Passthrough;
936 pass->source = source_index;
937 pass->line = current_line;
938 if(cur_stage->type==GEOMETRY)
941 pass->subscript = parse_expression();
948 RefPtr<Return> Parser::parse_return()
951 RefPtr<Return> ret = new Return;
952 ret->source = source_index;
953 ret->line = current_line;
954 if(peek_token()!=";")
955 ret->expression = parse_expression();