3 This file is part of libmspdatafile
4 Copyright © 2007-2008, 2010 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)
43 token = parse_token();
45 if(result.keyword.empty())
49 else if(token.type!=Token::IDENTIFIER)
50 throw_at(ParseError(format("Syntax error at token '%s' (expected an identifier)", token.str)), get_location());
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_at(ParseError(format("Syntax error at token '%s' (Expected a ';')", token.str)), get_location());
75 else if(token.str=="{")
77 else if(token.str==";")
79 else if(token.type==Token::INTEGER)
80 result.append(lexical_cast<IntType::Store>(token.str));
81 else if(token.type==Token::FLOAT)
82 result.append(lexical_cast<FloatType::Store>(token.str));
83 else if(token.type==Token::STRING)
84 result.append(token.str);
85 else if(token.type==Token::IDENTIFIER)
89 else if(token.str=="false")
92 result.append(Symbol(token.str));
94 else if(token.str=="")
95 throw_at(ParseError("Unexcepted end of input"), get_location());
97 throw_at(ParseError("Syntax error"), get_location());
103 Token TextParser::parse_token()
108 // Skip over comments and whitespace
109 while(in && comment>=0)
112 int next = in.peek();
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>0) // EOF while in comment
129 throw_at(ParseError("Unfinished comment at end of input"), get_location());
130 else if(comment==0) // Didn't hit any non-whitespace
131 return Token(Token::SPECIAL, "");
150 static Token::Type token_type[]=
167 ParseState state = INIT;
171 while(in || state==INIT)
175 int next = in.peek();
184 else if(c=='-' || c=='+')
190 else if(c=='{' || c=='}' || c==';')
191 return Token(Token::SPECIAL, string(1, c));
194 else if(isalpha(c) || c=='_')
197 parse_error(c, "0-9A-Za-z_.\"{};+-");
208 parse_error(c, "0-9.");
219 parse_error(c, "0-9A-Fa-f.");
226 parse_error(c, "0-9.");
231 parse_error(c, "0-9A-Fa-f");
236 parse_error(c, "0-7");
241 state = FLOATEXPINIT;
243 parse_error(c, "0-9Ee");
248 state = FLOATEXPSIGN;
252 parse_error(c, "0-9+-");
259 parse_error(c, "0-9");
264 parse_error(c, "0-9");
270 else if(c=='"' && !escape)
274 return Token(Token::STRING, c_unescape(buf.substr(1, buf.size()-2)));
278 e.at(get_location());
287 if(!isalpha(c) && !isdigit(c) && c!='_')
288 parse_error(c, "0-9A-Za-z_");
292 throw_at(InvalidState("Internal error (bad state)"), get_location());
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, const char *e)
321 throw_at(ParseError(format("Parse error at '%c', expected one of \"%s\"", static_cast<char>(c), e)), get_location());
324 } // namespace DataFile