source: src/main.cpp @ 62b5940

Last change on this file since 62b5940 was 17fa94f, checked in by Andrew Beach <ajbeach@…>, 7 weeks 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.