source: src/main.cpp@ 5ad6f0d

Last change on this file since 5ad6f0d was 17fa94f, checked in by Andrew Beach <ajbeach@…>, 7 months ago

Reworked some nodes so they can be typed or untyped. This allowed me to remove TranslationDeps as the type information is only needed in the candidate finder, which can easily insert it.

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