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 ProgramParser::ProgramParser():
65 ProgramParser::~ProgramParser()
70 Module &ProgramParser::parse(const string &s, const string &n)
78 Module &ProgramParser::parse(IO::Base &io, const string &n)
85 unsigned len = io.read(buffer, sizeof(buffer));
86 source.append(buffer, len);
92 void ProgramParser::parse_source()
96 cur_stage = &module->shared;
97 iter = source.begin();
101 while(RefPtr<Node> statement = parse_global_declaration())
102 cur_stage->content.body.push_back(statement);
105 string token = parse_token();
108 else if(token=="vertex")
109 module->stages.push_back(VERTEX);
110 else if(token=="geometry")
111 module->stages.push_back(GEOMETRY);
112 else if(token=="fragment")
113 module->stages.push_back(FRAGMENT);
115 throw runtime_error(format("Parse error at '%s': expected stage identifier", token));
117 if(cur_stage->type!=SHARED)
118 module->stages.back().previous = cur_stage;
119 cur_stage = &module->stages.back();
121 for(; (iter!=source.end() && *iter!='\n'); ++iter) ;
125 string ProgramParser::format_error(const std::string &message)
127 string location = format("%s:%d: ", source_name, current_line);
128 return location+message;
131 string ProgramParser::format_syntax_error(const std::string &expected)
133 return format_error(format("Syntax error at '%s': expected %s", last_token, expected));
136 const string &ProgramParser::peek_token(unsigned index)
138 while(next_tokens.size()<=index)
139 next_tokens.push_back(parse_token_());
140 return (last_token = next_tokens[index]);
143 const string &ProgramParser::parse_token()
145 if(!next_tokens.empty())
147 last_token = next_tokens.front();
148 next_tokens.pop_front();
152 return (last_token = parse_token_());
155 string ProgramParser::parse_token_()
157 if(!skip_comment_and_whitespace())
160 if(isalpha(*iter) || *iter=='_')
161 return parse_identifier();
162 else if(isdigit(*iter))
163 return parse_number();
165 return parse_other();
168 string ProgramParser::parse_identifier()
171 while(iter!=source.end())
173 if(isalnum(*iter) || *iter=='_')
182 string ProgramParser::parse_number()
184 bool accept_sign = false;
186 while(iter!=source.end())
188 if(isdigit(*iter) || *iter=='.')
190 else if(*iter=='e' || *iter=='E')
195 else if(accept_sign && (*iter=='+' || *iter=='-'))
204 string ProgramParser::parse_other()
206 if(iter==source.end())
209 string token(1, *iter++);
210 for(unsigned i=1; (i<3 && iter!=source.end()); ++i)
212 bool matched = false;
213 for(const Operator *j=operators; (!matched && j->type); ++j)
215 matched = (j->token[i]==*iter);
216 for(unsigned k=0; (matched && k<i && j->token[k]); ++k)
217 matched = (j->token[k]==token[k]);
229 bool ProgramParser::skip_comment_and_whitespace()
231 unsigned comment = 0;
232 unsigned slashes = 0;
233 while(iter!=source.end())
239 else if(!isspace(*iter))
264 else if(!isspace(*iter) && slashes>=6)
267 else if(comment==3 && *iter=='*')
283 return iter!=source.end();
286 void ProgramParser::expect(const string &token)
288 string parsed = parse_token();
290 throw runtime_error(format_syntax_error(format("'%s'", token)));
293 string ProgramParser::expect_type()
295 string token = parse_token();
297 throw runtime_error(format_syntax_error("a type"));
301 string ProgramParser::expect_identifier()
303 string token = parse_token();
304 if(!is_identifier(token))
305 throw runtime_error(format_syntax_error("an identifier"));
309 bool ProgramParser::check(const string &token)
311 bool result = (peek_token()==token);
317 bool ProgramParser::is_interface_qualifier(const string &token)
319 return (token=="uniform" || token=="in" || token=="out");
322 bool ProgramParser::is_sampling_qualifier(const string &token)
324 return token=="centroid";
327 bool ProgramParser::is_precision_qualifier(const string &token)
329 return (token=="highp" || token=="mediump" || token=="lowp");
332 bool ProgramParser::is_qualifier(const string &token)
334 return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token) || is_precision_qualifier(token));
337 bool ProgramParser::is_builtin_type(const string &token)
339 static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D)(Array)?(Shadow)?|Cube(Shadow)?|3D))$");
340 return re.match(token);
343 bool ProgramParser::is_type(const string &token)
345 return is_builtin_type(token) || declared_types.count(token);
348 bool ProgramParser::is_identifier(const string &token)
350 static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
351 return re.match(token);
354 RefPtr<Node> ProgramParser::parse_global_declaration()
356 string token = peek_token();
358 return parse_import();
359 else if(token=="precision")
360 return parse_precision();
361 else if(token=="layout")
363 RefPtr<Layout> layout = parse_layout();
364 token = peek_token();
365 if(is_interface_qualifier(token) && peek_token(1)==";")
367 RefPtr<InterfaceLayout> iface_lo = new InterfaceLayout;
368 iface_lo->layout.qualifiers = layout->qualifiers;
369 iface_lo->interface = parse_token();
375 RefPtr<VariableDeclaration> var = parse_variable_declaration();
376 var->layout = layout;
380 else if(token=="struct")
381 return parse_struct_declaration();
382 else if(is_interface_qualifier(token))
384 string next = peek_token(1);
385 if(is_type(next) || is_precision_qualifier(next))
386 return parse_variable_declaration();
388 return parse_interface_block();
390 else if(is_qualifier(token))
391 return parse_variable_declaration();
392 else if(is_type(token))
394 if(peek_token(2)=="(")
395 return parse_function_declaration();
397 return parse_variable_declaration();
399 else if(token.empty())
402 throw runtime_error(format_syntax_error("a global declaration"));
405 RefPtr<Node> ProgramParser::parse_statement()
407 string token = peek_token();
409 return parse_conditional();
410 else if(token=="for")
411 return parse_iteration();
412 else if(token=="passthrough")
413 return parse_passthrough();
414 else if(token=="return")
415 return parse_return();
416 else if(token=="break" || token=="continue" || token=="discard")
418 RefPtr<Jump> jump = new Jump;
419 jump->keyword = parse_token();
424 else if(is_qualifier(token) || is_type(token))
425 return parse_variable_declaration();
426 else if(!token.empty())
428 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
429 expr->expression = parse_expression();
435 throw runtime_error(format_syntax_error("a statement"));
438 RefPtr<Import> ProgramParser::parse_import()
440 if(cur_stage->type!=SHARED)
441 throw runtime_error(format_error("Imports are only allowed in the shared section"));
444 RefPtr<Import> import = new Import;
445 import->module = parse_token();
450 RefPtr<Precision> ProgramParser::parse_precision()
453 RefPtr<Precision> precision = new Precision;
455 precision->precision = parse_token();
456 if(!is_precision_qualifier(precision->precision))
457 throw runtime_error(format_syntax_error("a precision qualifier"));
459 precision->type = parse_token();
460 // Not entirely accurate; only float, int and sampler types are allowed
461 if(!is_builtin_type(precision->type))
462 throw runtime_error(format_syntax_error("a builtin type"));
469 RefPtr<Layout> ProgramParser::parse_layout()
473 RefPtr<Layout> layout = new Layout;
476 string token = parse_token();
478 throw runtime_error(format_syntax_error("a layout qualifier name"));
480 layout->qualifiers.push_back(Layout::Qualifier());
481 Layout::Qualifier &qual = layout->qualifiers.back();
482 qual.identifier = token;
485 qual.value = parse_token();
487 if(peek_token()==")")
497 void ProgramParser::parse_block(Block &block, bool require_braces)
499 bool have_braces = (require_braces || peek_token()=="{");
505 while(peek_token()!="}")
506 block.body.push_back(parse_statement());
509 block.body.push_back(parse_statement());
511 block.use_braces = (require_braces || block.body.size()!=1);
517 RefPtr<Expression> ProgramParser::parse_expression(unsigned precedence)
519 RefPtr<Expression> left;
520 VariableReference *left_var = 0;
523 string token = peek_token();
525 const Operator *oper = 0;
526 for(Operator *i=operators; (!oper && i->type); ++i)
527 if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX))
530 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
535 throw runtime_error(format_syntax_error("an expression"));
542 throw runtime_error(format_error("Syntax error before '(': function name must be an identifier"));
543 left = parse_function_call(*left_var);
547 RefPtr<MemberAccess> memacc = new MemberAccess;
550 memacc->member = expect_identifier();
553 else if(oper && oper->type==POSTFIX)
555 RefPtr<UnaryExpression> unary = new UnaryExpression;
556 unary->oper = parse_token();
557 unary->prefix = false;
558 unary->expression = left;
561 else if(oper && oper->type==BINARY)
562 left = parse_binary(left, oper);
564 throw runtime_error(format_syntax_error("an operator"));
572 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
573 parexpr->expression = parse_expression();
577 else if(isdigit(token[0]) || token=="true" || token=="false")
579 RefPtr<Literal> literal = new Literal;
580 literal->token = parse_token();
583 else if(is_identifier(token))
585 RefPtr<VariableReference> var = new VariableReference;
586 var->name = expect_identifier();
588 left_var = var.get();
590 else if(oper && oper->type==PREFIX)
592 RefPtr<UnaryExpression> unary = new UnaryExpression;
593 unary->oper = parse_token();
594 unary->prefix = true;
595 unary->expression = parse_expression(oper->precedence);
599 throw runtime_error(format_syntax_error("an expression"));
604 RefPtr<BinaryExpression> ProgramParser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
606 RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
608 binary->oper = parse_token();
609 if(binary->oper=="[")
611 binary->right = parse_expression();
616 binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT));
620 RefPtr<FunctionCall> ProgramParser::parse_function_call(const VariableReference &var)
622 RefPtr<FunctionCall> call = new FunctionCall;
623 call->name = var.name;
624 call->constructor = is_type(call->name);
626 while(peek_token()!=")")
628 if(!call->arguments.empty())
630 call->arguments.push_back(parse_expression());
636 RefPtr<StructDeclaration> ProgramParser::parse_struct_declaration()
639 RefPtr<StructDeclaration> strct = new StructDeclaration;
641 strct->name = expect_identifier();
642 parse_block(strct->members, true);
645 declared_types.insert(strct->name);
649 RefPtr<VariableDeclaration> ProgramParser::parse_variable_declaration()
651 RefPtr<VariableDeclaration> var = new VariableDeclaration;
653 string token = peek_token();
654 if(is_sampling_qualifier(token))
656 var->sampling = parse_token();
657 token = peek_token();
658 if(!is_interface_qualifier(token))
659 throw runtime_error(format_syntax_error("an interface qualifier"));
662 if(is_interface_qualifier(token))
663 var->interface = parse_token();
664 else if(token=="const")
666 var->constant = true;
670 if(is_precision_qualifier(token))
671 var->precision = parse_token();
673 var->type = expect_type();
674 var->name = expect_identifier();
681 var->array_size = parse_expression();
687 var->init_expression = parse_expression();
693 RefPtr<FunctionDeclaration> ProgramParser::parse_function_declaration()
695 RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
697 func->return_type = expect_type();
698 func->name = expect_identifier();
700 while(peek_token()!=")")
702 if(!func->parameters.empty())
705 RefPtr<VariableDeclaration> var = new VariableDeclaration;
706 var->type = expect_type();
707 var->name = expect_identifier();
708 func->parameters.push_back(var);
712 string token = peek_token();
715 func->definition = func.get();
716 parse_block(func->body, true);
721 throw runtime_error(format_syntax_error("'{' or ';'"));
726 RefPtr<InterfaceBlock> ProgramParser::parse_interface_block()
728 RefPtr<InterfaceBlock> iface = new InterfaceBlock;
730 iface->interface = parse_token();
731 if(!is_interface_qualifier(iface->interface))
732 throw runtime_error(format_syntax_error("an interface qualifier"));
734 iface->name = expect_identifier();
735 parse_block(iface->members, true);
738 iface->instance_name = expect_identifier();
750 RefPtr<Conditional> ProgramParser::parse_conditional()
754 RefPtr<Conditional> cond = new Conditional;
755 cond->condition = parse_expression();
758 parse_block(cond->body, false);
760 string token = peek_token();
764 parse_block(cond->else_body, false);
770 RefPtr<Iteration> ProgramParser::parse_iteration()
774 RefPtr<Iteration> loop = new Iteration;
775 string token = peek_token();
777 loop->init_statement = parse_statement();
780 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
781 expr->expression = parse_expression();
783 loop->init_statement = expr;
785 loop->condition = parse_expression();
787 loop->loop_expression = parse_expression();
790 parse_block(loop->body, false);
795 RefPtr<Passthrough> ProgramParser::parse_passthrough()
797 expect("passthrough");
798 RefPtr<Passthrough> pass = new Passthrough;
799 if(cur_stage->type==GEOMETRY)
802 pass->subscript = parse_expression();
809 RefPtr<Return> ProgramParser::parse_return()
812 RefPtr<Return> ret = new Return;
813 if(peek_token()!=";")
814 ret->expression = parse_expression();