Commits

Tommaso Urli committed 227e67a

Restructured directory, extended README.md, taking care of pointers and memory now.

  • Participants
  • Parent commits 60105b3

Comments (0)

Files changed (8)

 	
 all: json test
 	
-json: json.tab.c lex.yy.c json.hh json.cc
-	g++ -lfl -std=c++11 json.cc json.tab.c lex.yy.c -o json  
+json: json.tab.c lex.yy.c json_st.hh json_st.cc
+	g++ -std=c++11 $^ -o $@  
 	
+test: json_st.cc json_st.hh test.cc
+	g++ -std=c++11 $^ -o $@	
+
 json.tab.c: json.y
 	bison -d json.y
 	
 
 clean:
 	rm -rf json.tab.c json.tab.h lex.yy.c json test
-	
-test: json.hh test.cc json.cc
-	g++ -std=c++11 test.cc json.cc -o test
 # JSON++
 
-A flex+bison JSON parser to be controlled from C++.
+A Flex/Bison JSON parser for C++.
 
 ## Usage
 
-
+	#include <iostream>
+	#include "json.hh"
+	
+	using namespace std;
+	using namespace JSON;
+	
+	int main(int argc, char** argv)
+	{
+		// Read JSON from a string
+		Value* v = parse_string(<your_json_string>);
+        
+        // Do something with v ...
+        
+        delete v;
+		
+		// Read JSON from a file
+		v = parse_file("<your_json_file>.json");
+		
+		cout << "JSON file contains: " << *v << endl;
+		
+        delete v;
+		return 0;
+	}
 
 ## How to build JSON++
 
-Just run
+Make sure you have Flex and Bison installed, since the parser and lexer will be generated on the fly. Then just run (to build the test ).
 
     make
 
 ## Flex/Bison quirks when using C++ classes
 
-* `%union { ... }` must only contain native C types or pointers to C++ classes,
-* in case pointers to C++ classes are used in `%union`, classes extended from `std` containers won't work,
-* 
+This section is for the ones who got here because they're trying to build stuff with Flex/Bison and C++. This was my first Flex/Bison parser (the main motivation behind its development being that I didn't find a parser for JSON in C++ which didn't require a number of extra libraries).
+
+So, for the ones venturing in this world, here's a few things I wish I knew when I set off to write the parser.
+
+1. `%union { ... }` must only contain native C types or pointers to C++ classes,
+2. in case pointers to C++ classes are used in `%union`, classes extending `std` containers won't work,
+3. put a starting rule in the grammar to assign the result of the parse to a variable, e.g., `json: value { $$ = $1; }`,
+4. as a general rule, functions requiring Flex functions, e.g., `yy_scan_string`, etc., should be defined in the `.l` file, and their prototypes put in the `.y` file as well, so that they can be called from the parser's functions,
+5. the JSON syntax tree classes (`json_st.hh` and `json_st.cc`) are implemented as collections of pointers for performance reasons (because of 1. the returned values from the parser must be pointers),
+6. 

File json.cc

