1 #include <msp/strings/format.h>
2 #include <msp/strings/regex.h>
3 #include "programparser.h"
10 using namespace ProgramSyntax;
12 Module &ProgramParser::parse(const string &s)
15 parse_source(main_module);
19 Module &ProgramParser::parse(IO::Base &io)
25 unsigned len = io.read(buffer, sizeof(buffer));
26 source.append(buffer, len);
28 parse_source(main_module);
32 void ProgramParser::parse_source(Module &module)
35 iter = source.begin();
36 Context *cur_context = &module.global_context;
39 while(Node *statement = parse_global_declaration())
40 cur_context->content.body.push_back(statement);
41 cur_context->present = !cur_context->content.body.empty();
44 string token = parse_token();
47 else if(token=="global")
48 cur_context = &module.global_context;
49 else if(token=="vertex")
50 cur_context = &module.vertex_context;
51 else if(token=="geometry")
52 cur_context = &module.geometry_context;
53 else if(token=="fragment")
54 cur_context = &module.fragment_context;
56 throw runtime_error(format("Parse error at '%s': expected context identifier", token));
58 for(; (iter!=source.end() && *iter!='\n'); ++iter) ;
62 const string &ProgramParser::peek_token(unsigned index)
64 while(next_tokens.size()<=index)
65 next_tokens.push_back(parse_token_());
66 return next_tokens[index];
69 string ProgramParser::parse_token()
71 if(!next_tokens.empty())
73 string token = next_tokens.front();
74 next_tokens.pop_front();
78 return parse_token_();
81 string ProgramParser::parse_token_()
83 if(!skip_comment_and_whitespace())
86 if(isalpha(*iter) || *iter=='_')
87 return parse_identifier();
88 else if(isdigit(*iter))
89 return parse_number();
94 string ProgramParser::parse_identifier()
97 while(iter!=source.end())
99 if(isalnum(*iter) || *iter=='_')
108 string ProgramParser::parse_number()
110 bool accept_sign = false;
112 while(iter!=source.end())
114 if(isdigit(*iter) || *iter=='.')
116 else if(*iter=='e' || *iter=='E')
121 else if(accept_sign && (*iter=='+' || *iter=='-'))
130 string ProgramParser::parse_other()
133 while(iter!=source.end())
135 if(isalnum(*iter) || *iter=='_' || isspace(*iter))
138 if(*iter==';' || *iter=='(' || *iter==')' || *iter=='[' || *iter==']')
145 bool ProgramParser::skip_comment_and_whitespace()
147 unsigned comment = 0;
148 unsigned slashes = 0;
149 while(iter!=source.end())
151 //IO::print("%d '%c'\n", comment, *iter);
156 else if(!isspace(*iter))
181 else if(!isspace(*iter) && slashes>=6)
184 else if(comment==3 && *iter=='*')
197 return iter!=source.end();
200 void ProgramParser::expect(const string &token)
202 string parsed = parse_token();
204 throw runtime_error(format("Parse error at '%s': expected '%s'", parsed, token));
207 string ProgramParser::expect_type()
209 string token = parse_token();
211 throw runtime_error(format("Parse error at '%s': expected a type", token));
215 string ProgramParser::expect_identifier()
217 static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
218 string token = parse_token();
220 throw runtime_error(format("Parse error at '%s': expected an identifier", token));
224 bool ProgramParser::check(const string &token)
226 bool result = (peek_token()==token);
232 bool ProgramParser::is_interface_qualifier(const string &token)
234 return (token=="uniform" || token=="in" || token=="out");
237 bool ProgramParser::is_sampling_qualifier(const string &token)
239 return token=="centroid";
242 bool ProgramParser::is_qualifier(const string &token)
244 return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token));
247 bool ProgramParser::is_builtin_type(const string &token)
249 static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D)(Array)?(Shadow)?|Cube(Shadow)?|3D))$");
250 return re.match(token);
253 bool ProgramParser::is_type(const string &token)
255 return is_builtin_type(token) || cur_module->structs.count(token);
258 Node *ProgramParser::parse_global_declaration()
260 string token = peek_token();
262 return parse_layout();
263 else if(token=="struct")
264 return parse_struct_declaration();
265 else if(is_sampling_qualifier(token) || token=="const")
266 return parse_variable_declaration();
267 else if(is_interface_qualifier(token))
269 if(is_type(peek_token(1)))
270 return parse_variable_declaration();
272 return parse_interface_block();
274 else if(is_type(token))
276 if(peek_token(2)=="(")
277 return parse_function_declaration();
279 return parse_variable_declaration();
281 else if(token.empty())
284 throw runtime_error(format("Syntax error at '%s': expected a global declaration", token));
287 Node *ProgramParser::parse_statement()
289 string token = peek_token();
291 return parse_conditional();
292 else if(token=="for")
293 return parse_iteration();
294 else if(token=="return")
295 return parse_return();
296 else if(is_qualifier(token) || is_type(token))
297 return parse_variable_declaration();
298 else if(!token.empty())
300 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
301 parse_expression(expr->expression);
304 return expr.release();
307 throw runtime_error(format("Syntax error at '%s': expected a statement", token));
310 Layout *ProgramParser::parse_layout()
314 RefPtr<Layout> layout = new Layout;
317 string token = parse_token();
319 throw runtime_error(format("Parse error at '%s': expected layout qualifier id", token));
321 layout->qualifiers.push_back(Layout::Qualifier());
322 Layout::Qualifier &qual = layout->qualifiers.back();
323 qual.identifier = token;
326 qual.value = parse_token();
328 if(peek_token()==")")
334 layout->interface = parse_token();
337 return layout.release();
340 void ProgramParser::parse_block(Block &block, bool require_braces)
342 bool have_braces = (require_braces || peek_token()=="{");
348 string token = peek_token();
352 block.body.push_back(parse_statement());
357 block.use_braces = (require_braces || block.body.size()!=1);
363 void ProgramParser::parse_expression(Expression &expr)
365 unsigned nesting_level = 0;
366 while(iter!=source.end())
368 string token = peek_token();
369 if(token=="(" || token=="[")
371 else if(token==")" || token=="]")
381 expr.tokens.push_back(token);
385 StructDeclaration *ProgramParser::parse_struct_declaration()
388 RefPtr<StructDeclaration> strct = new StructDeclaration;
390 strct->name = expect_identifier();
391 parse_block(strct->members, true);
394 cur_module->structs[strct->name] = strct.get();
395 return strct.release();
398 VariableDeclaration *ProgramParser::parse_variable_declaration()
400 RefPtr<VariableDeclaration> var = new VariableDeclaration;
402 string token = peek_token();
403 if(is_sampling_qualifier(token))
405 var->sampling = parse_token();
406 token = peek_token();
407 if(!is_interface_qualifier(token))
408 throw runtime_error(format("Parse error at '%s': expected an interface qualifier", token));
411 if(is_interface_qualifier(token))
412 var->interface = parse_token();
413 else if(token=="const")
415 var->constant = true;
419 var->type = expect_type();
420 var->name = expect_identifier();
427 parse_expression(var->array_size);
433 parse_expression(var->init_expression);
436 return var.release();
439 FunctionDeclaration *ProgramParser::parse_function_declaration()
441 RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
443 func->return_type = expect_type();
444 func->name = expect_identifier();
445 parse_function_parameter_list(*func);
447 string token = peek_token();
450 func->definition = true;
451 parse_block(func->body, true);
456 throw runtime_error(format("Parse error at '%s': expected '{' or ';'", token));
458 return func.release();
461 void ProgramParser::parse_function_parameter_list(FunctionDeclaration &func)
466 string token = peek_token();
469 else if(!func.parameters.empty())
472 RefPtr<VariableDeclaration> var = new VariableDeclaration;
473 var->type = expect_type();
474 var->name = expect_identifier();
475 func.parameters.push_back(var.release());
480 InterfaceBlock *ProgramParser::parse_interface_block()
482 RefPtr<InterfaceBlock> iface = new InterfaceBlock;
484 iface->interface = parse_token();
485 if(!is_interface_qualifier(iface->interface))
486 throw runtime_error(format("Parse error at '%s': expected an interface qualifier", iface->interface));
488 iface->name = expect_identifier();
489 parse_block(iface->members, true);
492 return iface.release();
495 Conditional *ProgramParser::parse_conditional()
499 RefPtr<Conditional> cond = new Conditional;
500 parse_expression(cond->condition);
503 parse_block(cond->body, false);
505 string token = peek_token();
509 parse_block(cond->else_body, false);
512 return cond.release();
515 Iteration *ProgramParser::parse_iteration()
519 RefPtr<Iteration> loop = new Iteration;
520 string token = peek_token();
522 loop->init_statement = parse_statement();
525 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
526 parse_expression(expr->expression);
528 loop->init_statement = expr.release();
530 parse_expression(loop->condition);
532 parse_expression(loop->loop_expression);
535 parse_block(loop->body, false);
537 return loop.release();
540 Return *ProgramParser::parse_return()
543 RefPtr<Return> ret = new Return;
544 parse_expression(ret->expression);
546 return ret.release();