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