Checking in miniswig: It's a flex/bison based parser that is able to parse
authorMatthias Braun <matze@braunis.de>
Tue, 3 May 2005 18:32:14 +0000 (18:32 +0000)
committerMatthias Braun <matze@braunis.de>
Tue, 3 May 2005 18:32:14 +0000 (18:32 +0000)
simple c++ header files and create squirrel wrappers for them.

SVN-Revision: 2391

12 files changed:
Jamfile
configure.ac
mk/jam/bisonflex.jam
tools/miniswig/Jamfile [new file with mode: 0644]
tools/miniswig/create_wrapper.cpp [new file with mode: 0644]
tools/miniswig/create_wrapper.h [new file with mode: 0644]
tools/miniswig/globals.h [new file with mode: 0644]
tools/miniswig/lexer.ll [new file with mode: 0644]
tools/miniswig/main.cpp [new file with mode: 0644]
tools/miniswig/parser.yy [new file with mode: 0644]
tools/miniswig/tree.cpp [new file with mode: 0644]
tools/miniswig/tree.h [new file with mode: 0644]

diff --git a/Jamfile b/Jamfile
index 3c3fab3..bcb3208 100644 (file)
--- a/Jamfile
+++ b/Jamfile
@@ -1,6 +1,7 @@
 SubDir TOP ;
 
 # Decend into subdirs
+SubInclude TOP tools miniswig ;
 SubInclude TOP lib ;
 SubInclude TOP src ;
 SubInclude TOP data ;
index a2c8bef..f54ef01 100644 (file)
@@ -39,6 +39,12 @@ if test -n "$XGETTEXT" ; then
     fi
 fi
 
+AC_PROG_LEX
+LEX_LIBS=$LEXLIB
+AC_SUBST([LEX_LIBS])
+AC_CHECK_PROGS([BISON], bison)
+AC_SUBST([BISON])
+
 dnl Checks for header files.
 AC_HEADER_DIRENT
 AC_HEADER_STDC
index 83912b5..141f839 100644 (file)
@@ -24,7 +24,7 @@ if $(LEX)
 
     return $(object) ;
   }
-  RegisterFileType Flex++Rule : .ll ;
+  RegisterFileType Lex++Rule : .ll ;
 
   if $(COMPILER_TYPE) != "GCC"
   {
@@ -57,7 +57,7 @@ if $(BISON)
 
     Includes $(headerfile:G=) : $(headerfile) ;
     
-    Bison $(cfile) $(headerfile) : $(<) ;
+    Bison $(cfile) : $(<) ;
     # work around jam warning about independent target 
     Includes $(cfile) : $(headerfile) ;
 
@@ -76,8 +76,8 @@ if $(BISON)
     # here
     Includes $(headerfile:G=) : $(headerfile) ;
 
-    Bison $(cppfile) $(headerfile) : $(<) ;
-    Includes $(cppfile) : $(headerfile) ;
+    Bison $(cppfile) : $(<) ;
+#Includes $(cppfile) : $(headerfile) ;
 
     return $(object) ;
   }
