Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Parser/C++/syn/occ.cc
    1| // Synopsis C++ Parser: occ.cc source file
    2| // Main entry point for the C++ parser module, and also debugging main
    3| // function.
    4| 
    5| // $Id: occ.cc,v 1.85 2003/01/27 06:53:37 chalky Exp $
    6| //
    7| // This file is a part of Synopsis.
    8| // Copyright (C) 2000-2002 Stephen Davies
    9| // Copyright (C) 2000, 2001 Stefan Seefeld
   10| //
   11| // Synopsis is free software; you can redistribute it and/or modify it
   12| // under the terms of the GNU General Public License as published by
   13| // the Free Software Foundation; either version 2 of the License, or
   14| // (at your option) any later version.
   15| //
   16| // This program is distributed in the hope that it will be useful,
   17| // but WITHOUT ANY WARRANTY; without even the implied warranty of
   18| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   19| // General Public License for more details.
   20| //
   21| // You should have received a copy of the GNU General Public License
   22| // along with this program; if not, write to the Free Software
   23| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   24| // 02111-1307, USA.
   25| 
   26| // $Log: occ.cc,v $
   27| // Revision 1.85  2003/01/27 06:53:37  chalky
   28| // Added macro support for C++.
   29| //
   30| // Revision 1.84  2003/01/15 12:10:26  chalky
   31| // Removed more global constructors
   32| //
   33| // Revision 1.83  2002/12/23 07:50:10  chalky
   34| // Get rid of statically initialised objects due to non-deterministic
   35| // initialisation order (particularly, the GC may not be available).
   36| //
   37| // Revision 1.82  2002/12/20 21:14:25  stefan
   38| // adapt signal handler to new SourceFile code
   39| //
   40| // Revision 1.81  2002/12/12 17:25:34  chalky
   41| // Implemented Include support for C++ parser. A few other minor fixes.
   42| //
   43| // Revision 1.80  2002/12/09 04:01:01  chalky
   44| // Added multiple file support to parsers, changed AST datastructure to handle
   45| // new information, added a demo to demo/C++. AST Declarations now have a
   46| // reference to a SourceFile (which includes a filename) instead of a filename.
   47| //
   48| // Revision 1.79  2002/11/22 05:59:37  chalky
   49| // Removed free() that shouldn't be there.
   50| //
   51| // Revision 1.78  2002/11/17 12:11:44  chalky
   52| // Reformatted all files with astyle --style=ansi, renamed fakegc.hh
   53| //
   54| //
   55| 
   56| #include <cstdio>
   57| #include <iostream>
   58| #include <string>
   59| #include <vector>
   60| #include <cstring>
   61| #include <cstdio>
   62| #include <unistd.h>
   63| #include <signal.h>
   64| #include <sys/wait.h>
   65| 
   66| #include <occ/walker.h>
   67| #include <occ/token.h>
   68| #include <occ/buffer.h>
   69| #include <occ/parse.h>
   70| #include <occ/ptree-core.h>
   71| #include <occ/ptree.h>
   72| #include <occ/encoding.h>
   73| #include <occ/mop.h>
   74| #include <occ/metaclass.h>
   75| #include <occ/env.h>
   76| #include <occ/encoding.h>
   77| 
   78| // Stupid macro
   79| #undef Scope
   80| 
   81| #include "synopsis.hh"
   82| #include "swalker.hh"
   83| #include "builder.hh"
   84| #include "dumper.hh"
   85| #include "link_map.hh"
   86| #include "filter.hh"
   87| #include "linkstore.hh"
   88| 
   89| // Define this to test refcounting
   90| //#define SYN_TEST_REFCOUNT
   91| 
   92| // ucpp_main is the renamed main() func of ucpp, since it is included in this
   93| // module
   94| extern "C" int ucpp_main(int argc, char** argv);
   95| 
   96| /* The following aren't used anywhere. Though it has to be defined and initialized to some dummy default
   97|  * values since it is required by the opencxx.a module, which I don't want to modify...
   98|  */
   99| bool showProgramdoCompilemakeExecutabledoPreprocessdoTranslate;
  100| bool verboseModeregularCppmakeSharedLibrarypreprocessTwice;
  101| charsharedLibraryName;
  102| 
  103| /* These also are just dummies needed by the opencxx module */
  104| void RunSoCompiler(const char *)
  105| {}
  106| void *LoadSoLib(char *)
  107| {
  108|     return 0;
  109| }
  110| void *LookupSymbol(void *, char *)
  111| {
  112|     return 0;
  113| }
  114| 
  115| /* This implements the static var and method from fakegc.h */
  116| cleanup* FakeGC::head = NULL;
  117| void FakeGC::delete_all()
  118| {
  119|     cleanupnode = FakeGC::head;
  120|     cleanupnext;
  121|     size_t count = 0;
  122|     while (node)
  123|     {
  124|         next = node->cleanup_next;
  125|         delete node;
  126|         node = next;
  127|         count++;
  128|     }
  129|     FakeGC::head = NULL;
  130|     //std::cout << "FakeGC::delete_all(): deleted " << count << " objects." << std::endl;
  131| }
  132| 
  133| bool verbose;
  134| 
  135| // If true then everything but what's in the main file will be stripped
  136| bool syn_main_only;
  137| bool syn_extract_tailssyn_use_gccsyn_fake_std;
  138| bool syn_multi_files;
  139| 
  140| // If set then this is stripped from the start of all filenames
  141| const charsyn_basename = "";
  142| 
  143| // If set then this is the prefix for the filename to store links to
  144| const charsyn_syntax_prefix = 0;
  145| 
  146| // If set then this is the prefix for the filename to store xref info to
  147| const charsyn_xref_prefix = 0;
  148| 
  149| // If set then this is the filename to store links to
  150| const charsyn_file_syntax = 0;
  151| 
  152| // If set then this is the filename to store xref to
  153| const charsyn_file_xref = 0;
  154| 
  155| // This is the compiler to emulate
  156| const charsyn_emulate_compiler = "c++";
  157| 
  158| // A list of extra filenames to store info for
  159| std::vector<const char*>* syn_extra_filenames = NULL;
  160| 
  161| // A place to temporarily store Python's thread state
  162| PyThreadStatepythread_save;
  163| 
  164| 
  165| #ifdef DEBUG
  166| // For use in gdb, since decl->Display() doesn't work too well..
  167| void show(Ptree* p)
  168| {
  169|     p->Display();
  170| }
  171| #endif
  172| 
  173| namespace
  174| {
  175| 
  176| //. Override unexpected() to print a message before we abort
  177| void unexpected()
  178| {
  179|     std::cout << "Warning: Aborting due to unexpected exception." << std::endl;
  180|     throw std::bad_exception();
  181| }
  182| 
  183| void getopts(PyObject *args, std::vector<const char *> &cppflags, 
  184|         std::vector<const char *> &occflags, PyObject* config, PyObject* extra_files)
  185| {
  186|     // Initialise defaults
  187|     showProgram = doCompile = verboseMode = makeExecutable = false;
  188|     doTranslate = regularCpp = makeSharedLibrary = preprocessTwice = false;
  189|     doPreprocess = true;
  190|     sharedLibraryName = 0;
  191|     verbose = false;
  192|     syn_main_only = false;
  193|     syn_extract_tails = false;
  194|     syn_use_gcc = false;
  195|     syn_fake_std = false;
  196|     syn_multi_files = false;
  197|     Class::do_init_static();
  198|     Metaclass::do_init_static();
  199|     Environment::do_init_static();
  200|     Encoding::do_init_static();
  201| 
  202| #define IsType(obj, type) (Py##type##_Check(obj))
  203| 
  204| #define OPT_FLAG(syn_flag, config_name) \
  205| if ((value = PyObject_GetAttrString(config, config_name)) != 0)\
  206|     syn_flag = PyObject_IsTrue(value);\
  207| Py_XDECREF(value);
  208| 
  209| #define OPT_STRING(syn_name, config_name) \
  210| if ((value = PyObject_GetAttrString(config, config_name)) != 0)\
  211| { if (!IsType(value, String)) throw "Error: " config_name " must be a string.";\
  212|   syn_name = PyString_AsString(value);\
  213| }\
  214| Py_XDECREF(value);
  215| 
  216|     // Check config object first
  217|     if (config)
  218|     {
  219|         PyObjectvalue;
  220|         OPT_FLAG(verbose, "verbose");
  221|         OPT_FLAG(syn_main_only, "main_file");
  222|         // Grab the include paths
  223|         if ((value = PyObject_GetAttrString(config"include_path")) != 0)
  224|         {
  225|             if (!IsType(value, List))
  226|             {
  227|                 std::cerr << "Error: include_path must be a list of strings." << std::endl;
  228|                 exit(1);
  229|             }
  230|             // Loop through the include paths
  231|             for (int i=0end=PyList_Size(value); i < endi++)
  232|             {
  233|                 PyObjectitem = PyList_GetItem(valuei);
  234|                 if (!item || !IsType(item, String))
  235|                 {
  236|                     std::cerr << "Error: include_path must be a list of strings." << std::endl;
  237|                     exit(1);
  238|                 }
  239|                 // mem leak.. how to fix?
  240|                 charbuf = new char[PyString_Size(item)+3];
  241|                 strcpy(buf"-I");
  242|                 strcat(bufPyString_AsString(item));
  243|                 cppflags.push_back(buf);
  244|             // for
  245|         }
  246|         Py_XDECREF(value);
  247|         // Grab the list of defines
  248|         if ((value = PyObject_GetAttrString(config"defines")) != 0)
  249|         {
  250|             if (!IsType(value, List))
  251|             {
  252|                 std::cerr << "Error: defines must be a list of strings." << std::endl;
  253|                 exit(1);
  254|             }
  255|             // Loop through the include paths
  256|             for (int i=0end=PyList_Size(value); i < endi++)
  257|             {
  258|                 PyObjectitem = PyList_GetItem(valuei);
  259|                 if (!item || !IsType(item, String))
  260|                 {
  261|                     std::cerr << "Error: defines must be a list of strings." << std::endl;
  262|                     exit(1);
  263|                 }
  264|                 // mem leak.. how to fix?
  265|                 charbuf = new char[PyString_Size(item)+3];
  266|                 strcpy(buf"-D");
  267|                 strcat(bufPyString_AsString(item));
  268|                 cppflags.push_back(buf);
  269|             // for
  270|         }
  271|         Py_XDECREF(value);
  272| 
  273|         // Basename is the prefix to strip from filenames
  274|         OPT_STRING(syn_basename, "basename");
  275|         // Extract tails tells the parser to find tail comments
  276|         OPT_FLAG(syn_extract_tails, "extract_tails");
  277|         // 'storage' defines the filename to write syntax hilite info to (OBSOLETE)
  278|         OPT_STRING(syn_file_syntax, "storage");
  279|         // 'syntax_prefix' defines the prefix for the filename to write syntax hilite info to
  280|         OPT_STRING(syn_syntax_prefix, "syntax_prefix");
  281|         // 'syntax_file' defines the filename to write syntax hilite info to
  282|         OPT_STRING(syn_file_syntax, "syntax_file");
  283|         // 'xref_prefix' defines the prefix for the xrefname to write syntax hilite info to
  284|         OPT_STRING(syn_xref_prefix, "xref_prefix");
  285|         // 'xref_file' defines the filename to write syntax hilite info to
  286|         OPT_STRING(syn_file_xref, "xref_file");
  287|         // 'preprocessor' defines whether to use gcc or not
  288|         chartemp_string = NULL;
  289|         OPT_STRING(temp_string, "preprocessor");
  290|         if (temp_string)
  291|         {
  292|             syn_use_gcc = !strcmp("gcc"temp_string);
  293|         }
  294|         // 'emulate_compiler' specifies the compiler to emulate in terms of
  295|         // include paths and macros
  296|         OPT_STRING(syn_emulate_compiler, "emulate_compiler");
  297|         OPT_FLAG(syn_fake_std, "fake_std");
  298|         // If multiple_files is set then the parser handles multiple files
  299|         // included from the main one at the same time (they get into the AST,
  300|         // plus they get their own xref and links files).
  301|         OPT_FLAG(syn_multi_files, "multiple_files");
  302|     // if config
  303| #undef OPT_STRING
  304| #undef OPT_FLAG
  305| #undef IsType
  306| 
  307|     // Now check command line args
  308|     size_t argsize = PyList_Size(args);
  309|     for (size_t i = 0i != argsize; ++i)
  310|     {
  311|         const char *argument = PyString_AsString(PyList_GetItem(argsi));
  312|         if (strncmp(argument"-I"2) == 0)
  313|             cppflags.push_back(argument);
  314|         else if (strncmp(argument"-D"2) == 0)
  315|             cppflags.push_back(argument);
  316|         else if (strcmp(argument"-v") == 0)
  317|             verbose = true;
  318|         else if (strcmp(argument"-m") == 0)
  319|             syn_main_only = true;
  320|         else if (strcmp(argument"-b") == 0)
  321|             syn_basename = PyString_AsString(PyList_GetItem(args, ++i));
  322|         else if (strcmp(argument"-t") == 0)
  323|             syn_extract_tails = true;
  324|         else if (strcmp(argument"-s") == 0)
  325|             syn_file_syntax = PyString_AsString(PyList_GetItem(args, ++i));
  326|         else if (strcmp(argument"-x") == 0)
  327|             syn_file_xref = PyString_AsString(PyList_GetItem(args, ++i));
  328|         else if (strcmp(argument"-g") == 0)
  329|             syn_use_gcc = true;
  330|         else if (strcmp(argument"-f") == 0)
  331|             syn_fake_std = true;
  332|     }
  333| 
  334|     // If multi_files is set, we check the extra_files argument to see if it
  335|     // has a list of filenames like it should do
  336|     if (extra_files && PyList_Check(extra_files))
  337|     {
  338|         size_t extra_size = PyList_Size(extra_files);
  339|         if (extra_size > 0)
  340|         {
  341|             PyObjectitem;
  342|             const charstring;
  343|             syn_extra_filenames = new std::vector<const char*>;
  344|             for (size_t i = 0i < extra_sizei++)
  345|             {
  346|                 item = PyList_GetItem(extra_filesi);
  347|                 string = PyString_AsString(item);
  348|                 syn_extra_filenames->push_back(string);
  349|             }
  350|         }
  351|     }
  352| }
  353| 
  354| //. Emulates the compiler in 'syn_emulate_compiler' by calling the Python
  355| //. module Synopsis.Parser.C++.emul to get a list of include paths and macros to
  356| //. add to the args vector.
  357| void emulate_compiler(std::vector<const char*>& args)
  358| {
  359|     PyObjectemul_module = PyImport_ImportModule("Synopsis.Parser.C++.emul");
  360|     if (!emul_module)
  361|         return;
  362|     PyObjectinfo = PyObject_CallMethod(emul_module"get_compiler_info""s"syn_emulate_compiler);
  363|     if (!info)
  364|     {
  365|         PyErr_Print();
  366|         return;
  367|     }
  368|     PyObjectpaths = PyObject_GetAttrString(info"include_paths");
  369|     if (paths)
  370|     {
  371|         // Add each path..
  372|         int num_paths = PyList_Size(paths);
  373|         for (int i = 0i < num_pathsi++)
  374|         {
  375|             PyObjectpath = PyList_GetItem(pathsi);
  376|             if (!path)
  377|             {
  378|                 PyErr_Print();
  379|                 continue;
  380|             }
  381|             charpath_str = PyString_AsString(path);
  382|             if (path_str)
  383|             {
  384|                 // Add this path
  385|                 args.push_back("-I");
  386|                 args.push_back(path_str);
  387|             }
  388|         }
  389|         Py_DECREF(paths);
  390|     }
  391|     PyObjectmacros = PyObject_GetAttrString(info"macros");
  392|     if (macros)
  393|     {
  394|         // Add each macro..
  395|         int num_macros = PyList_Size(macros);
  396|         for (int i = 0i < num_macrosi++)
  397|         {
  398|             PyObjectmacro_tuple = PyList_GetItem(macrosi);
  399|             if (!macro_tuple)
  400|             {
  401|                 PyErr_Print();
  402|                 continue;
  403|             }
  404|             PyObjectmacro_name = PyTuple_GetItem(macro_tuple0);
  405|             if (!macro_name)
  406|             {
  407|                 PyErr_Print();
  408|                 continue;
  409|             }
  410|             PyObjectmacro_value = PyTuple_GetItem(macro_tuple1);
  411|             if (!macro_value)
  412|             {
  413|                 PyErr_Print();
  414|                 continue;
  415|             }
  416|             if (macro_value == Py_None)
  417|             /* TODO: Do remove macro */
  418|             }
  419|             else
  420|             {
  421|                 // Add the argument in the form -DNAME=VALUE to the list of arguments
  422|                 chardef = (char*)malloc(4 + PyString_Size(macro_name) + PyString_Size(macro_value));
  423|                 strcpy(def"-D");
  424|                 strcat(defPyString_AsString(macro_name));
  425|                 strcat(def"=");
  426|                 strcat(defPyString_AsString(macro_value));
  427|                 args.push_back(def);
  428|                 // TODO: Figure out where to free this string
  429|             }
  430|         }
  431|         Py_DECREF(macros);
  432|     }
  433|     Py_DECREF(info);
  434|     Py_DECREF(emul_module);
  435| }
  436| 
  437| char *RunPreprocessor(const char *file, const std::vector<const char *> &flags)
  438| {
  439|     static char dest[1024];
  440|     strcpy(dest"/tmp/synopsis-XXXXXX");
  441|     int temp_fd = mkstemp(dest);
  442|     if (temp_fd == -1)
  443|     {
  444|         perror("RunPreprocessor");
  445|         exit(1);
  446|     }
  447|     // Not interested in the open file, just the unique filename
  448|     close(temp_fd);
  449| 
  450|     if (syn_use_gcc)
  451|     {
  452|         // Release Python's global interpreter lock
  453|         pythread_save = PyEval_SaveThread();
  454| 
  455|         switch(fork())
  456|         {
  457|         case 0:
  458|             {
  459|                 std::vector<const char *> args = flags;
  460|                 char *cc = getenv("CC");
  461|                 args.insert(args.begin(), cc ? cc : "cpp");
  462|                 args.push_back("-C"); // keep comments
  463|                 args.push_back("-E"); // stop after preprocessing
  464|                 args.push_back("-o"); // output to...
  465|                 args.push_back(dest);
  466|                 args.push_back("-x"); // language c++
  467|                 args.push_back("c++");
  468|                 args.push_back(file);
  469|                 if (verbose)
  470|                 {
  471|                     std::cout << "calling external preprocessor\n" << args[0];
  472|                     for (std::vector<const char *>::iterator i = args.begin(); i != args.end(); ++i)
  473|                         std::cout << ' ' << *i;
  474|                     std::cout << std::endl;
  475|                 }
  476|                 args.push_back(0);
  477|                 execvp(args[0], (char **)&*args.begin());
  478|                 perror("cannot invoke compiler");
  479|                 exit(-1);
  480|                 break;
  481|             }
  482|         case -1:
  483|             perror("RunPreprocessor");
  484|             exit(-1);
  485|             break;
  486|         default:
  487|             {
  488|                 int status;
  489|                 wait(&status);
  490|                 if (status != 0)
  491|                 {
  492|                     if (WIFEXITED(status))
  493|                         std::cout << "exited with status " << WEXITSTATUS(status) << std::endl;
  494|                     else if (WIFSIGNALED(status))
  495|                         std::cout << "stopped with status " << WTERMSIG(status) << std::endl;
  496|                     exit(1);
  497|                 }
  498|             }
  499|         // switch
  500|     }
  501|     else
  502|     // else use ucpp
  503|         // Create argv vector
  504|         std::vector<const char *> args = flags;
  505|         char *cc = getenv("CC");
  506|         args.insert(args.begin(), cc ? cc : "ucpp");
  507|         args.push_back("-C"); // keep comments
  508|         args.push_back("-lg"); // gcc-like line numbers
  509|         emulate_compiler(args);
  510|         args.push_back("-o"); // output to...
  511|         args.push_back(dest);
  512|         args.push_back(file);
  513|         if (verbose)
  514|         {
  515|             std::cout << "calling ucpp\n";
  516|             for (std::vector<const char *>::iterator i = args.begin(); i != args.end(); ++i)
  517|                 std::cout << ' ' << *i;
  518|             std::cout << std::endl;
  519|         }
  520| 
  521|         // Release Python's global interpreter lock
  522|         pythread_save = PyEval_SaveThread();
  523| 
  524|         // Call ucpp
  525|         int status = ucpp_main(args.size(), (char **)&*args.begin());
  526|         if (status != 0)
  527|             std::cerr << "ucpp returned error flag. ignoring error." << std::endl;
  528|     }
  529|     return dest;
  530| }
  531| 
  532| void sighandler(int signo)
  533| {
  534|     std::string signame;
  535|     switch (signo)
  536|     {
  537|     case SIGABRT:
  538|         signame = "Abort";
  539|         break;
  540|     case SIGBUS:
  541|         signame = "Bus error";
  542|         break;
  543|     case SIGSEGV:
  544|         signame = "Segmentation Violation";
  545|         break;
  546|     default:
  547|         signame = "unknown";
  548|         break;
  549|     };
  550|     SWalker *instance = SWalker::instance();
  551|     std::cerr << signame << " caught while processing " << instance->current_file()->filename()
  552|               << " at line " << instance->current_lineno()
  553|               << std::endl;
  554|     exit(-1);
  555| }
  556| 
  557| void RunOpencxx(const char *src, const char *file, const std::vector<const char *> &args, PyObject *ast, PyObject *types, PyObject *declarations, PyObject* files)
  558| {
  559|     Trace trace("RunOpencxx");
  560|     std::set_unexpected(unexpected);
  561|     struct sigaction olda;
  562|     struct sigaction newa;
  563|     newa.sa_handler = &sighandler;
  564|     sigaction(SIGSEGV, &newa, &olda);
  565|     sigaction(SIGBUS, &newa, &olda);
  566|     sigaction(SIGABRT, &newa, &olda);
  567| 
  568|     std::ifstream ifs(file);
  569|     if(!ifs)
  570|     {
  571|         perror(file);
  572|         exit(1);
  573|     }
  574|     ProgramFile prog(ifs);
  575|     Lex lex(&prog);
  576|     Parser parse(&lex);
  577| #if 0
  578|     // Make sure basename ends in a '/'
  579|     std::string basename = syn_basename;
  580|     if (basename.size() > 0 && basename[basename.size()-1] != '/')
  581|         basename.append("/");
  582|     // Calculate source filename
  583|     std::string source(src);
  584|     if (source.substr(0, basename.size()) == basename)
  585|         source.erase(0, basename.size());
  586| #endif
  587| 
  588|     FileFilterfilter = FileFilter::instance();
  589| 
  590|     AST::SourceFilesourcefile = filter->get_sourcefile(src);
  591| 
  592|     Builder builder(sourcefile);
  593|     if (syn_macro_defines)
  594|         builder.add_macros(*syn_macro_defines);
  595|     SWalker swalker(filter, &parse, &builder, &prog);
  596|     swalker.set_extract_tails(syn_extract_tails);
  597|     Ptree *def;
  598|     if (syn_fake_std)
  599|     {
  600|         builder.set_file(sourcefile);
  601|         // Fake a using from "std" to global
  602|         builder.start_namespace("std"NamespaceNamed);
  603|         builder.add_using_namespace(builder.global()->declared());
  604|         builder.end_namespace();
  605|     }
  606| #ifdef DEBUG
  607|     swalker.set_extract_tails(syn_extract_tails);
  608|     while(parse.rProgram(def))
  609|         swalker.Translate(def);
  610| 
  611|     // Grab interpreter lock again so we can call python
  612|     PyEval_RestoreThread(pythread_save);
  613| #ifdef SYN_TEST_REFCOUNT
  614|     // Test Synopsis
  615|     Synopsis synopsis(src, declarations, types);
  616|     synopsis.translate(builder.scope(), ast);
  617|     synopsis.set_builtin_decls(builder.builtin_decls());
  618| #else
  619|     // Test Dumper
  620|     Dumper dumper;
  621|     if (syn_main_only)
  622|         dumper.onlyShow(src);
  623|     dumper.visit_scope(builder.scope());
  624| #endif
  625| #else
  626| 
  627| #if 0
  628|     std::ofstream* of_syntax = 0;
  629|     std::ofstream* of_xref = 0;
  630|     char syn_buffer[1024];
  631|     size_t baselen = basename.size();
  632|     if (syn_file_syntax)
  633|         of_syntax = new std::ofstream(syn_file_syntax);
  634|     else if (syn_syntax_prefix)
  635|     {
  636|         strcpy(syn_buffer, syn_syntax_prefix);
  637|         if (!strncmp(basename.c_str(), src, baselen))
  638|             strcat(syn_buffer, src + baselen);
  639|         else
  640|             strcat(syn_buffer, src);
  641|         makedirs(syn_buffer);
  642|         of_syntax = new std::ofstream(syn_buffer);
  643|     }
  644|     if (syn_file_xref)
  645|         of_xref = new std::ofstream(syn_file_xref);
  646|     else if (syn_xref_prefix)
  647|     {
  648|         strcpy(syn_buffer, syn_xref_prefix);
  649|         if (!strncmp(basename.c_str(), src, baselen))
  650|             strcat(syn_buffer, src + baselen);
  651|         else
  652|             strcat(syn_buffer, src);
  653|         makedirs(syn_buffer);
  654|         of_xref = new std::ofstream(syn_buffer);
  655|     }
  656|     if (of_syntax || of_xref)
  657|         swalker.set_store_links(true, of_syntax, of_xref);
  658| #endif
  659|     if (filter->should_link(sourcefile) || filter->should_xref(sourcefile))
  660|         swalker.set_store_links(new LinkStore(filter, &swalker));
  661|     try
  662|     {
  663|         while(parse.rProgram(def))
  664|             swalker.Translate(def);
  665|     }
  666|     catch (...)
  667|     {
  668|         std::cerr << "Warning: an uncaught exception occurred when translating the parse tree" << std::endl;
  669|     }
  670|     // Grab interpreter lock again so we can call python
  671|     PyEval_RestoreThread(pythread_save);
  672| 
  673|     // Setup synopsis c++ to py convertor
  674|     Synopsis synopsis(filter, declarations, types);
  675|     synopsis.set_builtin_decls(builder.builtin_decls());
  676|     // Convert!
  677|     synopsis.translate(builder.scope(), ast);
  678| #endif
  679| 
  680|     if(parse.NumOfErrors() != 0)
  681|     {
  682|         std::cerr << "Ignoring errors while parsing file: " << file << std::endl;
  683|     }
  684| 
  685|     if (files)
  686|     {
  687|         //PyObject_CallMethod(filenames, "append", "s", source.c_str());
  688|     }
  689|     ifs.close();
  690|     sigaction(SIGABRT, &olda0);
  691|     sigaction(SIGBUS, &olda0);
  692|     sigaction(SIGSEGV, &olda0);
  693| }
  694| 
  695| void do_parse(const char *src, 
  696|         const std::vector<const char *>& cppargs, 
  697|         const std::vector<const char *>& occargs, 
  698|         PyObject *ast, PyObject *types, PyObject *declarations, PyObject* files)
  699| {
  700|     // Setup the filter
  701|     FileFilter filter;
  702|     filter.set_only_main(syn_main_only);
  703|     filter.set_main_filename(src);
  704|     filter.set_basename(syn_basename);
  705|     if (syn_extra_filenamesfilter.add_extra_filenames(*syn_extra_filenames);
  706|     if (syn_file_syntaxfilter.set_syntax_filename(syn_file_syntax);
  707|     if (syn_file_xreffilter.set_xref_filename(syn_file_xref);
  708|     if (syn_syntax_prefixfilter.set_syntax_prefix(syn_syntax_prefix);
  709|     if (syn_xref_prefixfilter.set_xref_prefix(syn_xref_prefix);
  710| 
  711|     // Run the preprocessor
  712|     char *cppfile = RunPreprocessor(srccppargs);
  713| 
  714|     // Run OCC to generate the AST
  715|     RunOpencxx(srccppfileoccargsasttypesdeclarationsfiles);
  716|     unlink(cppfile);
  717| }
  718| 
  719| PyObject *occParse(PyObject *self, PyObject *args)
  720| {
  721|     Trace trace("occParse");
  722| #if 0
  723| 
  724|     Ptree::show_encoded = true;
  725| #endif
  726| 
  727|     char *src;
  728|     PyObject *extra_files, *parserargs, *types, *declarations, *config, *ast;
  729|     if (!PyArg_ParseTuple(args"sOO!O", &src, &extra_files, &PyList_Type, &parserargs, &config))
  730|         return 0;
  731|     std::vector<const char *> cppargs;
  732|     std::vector<const char *> occargs;
  733|     getopts(parserargscppargsoccargsconfigextra_files);
  734|     if (!src || *src == '\0')
  735|     {
  736|         std::cerr << "No source file" << std::endl;
  737|         exit(-1);
  738|     }
  739|     // Make AST object
  740| #define assertObject(pyo) if (!pyo) PyErr_Print(); assert(pyo)
  741|     PyObjectast_module = PyImport_ImportModule("Synopsis.Core.AST");
  742|     assertObject(ast_module);
  743|     ast = PyObject_CallMethod(ast_module"AST""");
  744|     assertObject(ast);
  745|     PyObjectfiles = PyObject_CallMethod(ast"files""");
  746|     assertObject(files);
  747|     declarations = PyObject_CallMethod(ast"declarations""");
  748|     assertObject(declarations);
  749|     types = PyObject_CallMethod(ast"types""");
  750|     assertObject(types);
  751| #undef assertObject
  752| 
  753|     do_parse(srccppargsoccargsasttypesdeclarationsfiles);
  754| 
  755|     if (syn_extra_filenames)
  756|     {
  757|         delete syn_extra_filenames;
  758|         syn_extra_filenames = 0;
  759|     }
  760|     Py_DECREF(ast_module);
  761|     Py_DECREF(declarations);
  762|     Py_DECREF(files);
  763|     Py_DECREF(types);
  764| 
  765| #ifndef DONT_GC
  766|     // Try to cleanup GC if being used
  767|     //std::cout << "GC: Running Garbage Collection..." << std::endl;
  768|     //size_t size = GC_get_heap_size();
  769|     GC_gcollect();
  770|     //size_t size2 = GC_get_heap_size();
  771|     //std::cout << "GC: Heap went from " << size << " to " << size2 << std::endl;
  772| #endif
  773| 
  774| #ifdef SYN_TEST_REFCOUNT
  775|     // Now, there should *fingers crossed* be no python objects. Check..
  776|     {
  777|         PyGC_Head* node = _PyGC_generation0.gc.gc_next;
  778|         size_t count = 0;
  779|         while (node != &_PyGC_generation0)
  780|         {
  781|             //PyObject* obj = (PyObject*)(node + 1);
  782|             //PyObject* str = PyObject_Repr(obj);
  783|             //std::cout << obj->ob_refcnt << " " << PyString_AsString(str) << "\n";
  784|             //Py_DECREF(str);
  785|             node = node->gc.gc_next;
  786|             count++;
  787|         }
  788|         //std::cout << "Collection list contains " << count << " objects." << std::endl;
  789|     }
  790| #endif
  791| 
  792|     // Delete all the AST:: and Types:: objects we created
  793|     FakeGC::delete_all();
  794| 
  795|     // Clear the link map
  796|     LinkMap::instance()->clear();
  797| 
  798|     return ast;
  799| }
  800| 
  801| PyObject *occUsage(PyObject *self, PyObject *)
  802| {
  803|     Trace trace("occParse");
  804|     std::cout
  805|     << "  -I<path>                             Specify include path to be used by the preprocessor\n"
  806|     << "  -D<macro>                            Specify macro to be used by the preprocessor\n"
  807|     << "  -m                                   Unly keep declarations from the main file\n"
  808|     << "  -b basepath                          Strip basepath from start of filenames" << std::endl;
  809|     Py_INCREF(Py_None);
  810|     return Py_None;
  811| }
  812| 
  813| PyMethodDef occ_methods[] =
  814|     {
  815|         {(char*)"parse",            occParse,               METH_VARARGS},
  816|         {(char*)"usage",            occUsage,               METH_VARARGS},
  817|         {0, 0}
  818|     };
  819| };
  820| 
  821| extern "C" void initocc()
  822| {
  823|     PyObjectm = Py_InitModule((char*)"occ", occ_methods);
  824|     PyObject_SetAttrString(m, (char*)"version"PyString_FromString("0.1"));
  825| }
  826| 
  827| #ifdef DEBUG
  828| 
  829| int main(int argc, char **argv)
  830| {
  831|     char *src = 0;
  832|     std::vector<const char *> cppargs;
  833|     std::vector<const char *> occargs;
  834|     //   getopts(argc, argv, cppargs, occargs);
  835|     Py_Initialize();
  836|     int i, py_i;
  837|     bool all_args = false;
  838|     for (i = 1, py_i = 0; i != argc; ++i)
  839|         if (!all_args && argv[i][0] != '-')
  840|             src = argv[i];
  841|         else if (!strcmp(argv[i], "--"))
  842|             all_args = true;
  843|         else
  844|             ++py_i;
  845|     PyObject *pylist = PyList_New(py_i);
  846|     all_args = false;
  847|     for (i = 1, py_i = 0; i != argc; ++i)
  848|         if (!all_args && argv[i][0] != '-')
  849|             continue;
  850|         else if (!strcmp(argv[i], "--"))
  851|             all_args = true;
  852|         else
  853|             PyList_SetItem(pylist, py_i++, PyString_FromString(argv[i]));
  854|     getopts(pylist, cppargs, occargs, NULL, NULL);
  855|     if (!src || *src == '\0')
  856|     {
  857|         std::cerr << "Usage: " << argv[0] << " <filename>" << std::endl;
  858|         exit(-1);
  859|     }
  860|     PyObject* ast_module = PyImport_ImportModule("Synopsis.Core.AST");
  861|     PyObject* ast = PyObject_CallMethod(ast_module, "AST", 0);
  862|     PyObject* type = PyImport_ImportModule("Synopsis.Core.Type");
  863|     PyObject* types = PyObject_CallMethod(type, "Dictionary", 0);
  864|     PyObject* decls = PyList_New(0);
  865|     
  866|     do_parse(src, cppargs, occargs, ast, types, decls, NULL);
  867| 
  868| #ifdef SYN_TEST_REFCOUNT
  869| 
  870|     Py_DECREF(pylist);
  871|     Py_DECREF(type);
  872|     Py_DECREF(types);
  873|     Py_DECREF(decls);
  874|     Py_DECREF(ast);
  875|     Py_DECREF(ast_module);
  876|     
  877|     // Now, there should *fingers crossed* be no python objects. Check..
  878|     if (0)
  879|     {
  880|         PyGC_Head* node = _PyGC_generation0.gc.gc_next;
  881|         size_t count = 0;
  882|         while (node != &_PyGC_generation0)
  883|         {
  884|             PyObject* obj = (PyObject*)(node + 1);
  885|             PyObject* str = PyObject_Repr(obj);
  886|             //std::cout << obj->ob_refcnt << " " << PyString_AsString(str) << "\n";
  887|             Py_DECREF(str);
  888|             node = node->gc.gc_next;
  889|             count++;
  890|         }
  891|         //std::cout << "Collection list contains " << count << " objects." << std::endl;
  892|     }
  893| #endif
  894| #ifndef DONT_GC
  895|     // Try to cleanup GC if being used
  896|     //size_t size = GC_get_heap_size();
  897|     GC_gcollect();
  898|     //size_t size2 = GC_get_heap_size();
  899|     //std::cout << "Collection: Heap went from " << size << " to " << size2 << std::endl;
  900| #endif
  901| 
  902|     Py_Finalize();
  903| 
  904|     FakeGC::delete_all();
  905| }
  906| 
  907| #endif
  908| // vim: set ts=8 sts=4 sw=4 et: