3 This file is part of libmspdatafile
4 Copyright © 2007-2008 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.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_at(ParseError("Unexcepted end of input"), get_location());
98 throw_at(ParseError("Syntax error"), get_location());
104 Token TextParser::parse_token()
109 // Skip over comments and whitespace
110 while(in && comment>=0)
113 int next = in.peek();
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_at(ParseError("Unfinished comment at end of input"), get_location());
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)
176 int next = in.peek();
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, "0-9A-Za-z_.\"{};+-");
209 parse_error(c, "0-9.");
220 parse_error(c, "0-9A-Fa-f.");
227 parse_error(c, "0-9.");
232 parse_error(c, "0-9A-Fa-f");
237 parse_error(c, "0-7");
242 state = FLOATEXPINIT;
244 parse_error(c, "0-9Ee");
249 state = FLOATEXPSIGN;
253 parse_error(c, "0-9+-");
260 parse_error(c, "0-9");
265 parse_error(c, "0-9");
271 else if(c=='"' && !escape)
275 return Token(Token::STRING, c_unescape(buf.substr(1, buf.size()-2)));
279 e.at(get_location());
288 if(!isalpha(c) && !isdigit(c) && c!='_')
289 parse_error(c, "0-9A-Za-z_");
293 throw_at(InvalidState("Internal error (bad state)"), get_location());
296 if(is_delimiter(next) && state>=ACCEPT)
297 return Token(token_type[state], buf);
300 return Token(Token::SPECIAL, "");
303 bool TextParser::is_delimiter(int c)
305 return (isspace(c) || c=='{' || c=='}' || c==';' || c=='/');
308 bool TextParser::isodigit(int c)
310 return (c>='0' && c<='7');
313 string TextParser::get_location()
316 ss<<src<<':'<<in.get_line_number();
320 void TextParser::parse_error(int c, const char *e)
322 throw_at(ParseError(format("Parse error at '%c', expected one of \"%s\"", static_cast<char>(c), e)), get_location());
325 } // namespace DataFile