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