Commits

Tommaso Urli committed 54f7585

Added complete JSON tree spec and test file. Added notes in the README.

  • Participants
  • Parent commits 76e47bb

Comments (0)

Files changed (7)

 .PHONY: all clean
 	
-all: json
+all: json test
 	
 json: json.tab.c lex.yy.c json.hh
-	g++ -lfl json.tab.c json.tab.h lex.yy.c -o json  
+	g++ -std=c++11 -lfl json.tab.c json.tab.h lex.yy.c -o json  
 	
 json.tab.c: json.y
 	bison -d json.y
 	flex json.l
 
 clean:
-	rm -rf json.tab.c json.tab.h lex.yy.c
+	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 to be controlled from C++.
+
+## Usage
+
+
+
+## How to build JSON++
+
+Just run
+
+    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,
+* 
+#include "json.hh"
+
+using namespace std;
+
+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 map<string, Value>& 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 vector<Value>& 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 << "]";
+}
 #include <iostream>
 #include <map>
 
-using namespace std;
 
-namespace JSON
-{
     enum ValueType
     {
         INT,
     };
     
     class Value;
-    
-    typedef std::string Key;
-    typedef std::vector<JSON::Value> Array;
-    typedef std::map<JSON::Key, JSON::Value> Object;
-    
+            
     class Value
     {
     public:
         
-        Value(int i) : int_v(i), type_t(INT) { }
+        Value() {}
         
-        Value(float f) : float_v(f), type_t(FLOAT) { }
+        Value(const int& i) : int_v(i), type_t(INT) { }
         
-        Value(bool b) : bool_v(b), type_t() { }
+        Value(const float& f) : float_v(f), type_t(FLOAT) { }
         
-        Value(string s) : string_v(s), type_t(INT) { }
+        Value(const bool& b) : bool_v(b), type_t(BOOL) { }
         
-        Value(const Object& o) : object_v(o), type_t(OBJECT) { }
+        Value(const std::string& s) : string_v(s), type_t(STRING) { }
         
-        Value(const Array& o) : array_v(o), type_t(ARRAY) { }
+        Value(const char* s) : string_v(s), type_t(STRING) { }
+        
+        Value(const std::map<std::string, Value>& o) : object_v(o), type_t(OBJECT) { }
+        
+        Value(const std::vector<Value>& o) : array_v(o), type_t(ARRAY) { }
+
+        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;
+        }
+        
         
         ValueType type() const
         {
             return type_t;
         }
-        
-    protected:
-        
-        float       float_v;
-        int         int_v;
-        bool        bool_v;
-        string      string_v;
-        Object      object_v;
-        Array       array_v;
-        ValueType   type_t;
+                
+        float float_v;
+        int int_v;
+        bool bool_v;
+        std::string string_v;
+        std::map<std::string, Value> object_v;
+        std::vector<Value> array_v;
+        ValueType type_t;
     };
-}
+
+
+std::ostream& operator<<(std::ostream&, const Value&);
+
+std::ostream& operator<<(std::ostream&, const std::map<std::string, Value>&);
+
+std::ostream& operator<<(std::ostream&, const std::vector<Value>&);
+
+static unsigned int ind;
+
+static void indent(std::ostream& os = std::cout);
 
 #endif
 %option noyywrap yylineno nodefault
 %{
     #include <iostream>
-    using namespace std;
 
     extern "C" 
     {
 [ \t]                   { }
 [-+]?[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 = (string(yytext) == "true" ? true : false); return BOOL; }
+true|false              { yylval.bool_v = (std::string(yytext) == "true" ? true : false); return BOOLEAN; }
 .                       { printf("Unrecognized: ", yytext); }
 %%
 
     #include <iostream>
     #include "json.hh"
-    using namespace std;
     
     extern "C" 
     {
         int yylex();
     } 
     
-    #include "json.hh"
-    
+    #include "json.hh"    
 %}
 
 %union
     float float_v;
     char* string_v;
     bool bool_v;
+    std::map<std::string, Value>* object_p;
+    Value* value_p;
 } 
 
+
 /** Define types for union values */
 %type<string_v> key string DOUBLE_QUOTED_STRING SINGLE_QUOTED_STRING
 %type<int_v> NUMBER_I
 %type<float_v> NUMBER_F
-%type<bool_v> BOOL
+%type<bool_v> BOOLEAN
     
 /** Declare tokens */
 %token COMMA COLON
 %token CURLY_BRACKET_L CURLY_BRACKET_R
 %token DOUBLE_QUOTED_STRING SINGLE_QUOTED_STRING
 %token NUMBER_I NUMBER_F
-%token BOOL
+%token BOOLEAN
+
+%type <object_p> object assignment_list
+%type <value_p> value
+    
 
 %%
 
     { "foo": 1, "bar": "k" }
 */
 
-object:
-    | CURLY_BRACKET_L CURLY_BRACKET_R
-    | CURLY_BRACKET_L assignment_list CURLY_BRACKET_R
+object: CURLY_BRACKET_L CURLY_BRACKET_R { $$ = new Object(); }
+    | CURLY_BRACKET_L assignment_list CURLY_BRACKET_R { $$ = $2; }
     ;
 
-value : NUMBER_I
-    | NUMBER_F
-    | BOOL
-    | string
-    | object
+value : NUMBER_I { $$ = new Value($1); }
+    | NUMBER_F { $$ = new Value($1); }
+    | BOOLEAN { $$ = new Value($1); }
+    | string { $$ = new Value($1); }
+    | object { $$ = new Value($1); }
     ;
 
-string : DOUBLE_QUOTED_STRING
-    | SINGLE_QUOTED_STRING
+string : DOUBLE_QUOTED_STRING { $$ = $1; }
+    | SINGLE_QUOTED_STRING { $$ = $1; }
     ;
 
 key: string 
     ;
     
-assignment_list: key COLON value
-    |   key COLON value COMMA assignment_list
+assignment_list: 
+    key COLON value 
+    {
+        $$ = new Object();
+        $$->insert( std::make_pair($1, Value($3) ));
+    }
+    | key COLON value COMMA assignment_list 
+    {
+        $$ = $5;
+        $$->insert( std::make_pair($1, Value($3) ));
+    }
     ;
 
 
+#include <iostream>
+#include "json.hh"
+
+using namespace std;
+
+int main(int argc, char** argv)
+{
+    map<string, Value> obj;
+    
+    obj["foo"] = true;
+    obj["bar"] = 1;
+    
+    map<string, Value> o;
+    o["failure"] = true;
+    o["success"] = "no way";
+    
+    obj["baz"] = o;
+        
+    vector<Value> a;
+    a.push_back(Value(true));
+    a.push_back(Value("iajsia"));
+    a.push_back(Value("asas"));
+    a.push_back(Value(55));
+    
+    obj["beer"] = a;
+
+    cerr << obj << endl;
+    
+    return 0;
+}