3 This file is part of libmspdatafile
4 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
11 #include "statement.h"
19 Parser::Parser(istream &i, const string &s):
25 Statement Parser::parse()
28 throw Exception("Parser is not good");
34 catch(const Exception &e)
41 Statement Parser::parse_(const Token *t)
58 if(result.keyword.empty())
62 else if(token.type!=Token::IDENTIFIER)
63 throw ParseError(get_location()+": Syntax error at token '"+token.str+"' (expected an identifier)", src, in.get_line_number());
64 result.keyword=token.str;
67 result.line=in.get_line_number();
78 Statement ss=parse_(&token);
79 result.sub.push_back(ss);
85 throw ParseError(get_location()+": Syntax error at token '"+token.str+"' (Expected a ';')", src, in.get_line_number());
88 else if(token.str=="{")
90 else if(token.str==";")
92 else if(token.type==Token::INTEGER)
93 result.args.push_back(Value(Value::INTEGER, token.str));
94 else if(token.type==Token::FLOAT)
95 result.args.push_back(Value(Value::FLOAT, token.str));
96 else if(token.type==Token::STRING)
97 result.args.push_back(Value(Value::STRING, token.str));
98 else if(token.type==Token::IDENTIFIER)
100 if(token.str=="true")
101 result.args.push_back(Value(Value::BOOLEAN, "1"));
102 else if(token.str=="false")
103 result.args.push_back(Value(Value::BOOLEAN, "0"));
105 result.args.push_back(Value(Value::ENUM, token.str));
106 //result.args.push_back(resolve_identifiertoken.str);
108 else if(token.str=="")
109 throw ParseError(src+": Unexcepted EOF", src, in.get_line_number());
111 throw ParseError(get_location()+": Syntax error", src, in.get_line_number());
117 Token Parser::parse_token()
122 // Skip over comments and whitespace
128 if(c=='/' && next=='/')
130 else if(c=='/' && next=='*')
132 else if(c=='\n' && comment==1)
134 else if(c=='*' && next=='/' && comment==2)
136 else if(comment==3) // Skip the second character of block comment end
138 else if(!isspace(c) && !comment)
142 if(comment) // Didn't hit any non-whitespace
143 throw ParseError(src+": Unfinished comment", src, in.get_line_number());
162 static Token::Type token_type[]=
179 ParseState state=INIT;
196 else if(c=='-' || c=='+')
202 else if(c=='{' || c=='}' || c==';')
203 return Token(Token::SPECIAL, string(1, c));
209 parse_error(c, state);
220 parse_error(c, state);
231 parse_error(c, state);
238 parse_error(c, state);
243 parse_error(c, state);
248 parse_error(c, state);
255 parse_error(c, state);
264 parse_error(c, state);
271 parse_error(c, state);
276 parse_error(c, state);
282 else if(c=='"' && !escape)
283 return Token(Token::STRING, unescape_string(buf));
289 if(!isalpha(c) && !isdigit(c) && c!='_')
290 parse_error(c, state);
294 throw Exception(get_location()+": Internal error (bad state)");
297 if(is_delimiter(next) && state>=ACCEPT)
298 return Token(token_type[state], buf);
301 return Token(Token::SPECIAL, "");
304 bool Parser::is_delimiter(int c)
306 return (isspace(c) || c=='{' || c=='}' || c==';' || c=='/');
309 bool Parser::isodigit(int c)
311 return (c>='0' && c<='7');
314 string Parser::unescape_string(const string &str)
319 for(string::const_iterator i=str.begin()+1; i!=str.end()-1; ++i)
334 throw ParseError("Invalid escape", src, in.get_line_number());
340 if(*i>='0' && *i<='9')
342 else if(*i>='a' && *i<='f')
344 else if(*i>='A' && *i<='F')
347 throw ParseError("Invalid hex digit", src, in.get_line_number());
349 hexcape=(hexcape<<4)|digit;
352 result+=hexcape&0xFF;
365 string Parser::get_location()
368 ss<<src<<':'<<in.get_line_number();
372 void Parser::parse_error(int c, int state)
375 ss<<get_location()<<": Parse error at '"<<(char)c<<"' (state "<<state<<')';
376 throw ParseError(ss.str(), src, in.get_line_number());
379 } // namespace DataFile