source: src/main.cc@ cd79053

Last change on this file since cd79053 was 37b3151, checked in by Andrew Beach <ajbeach@…>, 22 months ago

Rename the linkReferenceTypes pass and the file that contains it. BaseInstType used to be called ReferenceToType, so the reason for the pass being called that is no longer true.

  • Property mode set to 100644
File size: 27.8 KB
RevLine 
[b87a5ed]1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
[71f4e4f]7// main.cc --
[b87a5ed]8//
[3e96559]9// Author : Peter Buhr and Rob Schluntz
[b87a5ed]10// Created On : Fri May 15 23:12:02 2015
[372b6d3]11// Last Modified By : Peter A. Buhr
[be3f163]12// Last Modified On : Wed Nov 1 21:12:58 2023
13// Update Count : 690
[b87a5ed]14//
15
[bf2438c]16#include <cxxabi.h> // for __cxa_demangle
17#include <execinfo.h> // for backtrace, backtrace_symbols
18#include <getopt.h> // for no_argument, optind, geto...
[08fc48f]19#include <cassert> // for assertf
[bf2438c]20#include <cstdio> // for fopen, FILE, fclose, stdin
21#include <cstdlib> // for exit, free, abort, EXIT_F...
[bffcd66]22#include <csignal> // for signal, SIGABRT, SIGSEGV
[bf2438c]23#include <cstring> // for index
[be9288a]24#include <fstream> // for ofstream
[bf2438c]25#include <iostream> // for operator<<, basic_ostream
[62ce290]26#include <iomanip>
[bf2438c]27#include <iterator> // for back_inserter
28#include <list> // for list
[08fc48f]29#include <string> // for char_traits, operator<<
[e6955b1]30
[bccd70a]31#include "AST/Pass.hpp" // for pass_visitor_stats
[0b5e780]32#include "AST/Print.hpp" // for printAll
[bccd70a]33#include "AST/TranslationUnit.hpp" // for TranslationUnit
[52f9804]34#include "AST/Util.hpp" // for checkInvariants
[7f38b67a]35#include "CompilationState.h"
[bf2438c]36#include "../config.h" // for CFA_LIBDIR
37#include "CodeGen/FixMain.h" // for FixMain
38#include "CodeGen/FixNames.h" // for fixNames
39#include "CodeGen/Generate.h" // for generate
[aff7e86]40#include "CodeGen/LinkOnce.h" // for translateLinkOnce
[f57faf6f]41#include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations
[55cbff8]42#include "Common/DeclStats.hpp" // for printDeclStats
43#include "Common/ResolvProtoDump.hpp" // for dumpAsResolverProto
[09366b8]44#include "Common/Stats.h" // for Stats
[bf2438c]45#include "Common/utility.h" // for deleteAll, filter, printAll
[3dd8f42]46#include "Concurrency/Actors.hpp" // for implementActors
[eb779d5]47#include "Concurrency/Corun.hpp" // for implementCorun
[2cf3b87]48#include "Concurrency/Keywords.h" // for implementMutex, implement...
[9f5ecf5]49#include "Concurrency/Waitfor.h" // for generateWaitfor
[c86b08d]50#include "Concurrency/Waituntil.hpp" // for generateWaitUntil
[0c730d9]51#include "ControlStruct/ExceptDecl.h" // for translateExcept
[09366b8]52#include "ControlStruct/ExceptTranslate.h" // for translateThrows, translat...
[b8ab91a]53#include "ControlStruct/FixLabels.hpp" // for fixLabels
[a488783]54#include "ControlStruct/HoistControlDecls.hpp" // hoistControlDecls
[bf2438c]55#include "GenPoly/Box.h" // for box
56#include "GenPoly/InstantiateGeneric.h" // for instantiateGeneric
57#include "GenPoly/Lvalue.h" // for convertLvalue
58#include "GenPoly/Specialize.h" // for convertSpecializations
59#include "InitTweak/FixInit.h" // for fix
60#include "InitTweak/GenInit.h" // for genInit
61#include "MakeLibCfa.h" // for makeLibCfa
[cbd1ba8]62#include "Parser/RunParser.hpp" // for buildList, dumpParseTree,...
[1622af5]63#include "ResolvExpr/CandidatePrinter.hpp" // for printCandidates
[d3652df]64#include "ResolvExpr/EraseWith.hpp" // for eraseWith
[bf2438c]65#include "ResolvExpr/Resolver.h" // for resolve
66#include "Tuples/Tuples.h" // for expandMemberTuples, expan...
[a488783]67#include "Validate/Autogen.hpp" // for autogenerateRoutines
[298fe57]68#include "Validate/CompoundLiteral.hpp" // for handleCompoundLiterals
69#include "Validate/EliminateTypedef.hpp" // for eliminateTypedef
[1931bb01]70#include "Validate/EnumAndPointerDecay.hpp" // for decayEnumsAndPointers
[ce36b55]71#include "Validate/FindSpecialDecls.h" // for findGlobalDecls
[298fe57]72#include "Validate/FixQualifiedTypes.hpp" // for fixQualifiedTypes
[1931bb01]73#include "Validate/FixReturnTypes.hpp" // for fixReturnTypes
[9490621]74#include "Validate/ForallPointerDecay.hpp" // for decayForallPointers
[298fe57]75#include "Validate/GenericParameter.hpp" // for fillGenericParameters, tr...
76#include "Validate/HoistStruct.hpp" // for hoistStruct
[1931bb01]77#include "Validate/HoistTypeDecls.hpp" // for hoistTypeDecls
[ce36b55]78#include "Validate/InitializerLength.hpp" // for setLengthFromInitializer
79#include "Validate/LabelAddressFixer.hpp" // for fixLabelAddresses
[37b3151]80#include "Validate/LinkInstanceTypes.hpp" // for linkInstanceTypes
[1931bb01]81#include "Validate/ReplaceTypedef.hpp" // for replaceTypedef
[4ec9513]82#include "Validate/ReturnCheck.hpp" // for checkReturnStatements
[1931bb01]83#include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign
[a5f0529]84#include "Virtual/ExpandCasts.h" // for expandCasts
[37b3151]85#include "Virtual/VirtualDtor.hpp" // for implementVirtDtors
[51b73452]86
[2c38b15]87using namespace std;
88
[3e96559]89static void NewPass( const char * const name ) {
90 Stats::Heap::newPass( name );
[1cb7fab2]91 using namespace Stats::Counters;
[b8665e3]92 {
[f43146e4]93 static auto group = build<CounterGroup>( "Pass Visitor Template" );
[3e96559]94 auto pass = build<CounterGroup>( name, group );
[f43146e4]95 ast::pass_visitor_stats.depth = 0;
96 ast::pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass );
97 ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass );
[b8665e3]98 }
[675716e]99}
100
[52f9804]101// Helpers for checkInvariant:
102void checkInvariants( std::list< Declaration * > & ) {}
103using ast::checkInvariants;
104
105#define PASS( name, pass, unit, ... ) \
[ecaeac6e]106 if ( errorp ) { cerr << name << endl; } \
[675716e]107 NewPass(name); \
[4f97937]108 Stats::Time::StartBlock(name); \
[52f9804]109 pass(unit,##__VA_ARGS__); \
110 Stats::Time::StopBlock(); \
111 if ( invariant ) { \
112 checkInvariants(unit); \
113 }
114
115#define DUMP( cond, unit ) \
116 if ( cond ) { \
117 dump(unit); \
118 return EXIT_SUCCESS; \
119 }
[0da3e2c]120
[ef22ad6]121static bool waiting_for_gdb = false; // flag to set cfa-cpp to wait for gdb on start
[dee1f89]122
[bffcd66]123static string PreludeDirector = "";
[4dcaed2]124
[77d601f]125static void parse_cmdline( int argc, char * argv[] );
[e499381]126static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );
[e6955b1]127
[0afffee]128static void backtrace( int start ) { // skip first N stack frames
[74330e7]129 enum { Frames = 50, }; // maximum number of stack frames
[e6955b1]130 void * array[Frames];
[74330e7]131 size_t size = ::backtrace( array, Frames );
[0afffee]132 char ** messages = ::backtrace_symbols( array, size ); // does not demangle names
133
134 *index( messages[0], '(' ) = '\0'; // find executable name
135 cerr << "Stack back trace for: " << messages[0] << endl;
[e6955b1]136
[b542bfb]137 // skip last 2 stack frames after main
[74330e7]138 for ( unsigned int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
[e6955b1]139 char * mangled_name = nullptr, * offset_begin = nullptr, * offset_end = nullptr;
[7006ba5]140
141 for ( char * p = messages[i]; *p; p += 1 ) { // find parantheses and +offset
[0afffee]142 if ( *p == '(' ) {
[46f6134]143 mangled_name = p;
[0afffee]144 } else if ( *p == '+' ) {
[e6955b1]145 offset_begin = p;
[0afffee]146 } else if ( *p == ')' ) {
[e6955b1]147 offset_end = p;
148 break;
149 } // if
150 } // for
151
152 // if line contains symbol, attempt to demangle
[b542bfb]153 int frameNo = i - start;
[e6955b1]154 if ( mangled_name && offset_begin && offset_end && mangled_name < offset_begin ) {
[0afffee]155 *mangled_name++ = '\0'; // delimit strings
[e6955b1]156 *offset_begin++ = '\0';
157 *offset_end++ = '\0';
158
[0afffee]159 int status;
[e6955b1]160 char * real_name = __cxxabiv1::__cxa_demangle( mangled_name, 0, 0, &status );
[0afffee]161 // bug in __cxa_demangle for single-character lower-case non-mangled names
[e6955b1]162 if ( status == 0 ) { // demangling successful ?
[b542bfb]163 cerr << "(" << frameNo << ") " << messages[i] << " : "
[e6955b1]164 << real_name << "+" << offset_begin << offset_end << endl;
165 } else { // otherwise, output mangled name
[b542bfb]166 cerr << "(" << frameNo << ") " << messages[i] << " : "
[0afffee]167 << mangled_name << "(/*unknown*/)+" << offset_begin << offset_end << endl;
[e6955b1]168 } // if
[0afffee]169
[e6955b1]170 free( real_name );
171 } else { // otherwise, print the whole line
[b542bfb]172 cerr << "(" << frameNo << ") " << messages[i] << endl;
[e6955b1]173 } // if
174 } // for
[b542bfb]175
[e6955b1]176 free( messages );
[b542bfb]177} // backtrace
178
[bffcd66]179#define SIGPARMS int sig __attribute__(( unused )), siginfo_t * sfp __attribute__(( unused )), ucontext_t * cxt __attribute__(( unused ))
180
[1f68d5d]181static void _Signal(struct sigaction & act, int sig, int flags ) {
[bffcd66]182 act.sa_flags = flags;
183
184 if ( sigaction( sig, &act, nullptr ) == -1 ) {
[77d601f]185 cerr << "*cfa-cpp compilation error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;
[bffcd66]186 _exit( EXIT_FAILURE );
187 } // if
[1f68d5d]188}
189
190static void Signal( int sig, void (* handler)(SIGPARMS), int flags ) {
191 struct sigaction act;
192 act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
193 _Signal(act, sig, flags);
194} // Signal
195
196static void Signal( int sig, void (* handler)(int), int flags ) {
197 struct sigaction act;
198 act.sa_handler = handler;
199 _Signal(act, sig, flags);
[bffcd66]200} // Signal
201
202static void sigSegvBusHandler( SIGPARMS ) {
203 if ( sfp->si_addr == nullptr ) {
204 cerr << "Null pointer (nullptr) dereference." << endl;
205 } else {
206 cerr << (sig == SIGSEGV ? "Segment fault" : "Bus error") << " at memory location " << sfp->si_addr << "." << endl
207 << "Possible cause is reading outside the address space or writing to a protected area within the address space with an invalid pointer or subscript." << endl;
208 } // if
[b542bfb]209 backtrace( 2 ); // skip first 2 stack frames
[3e96559]210 abort(); // cause core dump for debugging
[e6955b1]211} // sigSegvBusHandler
[0da3e2c]212
[74330e7]213static void sigFpeHandler( SIGPARMS ) {
214 const char * msg;
215
216 switch ( sfp->si_code ) {
217 case FPE_INTDIV: case FPE_FLTDIV: msg = "divide by zero"; break;
218 case FPE_FLTOVF: msg = "overflow"; break;
219 case FPE_FLTUND: msg = "underflow"; break;
220 case FPE_FLTRES: msg = "inexact result"; break;
221 case FPE_FLTINV: msg = "invalid operation"; break;
222 default: msg = "unknown";
223 } // choose
224 cerr << "Computation error " << msg << " at location " << sfp->si_addr << endl
225 << "Possible cause is constant-expression evaluation invalid." << endl;
226 backtrace( 2 ); // skip first 2 stack frames
227 abort(); // cause core dump for debugging
228} // sigFpeHandler
229
[bffcd66]230static void sigAbortHandler( SIGPARMS ) {
[b542bfb]231 backtrace( 6 ); // skip first 6 stack frames
[1f68d5d]232 Signal( SIGABRT, SIG_DFL, SA_SIGINFO ); // reset default signal handler
[9be45a2]233 raise( SIGABRT ); // reraise SIGABRT
[b542bfb]234} // sigAbortHandler
235
[cbaee0d]236int main( int argc, char * argv[] ) {
[3b8e52c]237 FILE * input; // use FILE rather than istream because yyin is FILE
[d08beee]238 ostream * output = & cout;
[64b3cda]239 ast::TranslationUnit transUnit;
[e6955b1]240
[bffcd66]241 Signal( SIGSEGV, sigSegvBusHandler, SA_SIGINFO );
242 Signal( SIGBUS, sigSegvBusHandler, SA_SIGINFO );
[74330e7]243 Signal( SIGFPE, sigFpeHandler, SA_SIGINFO );
[bffcd66]244 Signal( SIGABRT, sigAbortHandler, SA_SIGINFO );
[b87a5ed]245
[bffcd66]246 // cout << "main" << endl;
[44bca7f]247 // for ( int i = 0; i < argc; i += 1 ) {
[bffcd66]248 // cout << '\t' << argv[i] << endl;
[44bca7f]249 // } // for
250
[e0bd0f9]251 parse_cmdline( argc, argv ); // process command-line arguments
[b87a5ed]252
[ef22ad6]253 if ( waiting_for_gdb ) {
[bffcd66]254 cerr << "Waiting for gdb" << endl;
255 cerr << "run :" << endl;
256 cerr << " gdb attach " << getpid() << endl;
[dee1f89]257 raise(SIGSTOP);
[ef22ad6]258 } // if
[dee1f89]259
[b87a5ed]260 try {
[81419b5]261 // choose to read the program from a file or stdin
[3b8e52c]262 if ( optind < argc ) { // any commands after the flags ? => input file name
[b87a5ed]263 input = fopen( argv[ optind ], "r" );
[e0bd0f9]264 assertf( input, "cannot open %s because %s\n", argv[ optind ], strerror( errno ) );
[b87a5ed]265 optind += 1;
[3b8e52c]266 } else { // no input file name
[b87a5ed]267 input = stdin;
268 } // if
269
[79eaeb7]270 Stats::Time::StartGlobal();
[3c0d4cd]271 NewPass("Parse");
272 Stats::Time::StartBlock("Parse");
[675716e]273
[159c62e]274 // read in the builtins, extras, and the prelude
[de62360d]275 if ( ! nopreludep ) { // include gcc builtins
[faf8857]276 // -l is for initial build ONLY and builtins.cf is not in the lib directory so access it here.
[807ce84]277
[37fe352]278 assertf( !PreludeDirector.empty(), "Can't find prelude without option --prelude-dir must be used." );
[4dcaed2]279
[807ce84]280 // Read to gcc builtins, if not generating the cfa library
[be3f163]281 FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cfa").c_str(), "r" );
[6ce3ae9]282 assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
[f2f595d7]283 parse( gcc_builtins, ast::Linkage::Compiler );
[81419b5]284
[159c62e]285 // read the extra prelude in, if not generating the cfa library
[be3f163]286 FILE * extras = fopen( (PreludeDirector + "/extras.cfa").c_str(), "r" );
[3b8e52c]287 assertf( extras, "cannot open extras.cf\n" );
[f2f595d7]288 parse( extras, ast::Linkage::BuiltinC );
[159c62e]289
[81419b5]290 if ( ! libcfap ) {
[faf8857]291 // read the prelude in, if not generating the cfa library
[e523b07]292 FILE * prelude = fopen( (PreludeDirector + "/prelude.cfa").c_str(), "r" );
293 assertf( prelude, "cannot open prelude.cfa\n" );
[f2f595d7]294 parse( prelude, ast::Linkage::Intrinsic );
[fa4805f]295
296 // Read to cfa builtins, if not generating the cfa library
[be3f163]297 FILE * builtins = fopen( (PreludeDirector + "/builtins.cfa").c_str(), "r" );
[fa4805f]298 assertf( builtins, "cannot open builtins.cf\n" );
[f2f595d7]299 parse( builtins, ast::Linkage::BuiltinCFA );
[b87a5ed]300 } // if
301 } // if
[81419b5]302
[f2f595d7]303 parse( input, libcfap ? ast::Linkage::Intrinsic : ast::Linkage::Cforall, yydebug );
[71f4e4f]304
[64b3cda]305 transUnit = buildUnit();
[b87a5ed]306
[52f9804]307 DUMP( astp, std::move( transUnit ) );
[b87a5ed]308
[3c0d4cd]309 Stats::Time::StopBlock();
[036dd5f]310
[52f9804]311 PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit );
312
313 PASS( "Translate Exception Declarations", ControlStruct::translateExcept, transUnit );
314 DUMP( exdeclp, std::move( transUnit ) );
315 PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign, transUnit );
316 PASS( "Replace Typedefs", Validate::replaceTypedef, transUnit );
317 PASS( "Fix Return Types", Validate::fixReturnTypes, transUnit );
318 PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers, transUnit );
319
[37b3151]320 PASS( "Link Instance Types", Validate::linkInstanceTypes, transUnit );
[52f9804]321
[14c0f7b]322 PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
[52f9804]323 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
324 PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
[2c38b15]325 PASS( "Hoist Struct", Validate::hoistStruct, transUnit );
[52f9804]326 PASS( "Validate Generic Parameters", Validate::fillGenericParameters, transUnit );
327 PASS( "Translate Dimensions", Validate::translateDimensionParameters, transUnit );
328 PASS( "Check Function Returns", Validate::checkReturnStatements, transUnit );
329 PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit );
330 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
[14c0f7b]331 PASS( "Fix Unique Ids", Validate::fixUniqueIds, transUnit );
[cf3da24]332 PASS( "Implement Corun", Concurrency::implementCorun, transUnit );
[52f9804]333 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
334
335 PASS( "Generate Autogen Routines", Validate::autogenerateRoutines, transUnit );
336
337 PASS( "Implement Actors", Concurrency::implementActors, transUnit );
338 PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors, transUnit );
339 PASS( "Implement Mutex", Concurrency::implementMutex, transUnit );
340 PASS( "Implement Thread Start", Concurrency::implementThreadStarter, transUnit );
341 PASS( "Compound Literal", Validate::handleCompoundLiterals, transUnit );
342 PASS( "Set Length From Initializer", Validate::setLengthFromInitializer, transUnit );
343 PASS( "Find Global Decls", Validate::findGlobalDecls, transUnit );
344 PASS( "Fix Label Address", Validate::fixLabelAddresses, transUnit );
[09366b8]345
346 if ( symtabp ) {
347 return EXIT_SUCCESS;
348 } // if
[ccbc65c]349
[09366b8]350 if ( expraltp ) {
351 ResolvExpr::printCandidates( transUnit );
352 return EXIT_SUCCESS;
353 } // if
[3606fe4]354
[52f9804]355 DUMP( validp, std::move( transUnit ) );
[6a896b0]356
[52f9804]357 PASS( "Translate Throws", ControlStruct::translateThrows, transUnit );
358 PASS( "Fix Labels", ControlStruct::fixLabels, transUnit );
[14c0f7b]359 PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit );
[52f9804]360 PASS( "Fix Names", CodeGen::fixNames, transUnit );
361 PASS( "Gen Init", InitTweak::genInit, transUnit );
362 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples, transUnit );
[ce36b55]363
[09366b8]364 if ( libcfap ) {
365 // Generate the bodies of cfa library functions.
366 LibCfa::makeLibCfa( transUnit );
367 } // if
[1622af5]368
[09366b8]369 if ( declstatsp ) {
370 printDeclStats( transUnit );
371 return EXIT_SUCCESS;
372 } // if
[1622af5]373
[52f9804]374 DUMP( bresolvep, std::move( transUnit ) );
[1622af5]375
[09366b8]376 if ( resolvprotop ) {
377 dumpAsResolverProto( transUnit );
378 return EXIT_SUCCESS;
379 } // if
[9f5a19fa]380
[52f9804]381 PASS( "Resolve", ResolvExpr::resolve, transUnit );
382 DUMP( exprp, std::move( transUnit ) );
[68fe946e]383
[52f9804]384 PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
[d3652df]385 PASS( "Erase With", ResolvExpr::eraseWith, transUnit );
[68fe946e]386
[09366b8]387 // fix ObjectDecl - replaces ConstructorInit nodes
[52f9804]388 DUMP( ctorinitp, std::move( transUnit ) );
[68fe946e]389
[09366b8]390 // Currently not working due to unresolved issues with UniqueExpr
[52f9804]391 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr, transUnit ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
[68fe946e]392
[52f9804]393 PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
394 PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
[61efa42]395 PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp );
[4615ac8]396
[09366b8]397 // Needs to happen before tuple types are expanded.
[52f9804]398 PASS( "Convert Specializations", GenPoly::convertSpecializations, transUnit );
[81419b5]399
[52f9804]400 PASS( "Expand Tuples", Tuples::expandTuples, transUnit );
401 DUMP( tuplep, std::move( transUnit ) );
[626dbc10]402
[09366b8]403 // Must come after Translate Tries.
[52f9804]404 PASS( "Virtual Expand Casts", Virtual::expandCasts, transUnit );
[141b786]405
[52f9804]406 PASS( "Instantiate Generics", GenPoly::instantiateGeneric, transUnit );
407 DUMP( genericsp, std::move( transUnit ) );
[b4f8808]408
[52f9804]409 PASS( "Convert L-Value", GenPoly::convertLvalue, transUnit );
[1ee0a4da]410 DUMP( bboxp, std::move( transUnit ) );
411 PASS( "Box", GenPoly::box, transUnit );
[3cbe320]412 PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit );
[7fffb1b]413
[aff7e86]414 // Code has been lowered to C, now we can start generation.
415
[8941b6b]416 DUMP( bcodegenp, std::move( transUnit ) );
[8905f56]417
[13de47bc]418 if ( optind < argc ) { // any commands after the flags and input file ? => output file name
419 output = new ofstream( argv[ optind ] );
420 } // if
[0270824]421
[8941b6b]422 PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false );
[61efa42]423 CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() );
[8941b6b]424
[e6955b1]425 if ( output != &cout ) {
[b87a5ed]426 delete output;
427 } // if
[77d601f]428 } catch ( SemanticErrorException & e ) {
[b87a5ed]429 if ( errorp ) {
[e6955b1]430 cerr << "---AST at error:---" << endl;
[0b5e780]431 dump( std::move( transUnit ), cerr );
[e6955b1]432 cerr << endl << "---End of AST, begin error message:---\n" << endl;
[926af74]433 } // if
[d55d7a6]434 e.print();
[e6955b1]435 if ( output != &cout ) {
[b87a5ed]436 delete output;
437 } // if
[3e96559]438 return EXIT_FAILURE;
[77d601f]439 } catch ( std::bad_alloc & ) {
440 cerr << "*cfa-cpp compilation error* std::bad_alloc" << endl;
441 backtrace( 1 );
442 abort();
[3e96559]443 } catch ( ... ) {
[bffcd66]444 exception_ptr eptr = current_exception();
[4990812]445 try {
446 if (eptr) {
[bffcd66]447 rethrow_exception(eptr);
[3e96559]448 } else {
[77d601f]449 cerr << "*cfa-cpp compilation error* exception uncaught and unknown" << endl;
[3e96559]450 } // if
[77d601f]451 } catch( const exception & e ) {
452 cerr << "*cfa-cpp compilation error* uncaught exception \"" << e.what() << "\"\n";
[3e96559]453 } // try
454 return EXIT_FAILURE;
455 } // try
[b87a5ed]456
[1cb7fab2]457 Stats::print();
[3e96559]458 return EXIT_SUCCESS;
[d9a0e76]459} // main
[51b73452]460
[0da3e2c]461
[372b6d3]462static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:";
[3e96559]463
[62ce290]464enum { PreludeDir = 128 };
[3e96559]465static struct option long_opts[] = {
[1a69a90]466 { "colors", required_argument, nullptr, 'c' },
467 { "gdb", no_argument, nullptr, 'g' },
[3e96559]468 { "help", no_argument, nullptr, 'h' },
[372b6d3]469 { "invariant", no_argument, nullptr, 'i' },
[3e96559]470 { "libcfa", no_argument, nullptr, 'l' },
[62ce290]471 { "linemarks", no_argument, nullptr, 'L' },
[372b6d3]472 { "no-main", no_argument, nullptr, 'm' },
[62ce290]473 { "no-linemarks", no_argument, nullptr, 'N' },
474 { "no-prelude", no_argument, nullptr, 'n' },
[3e96559]475 { "prototypes", no_argument, nullptr, 'p' },
[7215000]476 { "deterministic-out", no_argument, nullptr, 'd' },
[62ce290]477 { "print", required_argument, nullptr, 'P' },
478 { "prelude-dir", required_argument, nullptr, PreludeDir },
479 { "statistics", required_argument, nullptr, 'S' },
[3e96559]480 { "tree", no_argument, nullptr, 't' },
481 { "", no_argument, nullptr, 0 }, // -w
482 { "", no_argument, nullptr, 0 }, // -W
483 { "", no_argument, nullptr, 0 }, // -D
484 { nullptr, 0, nullptr, 0 }
485}; // long_opts
486
487static const char * description[] = {
[aa88cb9a]488 "diagnostic color: never, always, auto", // -c
[3e9de01]489 "wait for gdb to attach", // -g
[aa88cb9a]490 "print translator help message", // -h
[372b6d3]491 "invariant checking during AST passes", // -i
[3e9de01]492 "generate libcfa.c", // -l
493 "generate line marks", // -L
494 "do not replace main", // -m
495 "do not generate line marks", // -N
496 "do not read prelude", // -n
[aa88cb9a]497 "do not generate prelude prototypes => prelude not printed", // -p
[3e9de01]498 "only print deterministic output", // -d
499 "print", // -P
[62ce290]500 "<directory> prelude directory for debug/nodebug", // no flag
[aa88cb9a]501 "<option-list> enable profiling information: counters, heap, time, all, none", // -S
[3e9de01]502 "building cfa standard lib", // -t
503 "", // -w
504 "", // -W
505 "", // -D
[3e96559]506}; // description
507
[0c0f548]508static_assert( sizeof( long_opts ) / sizeof( long_opts[0] ) - 1 == sizeof( description ) / sizeof( description[0] ), "Long opts and description must match" );
[62ce290]509
510static struct Printopts {
511 const char * name;
512 int & flag;
513 int val;
514 const char * descript;
515} printopts[] = {
[0e464f6]516 { "ascodegen", codegenp, true, "print AST as codegen rather than AST" },
517 { "asterr", errorp, true, "print AST on error" },
[12f671e]518 { "declstats", declstatsp, true, "print code property statistics" },
519 { "parse", yydebug, true, "print yacc (parsing) debug information" },
[62ce290]520 { "pretty", prettycodegenp, true, "prettyprint for ascodegen flag" },
521 { "rproto", resolvprotop, true, "resolver-proto instance" },
[0e464f6]522 { "rsteps", resolvep, true, "print resolver steps" },
[5f917740]523 // AST dumps
[0e464f6]524 { "ast", astp, true, "print AST after parsing" },
[5f917740]525 { "excpdecl", exdeclp, true, "print AST after translating exception decls" },
[0e464f6]526 { "symevt", symtabp, true, "print AST after symbol table events" },
[5f917740]527 { "expralt", expraltp, true, "print AST after expressions alternatives" },
528 { "valdecl", validp, true, "print AST after declaration validation pass" },
529 { "bresolver", bresolvep, true, "print AST before resolver step" },
530 { "expranly", exprp, true, "print AST after expression analysis" },
[0e464f6]531 { "ctordtor", ctorinitp, true, "print AST after ctor/dtor are replaced" },
532 { "tuple", tuplep, true, "print AST after tuple expansion" },
[5f917740]533 { "instgen", genericsp, true, "print AST after instantiate generics" },
534 { "bbox", bboxp, true, "print AST before box pass" },
535 { "bcodegen", bcodegenp, true, "print AST before code generation" },
[62ce290]536};
537enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) };
538
[77d601f]539static void usage( char * argv[] ) {
[e0bd0f9]540 cout << "Usage: " << argv[0] << " [options] [input-file (default stdin)] [output-file (default stdout)], where options are:" << endl;
[3e96559]541 int i = 0, j = 1; // j skips starting colon
542 for ( ; long_opts[i].name != 0 && optstring[j] != '\0'; i += 1, j += 1 ) {
543 if ( long_opts[i].name[0] != '\0' ) { // hidden option, internal usage only
[62ce290]544 if ( strcmp( long_opts[i].name, "prelude-dir" ) != 0 ) { // flag
545 cout << " -" << optstring[j] << ",";
546 } else { // no flag
547 j -= 1; // compensate
548 cout << " ";
549 } // if
550 cout << " --" << left << setw(12) << long_opts[i].name << " ";
551 if ( strcmp( long_opts[i].name, "print" ) == 0 ) {
552 cout << "one of: " << endl;
553 for ( int i = 0; i < printoptsSize; i += 1 ) {
554 cout << setw(10) << " " << left << setw(10) << printopts[i].name << " " << printopts[i].descript << endl;
555 } // for
556 } else {
557 cout << description[i] << endl;
558 } // if
[3e96559]559 } // if
[62ce290]560 if ( optstring[j + 1] == ':' ) j += 1;
[3e96559]561 } // for
562 if ( long_opts[i].name != 0 || optstring[j] != '\0' ) assertf( false, "internal error, mismatch of option flags and names\n" );
563 exit( EXIT_FAILURE );
564} // usage
565
[e0bd0f9]566static void parse_cmdline( int argc, char * argv[] ) {
[0da3e2c]567 opterr = 0; // (global) prevent getopt from printing error messages
568
[c5e5109]569 bool Wsuppress = false, Werror = false;
[0da3e2c]570 int c;
[3e96559]571 while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr )) != -1 ) {
[0da3e2c]572 switch ( c ) {
[1a69a90]573 case 'c': // diagnostic colors
574 if ( strcmp( optarg, "always" ) == 0 ) {
575 ErrorHelpers::colors = ErrorHelpers::Colors::Always;
576 } else if ( strcmp( optarg, "never" ) == 0 ) {
577 ErrorHelpers::colors = ErrorHelpers::Colors::Never;
578 } else if ( strcmp( optarg, "auto" ) == 0 ) {
579 ErrorHelpers::colors = ErrorHelpers::Colors::Auto;
580 } // if
581 break;
[3e96559]582 case 'h': // help message
583 usage( argv ); // no return
[53d3ab4b]584 break;
[372b6d3]585 case 'i': // invariant checking
586 invariant = true;
587 break;
[3e96559]588 case 'l': // generate libcfa.c
[0da3e2c]589 libcfap = true;
590 break;
[62ce290]591 case 'L': // generate line marks
[6de43b6]592 linemarks = true;
[c850687]593 break;
[3e96559]594 case 'm': // do not replace main
595 nomainp = true;
[0da3e2c]596 break;
[62ce290]597 case 'N': // do not generate line marks
[6de43b6]598 linemarks = false;
[c59bde6]599 break;
[62ce290]600 case 'n': // do not read prelude
[3e96559]601 nopreludep = true;
[0da3e2c]602 break;
[62ce290]603 case 'p': // generate prototypes for prelude functions
604 genproto = true;
[0da3e2c]605 break;
[7215000]606 case 'd': // don't print non-deterministic output
[a77257be]607 deterministic_output = true;
608 break;
[62ce290]609 case 'P': // print options
610 for ( int i = 0;; i += 1 ) {
611 if ( i == printoptsSize ) {
612 cout << "Unknown --print option " << optarg << endl;
613 goto Default;
614 } // if
615 if ( strcmp( optarg, printopts[i].name ) == 0 ) {
616 printopts[i].flag = printopts[i].val;
617 break;
618 } // if
619 } // for
[0da3e2c]620 break;
[62ce290]621 case PreludeDir: // prelude directory for debug/nodebug, hidden
622 PreludeDirector = optarg;
[3b3491b6]623 break;
[3e96559]624 case 'S': // enable profiling information, argument comma separated list of names
625 Stats::parse_params( optarg );
[ebcc940]626 break;
[dee1f89]627 case 't': // building cfa stdlib
[0da3e2c]628 treep = true;
629 break;
[dee1f89]630 case 'g': // wait for gdb
631 waiting_for_gdb = true;
632 break;
[3e96559]633 case 'w': // suppress all warnings, hidden
[c5e5109]634 Wsuppress = true;
[44bca7f]635 break;
[3e96559]636 case 'W': // coordinate gcc -W with CFA, hidden
[44bca7f]637 if ( strcmp( optarg, "all" ) == 0 ) {
[68e9ace]638 SemanticWarning_EnableAll();
[44bca7f]639 } else if ( strcmp( optarg, "error" ) == 0 ) {
640 Werror = true;
641 } else {
642 char * warning = optarg;
643 Severity s;
644 if ( strncmp( optarg, "no-", 3 ) == 0 ) {
645 warning += 3;
646 s = Severity::Suppress;
647 } else {
648 s = Severity::Warn;
649 } // if
[68e9ace]650 SemanticWarning_Set( warning, s );
[44bca7f]651 } // if
652 break;
[3e96559]653 case 'D': // ignore -Dxxx, forwarded by cpp, hidden
[0da3e2c]654 break;
[3e96559]655 case '?': // unknown option
656 if ( optopt ) { // short option ?
657 cout << "Unknown option -" << (char)optopt << endl;
658 } else {
659 cout << "Unknown option " << argv[optind - 1] << endl;
660 } // if
661 goto Default;
662 case ':': // missing option
[ae47a23]663 if ( optopt ) { // short option ?
[3e96559]664 cout << "Missing option for -" << (char)optopt << endl;
[ae47a23]665 } else {
[3e96559]666 cout << "Missing option for " << argv[optind - 1] << endl;
[ae47a23]667 } // if
[3e96559]668 goto Default;
669 Default:
670 default:
671 usage( argv ); // no return
[0da3e2c]672 } // switch
673 } // while
[44bca7f]674
675 if ( Werror ) {
[68e9ace]676 SemanticWarning_WarningAsError();
[44bca7f]677 } // if
[c5e5109]678 if ( Wsuppress ) {
679 SemanticWarning_SuppressAll();
680 } // if
[44bca7f]681 // for ( const auto w : WarningFormats ) {
682 // cout << w.name << ' ' << (int)w.severity << endl;
683 // } // for
[0da3e2c]684} // parse_cmdline
685
[0b5e780]686static bool notPrelude( ast::ptr<ast::Decl> & decl ) {
687 return !decl->linkage.is_builtin;
688}
[926af74]689
[0b5e780]690static void dump( ast::TranslationUnit && unit, std::ostream & out ) {
691 // May filter out all prelude declarations.
[62ce290]692 if ( genproto ) {
[0b5e780]693 std::list<ast::ptr<ast::Decl>> decls;
694 std::copy_if( unit.decls.begin(), unit.decls.end(),
695 std::back_inserter( decls ), notPrelude );
696 decls.swap( unit.decls );
697 }
[1ab4ce2]698
[0b5e780]699 // May print as full dump or as code generation.
[e39241b]700 if ( codegenp ) {
[0b5e780]701 CodeGen::generate( unit, out, !genproto, prettycodegenp, false, false, false );
[e39241b]702 } else {
[0b5e780]703 ast::printAll( out, unit.decls );
704 }
[e499381]705}
706
[51b73452]707// Local Variables: //
[b87a5ed]708// tab-width: 4 //
709// mode: c++ //
710// compile-command: "make install" //
[51b73452]711// End: //
Note: See TracBrowser for help on using the repository browser.