1 #include <msp/strings/format.h>
2 #include <msp/strings/utils.h>
4 #include "textparser.h"
12 class parse_error: public runtime_error
15 parse_error(const std::string &t):
16 runtime_error(t.empty() ? "at end of input" : format("after '%s'", t))
19 virtual ~parse_error() throw() { }
23 class syntax_error: public runtime_error
26 syntax_error(const std::string &t):
27 runtime_error(t.empty() ? "at end of input" : format("at '%s'", t))
30 virtual ~syntax_error() throw() { }
34 TextParser::TextParser(Input &i, const string &s):
38 Statement TextParser::parse()
40 return parse_statement(0);
43 Statement TextParser::parse_statement(const Token *t)
58 token = parse_token();
60 if(result.keyword.empty())
64 else if(token.type!=Token::IDENTIFIER)
65 throw syntax_error(token.str);
66 result.keyword = token.str;
69 result.line = in.get_line_number();
80 Statement ss = parse_statement(&token);
81 result.sub.push_back(ss);
87 throw syntax_error(token.str);
90 else if(token.str=="{")
92 else if(token.str==";")
94 else if(token.type==Token::INTEGER)
95 result.append(lexical_cast<IntType::Store>(token.str));
96 else if(token.type==Token::FLOAT)
97 result.append(lexical_cast<FloatType::Store>(token.str));
98 else if(token.type==Token::STRING)
99 result.append(token.str);
100 else if(token.type==Token::IDENTIFIER)
102 if(token.str=="true")
104 else if(token.str=="false")
105 result.append(false);
107 result.append(Symbol(token.str));
110 throw syntax_error(token.str);
116 Token TextParser::parse_token()
121 // Skip over comments and whitespace
122 while(in && comment>=0)
125 int next = in.peek();
127 if(c=='/' && next=='/')
129 else if(c=='/' && next=='*')
131 else if(c=='\n' && comment==1)
133 else if(c=='*' && next=='/' && comment==2)
135 else if(comment==3) // Skip the second character of block comment end
137 else if(c!=-1 && !isspace(c) && !comment)
141 if(comment>0) // EOF while in comment
142 throw parse_error(string());
143 else if(comment==0) // Didn't hit any non-whitespace
144 return Token(Token::SPECIAL, "");
164 static Token::Type token_type[]=
182 ParseState state = INIT;
186 while(in || state==INIT)
190 int next = in.peek();
199 else if(c=='-' || c=='+')
205 else if(c=='{' || c=='}' || c==';')
206 return Token(Token::SPECIAL, string(1, c));
209 else if(isalpha(c) || c=='_' || c=='\\')
212 throw parse_error(buf);
223 throw parse_error(buf);
234 throw parse_error(buf);
240 else if(c=='e' || c=='E')
241 state = FLOATEXPINIT;
243 throw parse_error(buf);
248 throw parse_error(buf);
253 throw parse_error(buf);
258 state = FLOATEXPINIT;
260 throw parse_error(buf);
265 state = FLOATEXPSIGN;
269 throw parse_error(buf);
276 throw parse_error(buf);
281 throw parse_error(buf);
287 else if(c=='"' && !escape)
294 if(!isalpha(c) && !isdigit(c) && c!='_' && c!='-' && c!='/')
295 throw parse_error(buf);
299 throw parse_error(buf);
302 throw logic_error("bad parser state");
305 if(is_delimiter(next) && state>=ACCEPT)
307 if(state==IDENTIFIER && buf[0]=='\\')
308 return Token(Token::IDENTIFIER, buf.substr(1));
309 else if(state==STRING_END)
310 return Token(Token::STRING, c_unescape(buf.substr(1, buf.size()-2)));
312 return Token(token_type[state], buf);
316 return Token(Token::SPECIAL, "");
319 bool TextParser::is_delimiter(int c)
321 return (isspace(c) || c=='{' || c=='}' || c==';' || c=='/');
324 bool TextParser::isodigit(int c)
326 return (c>='0' && c<='7');
329 } // namespace DataFile