3 This file is part of libmspdatafile
4 Copyright © 2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
8 #include <msp/strings/formatter.h>
9 #include <msp/strings/utils.h>
11 #include "textparser.h"
19 TextParser::TextParser(Input &i, const string &s):
23 Statement TextParser::parse()
25 return parse_statement(0);
28 Statement TextParser::parse_statement(const Token *t)
45 if(result.keyword.empty())
49 else if(token.type!=Token::IDENTIFIER)
50 throw ParseError(format("%s: Syntax error at token '%s' (expected an identifier)", get_location(), token.str), src, in.get_line_number());
51 result.keyword=token.str;
54 result.line=in.get_line_number();
65 Statement ss=parse_statement(&token);
66 result.sub.push_back(ss);
72 throw ParseError(format("%s: Syntax error at token '%s' (Expected a ';')", get_location(), token.str), src, in.get_line_number());
75 else if(token.str=="{")
77 else if(token.str==";")
79 else if(token.type==Token::INTEGER)
80 result.args.push_back(Value(INTEGER, token.str));
81 else if(token.type==Token::FLOAT)
82 result.args.push_back(Value(FLOAT, token.str));
83 else if(token.type==Token::STRING)
84 result.args.push_back(Value(STRING, token.str));
85 else if(token.type==Token::IDENTIFIER)
88 result.args.push_back(Value(BOOLEAN, "1"));
89 else if(token.str=="false")
90 result.args.push_back(Value(BOOLEAN, "0"));
92 result.args.push_back(Value(ENUM, token.str));
93 //result.args.push_back(resolve_identifiertoken.str);
95 else if(token.str=="")
96 throw ParseError(src+": Unexcepted end of input", src, in.get_line_number());
98 throw ParseError(get_location()+": Syntax error", src, in.get_line_number());
104 Token TextParser::parse_token()
109 // Skip over comments and whitespace
115 if(c=='/' && next=='/')
117 else if(c=='/' && next=='*')
119 else if(c=='\n' && comment==1)
121 else if(c=='*' && next=='/' && comment==2)
123 else if(comment==3) // Skip the second character of block comment end
125 else if(!isspace(c) && !comment)
129 if(comment) // Didn't hit any non-whitespace
130 throw ParseError(src+": Unfinished comment at end of input", src, in.get_line_number());
149 static Token::Type token_type[]=
166 ParseState state=INIT;
183 else if(c=='-' || c=='+')
189 else if(c=='{' || c=='}' || c==';')
190 return Token(Token::SPECIAL, string(1, c));
193 else if(isalpha(c) || c=='_')
196 parse_error(c, state);
207 parse_error(c, state);
218 parse_error(c, state);
225 parse_error(c, state);
230 parse_error(c, state);
235 parse_error(c, state);
242 parse_error(c, state);
251 parse_error(c, state);
258 parse_error(c, state);
263 parse_error(c, state);
269 else if(c=='"' && !escape)
273 return Token(Token::STRING, c_unescape(buf.substr(1, buf.size()-2)));
275 catch(const Exception &e)
277 throw ParseError(format("%s: %s", get_location(), e.what()), src, in.get_line_number());
285 if(!isalpha(c) && !isdigit(c) && c!='_')
286 parse_error(c, state);
290 throw Exception(get_location()+": Internal error (bad state)");
293 if(is_delimiter(next) && state>=ACCEPT)
294 return Token(token_type[state], buf);
297 return Token(Token::SPECIAL, "");
300 bool TextParser::is_delimiter(int c)
302 return (isspace(c) || c=='{' || c=='}' || c==';' || c=='/');
305 bool TextParser::isodigit(int c)
307 return (c>='0' && c<='7');
310 string TextParser::get_location()
313 ss<<src<<':'<<in.get_line_number();
317 void TextParser::parse_error(int c, int state)
319 throw ParseError(format("%s: Parse error at '%c' (state %d)", get_location(), static_cast<char>(c), state), src, in.get_line_number());
322 } // namespace DataFile