]> git.tdb.fi Git - libs/gl.git/blob - source/programparser.cpp
Use bezier splines in Animation
[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_for();
488         else if(token=="while")
489                 return parse_while();
490         else if(token=="passthrough")
491                 return parse_passthrough();
492         else if(token=="return")
493                 return parse_return();
494         else if(token=="break" || token=="continue" || token=="discard")
495         {
496                 RefPtr<Jump> jump = new Jump;
497                 jump->keyword = parse_token();
498                 expect(";");
499
500                 return jump;
501         }
502         else if(is_qualifier(token) || is_type(token))
503                 return parse_variable_declaration();
504         else if(!token.empty())
505         {
506                 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
507                 expr->expression = parse_expression();
508                 expect(";");
509
510                 return expr;
511         }
512         else
513                 throw runtime_error(format_syntax_error("a statement"));
514 }
515
516 RefPtr<Import> ProgramParser::parse_import()
517 {
518         if(cur_stage->type!=SHARED)
519                 throw runtime_error(format_error("Imports are only allowed in the shared section"));
520
521         expect("import");
522         RefPtr<Import> import = new Import;
523         import->module = parse_token();
524         expect(";");
525         return import;
526 }
527
528 RefPtr<Precision> ProgramParser::parse_precision()
529 {
530         expect("precision");
531         RefPtr<Precision> precision = new Precision;
532
533         precision->precision = parse_token();
534         if(!is_precision_qualifier(precision->precision))
535                 throw runtime_error(format_syntax_error("a precision qualifier"));
536
537         precision->type = parse_token();
538         // Not entirely accurate; only float, int and sampler types are allowed
539         if(!is_builtin_type(precision->type))
540                 throw runtime_error(format_syntax_error("a builtin type"));
541
542         expect(";");
543
544         return precision;
545 }
546
547 RefPtr<Layout> ProgramParser::parse_layout()
548 {
549         expect("layout");
550         expect("(");
551         RefPtr<Layout> layout = new Layout;
552         while(1)
553         {
554                 string token = parse_token();
555                 if(token==")")
556                         throw runtime_error(format_syntax_error("a layout qualifier name"));
557
558                 layout->qualifiers.push_back(Layout::Qualifier());
559                 Layout::Qualifier &qual = layout->qualifiers.back();
560                 qual.identifier = token;
561
562                 if(check("="))
563                         qual.value = parse_token();
564
565                 if(peek_token()==")")
566                         break;
567
568                 expect(",");
569         }
570         expect(")");
571
572         return layout;
573 }
574
575 void ProgramParser::parse_block(Block &block, bool require_braces)
576 {
577         bool have_braces = (require_braces || peek_token()=="{");
578         if(have_braces)
579                 expect("{");
580
581         if(have_braces)
582         {
583                 while(peek_token()!="}")
584                         block.body.push_back(parse_statement());
585         }
586         else
587                 block.body.push_back(parse_statement());
588
589         block.use_braces = (require_braces || block.body.size()!=1);
590
591         if(have_braces)
592                 expect("}");
593 }
594
595 RefPtr<Expression> ProgramParser::parse_expression(unsigned precedence)
596 {
597         RefPtr<Expression> left;
598         VariableReference *left_var = 0;
599         while(1)
600         {
601                 string token = peek_token();
602
603                 const Operator *oper = 0;
604                 for(Operator *i=operators; (!oper && i->type); ++i)
605                         if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX))
606                                 oper = i;
607
608                 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
609                 {
610                         if(left)
611                                 return left;
612                         else
613                                 throw runtime_error(format_syntax_error("an expression"));
614                 }
615                 else if(left)
616                 {
617                         if(token=="(")
618                         {
619                                 if(!left_var)
620                                         throw runtime_error(format_error("Syntax error before '(': function name must be an identifier"));
621                                 left = parse_function_call(*left_var);
622                         }
623                         else if(token==".")
624                         {
625                                 RefPtr<MemberAccess> memacc = new MemberAccess;
626                                 memacc->left = left;
627                                 parse_token();
628                                 memacc->member = expect_identifier();
629                                 left = memacc;
630                         }
631                         else if(oper && oper->type==POSTFIX)
632                         {
633                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
634                                 unary->oper = parse_token();
635                                 unary->prefix = false;
636                                 unary->expression = left;
637                                 left = unary;
638                         }
639                         else if(oper && oper->type==BINARY)
640                                 left = parse_binary(left, oper);
641                         else
642                                 throw runtime_error(format_syntax_error("an operator"));
643                         left_var = 0;
644                 }
645                 else
646                 {
647                         if(token=="(")
648                         {
649                                 parse_token();
650                                 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
651                                 parexpr->expression = parse_expression();
652                                 expect(")");
653                                 left = parexpr;
654                         }
655                         else if(isdigit(token[0]) || token=="true" || token=="false")
656                         {
657                                 RefPtr<Literal> literal = new Literal;
658                                 literal->token = parse_token();
659                                 left = literal;
660                         }
661                         else if(is_identifier(token))
662                         {
663                                 RefPtr<VariableReference> var = new VariableReference;
664                                 var->name = expect_identifier();
665                                 left = var;
666                                 left_var = var.get();
667                         }
668                         else if(oper && oper->type==PREFIX)
669                         {
670                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
671                                 unary->oper = parse_token();
672                                 unary->prefix = true;
673                                 unary->expression = parse_expression(oper->precedence);
674                                 left = unary;
675                         }
676                         else
677                                 throw runtime_error(format_syntax_error("an expression"));
678                 }
679         }
680 }
681
682 RefPtr<BinaryExpression> ProgramParser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
683 {
684         RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
685         binary->left = left;
686         binary->oper = parse_token();
687         if(binary->oper=="[")
688         {
689                 binary->right = parse_expression();
690                 expect("]");
691                 binary->after = "]";
692         }
693         else
694                 binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT));
695         return binary;
696 }
697
698 RefPtr<FunctionCall> ProgramParser::parse_function_call(const VariableReference &var)
699 {
700         RefPtr<FunctionCall> call = new FunctionCall;
701         call->name = var.name;
702         call->constructor = is_type(call->name);
703         expect("(");
704         while(peek_token()!=")")
705         {
706                 if(!call->arguments.empty())
707                         expect(",");
708                 call->arguments.push_back(parse_expression());
709         }
710         expect(")");
711         return call;
712 }
713
714 RefPtr<StructDeclaration> ProgramParser::parse_struct_declaration()
715 {
716         expect("struct");
717         RefPtr<StructDeclaration> strct = new StructDeclaration;
718
719         strct->name = expect_identifier();
720         parse_block(strct->members, true);
721         expect(";");
722
723         declared_types.insert(strct->name);
724         return strct;
725 }
726
727 RefPtr<VariableDeclaration> ProgramParser::parse_variable_declaration()
728 {
729         RefPtr<VariableDeclaration> var = new VariableDeclaration;
730
731         string token = peek_token();
732         while(is_qualifier(token))
733         {
734                 parse_token();
735                 if(is_interface_qualifier(token))
736                         var->interface = token;
737                 else if(is_sampling_qualifier(token))
738                         var->sampling = token;
739                 else if(is_interpolation_qualifier(token))
740                         var->interpolation = token;
741                 else if(is_precision_qualifier(token))
742                         var->precision = token;
743                 else if(token=="const")
744                         var->constant = true;
745                 token = peek_token();
746         }
747
748         var->type = expect_type();
749         var->name = expect_identifier();
750
751         if(check("["))
752         {
753                 var->array = true;
754                 if(!check("]"))
755                 {
756                         var->array_size = parse_expression();
757                         expect("]");
758                 }
759         }
760
761         if(check("="))
762                 var->init_expression = parse_expression();
763
764         expect(";");
765         return var;
766 }
767
768 RefPtr<FunctionDeclaration> ProgramParser::parse_function_declaration()
769 {
770         RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
771
772         func->return_type = expect_type();
773         func->name = expect_identifier();
774         expect("(");
775         while(peek_token()!=")")
776         {
777                 if(!func->parameters.empty())
778                         expect(",");
779
780                 RefPtr<VariableDeclaration> var = new VariableDeclaration;
781                 string token = peek_token();
782                 if(token=="in" || token=="out" || token=="inout")
783                         var->interface = parse_token();
784                 var->type = expect_type();
785                 var->name = expect_identifier();
786                 func->parameters.push_back(var);
787         }
788         expect(")");
789
790         string token = peek_token();
791         if(token=="{")
792         {
793                 func->definition = func.get();
794                 parse_block(func->body, true);
795         }
796         else if(token==";")
797                 parse_token();
798         else
799                 throw runtime_error(format_syntax_error("'{' or ';'"));
800
801         return func;
802 }
803
804 RefPtr<InterfaceBlock> ProgramParser::parse_interface_block()
805 {
806         RefPtr<InterfaceBlock> iface = new InterfaceBlock;
807
808         iface->interface = parse_token();
809         if(!is_interface_qualifier(iface->interface))
810                 throw runtime_error(format_syntax_error("an interface qualifier"));
811
812         iface->name = expect_identifier();
813         parse_block(iface->members, true);
814         if(!check(";"))
815         {
816                 iface->instance_name = expect_identifier();
817                 if(check("["))
818                 {
819                         iface->array = true;
820                         expect("]");
821                 }
822                 expect(";");
823         }
824
825         return iface;
826 }
827
828 RefPtr<Conditional> ProgramParser::parse_conditional()
829 {
830         expect("if");
831         expect("(");
832         RefPtr<Conditional> cond = new Conditional;
833         cond->condition = parse_expression();
834         expect(")");
835
836         parse_block(cond->body, false);
837
838         string token = peek_token();
839         if(token=="else")
840         {
841                 parse_token();
842                 parse_block(cond->else_body, false);
843         }
844
845         return cond;
846 }
847
848 RefPtr<Iteration> ProgramParser::parse_for()
849 {
850         expect("for");
851         expect("(");
852         RefPtr<Iteration> loop = new Iteration;
853         string token = peek_token();
854         if(is_type(token))
855                 loop->init_statement = parse_statement();
856         else
857         {
858                 if(token!=";")
859                 {
860                         RefPtr<ExpressionStatement> expr = new ExpressionStatement;
861                         expr->expression = parse_expression();
862                         loop->init_statement = expr;
863                 }
864                 expect(";");
865         }
866         if(peek_token()!=";")
867                 loop->condition = parse_expression();
868         expect(";");
869         if(peek_token()!=")")
870                 loop->loop_expression = parse_expression();
871         expect(")");
872
873         parse_block(loop->body, false);
874
875         return loop;
876 }
877
878 RefPtr<Iteration> ProgramParser::parse_while()
879 {
880         expect("while");
881         expect("(");
882         RefPtr<Iteration> loop = new Iteration;
883         loop->condition = parse_expression();
884         expect(")");
885
886         parse_block(loop->body, false);
887
888         return loop;
889 }
890
891 RefPtr<Passthrough> ProgramParser::parse_passthrough()
892 {
893         expect("passthrough");
894         RefPtr<Passthrough> pass = new Passthrough;
895         if(cur_stage->type==GEOMETRY)
896         {
897                 expect("[");
898                 pass->subscript = parse_expression();
899                 expect("]");
900         }
901         expect(";");
902         return pass;
903 }
904
905 RefPtr<Return> ProgramParser::parse_return()
906 {
907         expect("return");
908         RefPtr<Return> ret = new Return;
909         if(peek_token()!=";")
910                 ret->expression = parse_expression();
911         expect(";");
912         return ret;
913 }
914
915 } // namespace GL
916 } // namespace Msp