Synopsis - Cross-Reference
File: /Synopsis/Parsers/Cxx/ParserImpl.cc1// 2// Copyright (C) 2000 Stefan Seefeld 3// Copyright (C) 2000 Stephen Davies 4// All rights reserved. 5// Licensed to the public under the terms of the GNU LGPL (>= 2), 6// see the file COPYING for details. 7// 8 9#include <Synopsis/Python/Module.hh> 10#include <Synopsis/Trace.hh> 11#include <Support/ErrorHandler.hh> 12#include "Translator.hh" 13#include "SXRGenerator.hh" 14#include "Walker.hh" 15#include "Builder.hh" 16#include "Filter.hh" 17#include "FakeGC.hh" 18#include "exception.hh" 19#include <Synopsis/PTree.hh> 20#include <Synopsis/PTree/Display.hh> 21#include <Synopsis/SymbolLookup.hh> 22#include <Synopsis/Buffer.hh> 23#include <Synopsis/Lexer.hh> 24#include <Synopsis/SymbolFactory.hh> 25#include <Synopsis/Parser.hh> 26 27#include <cstdio> 28#include <iostream> 29#include <fstream> 30#include <string> 31#include <vector> 32#include <cstring> 33#include <cstdio> 34#include <stdexcept> 35#include <memory> 36 37using namespace Synopsis; 38 39// 40// for now occ remains the 'C++ parser backend' for synopsis, 41// and GCC extension and MSVC tokens are activated in compatibility 42// mode. 43// Later this may become an option for the python frontend, too. 44// 45#if defined(__GNUG__) || defined(_GNUG_SYNTAX) 46# if defined(PARSE_MSVC) 47const int tokenset = Lexer::CXX | Lexer::GCC | Lexer::MSVC; 48const int ruleset = Parser::CXX | Parser::GCC | Parser::MSVC; 49# else 50const int tokenset = Lexer::CXX | Lexer::GCC; 51const int ruleset = Parser::CXX | Parser::GCC; 52# endif 53#else 54# if defined(PARSE_MSVC) 55const int tokenset = Lexer::CXX | Lexer::MSVC; 56const int ruleset = Parser::CXX | Parser::MSVC; 57# else 58const int tokenset = Lexer::CXX; 59const int ruleset = Parser::CXX; 60# endif 61#endif 62 63FakeGC::LightObject *FakeGC::LightObject::head = 0; 64 65bool verbose; 66 67// If true then everything but what's in the primary file will be stripped 68bool syn_primary_only; 69bool syn_fake_std; 70bool syn_multi_files; 71 72// If set then this is stripped from the start of all filenames 73const char* syn_base_path = ""; 74 75// If set then this is the prefix for the filename to store links to 76const char* syn_sxr_prefix = 0; 77 78PyObject *py_error; 79 80namespace 81{ 82 83//. Override unexpected() to print a message before we abort 84void unexpected() 85{ 86 std::cout << "Warning: Aborting due to unexpected exception." << std::endl; 87 throw std::bad_exception(); 88} 89 90const char *strip_prefix(const char *filename, const char *prefix) 91{ 92 if (!prefix) return filename; 93 size_t length = strlen(prefix); 94 if (strncmp(filename, prefix, length) == 0) 95 return filename + length; 96 return filename; 97} 98 99void error() 100{ 101 Walker *instance = Walker::instance(); 102 std::cerr << "processing " << instance->current_file()->name() 103 << " at line " << instance->current_lineno() 104 << std::endl; 105} 106 107PyObject *parse(PyObject * /* self */, PyObject *args) 108{ 109 PTree::Encoding::do_init_static(); 110 111 PyObject *ir; 112 const char *src, *cppfile; 113 int primary_file_only, verbose, debug; 114 if (!PyArg_ParseTuple(args, "Ossizzii", 115 &ir, &cppfile, &src, 116 &primary_file_only, 117 &syn_base_path, 118 &syn_sxr_prefix, 119 &verbose, 120 &debug)) 121 return 0; 122 123 Py_INCREF(py_error); 124 std::auto_ptr<Python::Object> error_type(new Python::Object(py_error)); 125 Py_INCREF(ir); 126 127 if (verbose) ::verbose = true; 128 if (debug) Trace::enable(Trace::ALL); 129 if (primary_file_only) syn_primary_only = true; 130 131 if (!src || *src == '\0') 132 { 133 PyErr_SetString(PyExc_RuntimeError, "no input file"); 134 return 0; 135 } 136 std::ifstream ifs(cppfile); 137 if(!ifs) 138 { 139 PyErr_SetString(PyExc_RuntimeError, "unable to open output file"); 140 return 0; 141 } 142 143 std::set_unexpected(unexpected); 144 ErrorHandler error_handler(error); 145 146 // Setup the filter 147 FileFilter filter(ir, src, syn_base_path, syn_primary_only); 148 if (syn_sxr_prefix) filter.set_sxr_prefix(syn_sxr_prefix); 149 150 ASG::SourceFile *source_file = filter.get_sourcefile(src); 151 // Run OCC to generate the IR 152 try 153 { 154 Buffer buffer(ifs.rdbuf(), source_file->abs_name()); 155 Lexer lexer(&buffer, tokenset); 156 SymbolFactory symbols(SymbolFactory::NONE); 157 Parser parser(lexer, symbols, ruleset); 158 159 PTree::Node *ptree = parser.parse(); 160 Parser::ErrorList const &errors = parser.errors(); 161 if (!errors.empty()) 162 { 163 for (Parser::ErrorList::const_iterator i = errors.begin(); i != errors.end(); ++i) 164 (*i)->write(std::cerr); 165 throw std::runtime_error("The input contains errors."); 166 } 167 else if (ptree) 168 { 169 FileFilter* filter = FileFilter::instance(); 170 Builder builder(source_file); 171 Walker walker(filter, &builder, &buffer); 172 SXRGenerator *sxr_generator = 0; 173 if (filter->should_xref(source_file)) 174 { 175 sxr_generator = new SXRGenerator(filter, &walker); 176 walker.set_store_links(sxr_generator); 177 } 178 walker.translate(ptree); 179 Translator translator(filter, ir); 180 translator.set_builtin_decls(builder.builtin_decls()); 181 translator.translate(builder.scope()); 182 delete sxr_generator; 183 } 184 } 185 catch (const std::exception &e) 186 { 187 Python::Object py_e((*error_type)(Python::Tuple(e.what()))); 188 PyErr_SetObject(py_error, py_e.ref()); 189 return 0; 190 } 191 catch (py_error_already_set const &) 192 { 193 return 0; 194 } 195 catch (...) 196 { 197 Python::Object py_e((*error_type)(Python::Tuple("internal error"))); 198 PyErr_SetObject(py_error, py_e.ref()); 199 return 0; 200 } 201 202 PTree::cleanup_gc(); 203 delete FakeGC::LightObject::head; 204 205 return ir; 206} 207 208PyMethodDef methods[] = {{(char*)"parse", parse, METH_VARARGS}, 209 {0}}; 210} 211 212extern "C" void initParserImpl() 213{ 214 Python::Module module = Python::Module::define("ParserImpl", methods); 215 module.set_attr("version", "0.10"); 216 Python::Object processor = Python::Object::import("Synopsis.Processor"); 217 Python::Object error_base = processor.attr("Error"); 218 py_error = PyErr_NewException("ParserImpl.ParseError", error_base.ref(), 0); 219 module.set_attr("ParseError", py_error); 220}