1 #include <msp/core/raii.h>
2 #include <msp/strings/format.h>
3 #include <msp/strings/regex.h>
4 #include <msp/strings/utils.h>
5 #include "glsl_error.h"
17 preprocessor(tokenizer),
20 tokenizer.signal_preprocess.connect(sigc::mem_fun(&preprocessor, &Preprocessor::preprocess));
21 preprocessor.signal_version.connect(sigc::mem_fun(this, &Parser::set_required_version));
22 preprocessor.signal_source.connect(sigc::mem_fun(this, &Parser::source_reference));
23 preprocessor.signal_stage_change.connect(sigc::mem_fun(this, &Parser::stage_change));
24 preprocessor.signal_line.connect(sigc::mem_fun(this, &Parser::line_change));
32 Module &Parser::parse(const string &s, const string &n, unsigned i)
39 Module &Parser::parse(IO::Base &io, const string &n, unsigned i)
45 unsigned len = io.read(buffer, sizeof(buffer));
46 source.append(buffer, len);
52 void Parser::parse_source(const string &name, unsigned index)
56 cur_stage = &module->shared;
59 source_reference(1, name);
60 tokenizer.begin(name, source);
61 allow_stage_change = true;
62 while(!tokenizer.peek_token().empty())
63 if(RefPtr<Statement> statement = parse_with_recovery(&Parser::parse_global_declaration))
64 cur_stage->content.body.push_back(statement);
67 throw invalid_shader_source(join(errors.begin(), errors.end(), "\n"));
70 void Parser::set_required_version(const Version &ver)
72 cur_stage->required_features.glsl_version = ver;
75 void Parser::source_reference(unsigned index, const string &name)
78 throw invalid_shader_source(tokenizer.get_location(), "Invalid source reference");
80 module->source_map.set_name(base_index+index-1, name);
83 void Parser::stage_change(Stage::Type stage)
85 if(!allow_stage_change)
86 throw invalid_shader_source(tokenizer.get_location(), "Changing stage not allowed here");
87 else if(stage<=cur_stage->type)
88 throw invalid_shader_source(tokenizer.get_location(), "Stage '%s' not allowed here", Stage::get_stage_name(stage));
90 module->stages.push_back(stage);
92 if(cur_stage->type!=Stage::SHARED)
93 module->stages.back().previous = cur_stage;
94 cur_stage = &module->stages.back();
97 void Parser::line_change(int index, unsigned line)
100 source_index = base_index+index-1;
104 index = source_index;
106 string name = module->source_map.get_name(index);
108 name = format("<%d>", index);
109 tokenizer.set_location(Location(name, line));
112 string Parser::expect_type()
114 string token = tokenizer.parse_token();
116 throw parse_error(tokenizer.get_location(), token, "a type");
120 string Parser::expect_identifier()
122 string token = tokenizer.parse_token();
123 if(!is_identifier(token))
124 throw parse_error(tokenizer.get_location(), token, "an identifier");
128 int Parser::expect_integer()
130 string token = tokenizer.parse_token();
132 throw parse_error(tokenizer.get_location(), token, "an integer literal");
133 return lexical_cast<int>(token);
136 bool Parser::check(const string &token)
138 bool result = (tokenizer.peek_token()==token);
140 tokenizer.parse_token();
144 bool Parser::is_interface_qualifier(const string &token)
146 return (token=="uniform" || token=="in" || token=="out");
149 bool Parser::is_sampling_qualifier(const string &token)
151 return (token=="centroid" || token=="sample");
154 bool Parser::is_interpolation_qualifier(const string &token)
156 return (token=="smooth" || token=="flat" || token=="noperspective");
159 bool Parser::is_precision_qualifier(const string &token)
161 return (token=="highp" || token=="mediump" || token=="lowp");
164 bool Parser::is_qualifier(const string &token)
166 return (token=="const" ||
167 is_interface_qualifier(token) ||
168 is_sampling_qualifier(token) ||
169 is_interpolation_qualifier(token) ||
170 is_precision_qualifier(token));
173 bool Parser::is_builtin_type(const string &token)
175 static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D|Cube)(Array)?(Shadow)?|3D))$");
176 return re.match(token);
179 bool Parser::is_type(const string &token)
181 return is_builtin_type(token) || declared_types.count(token);
184 bool Parser::is_identifier(const string &token)
186 static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
187 return re.match(token);
191 RefPtr<T> Parser::parse_with_recovery(RefPtr<T> (Parser::*parse_func)())
193 tokenizer.clear_progress_mark();
196 return (this->*parse_func)();
198 catch(const invalid_shader_source &exc)
200 errors.push_back(exc.what());
203 if(tokenizer.get_last_token()!=";" || !tokenizer.get_progress_mark())
205 unsigned scope_level = 0;
208 if(tokenizer.peek_token()=="}" && scope_level==0)
210 if(!tokenizer.get_progress_mark())
211 tokenizer.parse_token();
215 string token = tokenizer.parse_token();
224 else if(token==";" && scope_level==0)
226 else if(token.empty())
234 RefPtr<Statement> Parser::parse_global_declaration()
236 string token = tokenizer.peek_token();
237 SetFlag disallow(allow_stage_change, false);
240 return parse_import();
241 else if(token=="precision")
242 return parse_precision();
243 else if(token=="layout")
245 RefPtr<Layout> layout = parse_layout();
246 token = tokenizer.peek_token();
247 if(is_interface_qualifier(token) && tokenizer.peek_token(1)==";")
249 RefPtr<InterfaceLayout> iface_lo = new InterfaceLayout;
250 iface_lo->source = source_index;
251 iface_lo->line = tokenizer.get_location().line;
252 iface_lo->layout.qualifiers = layout->qualifiers;
253 iface_lo->interface = tokenizer.parse_token();
254 tokenizer.expect(";");
259 RefPtr<VariableDeclaration> var = parse_variable_declaration();
260 var->layout = layout;
264 else if(token=="struct")
265 return parse_struct_declaration();
266 else if(is_interface_qualifier(token))
268 string next = tokenizer.peek_token(1);
269 if(is_type(next) || is_qualifier(next))
270 return parse_variable_declaration();
272 return parse_interface_block();
274 else if(is_qualifier(token))
275 return parse_variable_declaration();
276 else if(is_type(token))
278 if(tokenizer.peek_token(2)=="(")
279 return parse_function_declaration();
281 return parse_variable_declaration();
283 else if(token.empty())
286 throw parse_error(tokenizer.get_location(), token, "a global declaration");
289 RefPtr<Statement> Parser::parse_statement()
291 string token = tokenizer.peek_token();
293 return parse_conditional();
294 else if(token=="for")
296 else if(token=="while")
297 return parse_while();
298 else if(token=="passthrough")
299 return parse_passthrough();
300 else if(token=="return")
301 return parse_return();
302 else if(token=="break" || token=="continue" || token=="discard")
304 RefPtr<Jump> jump = new Jump;
305 jump->source = source_index;
306 jump->line = tokenizer.get_location().line;
307 jump->keyword = tokenizer.parse_token();
308 tokenizer.expect(";");
312 else if(is_qualifier(token) || is_type(token))
313 return parse_variable_declaration();
316 tokenizer.parse_token();
317 throw invalid_shader_source(tokenizer.get_location(), "Empty statement not allowed");
319 else if(!token.empty())
321 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
322 expr->source = source_index;
323 expr->line = tokenizer.get_location().line;
324 expr->expression = parse_expression();
325 tokenizer.expect(";");
330 throw parse_error(tokenizer.get_location(), token, "a statement");
333 RefPtr<Import> Parser::parse_import()
335 if(cur_stage->type!=Stage::SHARED)
336 throw invalid_shader_source(tokenizer.get_location(), "Imports are only allowed in the shared section");
338 tokenizer.expect("import");
339 RefPtr<Import> import = new Import;
340 import->source = source_index;
341 import->line = tokenizer.get_location().line;
342 import->module = expect_identifier();
343 tokenizer.expect(";");
347 RefPtr<Precision> Parser::parse_precision()
349 tokenizer.expect("precision");
350 RefPtr<Precision> precision = new Precision;
351 precision->source = source_index;
352 precision->line = tokenizer.get_location().line;
354 precision->precision = tokenizer.parse_token();
355 if(!is_precision_qualifier(precision->precision))
356 throw parse_error(tokenizer.get_location(), precision->precision, "a precision qualifier");
358 precision->type = tokenizer.parse_token();
359 // Not entirely accurate; only float, int and sampler types are allowed
360 if(!is_builtin_type(precision->type))
361 throw parse_error(tokenizer.get_location(), precision->type, "a builtin type");
363 tokenizer.expect(";");
368 RefPtr<Layout> Parser::parse_layout()
370 tokenizer.expect("layout");
371 tokenizer.expect("(");
372 RefPtr<Layout> layout = new Layout;
375 string token = tokenizer.parse_token();
377 throw parse_error(tokenizer.get_location(), token, "a layout qualifier name");
379 layout->qualifiers.push_back(Layout::Qualifier());
380 Layout::Qualifier &qual = layout->qualifiers.back();
383 if((qual.has_value = check("=")))
385 if(qual.name=="constant_id" && tokenizer.peek_token()=="auto")
388 tokenizer.parse_token();
391 qual.value = expect_integer();
394 if(tokenizer.peek_token()==")")
397 tokenizer.expect(",");
399 tokenizer.expect(")");
405 void Parser::parse_block(Block &block, bool require_braces, RefPtr<T> (Parser::*parse_content)())
407 bool have_braces = (require_braces || tokenizer.peek_token()=="{");
409 tokenizer.expect("{");
413 while(tokenizer.peek_token()!="}")
414 if(RefPtr<Statement> node = parse_with_recovery(parse_content))
415 block.body.push_back(node);
418 block.body.push_back((this->*parse_content)());
420 block.use_braces = (require_braces || block.body.size()!=1);
423 tokenizer.expect("}");
426 RefPtr<Expression> Parser::parse_expression(unsigned precedence)
428 RefPtr<Expression> left;
429 VariableReference *left_var = 0;
432 string token = tokenizer.peek_token();
434 const Operator *oper = 0;
435 for(const Operator *i=Operator::operators; (!oper && i->type); ++i)
436 if(token==i->token && (!left || i->type!=Operator::PREFIX) && (left || i->type!=Operator::POSTFIX))
439 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
444 throw parse_error(tokenizer.get_location(), token, "an expression");
451 throw invalid_shader_source(tokenizer.get_location(), "Syntax error before '(': function name must be an identifier");
452 left = parse_function_call(*left_var);
456 RefPtr<MemberAccess> memacc = new MemberAccess;
458 tokenizer.parse_token();
459 memacc->member = expect_identifier();
462 else if(oper && oper->type==Operator::POSTFIX)
464 RefPtr<UnaryExpression> unary = new UnaryExpression;
465 unary->oper = tokenizer.parse_token();
466 unary->prefix = false;
467 unary->expression = left;
470 else if(oper && oper->type==Operator::BINARY)
471 left = parse_binary(left, oper);
473 throw parse_error(tokenizer.get_location(), token, "an operator");
480 tokenizer.parse_token();
481 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
482 parexpr->expression = parse_expression();
483 tokenizer.expect(")");
486 else if(isdigit(token[0]) || token=="true" || token=="false")
488 RefPtr<Literal> literal = new Literal;
489 literal->token = tokenizer.parse_token();
492 else if(is_identifier(token))
494 RefPtr<VariableReference> var = new VariableReference;
495 var->name = expect_identifier();
497 left_var = var.get();
499 else if(oper && oper->type==Operator::PREFIX)
501 RefPtr<UnaryExpression> unary = new UnaryExpression;
502 unary->oper = tokenizer.parse_token();
503 unary->prefix = true;
504 unary->expression = parse_expression(oper->precedence);
508 throw parse_error(tokenizer.get_location(), token, "an expression");
513 RefPtr<BinaryExpression> Parser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
515 RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
517 binary->oper = tokenizer.parse_token();
518 if(binary->oper=="[")
520 binary->right = parse_expression();
521 tokenizer.expect("]");
525 binary->right = parse_expression(oper->precedence+(oper->assoc==Operator::RIGHT_TO_LEFT));
529 RefPtr<FunctionCall> Parser::parse_function_call(const VariableReference &var)
531 RefPtr<FunctionCall> call = new FunctionCall;
532 call->name = var.name;
533 call->constructor = is_type(call->name);
534 tokenizer.expect("(");
535 while(tokenizer.peek_token()!=")")
537 if(!call->arguments.empty())
538 tokenizer.expect(",");
539 call->arguments.push_back(parse_expression());
541 tokenizer.expect(")");
545 RefPtr<StructDeclaration> Parser::parse_struct_declaration()
547 tokenizer.expect("struct");
548 RefPtr<StructDeclaration> strct = new StructDeclaration;
549 strct->source = source_index;
550 strct->line = tokenizer.get_location().line;
552 strct->name = expect_identifier();
553 parse_block(strct->members, true, &Parser::parse_variable_declaration);
554 tokenizer.expect(";");
556 declared_types.insert(strct->name);
560 RefPtr<VariableDeclaration> Parser::parse_variable_declaration()
562 RefPtr<VariableDeclaration> var = new VariableDeclaration;
563 var->source = source_index;
564 var->line = tokenizer.get_location().line;
566 string token = tokenizer.peek_token();
567 while(is_qualifier(token))
569 tokenizer.parse_token();
570 if(is_interface_qualifier(token))
571 var->interface = token;
572 else if(is_sampling_qualifier(token))
573 var->sampling = token;
574 else if(is_interpolation_qualifier(token))
575 var->interpolation = token;
576 else if(is_precision_qualifier(token))
577 var->precision = token;
578 else if(token=="const")
579 var->constant = true;
580 token = tokenizer.peek_token();
583 var->type = expect_type();
584 var->name = expect_identifier();
591 var->array_size = parse_expression();
592 tokenizer.expect("]");
597 var->init_expression = parse_expression();
599 tokenizer.expect(";");
603 RefPtr<VariableDeclaration> Parser::parse_variable_declaration_with_layout()
605 RefPtr<Layout> layout;
606 if(tokenizer.peek_token()=="layout")
607 layout = parse_layout();
609 RefPtr<VariableDeclaration> var = parse_variable_declaration();
610 var->layout = layout;
615 RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
617 RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
618 func->source = source_index;
619 func->line = tokenizer.get_location().line;
621 func->return_type = expect_type();
622 func->name = expect_identifier();
623 tokenizer.expect("(");
624 while(tokenizer.peek_token()!=")")
626 if(!func->parameters.empty())
627 tokenizer.expect(",");
629 RefPtr<VariableDeclaration> var = new VariableDeclaration;
630 string token = tokenizer.peek_token();
631 if(token=="in" || token=="out" || token=="inout")
632 var->interface = tokenizer.parse_token();
633 var->type = expect_type();
634 var->name = expect_identifier();
635 func->parameters.push_back(var);
637 tokenizer.expect(")");
639 string token = tokenizer.peek_token();
642 func->definition = func.get();
643 parse_block(func->body, true, &Parser::parse_statement);
646 tokenizer.parse_token();
648 throw parse_error(tokenizer.get_location(), token, "'{' or ';'");
653 RefPtr<InterfaceBlock> Parser::parse_interface_block()
655 RefPtr<InterfaceBlock> iface = new InterfaceBlock;
656 iface->source = source_index;
657 iface->line = tokenizer.get_location().line;
659 iface->interface = tokenizer.parse_token();
660 if(!is_interface_qualifier(iface->interface))
661 throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier");
663 iface->name = expect_identifier();
664 parse_block(iface->members, true, &Parser::parse_variable_declaration_with_layout);
667 iface->instance_name = expect_identifier();
671 tokenizer.expect("]");
673 tokenizer.expect(";");
679 RefPtr<Conditional> Parser::parse_conditional()
681 tokenizer.expect("if");
682 RefPtr<Conditional> cond = new Conditional;
683 cond->source = source_index;
684 cond->line = tokenizer.get_location().line;
685 tokenizer.expect("(");
686 cond->condition = parse_expression();
687 tokenizer.expect(")");
689 parse_block(cond->body, false, &Parser::parse_statement);
691 string token = tokenizer.peek_token();
694 tokenizer.parse_token();
695 parse_block(cond->else_body, false, &Parser::parse_statement);
701 RefPtr<Iteration> Parser::parse_for()
703 tokenizer.expect("for");
704 RefPtr<Iteration> loop = new Iteration;
705 loop->source = source_index;
706 loop->line = tokenizer.get_location().line;
707 tokenizer.expect("(");
708 string token = tokenizer.peek_token();
710 loop->init_statement = parse_statement();
715 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
716 expr->expression = parse_expression();
717 loop->init_statement = expr;
719 tokenizer.expect(";");
721 if(tokenizer.peek_token()!=";")
722 loop->condition = parse_expression();
723 tokenizer.expect(";");
724 if(tokenizer.peek_token()!=")")
725 loop->loop_expression = parse_expression();
726 tokenizer.expect(")");
728 parse_block(loop->body, false, &Parser::parse_statement);
733 RefPtr<Iteration> Parser::parse_while()
735 tokenizer.expect("while");
736 RefPtr<Iteration> loop = new Iteration;
737 loop->source = source_index;
738 loop->line = tokenizer.get_location().line;
739 tokenizer.expect("(");
740 loop->condition = parse_expression();
741 tokenizer.expect(")");
743 parse_block(loop->body, false, &Parser::parse_statement);
748 RefPtr<Passthrough> Parser::parse_passthrough()
750 tokenizer.expect("passthrough");
751 RefPtr<Passthrough> pass = new Passthrough;
752 pass->source = source_index;
753 pass->line = tokenizer.get_location().line;
754 if(cur_stage->type==Stage::GEOMETRY)
756 tokenizer.expect("[");
757 pass->subscript = parse_expression();
758 tokenizer.expect("]");
760 tokenizer.expect(";");
764 RefPtr<Return> Parser::parse_return()
766 tokenizer.expect("return");
767 RefPtr<Return> ret = new Return;
768 ret->source = source_index;
769 ret->line = tokenizer.get_location().line;
770 if(tokenizer.peek_token()!=";")
771 ret->expression = parse_expression();
772 tokenizer.expect(";");