diff --git a/tools/miniswig/Jamfile b/tools/miniswig/Jamfile
new file mode 100644 (file)
index 0000000..bc621c9
--- /dev/null
@@ -0,0 +1,9 @@
+SubDir TOP tools miniswig ;
+
+if $(LEX) && $(BISON) {
+    MINISWIG = [ Application miniswig : [ Wildcard *.yy *.ll *.cpp ] ] ;
+    C++Flags miniswig : -Wno-unused ;
+    IncludeDir miniswig : . ;
+    ExternalLibs miniswig : LEX ;
+}
+
diff --git a/tools/miniswig/create_wrapper.cpp b/tools/miniswig/create_wrapper.cpp
new file mode 100644 (file)
index 0000000..a806de4
--- /dev/null
@@ -0,0 +1,270 @@
+#include "tree.h"
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include "create_wrapper.h"
+#include "globals.h"
+
+void
+WrapperCreator::create_wrapper(CompilationUnit* unit)
+{
+    // hpp file
+    hppout
+        << "/**\n"
+        << " * WARNING: This file is automatically generated from '"
+        << inputfile << "' - do not change\n"
+        << " */\n"
+        << "#ifndef __" << modulename << "_WRAPPER_HPP__\n"
+        << "#define __" << modulename << "_WRAPPER_HPP__\n"
+        << "\n"
+        << "#include \"WrapperUtil.hpp\"\n"
+        << "\n"
+        << "extern WrappedFunction " << modulename << "_global_functions[];\n"
+        << "extern WrappedClass " << modulename << "_classes[];\n"
+        << "\n"
+        << "#endif\n"
+        << "\n";
+    
+    // cpp header
+    out << "/**\n"
+        << " * WARNING: This file is automatically generated from '"
+        << inputfile << "' - do not change\n"
+        << " */\n"
+        << "\n"
+        << "#include <new>\n"
+        << "#include <string>\n"
+        << "#include <squirrel.h>\n"
+        << "#include \"WrapperUtil.hpp\"\n"
+        << "#include \"" << inputfile << "\"\n"
+        << "\n";
+    
+    for(std::vector<AtomicType*>::iterator i = unit->types.begin();
+            i != unit->types.end(); ++i) {
+        AtomicType* type = *i;
+        Class* _class = dynamic_cast<Class*> (type);
+        if(_class != 0)
+            create_class_wrapper(_class);
+    }
+    for(std::vector<Function*>::iterator i = unit->functions.begin();
+            i != unit->functions.end(); ++i) {
+        create_function_wrapper(0, *i);
+    }
+
+    // create function list...
+    out << "WrappedFunction " << modulename << "_global_functions[] = {\n";
+    for(std::vector<Function*>::iterator i = unit->functions.begin();
+            i != unit->functions.end(); ++i) {
+        Function* function = *i;
+        out << ind << "{ \"" << function->name << "\", &"
+            << function->name << "_wrapper },\n";
+    }
+    out << ind << "{ 0, 0 }\n"
+        << "};\n"
+        << "\n";
+
+    // create class list...
+    std::ostringstream classlist;
+    classlist << "WrappedClass " << modulename << "_classes[] = {\n";
+
+    for(std::vector<AtomicType*>::iterator i = unit->types.begin();
+            i != unit->types.end(); ++i) {
+        AtomicType* type = *i;
+        Class* _class = dynamic_cast<Class*> (type);
+        if(_class == 0)
+            continue;
+        
+        classlist << ind << "{ \"" << _class->name << "\", "
+            << modulename << "_" << _class->name
+            << "_methods },\n";
+            
+        out << "static WrappedFunction " << modulename << "_"
+            << _class->name << "_methods[] = {\n";
+        out << ind << "{ \"constructor\", &"
+            << _class->name << "_" << "construct_wrapper },\n";
+        for(std::vector<ClassMember*>::iterator i = _class->members.begin();
+                i != _class->members.end(); ++i) {
+            ClassMember* member = *i;
+            if(member->visibility != ClassMember::PUBLIC)
+                continue;
+            Function* function = dynamic_cast<Function*> (member);
+            if(!function || function->type != Function::FUNCTION)
+                continue;
+
+            out << ind << "{ \"" << function->name << "\", &"
+                << _class->name << "_" << function->name << "_wrapper },\n";
+        }
+        classlist << ind << "{ 0, 0 }\n";
+        out << "};\n"
+            << "\n";
+    }
+    classlist << "};\n";
+    out << classlist.str();
+    out << "\n";
+}
+
+void
+WrapperCreator::create_function_wrapper(Class* _class, Function* function)
+{
+    if(function->type == Function::CONSTRUCTOR)
+        throw std::runtime_error("Constructors not supported yet");
+    if(function->type == Function::DESTRUCTOR)
+        throw std::runtime_error("Destructors not supported yet");
+    
+    out << "static int ";
+    if(_class != 0) {
+        out << _class->name << "_";
+    }
+    out << function->name << "_wrapper(HSQUIRRELVM v)\n"
+        << "{\n";
+    // avoid warning...
+    if(_class == 0 && function->parameters.empty() 
+            && function->return_type.is_void()) {
+        out << ind << "(void) v;\n";
+    }
+    
+    // eventually retrieve pointer to class
+    if(_class != 0) {
+        out << ind << _class->name << "* _this;\n";
+        out << ind << "sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0);\n";
+        out << ind << "assert(_this != 0);\n";
+    }
+    
+    // declare and retrieve arguments
+    size_t i = 0;
+    for(std::vector<Parameter>::iterator p = function->parameters.begin();
+            p != function->parameters.end(); ++p) {
+        char argname[64];
+        snprintf(argname, sizeof(argname), "arg%u", i);
+        prepare_argument(p->type, i + 2, argname);
+        ++i;
+    }
+    // call function
+    out << ind << "\n";
+    out << ind;
+    if(!function->return_type.is_void()) {
+        function->return_type.write_c_type(out);
+        out << " return_value = ";
+    }
+    if(_class != 0) {
+        out << "_this->";
+    }
+    out << function->name << "(";
+    for(size_t i = 0; i < function->parameters.size(); ++i) {
+        if(i != 0)
+            out << ", ";
+        out << "arg" << i;
+    }
+    out << ");\n";
+    out << ind << "\n";
+    // push return value back on stack and return
+    if(function->return_type.is_void()) {
+        out << ind << "return 0;\n";
+    } else {
+        push_to_stack(function->return_type, "return_value");
+        out << ind << "return 1;\n";
+    }
+    out << "}\n";
+    out << "\n";
+}
+
+void
+WrapperCreator::prepare_argument(const Type& type, size_t index,
+        const std::string& var)
+{
+    if(type.ref > 0 && type.atomic_type != StringType::instance())
+        throw std::runtime_error("References not handled yet");
+    if(type.pointer > 0)
+        throw std::runtime_error("Pointers not handled yet");
+    if(type.atomic_type == &BasicType::INT) {
+        out << ind << "int " << var << ";\n";
+        out << ind << "sq_getinteger(v, " << index << ", &" << var << ");\n";
+    } else if(type.atomic_type == &BasicType::FLOAT) {
+        out << ind << "float " << var << ";\n";
+        out << ind << "sq_getfloat(v, " << index << ", &" << var << ");\n";
+    } else if(type.atomic_type == &BasicType::BOOL) {
+        out << ind << "SQBool " << var << ";\n";
+        out << ind << "sq_getbool(v, " << index << ", &" << var << ");\n";
+    } else if(type.atomic_type == StringType::instance()) {
+        out << ind << "const char* " << var << ";\n";
+        out << ind << "sq_getstring(v, " << index << ", &" << var << ");\n";
+    } else {
+        std::ostringstream msg;
+        msg << "Type '" << type.atomic_type->name << "' not supported yet.";
+        throw std::runtime_error(msg.str());
+    }
+}
+
+void
+WrapperCreator::push_to_stack(const Type& type, const std::string& var)
+{
+    if(type.ref > 0 && type.atomic_type != StringType::instance())
+        throw std::runtime_error("References not handled yet");
+    if(type.pointer > 0)
+        throw std::runtime_error("Pointers not handled yet");
+    out << ind;
+    if(type.atomic_type == &BasicType::INT) {
+        out << "sq_pushinteger(v, " << var << ");\n";
+    } else if(type.atomic_type == &BasicType::FLOAT) {
+        out << "sq_pushfloat(v, " << var << ");\n";
+    } else if(type.atomic_type == &BasicType::BOOL) {
+        out << "sq_pushbool(v, " << var << ");\n";
+    } else if(type.atomic_type == StringType::instance()) {
+        out << "sq_pushstring(v, " << var << ".c_str(), " 
+            << var << ".size());\n";
+    } else {
+        std::ostringstream msg;
+        msg << "Type '" << type.atomic_type->name << "' not supported yet.";
+        throw std::runtime_error(msg.str());
+    }
+}
+
+void
+WrapperCreator::create_class_wrapper(Class* _class)
+{
+    create_class_destruct_function(_class);
+    create_class_construct_function(_class);
+    for(std::vector<ClassMember*>::iterator i = _class->members.begin();
+            i != _class->members.end(); ++i) {
+        ClassMember* member = *i;
+        if(member->visibility != ClassMember::PUBLIC)
+            continue;
+        Function* function = dynamic_cast<Function*> (member);
+        if(!function)
+            continue;
+        // don't wrap constructors and destructors (for now...)
+        if(function->type != Function::FUNCTION)
+            continue;
+        create_function_wrapper(_class, function);
+    }
+}
+
+void
+WrapperCreator::create_class_construct_function(Class* _class)
+{
+    out << "static int " << _class->name << "_construct_wrapper(HSQUIRRELVM v)\n";
+    out << "{\n";
+    out << ind << _class->name << "* _this = new "
+        << _class->name << "();\n";
+    out << ind << "sq_setinstanceup(v, 1, _this);\n";
+    out << ind << "sq_setreleasehook(v, 1, " 
+        << _class->name << "_release_wrapper);\n";
+    out << "\n";
+    out << ind << "return 0;\n";
+    out << "}\n";
+    out << "\n";
+}
+
+void
+WrapperCreator::create_class_destruct_function(Class* _class)
+{
+    out << "static int " << _class->name << "_release_wrapper(SQUserPointer ptr, int )\n"
+        << "{\n"
+        << ind << _class->name 
+        << "* _this = reinterpret_cast<" << _class->name << "*> (ptr);\n"
+        << ind << "_this->~" << _class->name << "();\n"
+        << ind << "return 0;\n"
+        << "}\n"
+        << "\n";
+}
+
diff --git a/tools/miniswig/create_wrapper.h b/tools/miniswig/create_wrapper.h
new file mode 100644 (file)
index 0000000..7b51a18
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __CREATE_WRAPPER_H__
+#define __CREATE_WRAPPER_H__
+
+#include "tree.h"
+
+class WrapperCreator
+{
+public:
+    /// this is used for indentation
+    const char* ind;
+    // output stream
+    std::ostream& out;
+    std::ostream& hppout;
+
+    WrapperCreator(std::ostream& _out = std::cout, std::ostream& _hppout = std::cout)
+        : out(_out), hppout(_hppout)
+    {
+        ind = "  ";
+    }
+
+    void create_wrapper(CompilationUnit* unit);
+    void create_class_wrapper(Class* _class);
+    void create_class_construct_function(Class* _class);
+    void create_class_destruct_function(Class* _class);
+    void create_function_wrapper(Class* _class, Function* function);
+    void prepare_argument(const Type& type, size_t idx, const std::string& var);
+    void push_to_stack(const Type& type, const std::string& var);
+};
+
+#endif
+
diff --git a/tools/miniswig/globals.h b/tools/miniswig/globals.h
new file mode 100644 (file)
index 0000000..652f688
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __GLOBALS_H__
+#define __GLOBALS_H__
+
+#include "tree.h"
+#include <iostream>
+
+extern CompilationUnit* unit;
+extern std::istream* input;
+extern std::string inputfile;
+extern std::string modulename;
+
+#endif
+
diff --git a/tools/miniswig/lexer.ll b/tools/miniswig/lexer.ll
new file mode 100644 (file)
index 0000000..dc019e8
--- /dev/null
@@ -0,0 +1,78 @@
+%{
+#include <math.h>
+#include <stdlib.h>
+#include "tree.h"
+#include "parser.hpp"
+#include "globals.h"
+
+#define YY_DECL int yylex YY_PROTO(( YYSTYPE* yylval ))
+
+#define YY_INPUT(buf, result, max_size)                     \
+{                                                           \
+    input->read(buf, max_size);                             \
+    result = input->gcount();                               \
+}
+    
+%}
+
+%option noyywrap
+%option yylineno
+/* %option never-interactive */
+
+%%
+
+[[:space:]]+                            /* eat spaces */
+\/\*.*\*\/                              /* eat comment */
+\/\/[^\n]*\n                            /* eat comment */        
+class                                   { return T_CLASS; }
+struct                                  { return T_STRUCT; }
+static                                  { return T_STATIC; }
+const                                   { return T_CONST; }
+unsigned                                { return T_UNSIGNED; }
+signed                                  { return T_SIGNED; }
+void                                    { return T_VOID; }
+bool                                    { return T_BOOL; }
+char                                    { return T_CHAR; }
+short                                   { return T_SHORT; }
+int                                     { return T_INT; }
+long                                    { return T_LONG; }
+float                                   { return T_FLOAT; }
+double                                  { return T_DOUBLE; }
+public                                  { return T_PUBLIC; }
+protected                               { return T_PROTECTED; }
+private                                 { return T_PRIVATE; }
+[a-zA-Z_][a-zA-Z_0-9]*                  {
+        // is it a type?
+        for(std::vector<AtomicType*>::iterator i = unit->types.begin();
+                i != unit->types.end(); ++i) {
+            AtomicType* type = *i;
+            if(type->name == yytext) {
+                yylval->atomic_type = type;
+                return T_ATOMIC_TYPE;
+            }
+        }
+        // or a namespace? (hack for now...)
+        if(strcmp(yytext, "std") == 0) {
+            yylval->_namespace = unit->namespaces[0];
+            return T_NAMESPACE;
+        }
+        yylval->str = strdup(yytext);
+        return T_ID;
+}
+\:\:                                    { return T_DDCOL; }
+[0-9]+                                  { 
+                                            yylval->ival = atoi(yytext);
+                                            return T_INT;
+                                        }
+[0-9]*\.[0-9]+(e[0-9]+)?                { 
+                                            yylval->fval = atof(yytext);
+                                            return T_FLOAT;
+                                        }
+\".*\"                                  {
+                                            yylval->str = strdup(yytext);
+                                            return T_STRING;
+                                        }
+.                                       { return yytext[0]; }
+
+%%
+
diff --git a/tools/miniswig/main.cpp b/tools/miniswig/main.cpp
new file mode 100644 (file)
index 0000000..94393df
--- /dev/null
@@ -0,0 +1,100 @@
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+#include "tree.h"
+#include "globals.h"
+#include "create_wrapper.h"
+
+extern int yyparse();
+extern int yylex();
+
+CompilationUnit* unit = 0;
+std::istream* input = 0;
+std::string inputfile;
+std::string modulename = "wrapper";
+
+void usage()
+{
+    std::cout << "Usage: miniswig --input FILE --output-cpp FILE --output-hpp FILE [--module NAME]\n";
+    std::cout << "\n";
+}
+
+int main(int argc, char** argv)
+{
+    std::string outputcpp;
+    std::string outputhpp;
+    for(int i = 0; i < argc; ++i) {
+        if(strcmp(argv[i], "--module") == 0) {
+            if(i+1 >= argc) {
+                std::cerr << "Need to specify a module name.\n";
+                usage();
+                return 1;
+            }
+            modulename = argv[++i];
+        } else if(strcmp(argv[i], "--input") == 0) {
+            if(i+1 >= argc) {
+                std::cerr << "Need to specify input file name.\n";
+                usage();
+                return 1;
+            }
+            inputfile = argv[++i];
+        } else if(strcmp(argv[i], "--output-cpp") == 0) {
+            if(i+1 >= argc) {
+                std::cerr << "Need to specifiy output cpp name.\n";
+                usage();
+                return 1;
+            }
+            outputcpp = argv[++i];
+        } else if(strcmp(argv[i], "--output-hpp") == 0) {
+            if(i+1 >= argc) {
+                std::cerr << "Need to specify output hpp name.\n";
+                usage();
+                return 1;
+            }
+            outputhpp = argv[++i];
+        } else if(argv[i][0] == '-') {
+            std::cerr << "Unknown option '" << argv[i] << "'.\n";
+            usage();
+            return 1;
+        } else {
+        }
+    }
+    if(inputfile == "" || outputcpp == "" || outputhpp == "") {
+        std::cerr << "Not all options specified.\n";
+        usage();
+        return 1;
+    }
+    
+    try {
+        input = new std::ifstream(inputfile.c_str());
+        if(!input->good()) {
+            std::cerr << "Couldn't open file '" << input << "' for reading.\n";
+            return 1;
+        }
+        unit = new CompilationUnit();
+        unit->types.push_back(new StringType());
+        Namespace* std_namespace = new Namespace();
+        std_namespace->name = "std";
+        unit->namespaces.push_back(std_namespace);
+        yyparse();
+        std::ofstream cppout(outputcpp.c_str());
+        if(!cppout.good()) {
+            std::cerr << "Couldn't open file '" << outputcpp << "' for writing.\n";
+            return 1;
+        }
+        std::ofstream hppout(outputhpp.c_str());
+        if(!hppout.good()) {
+            std::cerr << "Couldn't open file '" << outputhpp << "' for writing.\n";
+            return 1;
+        }
+        WrapperCreator creator(cppout, hppout);
+        creator.create_wrapper(unit);
+    } catch(std::exception& e) {
+        std::cerr << e.what() << "\n";
+        return 1;
+    }
+
+    return 0;
+}
+
diff --git a/tools/miniswig/parser.yy b/tools/miniswig/parser.yy
new file mode 100644 (file)
index 0000000..f7865cc
--- /dev/null
@@ -0,0 +1,267 @@
+%{
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include "tree.h"
+#include "globals.h"
+
+%}
+
+%pure_parser
+%union {
+    char*       str;
+    int         ival;
+    float       fval;
+    Class*      _class;
+    Function*   function;
+    Type*       type;
+    AtomicType* atomic_type;
+    Namespace*  _namespace;
+}
+
+%{
+
+extern int yylex(YYSTYPE* yylval);
+void yyerror(const char* s);
+extern int yylineno;
+
+static Class* currentClass = 0;
+static Function* currentFunction = 0;
+static Type* currentType = 0;
+static ClassMember::Visbility currentVisibility;
+
+class ParseError : public std::exception
+{
+public:
+    ParseError(const std::string& message) throw()
+    {
+        std::ostringstream msg;
+        msg << "Parse error in line " << yylineno << ": "
+            << message;
+        this->message = msg.str();
+    }
+    virtual ~ParseError() throw()
+    {}
+    const char* what() const throw()
+    {
+        return message.c_str();
+    }
+
+private:
+    std::string message;
+};
+
+%}
+
+%token <ival> T_INT
+%token <fval> T_FLOAT
+%token <str>  T_STRING
+%token <str>  T_ID
+%token <atomic_type> T_ATOMIC_TYPE
+%token <_namespace> T_NAMESPACE;
+%token T_CLASS
+%token T_STRUCT
+%token T_STATIC
+%token T_CONST
+%token T_UNSIGNED
+%token T_SIGNED
+%token T_VOID
+%token T_BOOL
+%token T_CHAR
+%token T_SHORT
+%token T_INT
+%token T_LONG
+%token T_FLOAT
+%token T_DOUBLE
+%token T_PUBLIC
+%token T_PROTECTED
+%token T_PRIVATE
+%token T_DDCOL "::"
+
+%type <_class> class_declaration
+%type <function> function_declaration
+%type <function> constructor_declaration;
+%type <function> destructor_declaration;
+%type <type>   type
+%type <atomic_type> type_identifier
+
+%%
+
+input:  /* empty */
+    | compilation_unit
+;
+
+compilation_unit: compilation_unit_part
+    | compilation_unit compilation_unit_part
+;
+
+compilation_unit_part: class_declaration
+        { unit->types.push_back($1); }  
+    | function_declaration
+        { unit->functions.push_back($1); }
+;  
+
+class_declaration: T_CLASS T_ID '{' 
+            {
+                currentClass = new Class();
+                currentClass->name = $2;
+                free($2);
+                currentVisibility = ClassMember::PROTECTED;
+            }
+        class_body '}' ';'
+            {
+                $$ = currentClass;
+            }
+;
+
+class_body: /* empty */
+        | visibility_change class_body
+        | constructor_declaration
+            { 
+                $1->visibility = currentVisibility;
+                currentClass->members.push_back($1);
+            }
+          class_body
+        | destructor_declaration
+            {
+                $1->visibility = currentVisibility;
+                currentClass->members.push_back($1);
+            }
+          class_body
+        | function_declaration
+            {
+                $1->visibility = currentVisibility;
+                currentClass->members.push_back($1);
+            }
+          class_body
+        | variable_declaration class_body
+;
+
+visibility_change:  T_PUBLIC ':'
+            { currentVisibility = ClassMember::PUBLIC; }
+        |   T_PROTECTED ':'
+            { currentVisibility = ClassMember::PROTECTED; }
+        |   T_PRIVATE ':'
+            { currentVisibility = ClassMember::PRIVATE; }
+;
+
+constructor_declaration:    T_ID '('
+        {
+            currentFunction = new Function();
+            currentFunction->type = Function::CONSTRUCTOR;
+            free($1);
+        }
+    param_list ')' ';'
+        {
+            $$ = currentFunction;
+        }
+;
+
+destructor_declaration:     '~' T_ID '(' ')' ';'
+        {
+            currentFunction = new Function();
+            currentFunction->type = Function::DESTRUCTOR;
+            free($2);
+            $$ = currentFunction;
+        }
+;
+
+variable_declaration:   type T_ID ';'
+
+function_declaration:       type T_ID '(' 
+        {
+            currentFunction = new Function();
+            currentFunction->type = Function::FUNCTION;
+            currentFunction->return_type = *($1);
+            delete $1;
+            currentFunction->name = $2;
+            free($2);
+        }                           
+    param_list ')' ';'
+        {
+            $$ = currentFunction;
+        }
+;
+
+param_list: /* empty */
+        | param_list2
+;
+
+param_list2: parameter
+        | parameter ',' param_list2
+;
+
+parameter: type
+            {
+                Parameter parameter;
+                parameter.type = *($1);
+                delete $1;
+                currentFunction->parameters.push_back(parameter);
+            }
+        | type T_ID
+            {
+                Parameter parameter;
+                parameter.type = *($1);
+                delete $1;
+                parameter.name = *($2);
+                free($2);
+                currentFunction->parameters.push_back(parameter);
+            }
+;
+
+type: {
+          currentType = new Type();
+      }
+      prefix_type_modifiers atomic_type postfix_type_modifiers 
+      {
+          $$ = currentType;
+      }
+;
+
+prefix_type_modifiers: /* empty */
+            | T_UNSIGNED prefix_type_modifiers
+            | T_SIGNED prefix_type_modifiers
+            | T_STATIC prefix_type_modifiers
+            | T_CONST prefix_type_modifiers
+;
+
+postfix_type_modifiers: /* empty */
+            | T_CONST postfix_type_modifiers
+                { currentType->_const = true; }
+            |   '*' postfix_type_modifiers
+                { currentType->pointer++; }
+            |   '&' postfix_type_modifiers
+                { currentType->ref++; }
+;
+
+atomic_type:    T_VOID      { currentType->atomic_type = &BasicType::VOID; }
+            |   T_BOOL      { currentType->atomic_type = &BasicType::BOOL; }
+            |   T_CHAR      { currentType->atomic_type = &BasicType::CHAR; }
+            |   T_SHORT     { currentType->atomic_type = &BasicType::SHORT; }
+            |   T_INT       { currentType->atomic_type = &BasicType::INT; }
+            |   T_LONG      { currentType->atomic_type = &BasicType::LONG; }
+            |   T_FLOAT     { currentType->atomic_type = &BasicType::FLOAT; }
+            |   T_DOUBLE    { currentType->atomic_type = &BasicType::DOUBLE; }
+            |   type_identifier  { currentType->atomic_type = $1; }
+;
+
+type_identifier: T_ATOMIC_TYPE
+        {
+            // search for type in current compilation unit...
+            $$ = $1;
+        }
+        |   T_NAMESPACE "::" type_identifier
+        {
+            // hack...
+            $$ = $3;
+        }
+;
+
+%%
+
+void yyerror(const char* error)
+{
+    throw ParseError(error);
+}
+
diff --git a/tools/miniswig/tree.cpp b/tools/miniswig/tree.cpp
new file mode 100644 (file)
index 0000000..d05a38a
--- /dev/null
@@ -0,0 +1,12 @@
+#include "tree.h"
+
+BasicType BasicType::VOID("void");
+BasicType BasicType::BOOL("bool");
+BasicType BasicType::CHAR("char");
+BasicType BasicType::SHORT("short");
+BasicType BasicType::INT("int");
+BasicType BasicType::LONG("long");
+BasicType BasicType::FLOAT("float");
+BasicType BasicType::DOUBLE("double");
+
+StringType* StringType::_instance = 0;
diff --git a/tools/miniswig/tree.h b/tools/miniswig/tree.h
new file mode 100644 (file)
index 0000000..4b9485c
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef __TREE_H__
+#define __TREE_H__
+
+#include <vector>
+#include <string>
+#include <iostream>
+
+class AtomicType {
+public:
+    std::string name;
+    virtual ~AtomicType()
+    { }
+
+    virtual void write_c(std::ostream& out)
+    {
+        out << name;
+    }
+};
+
+class BasicType : public AtomicType {
+public:
+    static BasicType VOID;
+    static BasicType BOOL;
+    static BasicType CHAR;
+    static BasicType SHORT;
+    static BasicType INT;
+    static BasicType LONG;
+    static BasicType FLOAT;
+    static BasicType DOUBLE;
+
+private:
+    BasicType(const std::string& name)
+    { 
+        this->name = name;
+    }                                     
+};
+
+class Type {
+public:
+    Type() 
+        : atomic_type(0), _const(false), _static(false), pointer(0), ref(0)
+    { }
+
+    void write_c_type(std::ostream& out)
+    {
+        if(_static)
+            out << "static ";        
+        if(_const)
+            out << "const ";
+        atomic_type->write_c(out);
+        for(int i = 0; i < pointer; ++i)
+            out << "*";
+        for(int i = 0; i < ref; ++i)
+            out << "&";
+    }
+
+    bool is_void() const
+    {
+        if(atomic_type == &BasicType::VOID && pointer == 0)
+            return true;
+        return false;
+    }
+
+    AtomicType* atomic_type;
+    bool _const;
+    bool _static;
+    // number of '*' in the type declaration...
+    int pointer;
+    // number of '&' in the type declaration...
+    int ref;
+};
+
+class StringType : public AtomicType {
+public:
+    StringType()
+    {
+        this->name = "string";
+        assert(_instance == 0);
+        _instance = this;
+    }
+    virtual ~StringType()
+    {
+        assert(_instance == this);
+        _instance = 0;
+    }
+
+    static StringType* instance()
+    {
+        return _instance;
+    }
+
+    virtual void write_c(std::ostream& out)
+    {
+        out << "std::string";
+    }
+
+private:
+    static StringType* _instance;   
+};
+
+class Parameter {
+public:
+    std::string name;
+    Type type;
+};
+
+class ClassMember {
+public:
+    virtual ~ClassMember()
+    { }
+
+    enum Visbility {
+        PUBLIC,
+        PROTECTED,
+        PRIVATE
+    };
+    Visbility visibility;
+};
+
+class Function : public ClassMember {
+public:
+    enum FuncType {
+        FUNCTION,
+        CONSTRUCTOR,
+        DESTRUCTOR
+    };
+    FuncType type;
+    std::string name;
+    Type return_type;
+    std::vector<Parameter> parameters;
+};
+
+class Class : public AtomicType {
+public:
+    ~Class() {
+        for(std::vector<ClassMember*>::iterator i = members.begin();
+                i != members.end(); ++i)
+            delete *i;
+    }
+    
+    std::vector<ClassMember*> members;
+};
+
+class Namespace {
+public:
+    std::string name;
+};
+
+class CompilationUnit {
+public:
+    ~CompilationUnit() {
+        for(std::vector<Function*>::iterator i = functions.begin();
+                i != functions.end(); ++i)
+            delete *i;
+        for(std::vector<AtomicType*>::iterator i = types.begin();
+                i != types.end(); ++i)
+            delete *i;
+        for(std::vector<Namespace*>::iterator i = namespaces.begin();
+                i != namespaces.end(); ++i)
+            delete *i;
+    }
+    std::vector<Function*> functions;
+    std::vector<AtomicType*> types;
+    std::vector<Namespace*> namespaces;
+};
+
+#endif
+