1 #include <msp/strings/format.h>
2 #include <msp/strings/utils.h>
4 #include "textparser.h"
12 TextParser::TextParser(Input &i, const string &s):
16 Statement TextParser::parse()
18 return parse_statement(0);
21 Statement TextParser::parse_statement(const Token *t)
36 token = parse_token();
38 if(result.keyword.empty())
42 else if(token.type!=Token::IDENTIFIER)
43 throw_at(ParseError(format("Syntax error at token '%s' (expected an identifier)", token.str)), get_location());
44 result.keyword = token.str;
47 result.line = in.get_line_number();
58 Statement ss = parse_statement(&token);
59 result.sub.push_back(ss);
65 throw_at(ParseError(format("Syntax error at token '%s' (Expected a ';')", token.str)), get_location());
68 else if(token.str=="{")
70 else if(token.str==";")
72 else if(token.type==Token::INTEGER)
73 result.append(lexical_cast<IntType::Store>(token.str));
74 else if(token.type==Token::FLOAT)
75 result.append(lexical_cast<FloatType::Store>(token.str));
76 else if(token.type==Token::STRING)
77 result.append(token.str);
78 else if(token.type==Token::IDENTIFIER)
82 else if(token.str=="false")
85 result.append(Symbol(token.str));
87 else if(token.str=="")
88 throw_at(ParseError("Unexcepted end of input"), get_location());
90 throw_at(ParseError("Syntax error"), get_location());
96 Token TextParser::parse_token()
101 // Skip over comments and whitespace
102 while(in && comment>=0)
105 int next = in.peek();
107 if(c=='/' && next=='/')
109 else if(c=='/' && next=='*')
111 else if(c=='\n' && comment==1)
113 else if(c=='*' && next=='/' && comment==2)
115 else if(comment==3) // Skip the second character of block comment end
117 else if(c!=-1 && !isspace(c) && !comment)
121 if(comment>0) // EOF while in comment
122 throw_at(ParseError("Unfinished comment at end of input"), get_location());
123 else if(comment==0) // Didn't hit any non-whitespace
124 return Token(Token::SPECIAL, "");
144 static Token::Type token_type[]=
162 ParseState state = INIT;
166 while(in || state==INIT)
170 int next = in.peek();
179 else if(c=='-' || c=='+')
185 else if(c=='{' || c=='}' || c==';')
186 return Token(Token::SPECIAL, string(1, c));
189 else if(isalpha(c) || c=='_' || c=='\\')
192 parse_error(c, "0-9A-Za-z_\\.\"{};+-");
203 parse_error(c, "0-9.");
214 parse_error(c, "0-9A-Fa-f.");
221 parse_error(c, "0-9.");
226 parse_error(c, "0-9A-Fa-f");
231 parse_error(c, "0-7");
236 state = FLOATEXPINIT;
238 parse_error(c, "0-9Ee");
243 state = FLOATEXPSIGN;
247 parse_error(c, "0-9+-");
254 parse_error(c, "0-9");
259 parse_error(c, "0-9");
265 else if(c=='"' && !escape)
272 if(!isalpha(c) && !isdigit(c) && c!='_' && c!='-' && c!='/')
273 parse_error(c, "0-9A-Za-z_/-");
277 throw_at(ParseError("Garbage after string"), get_location());
280 throw_at(InvalidState("Internal error (bad state)"), get_location());
283 if(is_delimiter(next) && state>=ACCEPT)
285 if(state==IDENTIFIER && buf[0]=='\\')
286 return Token(Token::IDENTIFIER, buf.substr(1));
287 else if(state==STRING_END)
291 return Token(Token::STRING, c_unescape(buf.substr(1, buf.size()-2)));
295 e.at(get_location());
300 return Token(token_type[state], buf);
304 return Token(Token::SPECIAL, "");
307 bool TextParser::is_delimiter(int c)
309 return (isspace(c) || c=='{' || c=='}' || c==';' || c=='/');
312 bool TextParser::isodigit(int c)
314 return (c>='0' && c<='7');
317 string TextParser::get_location()
320 ss<<src<<':'<<in.get_line_number();
324 void TextParser::parse_error(int c, const char *e)
326 throw_at(ParseError(format("Parse error at '%c', expected one of \"%s\"", static_cast<char>(c), e)), get_location());
329 } // namespace DataFile