]> git.tdb.fi Git - libs/gl.git/blob - source/programparser.cpp
Make all components of a for loop optional
[libs/gl.git] / source / programparser.cpp
1 #include <msp/core/raii.h>
2 #include <msp/strings/format.h>
3 #include <msp/strings/regex.h>
4 #include "programparser.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace GL {
10
11 using namespace ProgramSyntax;
12
13 ProgramParser::Operator ProgramParser::operators[] =
14 {
15         { "[", 2, BINARY, LEFT_TO_RIGHT },
16         { "(", 2, BINARY, LEFT_TO_RIGHT },
17         { ".", 2, BINARY, LEFT_TO_RIGHT },
18         { "++", 2, POSTFIX, LEFT_TO_RIGHT },
19         { "--", 2, POSTFIX, LEFT_TO_RIGHT },
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         { "!", 3, PREFIX, RIGHT_TO_LEFT },
26         { "*", 4, BINARY, LEFT_TO_RIGHT },
27         { "/", 4, BINARY, LEFT_TO_RIGHT },
28         { "%", 4, BINARY, LEFT_TO_RIGHT },
29         { "+", 5, BINARY, LEFT_TO_RIGHT },
30         { "-", 5, BINARY, LEFT_TO_RIGHT },
31         { "<<", 6, BINARY, LEFT_TO_RIGHT },
32         { ">>", 6, BINARY, LEFT_TO_RIGHT },
33         { "<", 7, BINARY, LEFT_TO_RIGHT },
34         { ">", 7, BINARY, LEFT_TO_RIGHT },
35         { "<=", 7, BINARY, LEFT_TO_RIGHT },
36         { ">=", 7, BINARY, LEFT_TO_RIGHT },
37         { "==", 8, BINARY, LEFT_TO_RIGHT },
38         { "!=", 8, BINARY, LEFT_TO_RIGHT },
39         { "&", 9, BINARY, LEFT_TO_RIGHT },
40         { "^", 10, BINARY, LEFT_TO_RIGHT },
41         { "|", 11, BINARY, LEFT_TO_RIGHT },
42         { "&&", 12, BINARY, LEFT_TO_RIGHT },
43         { "^^", 13, BINARY, LEFT_TO_RIGHT },
44         { "||", 14, BINARY, LEFT_TO_RIGHT },
45         { "?", 15, BINARY, RIGHT_TO_LEFT },
46         { ":", 15, 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         { "|=", 16, BINARY, RIGHT_TO_LEFT },
58         { ",", 17, BINARY, LEFT_TO_RIGHT },
59         { { 0 }, 18, NO_OPERATOR, LEFT_TO_RIGHT }
60 };
61
62 ProgramParser::ProgramParser():
63         module(0)
64 { }
65
66 ProgramParser::~ProgramParser()
67 {
68         delete module;
69 }
70
71 Module &ProgramParser::parse(const string &s, const string &n)
72 {
73         source = s;
74         source_name = n;
75         parse_source();
76         return *module;
77 }
78
79 Module &ProgramParser::parse(IO::Base &io, const string &n)
80 {
81         source = string();
82         source_name = n;
83         while(!io.eof())
84         {
85                 char buffer[4096];
86                 unsigned len = io.read(buffer, sizeof(buffer));
87                 source.append(buffer, len);
88         }
89         parse_source();
90         return *module;
91 }
92
93 void ProgramParser::parse_source()
94 {
95         while(1)
96         {
97                 string::size_type slashes = source.find("//////");
98                 if(slashes==string::npos)
99                         break;
100
101                 string::size_type newline = source.find('\n', slashes);
102                 string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6));
103                 source.replace(slashes, newline-slashes, pragma);
104         }
105
106         delete module;
107         module = new Module;
108         cur_stage = &module->shared;
109         iter = source.begin();
110         source_end = source.end();
111         current_line = 1;
112         allow_preprocess = true;
113         while(RefPtr<Node> statement = parse_global_declaration())
114                 cur_stage->content.body.push_back(statement);
115 }
116
117 string ProgramParser::format_error(const std::string &message)
118 {
119         string location = format("%s:%d: ", source_name, current_line);
120         return location+message;
121 }
122
123 string ProgramParser::format_syntax_error(const std::string &expected)
124 {
125         return format_error(format("Syntax error at '%s': expected %s", last_token, expected));
126 }
127
128 const string &ProgramParser::peek_token(unsigned index)
129 {
130         while(next_tokens.size()<=index)
131                 next_tokens.push_back(parse_token_());
132         return (last_token = next_tokens[index]);
133 }
134
135 const string &ProgramParser::parse_token()
136 {
137         if(!next_tokens.empty())
138         {
139                 last_token = next_tokens.front();
140                 next_tokens.pop_front();
141                 return last_token;
142         }
143
144         return (last_token = parse_token_());
145 }
146
147 string ProgramParser::parse_token_()
148 {
149         while(1)
150         {
151                 skip_comment_and_whitespace();
152                 if(iter==source_end)
153                         return string();
154                 else if(allow_preprocess && *iter=='#')
155                 {
156                         allow_preprocess = false;
157                         SetForScope<deque<string> > clear_tokens(next_tokens, deque<string>());
158                         preprocess();
159                 }
160                 else if(isalpha(*iter) || *iter=='_')
161                         return parse_identifier();
162                 else if(isdigit(*iter))
163                         return parse_number();
164                 else
165                         return parse_other();
166         }
167 }
168
169 string ProgramParser::parse_identifier()
170 {
171         string ident;
172         while(iter!=source_end)
173         {
174                 if(isalnum(*iter) || *iter=='_')
175                         ident += *iter++;
176                 else
177                         break;
178         }
179
180         return ident;
181 }
182
183 string ProgramParser::parse_number()
184 {
185         bool accept_sign = false;
186         string number;
187         while(iter!=source_end)
188         {
189                 if(isdigit(*iter) || *iter=='.')
190                         number += *iter++;
191                 else if(*iter=='e' || *iter=='E')
192                 {
193                         number += *iter++;
194                         accept_sign = true;
195                 }
196                 else if(accept_sign && (*iter=='+' || *iter=='-'))
197                         number += *iter++;
198                 else
199                         break;
200         }
201
202         return number;
203 }
204
205 string ProgramParser::parse_other()
206 {
207         if(iter==source_end)
208                 return string();
209
210         string token(1, *iter++);
211         for(unsigned i=1; (i<3 && iter!=source_end); ++i)
212         {
213                 bool matched = false;
214                 for(const Operator *j=operators; (!matched && j->type); ++j)
215                 {
216                         matched = (j->token[i]==*iter);
217                         for(unsigned k=0; (matched && k<i && j->token[k]); ++k)
218                                 matched = (j->token[k]==token[k]);
219                 }
220
221                 if(!matched)
222                         break;
223
224                 token += *iter++;
225         }
226
227         return token;
228 }
229
230 void ProgramParser::skip_comment_and_whitespace()
231 {
232         unsigned comment = 0;
233         while(iter!=source_end)
234         {
235                 if(comment==0)
236                 {
237                         if(*iter=='/')
238                                 comment = 1;
239                         else if(!isspace(*iter))
240                                 break;
241                 }
242                 else if(comment==1)
243                 {
244                         if(*iter=='/')
245                                 comment = 2;
246                         else if(*iter=='*')
247                                 comment = 3;
248                         else
249                         {
250                                 comment = 0;
251                                 --iter;
252                                 break;
253                         }
254                 }
255                 else if(comment==2)
256                 {
257                         if(*iter=='\n')
258                                 comment = 0;
259                 }
260                 else if(comment==3 && *iter=='*')
261                         comment = 4;
262                 else if(comment==4)
263                 {
264                         if(*iter=='/')
265                                 comment = 0;
266                         else if(*iter!='*')
267                                 comment = 3;
268                 }
269
270                 if(*iter=='\n')
271                 {
272                         ++current_line;
273                         allow_preprocess = (comment<3);
274                 }
275
276                 ++iter;
277         }
278 }
279
280 void ProgramParser::expect(const string &token)
281 {
282         string parsed = parse_token();
283         if(parsed!=token)
284                 throw runtime_error(format_syntax_error(format("'%s'", token)));
285 }
286
287 string ProgramParser::expect_type()
288 {
289         string token = parse_token();
290         if(!is_type(token))
291                 throw runtime_error(format_syntax_error("a type"));
292         return token;
293 }
294
295 string ProgramParser::expect_identifier()
296 {
297         string token = parse_token();
298         if(!is_identifier(token))
299                 throw runtime_error(format_syntax_error("an identifier"));
300         return token;
301 }
302
303 bool ProgramParser::check(const string &token)
304 {
305         bool result = (peek_token()==token);
306         if(result)
307                 parse_token();
308         return result;
309 }
310
311 bool ProgramParser::is_interface_qualifier(const string &token)
312 {
313         return (token=="uniform" || token=="in" || token=="out");
314 }
315
316 bool ProgramParser::is_sampling_qualifier(const string &token)
317 {
318         return (token=="centroid" || token=="sample");
319 }
320
321 bool ProgramParser::is_interpolation_qualifier(const string &token)
322 {
323         return (token=="smooth" || token=="flat" || token=="noperspective");
324 }
325
326 bool ProgramParser::is_precision_qualifier(const string &token)
327 {
328         return (token=="highp" || token=="mediump" || token=="lowp");
329 }
330
331 bool ProgramParser::is_qualifier(const string &token)
332 {
333         return (token=="const" ||
334                 is_interface_qualifier(token) ||
335                 is_sampling_qualifier(token) ||
336                 is_interpolation_qualifier(token) ||
337                 is_precision_qualifier(token));
338 }
339
340 bool ProgramParser::is_builtin_type(const string &token)
341 {
342         static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D)(Array)?(Shadow)?|Cube(Shadow)?|3D))$");
343         return re.match(token);
344 }
345
346 bool ProgramParser::is_type(const string &token)
347 {
348         return is_builtin_type(token) || declared_types.count(token);
349 }
350
351 bool ProgramParser::is_identifier(const string &token)
352 {
353         static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
354         return re.match(token);
355 }
356
357 void ProgramParser::preprocess()
358 {
359         expect("#");
360
361         string::const_iterator line_end = iter;
362         for(; (line_end!=source_end && *line_end!='\n'); ++line_end) ;
363         SetForScope<string::const_iterator> stop_at_line_end(source_end, line_end);
364
365         string token = peek_token();
366         if(token=="pragma")
367                 preprocess_pragma();
368         else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" ||
369                 token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="version" || token=="line")
370                 throw runtime_error(format_error(format("Unsupported preprocessor directive '%s'", token)));
371         else if(!token.empty())
372                 throw runtime_error(format_syntax_error("a preprocessor directive"));
373
374         iter = line_end;
375 }
376
377 void ProgramParser::preprocess_pragma()
378 {
379         expect("pragma");
380         string token = parse_token();
381         if(token=="MSP")
382                 preprocess_pragma_msp();
383 }
384
385 void ProgramParser::preprocess_pragma_msp()
386 {
387         string token = peek_token();
388         if(token=="stage")
389                 preprocess_stage();
390         else
391                 throw runtime_error(format_error(format("Unrecognized MSP pragma '%s'", token)));
392
393         token = parse_token();
394         if(!token.empty())
395                 throw runtime_error(format_syntax_error("end of line"));
396 }
397
398 void ProgramParser::preprocess_stage()
399 {
400         if(!allow_stage_change)
401                 throw runtime_error(format_error("Changing stage not allowed here"));
402
403         expect("stage");
404         expect("(");
405         string token = expect_identifier();
406         StageType stage = SHARED;
407         if(token=="vertex")
408                 stage = VERTEX;
409         else if(token=="geometry")
410                 stage = GEOMETRY;
411         else if(token=="fragment")
412                 stage = FRAGMENT;
413         else
414                 throw runtime_error(format_syntax_error("stage identifier"));
415         expect(")");
416
417         if(stage<=cur_stage->type)
418                 throw runtime_error(format_error(format("Stage '%s' not allowed here", token)));
419
420         module->stages.push_back(stage);
421
422         if(cur_stage->type!=SHARED)
423                 module->stages.back().previous = cur_stage;
424         cur_stage = &module->stages.back();
425 }
426
427 RefPtr<Node> ProgramParser::parse_global_declaration()
428 {
429         allow_stage_change = true;
430         string token = peek_token();
431         allow_stage_change = false;
432
433         if(token=="import")
434                 return parse_import();
435         else if(token=="precision")
436                 return parse_precision();
437         else if(token=="layout")
438         {
439                 RefPtr<Layout> layout = parse_layout();
440                 token = peek_token();
441                 if(is_interface_qualifier(token) && peek_token(1)==";")
442                 {
443                         RefPtr<InterfaceLayout> iface_lo = new InterfaceLayout;
444                         iface_lo->layout.qualifiers = layout->qualifiers;
445                         iface_lo->interface = parse_token();
446                         expect(";");
447                         return iface_lo;
448                 }
449                 else
450                 {
451                         RefPtr<VariableDeclaration> var = parse_variable_declaration();
452                         var->layout = layout;
453                         return var;
454                 }
455         }
456         else if(token=="struct")
457                 return parse_struct_declaration();
458         else if(is_interface_qualifier(token))
459         {
460                 string next = peek_token(1);
461                 if(is_type(next) || is_qualifier(next))
462                         return parse_variable_declaration();
463                 else
464                         return parse_interface_block();
465         }
466         else if(is_qualifier(token))
467                 return parse_variable_declaration();
468         else if(is_type(token))
469         {
470                 if(peek_token(2)=="(")
471                         return parse_function_declaration();
472                 else
473                         return parse_variable_declaration();
474         }
475         else if(token.empty())
476                 return 0;
477         else
478                 throw runtime_error(format_syntax_error("a global declaration"));
479 }
480
481 RefPtr<Node> ProgramParser::parse_statement()
482 {
483         string token = peek_token();
484         if(token=="if")
485                 return parse_conditional();
486         else if(token=="for")
487                 return parse_iteration();
488         else if(token=="passthrough")
489                 return parse_passthrough();
490         else if(token=="return")
491                 return parse_return();
492         else if(token=="break" || token=="continue" || token=="discard")
493         {
494                 RefPtr<Jump> jump = new Jump;
495                 jump->keyword = parse_token();
496                 expect(";");
497
498                 return jump;
499         }
500         else if(is_qualifier(token) || is_type(token))
501                 return parse_variable_declaration();
502         else if(!token.empty())
503         {
504                 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
505                 expr->expression = parse_expression();
506                 expect(";");
507
508                 return expr;
509         }
510         else
511                 throw runtime_error(format_syntax_error("a statement"));
512 }
513
514 RefPtr<Import> ProgramParser::parse_import()
515 {
516         if(cur_stage->type!=SHARED)
517                 throw runtime_error(format_error("Imports are only allowed in the shared section"));
518
519         expect("import");
520         RefPtr<Import> import = new Import;
521         import->module = parse_token();
522         expect(";");
523         return import;
524 }
525
526 RefPtr<Precision> ProgramParser::parse_precision()
527 {
528         expect("precision");
529         RefPtr<Precision> precision = new Precision;
530
531         precision->precision = parse_token();
532         if(!is_precision_qualifier(precision->precision))
533                 throw runtime_error(format_syntax_error("a precision qualifier"));
534
535         precision->type = parse_token();
536         // Not entirely accurate; only float, int and sampler types are allowed
537         if(!is_builtin_type(precision->type))
538                 throw runtime_error(format_syntax_error("a builtin type"));
539
540         expect(";");
541
542         return precision;
543 }
544
545 RefPtr<Layout> ProgramParser::parse_layout()
546 {
547         expect("layout");
548         expect("(");
549         RefPtr<Layout> layout = new Layout;
550         while(1)
551         {
552                 string token = parse_token();
553                 if(token==")")
554                         throw runtime_error(format_syntax_error("a layout qualifier name"));
555
556                 layout->qualifiers.push_back(Layout::Qualifier());
557                 Layout::Qualifier &qual = layout->qualifiers.back();
558                 qual.identifier = token;
559
560                 if(check("="))
561                         qual.value = parse_token();
562
563                 if(peek_token()==")")
564                         break;
565
566                 expect(",");
567         }
568         expect(")");
569
570         return layout;
571 }
572
573 void ProgramParser::parse_block(Block &block, bool require_braces)
574 {
575         bool have_braces = (require_braces || peek_token()=="{");
576         if(have_braces)
577                 expect("{");
578
579         if(have_braces)
580         {
581                 while(peek_token()!="}")
582                         block.body.push_back(parse_statement());
583         }
584         else
585                 block.body.push_back(parse_statement());
586
587         block.use_braces = (require_braces || block.body.size()!=1);
588
589         if(have_braces)
590                 expect("}");
591 }
592
593 RefPtr<Expression> ProgramParser::parse_expression(unsigned precedence)
594 {
595         RefPtr<Expression> left;
596         VariableReference *left_var = 0;
597         while(1)
598         {
599                 string token = peek_token();
600
601                 const Operator *oper = 0;
602                 for(Operator *i=operators; (!oper && i->type); ++i)
603                         if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX))
604                                 oper = i;
605
606                 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
607                 {
608                         if(left)
609                                 return left;
610                         else
611                                 throw runtime_error(format_syntax_error("an expression"));
612                 }
613                 else if(left)
614                 {
615                         if(token=="(")
616                         {
617                                 if(!left_var)
618                                         throw runtime_error(format_error("Syntax error before '(': function name must be an identifier"));
619                                 left = parse_function_call(*left_var);
620                         }
621                         else if(token==".")
622                         {
623                                 RefPtr<MemberAccess> memacc = new MemberAccess;
624                                 memacc->left = left;
625                                 parse_token();
626                                 memacc->member = expect_identifier();
627                                 left = memacc;
628                         }
629                         else if(oper && oper->type==POSTFIX)
630                         {
631                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
632                                 unary->oper = parse_token();
633                                 unary->prefix = false;
634                                 unary->expression = left;
635                                 left = unary;
636                         }
637                         else if(oper && oper->type==BINARY)
638                                 left = parse_binary(left, oper);
639                         else
640                                 throw runtime_error(format_syntax_error("an operator"));
641                         left_var = 0;
642                 }
643                 else
644                 {
645                         if(token=="(")
646                         {
647                                 parse_token();
648                                 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
649                                 parexpr->expression = parse_expression();
650                                 expect(")");
651                                 left = parexpr;
652                         }
653                         else if(isdigit(token[0]) || token=="true" || token=="false")
654                         {
655                                 RefPtr<Literal> literal = new Literal;
656                                 literal->token = parse_token();
657                                 left = literal;
658                         }
659                         else if(is_identifier(token))
660                         {
661                                 RefPtr<VariableReference> var = new VariableReference;
662                                 var->name = expect_identifier();
663                                 left = var;
664                                 left_var = var.get();
665                         }
666                         else if(oper && oper->type==PREFIX)
667                         {
668                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
669                                 unary->oper = parse_token();
670                                 unary->prefix = true;
671                                 unary->expression = parse_expression(oper->precedence);
672                                 left = unary;
673                         }
674                         else
675                                 throw runtime_error(format_syntax_error("an expression"));
676                 }
677         }
678 }
679
680 RefPtr<BinaryExpression> ProgramParser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
681 {
682         RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
683         binary->left = left;
684         binary->oper = parse_token();
685         if(binary->oper=="[")
686         {
687                 binary->right = parse_expression();
688                 expect("]");
689                 binary->after = "]";
690         }
691         else
692                 binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT));
693         return binary;
694 }
695
696 RefPtr<FunctionCall> ProgramParser::parse_function_call(const VariableReference &var)
697 {
698         RefPtr<FunctionCall> call = new FunctionCall;
699         call->name = var.name;
700         call->constructor = is_type(call->name);
701         expect("(");
702         while(peek_token()!=")")
703         {
704                 if(!call->arguments.empty())
705                         expect(",");
706                 call->arguments.push_back(parse_expression());
707         }
708         expect(")");
709         return call;
710 }
711
712 RefPtr<StructDeclaration> ProgramParser::parse_struct_declaration()
713 {
714         expect("struct");
715         RefPtr<StructDeclaration> strct = new StructDeclaration;
716
717         strct->name = expect_identifier();
718         parse_block(strct->members, true);
719         expect(";");
720
721         declared_types.insert(strct->name);
722         return strct;
723 }
724
725 RefPtr<VariableDeclaration> ProgramParser::parse_variable_declaration()
726 {
727         RefPtr<VariableDeclaration> var = new VariableDeclaration;
728
729         string token = peek_token();
730         while(is_qualifier(token))
731         {
732                 parse_token();
733                 if(is_interface_qualifier(token))
734                         var->interface = token;
735                 else if(is_sampling_qualifier(token))
736                         var->sampling = token;
737                 else if(is_interpolation_qualifier(token))
738                         var->interpolation = token;
739                 else if(is_precision_qualifier(token))
740                         var->precision = token;
741                 else if(token=="const")
742                         var->constant = true;
743                 token = peek_token();
744         }
745
746         var->type = expect_type();
747         var->name = expect_identifier();
748
749         if(check("["))
750         {
751                 var->array = true;
752                 if(!check("]"))
753                 {
754                         var->array_size = parse_expression();
755                         expect("]");
756                 }
757         }
758
759         if(check("="))
760                 var->init_expression = parse_expression();
761
762         expect(";");
763         return var;
764 }
765
766 RefPtr<FunctionDeclaration> ProgramParser::parse_function_declaration()
767 {
768         RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
769
770         func->return_type = expect_type();
771         func->name = expect_identifier();
772         expect("(");
773         while(peek_token()!=")")
774         {
775                 if(!func->parameters.empty())
776                         expect(",");
777
778                 RefPtr<VariableDeclaration> var = new VariableDeclaration;
779                 string token = peek_token();
780                 if(token=="in" || token=="out" || token=="inout")
781                         var->interface = parse_token();
782                 var->type = expect_type();
783                 var->name = expect_identifier();
784                 func->parameters.push_back(var);
785         }
786         expect(")");
787
788         string token = peek_token();
789         if(token=="{")
790         {
791                 func->definition = func.get();
792                 parse_block(func->body, true);
793         }
794         else if(token==";")
795                 parse_token();
796         else
797                 throw runtime_error(format_syntax_error("'{' or ';'"));
798
799         return func;
800 }
801
802 RefPtr<InterfaceBlock> ProgramParser::parse_interface_block()
803 {
804         RefPtr<InterfaceBlock> iface = new InterfaceBlock;
805
806         iface->interface = parse_token();
807         if(!is_interface_qualifier(iface->interface))
808                 throw runtime_error(format_syntax_error("an interface qualifier"));
809
810         iface->name = expect_identifier();
811         parse_block(iface->members, true);
812         if(!check(";"))
813         {
814                 iface->instance_name = expect_identifier();
815                 if(check("["))
816                 {
817                         iface->array = true;
818                         expect("]");
819                 }
820                 expect(";");
821         }
822
823         return iface;
824 }
825
826 RefPtr<Conditional> ProgramParser::parse_conditional()
827 {
828         expect("if");
829         expect("(");
830         RefPtr<Conditional> cond = new Conditional;
831         cond->condition = parse_expression();
832         expect(")");
833
834         parse_block(cond->body, false);
835
836         string token = peek_token();
837         if(token=="else")
838         {
839                 parse_token();
840                 parse_block(cond->else_body, false);
841         }
842
843         return cond;
844 }
845
846 RefPtr<Iteration> ProgramParser::parse_iteration()
847 {
848         expect("for");
849         expect("(");
850         RefPtr<Iteration> loop = new Iteration;
851         string token = peek_token();
852         if(is_type(token))
853                 loop->init_statement = parse_statement();
854         else
855         {
856                 if(token!=";")
857                 {
858                         RefPtr<ExpressionStatement> expr = new ExpressionStatement;
859                         expr->expression = parse_expression();
860                         loop->init_statement = expr;
861                 }
862                 expect(";");
863         }
864         if(peek_token()!=";")
865                 loop->condition = parse_expression();
866         expect(";");
867         if(peek_token()!=")")
868                 loop->loop_expression = parse_expression();
869         expect(")");
870
871         parse_block(loop->body, false);
872
873         return loop;
874 }
875
876 RefPtr<Passthrough> ProgramParser::parse_passthrough()
877 {
878         expect("passthrough");
879         RefPtr<Passthrough> pass = new Passthrough;
880         if(cur_stage->type==GEOMETRY)
881         {
882                 expect("[");
883                 pass->subscript = parse_expression();
884                 expect("]");
885         }
886         expect(";");
887         return pass;
888 }
889
890 RefPtr<Return> ProgramParser::parse_return()
891 {
892         expect("return");
893         RefPtr<Return> ret = new Return;
894         if(peek_token()!=";")
895                 ret->expression = parse_expression();
896         expect(";");
897         return ret;
898 }
899
900 } // namespace GL
901 } // namespace Msp