1 #include <msp/strings/format.h>
2 #include <msp/strings/regex.h>
3 #include "glsl_error.h"
15 preprocessor(tokenizer),
18 tokenizer.signal_preprocess.connect(sigc::mem_fun(&preprocessor, &Preprocessor::preprocess));
19 preprocessor.signal_version.connect(sigc::mem_fun(this, &Parser::set_required_version));
20 preprocessor.signal_stage_change.connect(sigc::mem_fun(this, &Parser::stage_change));
28 Module &Parser::parse(const string &s, const string &n, unsigned i)
36 Module &Parser::parse(IO::Base &io, const string &n, unsigned i)
43 unsigned len = io.read(buffer, sizeof(buffer));
44 source.append(buffer, len);
50 void Parser::parse_source(const string &name)
54 string::size_type slashes = source.find("//////");
55 if(slashes==string::npos)
58 string::size_type newline = source.find('\n', slashes);
59 string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6));
60 source.replace(slashes, newline-slashes, pragma);
65 cur_stage = &module->shared;
66 tokenizer.begin(name, source);
67 while(RefPtr<Statement> statement = parse_global_declaration())
68 cur_stage->content.body.push_back(statement);
71 void Parser::set_required_version(const Version &ver)
73 cur_stage->required_version = ver;
76 void Parser::stage_change(Stage::Type stage)
78 if(!allow_stage_change)
79 throw invalid_shader_source(tokenizer.get_location(), "Changing stage not allowed here");
80 else if(stage<=cur_stage->type)
81 throw invalid_shader_source(tokenizer.get_location(), "Stage '%s' not allowed here", stage);
83 module->stages.push_back(stage);
85 if(cur_stage->type!=Stage::SHARED)
86 module->stages.back().previous = cur_stage;
87 cur_stage = &module->stages.back();
90 string Parser::expect_type()
92 string token = tokenizer.parse_token();
94 throw parse_error(tokenizer.get_location(), token, "a type");
98 string Parser::expect_identifier()
100 string token = tokenizer.parse_token();
101 if(!is_identifier(token))
102 throw parse_error(tokenizer.get_location(), token, "an identifier");
106 bool Parser::check(const string &token)
108 bool result = (tokenizer.peek_token()==token);
110 tokenizer.parse_token();
114 bool Parser::is_interface_qualifier(const string &token)
116 return (token=="uniform" || token=="in" || token=="out");
119 bool Parser::is_sampling_qualifier(const string &token)
121 return (token=="centroid" || token=="sample");
124 bool Parser::is_interpolation_qualifier(const string &token)
126 return (token=="smooth" || token=="flat" || token=="noperspective");
129 bool Parser::is_precision_qualifier(const string &token)
131 return (token=="highp" || token=="mediump" || token=="lowp");
134 bool Parser::is_qualifier(const string &token)
136 return (token=="const" ||
137 is_interface_qualifier(token) ||
138 is_sampling_qualifier(token) ||
139 is_interpolation_qualifier(token) ||
140 is_precision_qualifier(token));
143 bool Parser::is_builtin_type(const string &token)
145 static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D|Cube)(Array)?(Shadow)?|3D))$");
146 return re.match(token);
149 bool Parser::is_type(const string &token)
151 return is_builtin_type(token) || declared_types.count(token);
154 bool Parser::is_identifier(const string &token)
156 static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
157 return re.match(token);
160 RefPtr<Statement> Parser::parse_global_declaration()
162 allow_stage_change = true;
163 string token = tokenizer.peek_token();
164 allow_stage_change = false;
167 return parse_import();
168 else if(token=="precision")
169 return parse_precision();
170 else if(token=="layout")
172 RefPtr<Layout> layout = parse_layout();
173 token = tokenizer.peek_token();
174 if(is_interface_qualifier(token) && tokenizer.peek_token(1)==";")
176 RefPtr<InterfaceLayout> iface_lo = new InterfaceLayout;
177 iface_lo->source = source_index;
178 iface_lo->line = tokenizer.get_location().line;
179 iface_lo->layout.qualifiers = layout->qualifiers;
180 iface_lo->interface = tokenizer.parse_token();
181 tokenizer.expect(";");
186 RefPtr<VariableDeclaration> var = parse_variable_declaration();
187 var->layout = layout;
191 else if(token=="struct")
192 return parse_struct_declaration();
193 else if(is_interface_qualifier(token))
195 string next = tokenizer.peek_token(1);
196 if(is_type(next) || is_qualifier(next))
197 return parse_variable_declaration();
199 return parse_interface_block();
201 else if(is_qualifier(token))
202 return parse_variable_declaration();
203 else if(is_type(token))
205 if(tokenizer.peek_token(2)=="(")
206 return parse_function_declaration();
208 return parse_variable_declaration();
210 else if(token.empty())
213 throw parse_error(tokenizer.get_location(), token, "a global declaration");
216 RefPtr<Statement> Parser::parse_statement()
218 string token = tokenizer.peek_token();
220 return parse_conditional();
221 else if(token=="for")
223 else if(token=="while")
224 return parse_while();
225 else if(token=="passthrough")
226 return parse_passthrough();
227 else if(token=="return")
228 return parse_return();
229 else if(token=="break" || token=="continue" || token=="discard")
231 RefPtr<Jump> jump = new Jump;
232 jump->source = source_index;
233 jump->line = tokenizer.get_location().line;
234 jump->keyword = tokenizer.parse_token();
235 tokenizer.expect(";");
239 else if(is_qualifier(token) || is_type(token))
240 return parse_variable_declaration();
241 else if(!token.empty())
243 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
244 expr->source = source_index;
245 expr->line = tokenizer.get_location().line;
246 expr->expression = parse_expression();
247 tokenizer.expect(";");
252 throw parse_error(tokenizer.get_location(), token, "a statement");
255 RefPtr<Import> Parser::parse_import()
257 if(cur_stage->type!=Stage::SHARED)
258 throw invalid_shader_source(tokenizer.get_location(), "Imports are only allowed in the shared section");
260 tokenizer.expect("import");
261 RefPtr<Import> import = new Import;
262 import->source = source_index;
263 import->line = tokenizer.get_location().line;
264 import->module = expect_identifier();
265 tokenizer.expect(";");
269 RefPtr<Precision> Parser::parse_precision()
271 tokenizer.expect("precision");
272 RefPtr<Precision> precision = new Precision;
273 precision->source = source_index;
274 precision->line = tokenizer.get_location().line;
276 precision->precision = tokenizer.parse_token();
277 if(!is_precision_qualifier(precision->precision))
278 throw parse_error(tokenizer.get_location(), precision->precision, "a precision qualifier");
280 precision->type = tokenizer.parse_token();
281 // Not entirely accurate; only float, int and sampler types are allowed
282 if(!is_builtin_type(precision->type))
283 throw parse_error(tokenizer.get_location(), precision->type, "a builtin type");
285 tokenizer.expect(";");
290 RefPtr<Layout> Parser::parse_layout()
292 tokenizer.expect("layout");
293 tokenizer.expect("(");
294 RefPtr<Layout> layout = new Layout;
297 string token = tokenizer.parse_token();
299 throw parse_error(tokenizer.get_location(), token, "a layout qualifier name");
301 layout->qualifiers.push_back(Layout::Qualifier());
302 Layout::Qualifier &qual = layout->qualifiers.back();
303 qual.identifier = token;
306 qual.value = tokenizer.parse_token();
308 if(tokenizer.peek_token()==")")
311 tokenizer.expect(",");
313 tokenizer.expect(")");
318 void Parser::parse_block(Block &block, bool require_braces)
320 bool have_braces = (require_braces || tokenizer.peek_token()=="{");
322 tokenizer.expect("{");
326 while(tokenizer.peek_token()!="}")
327 block.body.push_back(parse_statement());
330 block.body.push_back(parse_statement());
332 block.use_braces = (require_braces || block.body.size()!=1);
335 tokenizer.expect("}");
338 RefPtr<Expression> Parser::parse_expression(unsigned precedence)
340 RefPtr<Expression> left;
341 VariableReference *left_var = 0;
344 string token = tokenizer.peek_token();
346 const Operator *oper = 0;
347 for(const Operator *i=Operator::operators; (!oper && i->type); ++i)
348 if(token==i->token && (!left || i->type!=Operator::PREFIX) && (left || i->type!=Operator::POSTFIX))
351 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
356 throw parse_error(tokenizer.get_location(), token, "an expression");
363 throw invalid_shader_source(tokenizer.get_location(), "Syntax error before '(': function name must be an identifier");
364 left = parse_function_call(*left_var);
368 RefPtr<MemberAccess> memacc = new MemberAccess;
370 tokenizer.parse_token();
371 memacc->member = expect_identifier();
374 else if(oper && oper->type==Operator::POSTFIX)
376 RefPtr<UnaryExpression> unary = new UnaryExpression;
377 unary->oper = tokenizer.parse_token();
378 unary->prefix = false;
379 unary->expression = left;
382 else if(oper && oper->type==Operator::BINARY)
383 left = parse_binary(left, oper);
385 throw parse_error(tokenizer.get_location(), token, "an operator");
392 tokenizer.parse_token();
393 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
394 parexpr->expression = parse_expression();
395 tokenizer.expect(")");
398 else if(isdigit(token[0]) || token=="true" || token=="false")
400 RefPtr<Literal> literal = new Literal;
401 literal->token = tokenizer.parse_token();
404 else if(is_identifier(token))
406 RefPtr<VariableReference> var = new VariableReference;
407 var->name = expect_identifier();
409 left_var = var.get();
411 else if(oper && oper->type==Operator::PREFIX)
413 RefPtr<UnaryExpression> unary = new UnaryExpression;
414 unary->oper = tokenizer.parse_token();
415 unary->prefix = true;
416 unary->expression = parse_expression(oper->precedence);
420 throw parse_error(tokenizer.get_location(), token, "an expression");
425 RefPtr<BinaryExpression> Parser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
427 RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
429 binary->oper = tokenizer.parse_token();
430 if(binary->oper=="[")
432 binary->right = parse_expression();
433 tokenizer.expect("]");
437 binary->right = parse_expression(oper->precedence+(oper->assoc==Operator::RIGHT_TO_LEFT));
441 RefPtr<FunctionCall> Parser::parse_function_call(const VariableReference &var)
443 RefPtr<FunctionCall> call = new FunctionCall;
444 call->name = var.name;
445 call->constructor = is_type(call->name);
446 tokenizer.expect("(");
447 while(tokenizer.peek_token()!=")")
449 if(!call->arguments.empty())
450 tokenizer.expect(",");
451 call->arguments.push_back(parse_expression());
453 tokenizer.expect(")");
457 RefPtr<StructDeclaration> Parser::parse_struct_declaration()
459 tokenizer.expect("struct");
460 RefPtr<StructDeclaration> strct = new StructDeclaration;
461 strct->source = source_index;
462 strct->line = tokenizer.get_location().line;
464 strct->name = expect_identifier();
465 parse_block(strct->members, true);
466 tokenizer.expect(";");
468 declared_types.insert(strct->name);
472 RefPtr<VariableDeclaration> Parser::parse_variable_declaration()
474 RefPtr<VariableDeclaration> var = new VariableDeclaration;
475 var->source = source_index;
476 var->line = tokenizer.get_location().line;
478 string token = tokenizer.peek_token();
479 while(is_qualifier(token))
481 tokenizer.parse_token();
482 if(is_interface_qualifier(token))
483 var->interface = token;
484 else if(is_sampling_qualifier(token))
485 var->sampling = token;
486 else if(is_interpolation_qualifier(token))
487 var->interpolation = token;
488 else if(is_precision_qualifier(token))
489 var->precision = token;
490 else if(token=="const")
491 var->constant = true;
492 token = tokenizer.peek_token();
495 var->type = expect_type();
496 var->name = expect_identifier();
503 var->array_size = parse_expression();
504 tokenizer.expect("]");
509 var->init_expression = parse_expression();
511 tokenizer.expect(";");
515 RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
517 RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
518 func->source = source_index;
519 func->line = tokenizer.get_location().line;
521 func->return_type = expect_type();
522 func->name = expect_identifier();
523 tokenizer.expect("(");
524 while(tokenizer.peek_token()!=")")
526 if(!func->parameters.empty())
527 tokenizer.expect(",");
529 RefPtr<VariableDeclaration> var = new VariableDeclaration;
530 string token = tokenizer.peek_token();
531 if(token=="in" || token=="out" || token=="inout")
532 var->interface = tokenizer.parse_token();
533 var->type = expect_type();
534 var->name = expect_identifier();
535 func->parameters.push_back(var);
537 tokenizer.expect(")");
539 string token = tokenizer.peek_token();
542 func->definition = func.get();
543 parse_block(func->body, true);
546 tokenizer.parse_token();
548 throw parse_error(tokenizer.get_location(), token, "'{' or ';'");
553 RefPtr<InterfaceBlock> Parser::parse_interface_block()
555 RefPtr<InterfaceBlock> iface = new InterfaceBlock;
556 iface->source = source_index;
557 iface->line = tokenizer.get_location().line;
559 iface->interface = tokenizer.parse_token();
560 if(!is_interface_qualifier(iface->interface))
561 throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier");
563 iface->name = expect_identifier();
564 parse_block(iface->members, true);
567 iface->instance_name = expect_identifier();
571 tokenizer.expect("]");
573 tokenizer.expect(";");
579 RefPtr<Conditional> Parser::parse_conditional()
581 tokenizer.expect("if");
582 RefPtr<Conditional> cond = new Conditional;
583 cond->source = source_index;
584 cond->line = tokenizer.get_location().line;
585 tokenizer.expect("(");
586 cond->condition = parse_expression();
587 tokenizer.expect(")");
589 parse_block(cond->body, false);
591 string token = tokenizer.peek_token();
594 tokenizer.parse_token();
595 parse_block(cond->else_body, false);
601 RefPtr<Iteration> Parser::parse_for()
603 tokenizer.expect("for");
604 RefPtr<Iteration> loop = new Iteration;
605 loop->source = source_index;
606 loop->line = tokenizer.get_location().line;
607 tokenizer.expect("(");
608 string token = tokenizer.peek_token();
610 loop->init_statement = parse_statement();
615 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
616 expr->expression = parse_expression();
617 loop->init_statement = expr;
619 tokenizer.expect(";");
621 if(tokenizer.peek_token()!=";")
622 loop->condition = parse_expression();
623 tokenizer.expect(";");
624 if(tokenizer.peek_token()!=")")
625 loop->loop_expression = parse_expression();
626 tokenizer.expect(")");
628 parse_block(loop->body, false);
633 RefPtr<Iteration> Parser::parse_while()
635 tokenizer.expect("while");
636 RefPtr<Iteration> loop = new Iteration;
637 loop->source = source_index;
638 loop->line = tokenizer.get_location().line;
639 tokenizer.expect("(");
640 loop->condition = parse_expression();
641 tokenizer.expect(")");
643 parse_block(loop->body, false);
648 RefPtr<Passthrough> Parser::parse_passthrough()
650 tokenizer.expect("passthrough");
651 RefPtr<Passthrough> pass = new Passthrough;
652 pass->source = source_index;
653 pass->line = tokenizer.get_location().line;
654 if(cur_stage->type==Stage::GEOMETRY)
656 tokenizer.expect("[");
657 pass->subscript = parse_expression();
658 tokenizer.expect("]");
660 tokenizer.expect(";");
664 RefPtr<Return> Parser::parse_return()
666 tokenizer.expect("return");
667 RefPtr<Return> ret = new Return;
668 ret->source = source_index;
669 ret->line = tokenizer.get_location().line;
670 if(tokenizer.peek_token()!=";")
671 ret->expression = parse_expression();
672 tokenizer.expect(";");