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
110 while(in && comment>=0)
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>0) // EOF while in comment
130 throw ParseError(src+": Unfinished comment at end of input", src, in.get_line_number());
131 else if(comment==0) // Didn't hit any non-whitespace
132 return Token(Token::SPECIAL, "");
151 static Token::Type token_type[]=
168 ParseState state=INIT;
172 while(in || state==INIT)
185 else if(c=='-' || c=='+')
191 else if(c=='{' || c=='}' || c==';')
192 return Token(Token::SPECIAL, string(1, c));
195 else if(isalpha(c) || c=='_')
198 parse_error(c, state);
209 parse_error(c, state);
220 parse_error(c, state);
227 parse_error(c, state);
232 parse_error(c, state);
237 parse_error(c, state);
244 parse_error(c, state);
253 parse_error(c, state);
260 parse_error(c, state);
265 parse_error(c, state);
271 else if(c=='"' && !escape)
275 return Token(Token::STRING, c_unescape(buf.substr(1, buf.size()-2)));
277 catch(const Exception &e)
279 throw ParseError(format("%s: %s", get_location(), e.what()), src, in.get_line_number());
287 if(!isalpha(c) && !isdigit(c) && c!='_')
288 parse_error(c, state);
292 throw Exception(get_location()+": Internal error (bad state)");
295 if(is_delimiter(next) && state>=ACCEPT)
296 return Token(token_type[state], buf);
299 return Token(Token::SPECIAL, "");
302 bool TextParser::is_delimiter(int c)
304 return (isspace(c) || c=='{' || c=='}' || c==';' || c=='/');
307 bool TextParser::isodigit(int c)
309 return (c>='0' && c<='7');
312 string TextParser::get_location()
315 ss<<src<<':'<<in.get_line_number();
319 void TextParser::parse_error(int c, int state)
321 throw ParseError(format("%s: Parse error at '%c' (state %d)", get_location(), static_cast<char>(c), state), src, in.get_line_number());
324 } // namespace DataFile