-#include "json.hh"
-
-using namespace std;
-
-Value::Value() {}
-
-Value::Value(const int& i) : int_v(i), type_t(INT) { }
-
-Value::Value(const float& f) : float_v(f), type_t(FLOAT) { }
-
-Value::Value(const bool& b) : bool_v(b), type_t(BOOL) { }
-
-Value::Value(const std::string& s) : string_v(s), type_t(STRING) { }
-
-Value::Value(const Object& o) : object_v(o), type_t(OBJECT) { }
-
-Value::Value(const Array& o) : array_v(o), type_t(ARRAY) { }
-
-Object::Object() { }
-
-Object::Object(const Object& o) : _object(o._object) { }
-
-Object& Object::operator=(const Object& o)
-{
-    _object = o._object;
-}
-
-Value& Object::operator[] (const std::string& key)
-{
-    return _object[key];
-}
-
-std::pair<std::map<std::string, Value>::iterator, bool> Object::insert(const std::pair<std::string, Value>& v)
-{
-    return _object.insert(v);
-}
-
-std::map<std::string, Value>::const_iterator Object::begin() const
-{
-    return _object.begin();
-}
-
-std::map<std::string, Value>::const_iterator Object::end() const
-{
-    return _object.end();
-}
-
-size_t Object::size() const
-{
-    return _object.size();
-}
-
-Array::Array() { }
-
-Array::Array(const Array& o)
-{
-    _array = o._array;
-}
-
-Value& Array::operator[] (const int i)
-{
-    return _array[i];
-}
-
-std::vector<Value>::const_iterator Array::begin() const
-{
-    return _array.begin();
-}
-
-std::vector<Value>::const_iterator Array::end() const
-{
-    return _array.end();
-}
-
-size_t Array::size() const
-{
-    return _array.size();
-}
-
-void Array::push_back(const Value& v)
-{
-    _array.push_back(v);
-}
-
-Value& Value::operator=(const Value& e)
-{
-    
-    type_t = e.type();
-    
-    switch (type_t)
-    {
-        case INT:
-        int_v = e.int_v;
-        break;
-
-        case FLOAT:
-        float_v = e.float_v;
-        break;
-
-        case BOOL:
-        bool_v = e.bool_v;
-        break;
-
-        case STRING:
-        string_v = e.string_v;
-        break;
-
-        case OBJECT:
-        object_v = e.object_v;
-        break;
-
-        case ARRAY:
-        array_v = e.array_v;
-        break;                
-    }
-
-    return *this;
-}
-
-
-void indent(ostream& os)
-{
-    for (unsigned int i  = 0; i < ind; i++)
-        os << "\t";
-}
-
-ostream& operator<<(ostream& os, const Value& v)
-{    
-    switch(v.type())
-    {
-        /** Base types */
-        
-        case INT:
-        os << v.int_v;
-        break;
-        
-        case FLOAT:
-        os << v.float_v;
-        break;
-        
-        case BOOL:
-        os << (v.bool_v ? "true" : "false");
-        break;
-        
-        case STRING:
-        os << '"' << v.string_v << '"';                
-        break;
-        
-        /** Compound types */
-        
-        case ARRAY:
-        os << v.array_v;                
-        break;
-        
-        case OBJECT:
-        os << v.object_v;                
-        break;
-        
-    }
-    return os;
-}
-
-std::ostream& operator<<(ostream& os, const Object& o)
-{    
-    os << "{" << endl;
-    ind++;
-    for (auto e = o.begin(); e != o.end();)
-    {
-        indent(os);
-        os << '"' << e->first << '"' << ": " << e->second;
-        if (++e != o.end())
-            os << ",";
-        os << endl;
-    }    
-    ind--;
-    indent(os);
-    os << "}";
-}
-
-std::ostream& operator<<(ostream& os, const Array& a)
-{
-    os << "[" << endl;
-    ind++;
-    for (auto e = a.begin(); e != a.end();)
-    {
-        indent(os);
-        os << *e;
-        if (++e != a.end())
-            os << ",";
-        os << endl;
-    }    
-    ind--;
-    indent(os);
-    os << "]";
-}
 #ifndef JSON_HH
 #define JSON_HH
 
-#include <vector>
-#include <iostream>
-#include <map>
-#include <stack>
-
-
-enum ValueType
-{
-    INT,
-    FLOAT,
-    BOOL,
-    STRING,
-    OBJECT,
-    ARRAY
-};
-
-class Value;
-
-class Object
-{
-public:
-
-    Object();
-    
-    Object(const Object& o);
-    
-    Object& operator=(const Object& o);
-
-    Value& operator[] (const std::string& key);
-
-    std::map<std::string, Value>::const_iterator begin() const;
-
-    std::map<std::string, Value>::const_iterator end() const;
-    
-    std::pair<std::map<std::string, Value>::iterator, bool> insert(const std::pair<std::string, Value>& v);
-
-    size_t size() const;
-
-protected:
-
-    std::map<std::string, Value> _object;
-};
-
-class Array
-{
-public:
-
-    Array();
-    
-    Array(const Array& o);
-    
-    Array& operator=(const Object& o);
-
-    Value& operator[] (const int i);
-
-    std::vector<Value>::const_iterator begin() const;
-
-    std::vector<Value>::const_iterator end() const;
-
-    void push_back(const Value& n);
-
-    size_t size() const;
-
-protected:
-
-    std::vector<Value> _array;
-
-};
-
-class Value
-{
-public:
-    
-    Value();
-    
-    Value(const int& i);
-    
-    Value(const float& f);
-    
-    Value(const bool& b);
-    
-    Value(const std::string& s);
-        
-    Value(const Object& o);
-    
-    Value(const Array& o);
-
-    Value& operator=(const Value& e);
-    
-    ValueType type() const
-    {
-        return type_t;
-    }
-            
-    float           float_v;
-    int             int_v;
-    bool            bool_v;
-    std::string     string_v;
-    Object          object_v;
-    Array           array_v;
-    ValueType       type_t;
-};
-    
-std::ostream& operator<<(std::ostream&, const Value&);
-
-std::ostream& operator<<(std::ostream&, const Object&);
-
-std::ostream& operator<<(std::ostream&, const Array&);
-
-static unsigned int ind;
-
-static unsigned int count;
-
-static std::stack<Value> list_s;
-
-static std::stack<std::pair<std::string, Value> > assign_list_s;
-
-static void indent(std::ostream& os = std::cout);
+#include "json_st.hh" // JSON syntax tree
+#include "json.tab.h" // parser
 
 #endif
 [-+]?[0-9]+             { yylval.int_v = atoi(yytext); return NUMBER_I; }
 [-+]?[0-9]*\.?[0-9]*    { yylval.float_v = atof(yytext); return NUMBER_F; }
 true|false              { yylval.bool_v = ( strcmp(yytext, "true") == 0 ? true : false); return BOOLEAN; }
