-
- return result;
-}
-
-Token Parser::parse_token()
-{
- int c=0;
- unsigned comment=0;
-
- // Skip over comments and whitespace
- while(in)
- {
- c=in.get();
- int next=in.peek();
-
- if(c=='/' && next=='/')
- comment=1;
- else if(c=='/' && next=='*')
- comment=2;
- else if(c=='\n' && comment==1)
- comment=0;
- else if(c=='*' && next=='/' && comment==2)
- comment=3;
- else if(comment==3) // Skip the second character of block comment end
- comment=0;
- else if(!isspace(c) && !comment)
- break;
- }
-
- if(comment) // Didn't hit any non-whitespace
- throw ParseError(src+": Unfinished comment", src, in.get_line_number());
-
- enum ParseState
- {
- INIT,
- SIGN,
- FLOATEXPINIT,
- FLOATEXPSIGN,
- STRING,
- ACCEPT,
- ZERO,
- DECIMAL,
- HEXADECIMAL,
- OCTAL,
- FLOAT,
- FLOATEXP,
- IDENTIFIER
- };
-
- static Token::Type token_type[]=
- {
- Token::SPECIAL,
- Token::SPECIAL,
- Token::SPECIAL,
- Token::SPECIAL,
- Token::STRING,
- Token::SPECIAL,
- Token::INTEGER,
- Token::INTEGER,
- Token::INTEGER,
- Token::INTEGER,
- Token::FLOAT,
- Token::FLOAT,
- Token::IDENTIFIER
- };
-
- ParseState state=INIT;
- string buf;
- bool escape=false;
-
- while(in)
- {
- if(state!=INIT)
- c=in.get();
- int next=in.peek();
-
- buf+=c;
-
- switch(state)
- {
- case INIT:
- if(c=='0')
- state=ZERO;
- else if(c=='-' || c=='+')
- state=SIGN;
- else if(c=='.')
- state=FLOAT;
- else if(c=='"')
- state=STRING;
- else if(c=='{' || c=='}' || c==';')
- return Token(Token::SPECIAL, string(1, c));
- else if(isdigit(c))
- state=DECIMAL;
- else if(isalpha(c))
- state=IDENTIFIER;
- else
- parse_error(c, state);
- break;
-
- case SIGN:
- if(c=='0')
- state=ZERO;
- else if(isdigit(c))
- state=DECIMAL;
- else if(c=='.')
- state=FLOAT;
- else
- parse_error(c, state);
- break;
-
- case ZERO:
- if(c=='x')
- state=HEXADECIMAL;
- else if(isdigit(c))
- state=OCTAL;
- else if(c=='.')
- state=FLOAT;
- else
- parse_error(c, state);
- break;
-
- case DECIMAL:
- if(c=='.')
- state=FLOAT;
- else if(!isdigit(c))
- parse_error(c, state);
- break;
-
- case HEXADECIMAL:
- if(!isxdigit(c))
- parse_error(c, state);
- break;
-
- case OCTAL:
- if(!isodigit(c))
- parse_error(c, state);
- break;
-
- case FLOAT:
- if(c=='e' || c=='E')
- state=FLOATEXPINIT;
- else if(!isdigit(c))
- parse_error(c, state);
- break;
-
- case FLOATEXPINIT:
- if(c=='+' || c=='-')
- state=FLOATEXPSIGN;
- else if(isdigit(c))
- state=FLOATEXP;
- else
- parse_error(c, state);
- break;
-
- case FLOATEXPSIGN:
- if(isdigit(c))
- state=FLOATEXP;
- else
- parse_error(c, state);
- break;
-
- case FLOATEXP:
- if(!isdigit(c))
- parse_error(c, state);
- break;
-
- case STRING:
- if(c=='\\')
- escape=!escape;
- else if(c=='"' && !escape)
- return Token(Token::STRING, unescape_string(buf));
- else
- escape=false;
- break;
-
- case IDENTIFIER:
- if(!isalpha(c) && !isdigit(c) && c!='_')
- parse_error(c, state);
- break;
-
- default:
- throw Exception(get_location()+": Internal error (bad state)");
- }
-
- if(is_delimiter(next) && state>=ACCEPT)
- return Token(token_type[state], buf);
- }
-
- return Token(Token::SPECIAL, "");
-}
-
-bool Parser::is_delimiter(int c)
-{
- return (isspace(c) || c=='{' || c=='}' || c==';' || c=='/');
-}
-
-bool Parser::isodigit(int c)
-{
- return (c>='0' && c<='7');
-}
-
-string Parser::unescape_string(const string &str)
-{
- string result;
- bool escape=false;
- unsigned hexcape=0;
- for(string::const_iterator i=str.begin()+1; i!=str.end()-1; ++i)