Synopsis - Cross-Reference

File: /Synopsis/Parsers/Cxx/ParserImpl.cc
  1//
  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}