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|
90|
91|
92|
93|
94| extern "C" int ucpp_main(int argc, char** argv);
95|
96|
97|
98|
99| bool showProgram, doCompile, makeExecutable, doPreprocess, doTranslate;
100| bool verboseMode, regularCpp, makeSharedLibrary, preprocessTwice;
101| char* sharedLibraryName;
102|
103|
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| cleanup* node = FakeGC::head;
120| cleanup* next;
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|
131| }
132|
133| bool verbose;
134|
135|
136| bool syn_main_only;
137| bool syn_extract_tails, syn_use_gcc, syn_fake_std;
138| bool syn_multi_files;
139|
140|
141| const char* syn_basename = "";
142|
143|
144| const char* syn_syntax_prefix = 0;
145|
146|
147| const char* syn_xref_prefix = 0;
148|
149|
150| const char* syn_file_syntax = 0;
151|
152|
153| const char* syn_file_xref = 0;
154|
155|
156| const char* syn_emulate_compiler = "c++";
157|
158|
159| std::vector<const char*>* syn_extra_filenames = NULL;
160|
161|
162| PyThreadState* pythread_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|
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| PyObject* value;
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=0, end=PyList_Size(value); i < end; i++)
232| {
233| PyObject* item = PyList_GetItem(value, i);
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| char* buf = new char[PyString_Size(item)+3];
241| strcpy(buf, "-I");
242| strcat(buf, PyString_AsString(item));
243| cppflags.push_back(buf);
244| }
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=0, end=PyList_Size(value); i < end; i++)
257| {
258| PyObject* item = PyList_GetItem(value, i);
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| char* buf = new char[PyString_Size(item)+3];
266| strcpy(buf, "-D");
267| strcat(buf, PyString_AsString(item));
268| cppflags.push_back(buf);
269| }
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| char* temp_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| }
303| #undef OPT_STRING
304| #undef OPT_FLAG
305| #undef IsType
306|
307|
308| size_t argsize = PyList_Size(args);
309| for (size_t i = 0; i != argsize; ++i)
310| {
311| const char *argument = PyString_AsString(PyList_GetItem(args, i));
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| PyObject* item;
342| const char* string;
343| syn_extra_filenames = new std::vector<const char*>;
344| for (size_t i = 0; i < extra_size; i++)
345| {
346| item = PyList_GetItem(extra_files, i);
347| string = PyString_AsString(item);
348| syn_extra_filenames->push_back(string);
349| }
350| }
351| }
352| }
353|
354|
355|
356|
357| void emulate_compiler(std::vector<const char*>& args)
358| {
359| PyObject* emul_module = PyImport_ImportModule("Synopsis.Parser.C++.emul");
360| if (!emul_module)
361| return;
362| PyObject* info = PyObject_CallMethod(emul_module, "get_compiler_info", "s", syn_emulate_compiler);
363| if (!info)
364| {
365| PyErr_Print();
366| return;
367| }
368| PyObject* paths = PyObject_GetAttrString(info, "include_paths");
369| if (paths)
370| {
371| // Add each path..
372| int num_paths = PyList_Size(paths);
373| for (int i = 0; i < num_paths; i++)
374| {
375| PyObject* path = PyList_GetItem(paths, i);
376| if (!path)
377| {
378| PyErr_Print();
379| continue;
380| }
381| char* path_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| PyObject* macros = PyObject_GetAttrString(info, "macros");
392| if (macros)
393| {
394| // Add each macro..
395| int num_macros = PyList_Size(macros);
396| for (int i = 0; i < num_macros; i++)
397| {
398| PyObject* macro_tuple = PyList_GetItem(macros, i);
399| if (!macro_tuple)
400| {
401| PyErr_Print();
402| continue;
403| }
404| PyObject* macro_name = PyTuple_GetItem(macro_tuple, 0);
405| if (!macro_name)
406| {
407| PyErr_Print();
408| continue;
409| }
410| PyObject* macro_value = PyTuple_GetItem(macro_tuple, 1);
411| if (!macro_value)
412| {
413| PyErr_Print();
414| continue;
415| }
416| if (macro_value == Py_None)
417| {
418| }
419| else
420| {
421| // Add the argument in the form -DNAME=VALUE to the list of arguments
422| char* def = (char*)malloc(4 + PyString_Size(macro_name) + PyString_Size(macro_value));
423| strcpy(def, "-D");
424| strcat(def, PyString_AsString(macro_name));
425| strcat(def, "=");
426| strcat(def, PyString_AsString(macro_value));
427| args.push_back(def);
428|
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| }
500| }
501| else
502| {
503|
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| FileFilter* filter = FileFilter::instance();
589|
590| AST::SourceFile* sourcefile = 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|
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|
688| }
689| ifs.close();
690| sigaction(SIGABRT, &olda, 0);
691| sigaction(SIGBUS, &olda, 0);
692| sigaction(SIGSEGV, &olda, 0);
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|
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_filenames) filter.add_extra_filenames(*syn_extra_filenames);
706| if (syn_file_syntax) filter.set_syntax_filename(syn_file_syntax);
707| if (syn_file_xref) filter.set_xref_filename(syn_file_xref);
708| if (syn_syntax_prefix) filter.set_syntax_prefix(syn_syntax_prefix);
709| if (syn_xref_prefix) filter.set_xref_prefix(syn_xref_prefix);
710|
711| // Run the preprocessor
712| char *cppfile = RunPreprocessor(src, cppargs);
713|
714| // Run OCC to generate the AST
715| RunOpencxx(src, cppfile, occargs, ast, types, declarations, files);
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(parserargs, cppargs, occargs, config, extra_files);
734| if (!src || *src == '\0')
735| {
736| std::cerr << "No source file" << std::endl;
737| exit(-1);
738| }
739|
740| #define assertObject(pyo) if (!pyo) PyErr_Print(); assert(pyo)
741| PyObject* ast_module = PyImport_ImportModule("Synopsis.Core.AST");
742| assertObject(ast_module);
743| ast = PyObject_CallMethod(ast_module, "AST", "");
744| assertObject(ast);
745| PyObject* files = 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(src, cppargs, occargs, ast, types, declarations, files);
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| PyObject* m = 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|