+null                    { yylval.null_p = true; return NULL; }
 .                       {  }
 
 %%
 
     #include <iostream>
     #include <cstring>
-    #include "json.hh"
+    #include "json_st.hh"
     
     extern "C" 
     {
         int yylex();
         
     } 
-    
-    #include "json.hh"
-    
+        
     void load_string(const char *);
     void load_file(FILE*);
     
     Value* parsd = nullptr;
 %}
 
-%code requires { #include "json.hh" }
+%code requires { #include "json_st.hh" }
 
 %union
 {
     int int_v;
     float float_v;
+    bool bool_v;
+    bool null_p;
     char* string_v;
-    bool bool_v;
     Object* object_p;
     Array* array_p;
     Value* value_p;
 %start json
 
 %%
+    
+/** JSON grammar */
 
 // Entry point (every JSON file represents a value)
 json: value { parsd = $1; } ;
 
-object: CURLY_BRACKET_L assignment_list CURLY_BRACKET_R 
-    { 
-        $$ = $2;
-    }
-    ;
+// Object rule
+object: CURLY_BRACKET_L assignment_list CURLY_BRACKET_R { $$ = $2; } ;
 
-array : SQUARE_BRACKET_L list SQUARE_BRACKET_R
-    {
-        $$ = $2;
-    }
-    ;
+array : SQUARE_BRACKET_L list SQUARE_BRACKET_R { $$ = $2; } ;
 
-value : NUMBER_I 
-    { 
-        $$ = new Value($1); 
-    }
-    | NUMBER_F 
-    { 
-        $$ = new Value($1); 
-    }
-    | BOOLEAN 
-    { 
-        $$ = new Value($1); 
-    }
-    | string 
-    { 
-        $$ = new Value(std::string($1));     
-    }
-    | object 
-    { 
-        $$ = new Value(*$1); 
-    }
-    | array 
-    { 
-        $$ = new Value(*$1); 
-    }
+value : NUMBER_I { $$ = new Value($1); }
+    | NUMBER_F { $$ = new Value($1); }
+    | BOOLEAN { $$ = new Value($1); }
+    | string { $$ = new Value(std::string($1)); }
+    | object { $$ = new Value(*$1); }
+    | array { $$ = new Value(*$1); }
     ;
     
-string : DOUBLE_QUOTED_STRING 
-    {
+string : DOUBLE_QUOTED_STRING {
         // Trim string
         std::string s($1);
         s = s.substr(1, s.length()-2);
-        
+
         char* t = new char[s.length()+1];
         strcpy(t, s.c_str());
 
         $$ = t;
     } 
-    | SINGLE_QUOTED_STRING
-    {
+    | SINGLE_QUOTED_STRING {
         // Trim string
         std::string s($1);
         s = s.substr(1, s.length()-2);
-        
+
         char* t = new char[s.length()+1];
         strcpy(t, s.c_str());
 
         $$ = t;
     };
 
-assignment_list:
-    {
-        $$ = new Object();
-    }
-    |   string COLON value
-    {
+assignment_list: /* empty */ { $$ = new Object(); } 
+    | string COLON value {
         $$ = new Object();
         $$->insert(std::make_pair($1, *$3));
     } 
-    | assignment_list COMMA string COLON value 
-    {
-        $$->insert(std::make_pair($3, *$5));
-    }
+    | assignment_list COMMA string COLON value { $$->insert(std::make_pair($3, *$5)); }
     ;
 
-list:  
-    {
-        $$ = new Array();
-    }
-    | value
-    {
+list: /* empty */ { $$ = new Array(); }
+    | value {
         $$ = new Array();
         $$->push_back(*$1);
     }
-    | list COMMA value
-    {
-        $$->push_back(*$3);   
-    }
+    | list COMMA value { $$->push_back(*$3); }
     ;
     
 %%
+#include "json_st.hh"
+
+using namespace std;
+
+Value::Value() {}
+
+Value::Value(const int& i) : int_v(i), type_t(INT) { }
+
+Value::Value(const float& f) : float_v(f), type_t(FLOAT) { }
+
+Value::Value(const bool& b) : bool_v(b), type_t(BOOL) { }
+
+Value::Value(const std::string& s) : string_v(s), type_t(STRING) { }
+
+Value::Value(const Object& o) : object_v(o), type_t(OBJECT) { }
+
+Value::Value(const Array& o) : array_v(o), type_t(ARRAY) { }
+
+Object::Object() { }
+
+Object::~Object()
+{
+    for (auto p : _object)
+        delete p;
+}
+
+Object::Object(const Object& o) : _object(o._object) { }
+
+Object& Object::operator=(const Object& o)
+{
+    _object = o._object;
+}
+
+Value& Object::operator[] (const std::string& key)
+{
+    return _object[key];
+}
+
+std::pair<std::map<std::string, Value>::iterator, bool> Object::insert(const std::pair<std::string, Value>& v)
+{
+    return _object.insert(v);
+}
+
+std::map<std::string, Value>::const_iterator Object::begin() const
+{
+    return _object.begin();
+}
+
+std::map<std::string, Value>::const_iterator Object::end() const
+{
+    return _object.end();
+}
+
+size_t Object::size() const
+{
+    return _object.size();
+}
+
+Array::Array() { }
+
+Array::Array(const Array& o)
+{
+    _array = o._array;
+}
+
+Value& Array::operator[] (const int i)
+{
+    return _array[i];
+}
+
+std::vector<Value>::const_iterator Array::begin() const
+{
+    return _array.begin();
+}
+
+std::vector<Value>::const_iterator Array::end() const
+{
+    return _array.end();
+}
+
+size_t Array::size() const
+{
+    return _array.size();
+}
+
+void Array::push_back(const Value& v)
+{
+    _array.push_back(v);
+}
+
+Value& Value::operator=(const Value& e)
+{
+    
+    type_t = e.type();
+    
+    switch (type_t)
+    {
+        case INT:
+        int_v = e.int_v;
+        break;
+
+        case FLOAT:
+        float_v = e.float_v;
+        break;
+
+        case BOOL:
+        bool_v = e.bool_v;
+        break;
+
+        case STRING:
+        string_v = e.string_v;
+        break;
+
+        case OBJECT:
+        object_v = e.object_v;
+        break;
+
+        case ARRAY:
+        array_v = e.array_v;
+        break;                
+    }
+
+    return *this;
+}
+
+
+void indent(ostream& os)
+{
+    for (unsigned int i  = 0; i < ind; i++)
+        os << "\t";
+}
+
+ostream& operator<<(ostream& os, const Value& v)
+{    
+    switch(v.type())
+    {
+        /** Base types */
+        
+        case INT:
+        os << v.int_v;
+        break;
+        
+        case FLOAT:
+        os << v.float_v;
+        break;
+        
+        case BOOL:
+        os << (v.bool_v ? "true" : "false");
+        break;
+        
+        case STRING:
+        os << '"' << v.string_v << '"';                
+        break;
+        
+        /** Compound types */
+        
+        case ARRAY:
+        os << v.array_v;                
+        break;
+        
+        case OBJECT:
+        os << v.object_v;                
+        break;
+        
+    }
+    return os;
+}
+
+std::ostream& operator<<(ostream& os, const Object& o)
+{    
+    os << "{" << endl;
+    ind++;
+    for (auto e = o.begin(); e != o.end();)
+    {
+        indent(os);
+        os << '"' << e->first << '"' << ": " << e->second;
+        if (++e != o.end())
+            os << ",";
+        os << endl;
+    }    
+    ind--;
+    indent(os);
+    os << "}";
+}
+
+std::ostream& operator<<(ostream& os, const Array& a)
+{
+    os << "[" << endl;
+    ind++;
+    for (auto e = a.begin(); e != a.end();)
+    {
+        indent(os);
+        os << *e;
+        if (++e != a.end())
+            os << ",";
+        os << endl;
+    }    
+    ind--;
+    indent(os);
+    os << "]";
+}
+#ifndef JSON_ST_HH
+#define JSON_ST_HH
+
+#include <iostream>
+#include <map>
+#include <vector>
+#include <stack>
+
+/** Possible JSON type of a value (array, object, bool, ...). */
+enum ValueType
+{
+    INT,
+    FLOAT,
+    BOOL,
+    STRING,
+    OBJECT,
+    ARRAY
+};
+
+// Forward declaration
+class Value;
+
+/** A JSON object, i.e., a container whose keys are strings, this
+is roughly equivalent to a Python dictionary, a PHP's associative
+array, a Perl or a C++ map (depending on the implementation). */
+class Object
+{
+public:
+
+    /** Constructor. */
+    Object();
+    
+    /** Copy constructor. 
+        @param o object to copy from
+    */
+    Object(const Object& o);
+    
+    /** Assignment operator. 
+        @param o object to copy from
+    */
+    Object& operator=(const Object& o);
+    
+    /** Destructor. */
+    ~Object();
+
+    /** Subscript operator, access an element by key.
+        @param key key of the object to access
+    */
+    Value* operator[] (const std::string& key) const;
+
+    /** Retrieves the starting iterator (const).
+        @remark mainly for printing
+    */
+    std::map<std::string, Value*>::const_iterator begin() const;
+
+    /** Retrieves the ending iterator (const).
+        @remark mainly for printing
+    */
+    std::map<std::string, Value*>::const_iterator end() const;
+    
+    /** Retrieves the starting iterator */
+    std::map<std::string, Value*>::iterator begin();
+
+    /** Retrieves the ending iterator */
+    std::map<std::string, Value*>::iterator end();
+    
+    /** Inserts a field in the object.
+        @param v pair <key, value> to insert
+        @return an iterator to the inserted object
+    */
+    std::pair<std::map<std::string, Value>::iterator, bool> insert(std::pair<std::string, Value*>* v);
+
+    /** Size of the object. */
+    size_t size() const;
+
+protected:
+
+    /** Inner container. */
+    std::map<std::string, Value*> _object;
+};
+
+/** A JSON array, i.e., an indexed container of elements. It contains
+JSON values, that can have any of the types in ValueType. */
+class Array
+{
+public:
+
+    /** Constructor. */
+    Array();
+    
+    /** Copy constructor. 
+        @param o the object to copy from
+    */
+    Array(const Array& a);
+    
+    /** Assignment operator. 
+        @param a array to copy from
+    */
+    Array& operator=(const Array& a);
+
+    /** Subscript operator, access an element by index. 
+        @param i index of the element to access
+    */
+    Value* operator[] (size_t i);
+    
+    /** Subscript operator, access an element by index. Const.
+        @param i index of the element to access
+    */
+    const Value* operator[] (size_t i) const;
+
+    /** Retrieves the starting iterator (const).
+        @remark mainly for printing
+    */
+    std::vector<Value*>::const_iterator begin() const;
+
+    /** Retrieves the ending iterator (const).
+        @remark mainly for printing
+    */
+    std::vector<Value*>::const_iterator end() const;
+
+    /** Retrieves the starting iterator. */
+    std::vector<Value*>::iterator begin();
+
+    /** Retrieves the ending iterator */
+    std::vector<Value*>::iterator end();
+
+    /** Inserts an element in the array.
+        @param n (a pointer to) the value to add
+    */
+    void push_back(Value* n);
+    
+    /** Size of the array. */
+    size_t size() const;
+
+protected:
+
+    /** Inner container. */
+    std::vector<Value*> _array;
+
+};
+
+/** A JSON value. Can have either type in ValueTypes. */
+class Value
+{
+public:
+    
+    /** Default constructor. */
+    Value();
+    
+    /** Constructor from pointer to int. */
+    Value(int* i);
+    
+    /** Constructor from pointer to float. */
+    Value(float* f);
+    
+    /** Constructor from pointer to bool. */
+    Value(bool* b);
+    
+    /** Constructor from pointer to string. */
+    Value(std::string* s);
+        
+    Value(Object* o);
+    
+    Value(Array* o);
+
+    Value& operator=(const Value& e);
+    
+    ValueType type() const
+    {
+        return type_t;
+    }
+            
+    float           float_v;
+    int             int_v;
+    bool            bool_v;
+    std::string     string_v;
+    Object          object_v;
+    Array           array_v;
+    ValueType       type_t;
+};
+    
+std::ostream& operator<<(std::ostream&, const Value&);
+
+std::ostream& operator<<(std::ostream&, const Object&);
+
+std::ostream& operator<<(std::ostream&, const Array&);
+
+static unsigned int ind;
+
+static unsigned int count;
+
+static std::stack<Value> list_s;
+
+static std::stack<std::pair<std::string, Value> > assign_list_s;
+
+static void indent(std::ostream& os = std::cout);
+
+#endif