]> git.tdb.fi Git - libs/datafile.git/blobdiff - source/parser.cpp
Rename to datafile
[libs/datafile.git] / source / parser.cpp
index ef2daa3e0ab8bd5dbb75ce8696a64c789c8417ab..8fccec2f94c208d93f966ec88f4279eeb133b081 100644 (file)
@@ -1,11 +1,12 @@
-/*
-This file is part of libmspparser
-Copyright © 2006 Mikko Rasa, Mikkosoft Productions
+/* $Id$
+
+This file is part of libmspdatafile
+Copyright © 2006  Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
 #include <cctype>
 #include <sstream>
-#include <msp/error.h>
+#include "error.h"
 #include "parser.h"
 #include "statement.h"
 #include "token.h"
@@ -13,7 +14,7 @@ Distributed under the LGPL
 using namespace std;
 
 namespace Msp {
-namespace Parser {
+namespace DataFile {
 
 Parser::Parser(istream &i, const string &s):
        in(i),
@@ -25,7 +26,7 @@ Statement Parser::parse()
 {
        if(!good)
                throw Exception("Parser is not good");
-       
+
        try
        {
                return parse_(0);
@@ -42,7 +43,7 @@ Statement Parser::parse_(const Token *t)
        Statement result;
        bool      sub=false;
        bool      finish=false;
-       
+
        while(in)
        {
                Token token;
@@ -53,13 +54,13 @@ Statement Parser::parse_(const Token *t)
                }
                else
                        token=parse_token();
-               
+
                if(result.keyword.empty())
                {
                        if(token.str.empty())
                                break;
                        else if(token.type!=Token::IDENTIFIER)
-                               throw DataError(get_location()+": Syntax error at token '"+token.str+"' (expected an identifier)");
+                               throw ParseError(get_location()+": Syntax error at token '"+token.str+"' (expected an identifier)", src, in.get_line_number());
                        result.keyword=token.str;
                        result.valid=true;
                        result.source=src;
@@ -81,7 +82,7 @@ Statement Parser::parse_(const Token *t)
                else if(finish)
                {
                        if(token.str!=";")
-                               throw DataError(get_location()+": Syntax error at token '"+token.str+"' (Expected a ';')");
+                               throw ParseError(get_location()+": Syntax error at token '"+token.str+"' (Expected a ';')", src, in.get_line_number());
                        break;
                }
                else if(token.str=="{")
@@ -96,12 +97,18 @@ Statement Parser::parse_(const Token *t)
                        result.args.push_back(Value(Value::STRING, token.str));
                else if(token.type==Token::IDENTIFIER)
                {
+                       if(token.str=="true")
+                               result.args.push_back(Value(Value::BOOLEAN, "1"));
+                       else if(token.str=="false")
+                               result.args.push_back(Value(Value::BOOLEAN, "0"));
+                       else
+                               result.args.push_back(Value(Value::ENUM, token.str));
                        //result.args.push_back(resolve_identifiertoken.str);
                }
                else if(token.str=="")
-                       throw DataError(src+": Unexcepted EOF");
+                       throw ParseError(src+": Unexcepted EOF", src, in.get_line_number());
                else
-                       throw DataError(get_location()+": Syntax error");
+                       throw ParseError(get_location()+": Syntax error", src, in.get_line_number());
        }
 
        return result;
@@ -109,15 +116,15 @@ Statement Parser::parse_(const Token *t)
 
 Token Parser::parse_token()
 {
-       int c;
+       int c=0;
        unsigned comment=0;
+
+       // Skip over comments and whitespace
        while(in)
        {
                c=in.get();
                int next=in.peek();
 
-               //cout<<c<<' '<<next<<'\n';
-
                if(c=='/' && next=='/')
                        comment=1;
                else if(c=='/' && next=='*')
@@ -131,13 +138,16 @@ Token Parser::parse_token()
                else if(!isspace(c) && !comment)
                        break;
        }
-       if(comment)
-               throw DataError(src+": Unfinished comment");
-       
+
+       if(comment)  // Didn't hit any non-whitespace
+               throw ParseError(src+": Unfinished comment", src, in.get_line_number());
+
        enum ParseState
        {
                INIT,
-               NEGATIVE,
+               SIGN,
+               FLOATEXPINIT,
+               FLOATEXPSIGN,
                STRING,
                ACCEPT,
                ZERO,
@@ -145,11 +155,14 @@ Token Parser::parse_token()
                HEXADECIMAL,
                OCTAL,
                FLOAT,
+               FLOATEXP,
                IDENTIFIER
        };
 
        static Token::Type token_type[]=
        {
+               Token::SPECIAL,
+               Token::SPECIAL,
                Token::SPECIAL,
                Token::SPECIAL,
                Token::STRING,
@@ -159,6 +172,7 @@ Token Parser::parse_token()
                Token::INTEGER,
                Token::INTEGER,
                Token::FLOAT,
+               Token::FLOAT,
                Token::IDENTIFIER
        };
 
@@ -171,7 +185,7 @@ Token Parser::parse_token()
                if(state!=INIT)
                        c=in.get();
                int next=in.peek();
-               
+
                buf+=c;
 
                switch(state)
@@ -179,8 +193,8 @@ Token Parser::parse_token()
                case INIT:
                        if(c=='0')
                                state=ZERO;
-                       else if(c=='-')
-                               state=NEGATIVE;
+                       else if(c=='-' || c=='+')
+                               state=SIGN;
                        else if(c=='.')
                                state=FLOAT;
                        else if(c=='"')
@@ -194,8 +208,8 @@ Token Parser::parse_token()
                        else
                                parse_error(c, state);
                        break;
-               
-               case NEGATIVE:
+
+               case SIGN:
                        if(c=='0')
                                state=ZERO;
                        else if(isdigit(c))
@@ -235,6 +249,29 @@ Token Parser::parse_token()
                        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;
@@ -247,7 +284,7 @@ Token Parser::parse_token()
                        else
                                escape=false;
                        break;
-               
+
                case IDENTIFIER:
                        if(!isalpha(c) && !isdigit(c) && c!='_')
                                parse_error(c, state);
@@ -294,7 +331,7 @@ string Parser::unescape_string(const string &str)
                        else if(*i=='x')
                                hexcape=0x100;
                        else
-                               throw DataError("Invalid escape");
+                               throw ParseError("Invalid escape", src, in.get_line_number());
                        escape=false;
                }
                else if(hexcape)
@@ -307,7 +344,7 @@ string Parser::unescape_string(const string &str)
                        else if(*i>='A' && *i<='F')
                                digit=*i-'A'+10;
                        else
-                               throw DataError("Invalid hex digit");
+                               throw ParseError("Invalid hex digit", src, in.get_line_number());
 
                        hexcape=(hexcape<<4)|digit;
                        if(hexcape&0x10000)
@@ -335,9 +372,9 @@ string Parser::get_location()
 void Parser::parse_error(int c, int state)
 {
        ostringstream ss;
-       ss<<get_location()<<": Parse error at '"<<c<<"' (state "<<state<<')';
-       throw DataError(ss.str());
+       ss<<get_location()<<": Parse error at '"<<(char)c<<"' (state "<<state<<')';
+       throw ParseError(ss.str(), src, in.get_line_number());
 }
 
-} // namespace Parser
+} // namespace DataFile
 } // namespace Msp