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>
10 #include "textparser.h"
18 TextParser::TextParser(Input &i, const string &s):
22 Statement TextParser::parse()
24 return parse_statement(0);
27 Statement TextParser::parse_statement(const Token *t)
44 if(result.keyword.empty())
48 else if(token.type!=Token::IDENTIFIER)
49 throw ParseError(format("%s: Syntax error at token '%s' (expected an identifier)", get_location(), token.str), src, in.get_line_number());
50 result.keyword=token.str;
53 result.line=in.get_line_number();
64 Statement ss=parse_statement(&token);
65 result.sub.push_back(ss);
71 throw ParseError(format("%s: Syntax error at token '%s' (Expected a ';')", get_location(), token.str), src, in.get_line_number());
74 else if(token.str=="{")
76 else if(token.str==";")
78 else if(token.type==Token::INTEGER)
79 result.args.push_back(Value(INTEGER, token.str));
80 else if(token.type==Token::FLOAT)
81 result.args.push_back(Value(FLOAT, token.str));
82 else if(token.type==Token::STRING)
83 result.args.push_back(Value(STRING, token.str));
84 else if(token.type==Token::IDENTIFIER)
87 result.args.push_back(Value(BOOLEAN, "1"));
88 else if(token.str=="false")
89 result.args.push_back(Value(BOOLEAN, "0"));
91 result.args.push_back(Value(ENUM, token.str));
92 //result.args.push_back(resolve_identifiertoken.str);
94 else if(token.str=="")
95 throw ParseError(src+": Unexcepted end of input", src, in.get_line_number());
97 throw ParseError(get_location()+": Syntax error", src, in.get_line_number());
103 Token TextParser::parse_token()
108 // Skip over comments and whitespace
114 if(c=='/' && next=='/')
116 else if(c=='/' && next=='*')
118 else if(c=='\n' && comment==1)
120 else if(c=='*' && next=='/' && comment==2)
122 else if(comment==3) // Skip the second character of block comment end
124 else if(!isspace(c) && !comment)
128 if(comment) // Didn't hit any non-whitespace
129 throw ParseError(src+": Unfinished comment at end of input", src, in.get_line_number());
148 static Token::Type token_type[]=
165 ParseState state=INIT;
182 else if(c=='-' || c=='+')
188 else if(c=='{' || c=='}' || c==';')
189 return Token(Token::SPECIAL, string(1, c));
192 else if(isalpha(c) || c=='_')
195 parse_error(c, state);
206 parse_error(c, state);
217 parse_error(c, state);
224 parse_error(c, state);
229 parse_error(c, state);
234 parse_error(c, state);
241 parse_error(c, state);
250 parse_error(c, state);
257 parse_error(c, state);
262 parse_error(c, state);
268 else if(c=='"' && !escape)
269 return Token(Token::STRING, unescape_string(buf));
275 if(!isalpha(c) && !isdigit(c) && c!='_')
276 parse_error(c, state);
280 throw Exception(get_location()+": Internal error (bad state)");
283 if(is_delimiter(next) && state>=ACCEPT)
284 return Token(token_type[state], buf);
287 return Token(Token::SPECIAL, "");
290 bool TextParser::is_delimiter(int c)
292 return (isspace(c) || c=='{' || c=='}' || c==';' || c=='/');
295 bool TextParser::isodigit(int c)
297 return (c>='0' && c<='7');
300 string TextParser::unescape_string(const string &str)
305 for(string::const_iterator i=str.begin()+1; i!=str.end()-1; ++i)
320 throw ParseError(format("%s: Invalid escape sequence '\\%c'", get_location(), *i), src, in.get_line_number());
326 if(*i>='0' && *i<='9')
328 else if(*i>='a' && *i<='f')
330 else if(*i>='A' && *i<='F')
333 throw ParseError(get_location()+": Invalid hex digit", src, in.get_line_number());
335 hexcape=(hexcape<<4)|digit;
338 result+=hexcape&0xFF;
351 string TextParser::get_location()
354 ss<<src<<':'<<in.get_line_number();
358 void TextParser::parse_error(int c, int state)
360 throw ParseError(format("%s: Parse error at '%c' (state %d)", get_location(), static_cast<char>(c), state), src, in.get_line_number());
363 } // namespace DataFile