source: src/main.cc @ 37b3151

Last change on this file since 37b3151 was 37b3151, checked in by Andrew Beach <ajbeach@…>, 5 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
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.cc --
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 : Wed Nov  1 21:12:58 2023
13// Update Count     : 690
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.h"
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
40#include "CodeGen/LinkOnce.h"               // 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.h"                   // for Stats
45#include "Common/utility.h"                 // for deleteAll, filter, printAll
46#include "Concurrency/Actors.hpp"           // for implementActors
47#include "Concurrency/Corun.hpp"            // for implementCorun
48#include "Concurrency/Keywords.h"           // for implementMutex, implement...
49#include "Concurrency/Waitfor.h"            // for generateWaitfor
50#include "Concurrency/Waituntil.hpp"        // for generateWaitUntil
51#include "ControlStruct/ExceptDecl.h"       // for translateExcept
52#include "ControlStruct/ExceptTranslate.h"  // for translateThrows, translat...
53#include "ControlStruct/FixLabels.hpp"      // for fixLabels
54#include "ControlStruct/HoistControlDecls.hpp" //  hoistControlDecls
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
62#include "Parser/RunParser.hpp"             // for buildList, dumpParseTree,...
63#include "ResolvExpr/CandidatePrinter.hpp"  // for printCandidates
64#include "ResolvExpr/EraseWith.hpp"         // for eraseWith
65#include "ResolvExpr/Resolver.h"            // for resolve
66#include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
67#include "Validate/Autogen.hpp"             // for autogenerateRoutines
68#include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
69#include "Validate/EliminateTypedef.hpp"    // for eliminateTypedef
70#include "Validate/EnumAndPointerDecay.hpp" // for decayEnumsAndPointers
71#include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
72#include "Validate/FixQualifiedTypes.hpp"   // for fixQualifiedTypes
73#include "Validate/FixReturnTypes.hpp"      // for fixReturnTypes
74#include "Validate/ForallPointerDecay.hpp"  // for decayForallPointers
75#include "Validate/GenericParameter.hpp"    // for fillGenericParameters, tr...
76#include "Validate/HoistStruct.hpp"         // for hoistStruct
77#include "Validate/HoistTypeDecls.hpp"      // for hoistTypeDecls
78#include "Validate/InitializerLength.hpp"   // for setLengthFromInitializer
79#include "Validate/LabelAddressFixer.hpp"   // for fixLabelAddresses
80#include "Validate/LinkInstanceTypes.hpp"   // for linkInstanceTypes
81#include "Validate/ReplaceTypedef.hpp"      // for replaceTypedef
82#include "Validate/ReturnCheck.hpp"         // for checkReturnStatements
83#include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign
84#include "Virtual/ExpandCasts.h"            // for expandCasts
85#include "Virtual/VirtualDtor.hpp"          // for implementVirtDtors
86
87using namespace std;
88
89static void NewPass( const char * const name ) {
90        Stats::Heap::newPass( name );
91        using namespace Stats::Counters;
92        {
93                static auto group = build<CounterGroup>( "Pass Visitor Template" );
94                auto pass = build<CounterGroup>( name, group );
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 );
98        }
99}
100
101// Helpers for checkInvariant:
102void checkInvariants( std::list< Declaration * > & ) {}
103using ast::checkInvariants;
104
105#define PASS( name, pass, unit, ... )       \
106        if ( errorp ) { cerr << name << endl; } \
107        NewPass(name);                          \
108        Stats::Time::StartBlock(name);          \
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        }
120
121static bool waiting_for_gdb = false;                                    // flag to set cfa-cpp to wait for gdb on start
122
123static string PreludeDirector = "";
124
125static void parse_cmdline( int argc, char * argv[] );
126static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );
127
128static void backtrace( int start ) {                                    // skip first N stack frames
129        enum { Frames = 50, };                                                          // maximum number of stack frames
130        void * array[Frames];
131        size_t size = ::backtrace( array, Frames );
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;
136
137        // skip last 2 stack frames after main
138        for ( unsigned int i = start; i < size - 2 && messages != nullptr; i += 1 ) {
139                char * mangled_name = nullptr, * offset_begin = nullptr, * offset_end = nullptr;
140
141                for ( char * p = messages[i]; *p; p += 1 ) {    // find parantheses and +offset
142                        if ( *p == '(' ) {
143                                mangled_name = p;
144                        } else if ( *p == '+' ) {
145                                offset_begin = p;
146                        } else if ( *p == ')' ) {
147                                offset_end = p;
148                                break;
149                        } // if
150                } // for
151
152                // if line contains symbol, attempt to demangle
153                int frameNo = i - start;
154                if ( mangled_name && offset_begin && offset_end && mangled_name < offset_begin ) {
155                        *mangled_name++ = '\0';                                         // delimit strings
156                        *offset_begin++ = '\0';
157                        *offset_end++ = '\0';
158
159                        int status;
160                        char * real_name = __cxxabiv1::__cxa_demangle( mangled_name, 0, 0, &status );
161                        // bug in __cxa_demangle for single-character lower-case non-mangled names
162                        if ( status == 0 ) {                                            // demangling successful ?
163                                cerr << "(" << frameNo << ") " << messages[i] << " : "
164                                         << real_name << "+" << offset_begin << offset_end << endl;
165                        } else {                                                                        // otherwise, output mangled name
166                                cerr << "(" << frameNo << ") " << messages[i] << " : "
167                                         << mangled_name << "(/*unknown*/)+" << offset_begin << offset_end << endl;
168                        } // if
169
170                        free( real_name );
171                } else {                                                                                // otherwise, print the whole line
172                        cerr << "(" << frameNo << ") " << messages[i] << endl;
173                } // if
174        } // for
175
176        free( messages );
177} // backtrace
178
179#define SIGPARMS int sig __attribute__(( unused )), siginfo_t * sfp __attribute__(( unused )), ucontext_t * cxt __attribute__(( unused ))
180
181static void _Signal(struct sigaction & act, int sig, int flags ) {
182        act.sa_flags = flags;
183
184        if ( sigaction( sig, &act, nullptr ) == -1 ) {
185            cerr << "*cfa-cpp compilation error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;
186            _exit( EXIT_FAILURE );
187        } // if
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);
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
209        backtrace( 2 );                                                                         // skip first 2 stack frames
210        abort();                                                                                        // cause core dump for debugging
211} // sigSegvBusHandler
212
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
230static void sigAbortHandler( SIGPARMS ) {
231        backtrace( 6 );                                                                         // skip first 6 stack frames
232        Signal( SIGABRT, SIG_DFL, SA_SIGINFO ); // reset default signal handler
233        raise( SIGABRT );                                                                       // reraise SIGABRT
234} // sigAbortHandler
235
236int main( int argc, char * argv[] ) {
237        FILE * input;                                                                           // use FILE rather than istream because yyin is FILE
238        ostream * output = & cout;
239        ast::TranslationUnit transUnit;
240
241        Signal( SIGSEGV, sigSegvBusHandler, SA_SIGINFO );
242        Signal( SIGBUS, sigSegvBusHandler, SA_SIGINFO );
243        Signal( SIGFPE, sigFpeHandler, SA_SIGINFO );
244        Signal( SIGABRT, sigAbortHandler, SA_SIGINFO );
245
246        // cout << "main" << endl;
247        // for ( int i = 0; i < argc; i += 1 ) {
248        //      cout << '\t' << argv[i] << endl;
249        // } // for
250
251        parse_cmdline( argc, argv );                                            // process command-line arguments
252
253        if ( waiting_for_gdb ) {
254                cerr << "Waiting for gdb" << endl;
255                cerr << "run :" << endl;
256                cerr << "  gdb attach " << getpid() << endl;
257                raise(SIGSTOP);
258        } // if
259
260        try {
261                // choose to read the program from a file or stdin
262                if ( optind < argc ) {                                                  // any commands after the flags ? => input file name
263                        input = fopen( argv[ optind ], "r" );
264                        assertf( input, "cannot open %s because %s\n", argv[ optind ], strerror( errno ) );
265                        optind += 1;
266                } else {                                                                                // no input file name
267                        input = stdin;
268                } // if
269
270                Stats::Time::StartGlobal();
271                NewPass("Parse");
272                Stats::Time::StartBlock("Parse");
273
274                // read in the builtins, extras, and the prelude
275                if ( ! nopreludep ) {                                                   // include gcc builtins
276                        // -l is for initial build ONLY and builtins.cf is not in the lib directory so access it here.
277
278                        assertf( !PreludeDirector.empty(), "Can't find prelude without option --prelude-dir must be used." );
279
280                        // Read to gcc builtins, if not generating the cfa library
281                        FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cfa").c_str(), "r" );
282                        assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
283                        parse( gcc_builtins, ast::Linkage::Compiler );
284
285                        // read the extra prelude in, if not generating the cfa library
286                        FILE * extras = fopen( (PreludeDirector + "/extras.cfa").c_str(), "r" );
287                        assertf( extras, "cannot open extras.cf\n" );
288                        parse( extras, ast::Linkage::BuiltinC );
289
290                        if ( ! libcfap ) {
291                                // read the prelude in, if not generating the cfa library
292                                FILE * prelude = fopen( (PreludeDirector + "/prelude.cfa").c_str(), "r" );
293                                assertf( prelude, "cannot open prelude.cfa\n" );
294                                parse( prelude, ast::Linkage::Intrinsic );
295
296                                // Read to cfa builtins, if not generating the cfa library
297                                FILE * builtins = fopen( (PreludeDirector + "/builtins.cfa").c_str(), "r" );
298                                assertf( builtins, "cannot open builtins.cf\n" );
299                                parse( builtins, ast::Linkage::BuiltinCFA );
300                        } // if
301                } // if
302
303                parse( input, libcfap ? ast::Linkage::Intrinsic : ast::Linkage::Cforall, yydebug );
304
305                transUnit = buildUnit();
306
307                DUMP( astp, std::move( transUnit ) );
308
309                Stats::Time::StopBlock();
310
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
320                PASS( "Link Instance Types", Validate::linkInstanceTypes, transUnit );
321
322                PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
323                PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
324                PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
325                PASS( "Hoist Struct", Validate::hoistStruct, transUnit );
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 );
331                PASS( "Fix Unique Ids", Validate::fixUniqueIds, transUnit );
332                PASS( "Implement Corun", Concurrency::implementCorun, transUnit );
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 );
345
346                if ( symtabp ) {
347                        return EXIT_SUCCESS;
348                } // if
349
350                if ( expraltp ) {
351                        ResolvExpr::printCandidates( transUnit );
352                        return EXIT_SUCCESS;
353                } // if
354
355                DUMP( validp, std::move( transUnit ) );
356
357                PASS( "Translate Throws", ControlStruct::translateThrows, transUnit );
358                PASS( "Fix Labels", ControlStruct::fixLabels, transUnit );
359                PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
360                PASS( "Fix Names", CodeGen::fixNames, transUnit );
361                PASS( "Gen Init", InitTweak::genInit, transUnit );
362                PASS( "Expand Member Tuples" , Tuples::expandMemberTuples, transUnit );
363
364                if ( libcfap ) {
365                        // Generate the bodies of cfa library functions.
366                        LibCfa::makeLibCfa( transUnit );
367                } // if
368
369                if ( declstatsp ) {
370                        printDeclStats( transUnit );
371                        return EXIT_SUCCESS;
372                } // if
373
374                DUMP( bresolvep, std::move( transUnit ) );
375
376                if ( resolvprotop ) {
377                        dumpAsResolverProto( transUnit );
378                        return EXIT_SUCCESS;
379                } // if
380
381                PASS( "Resolve", ResolvExpr::resolve, transUnit );
382                DUMP( exprp, std::move( transUnit ) );
383
384                PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
385                PASS( "Erase With", ResolvExpr::eraseWith, transUnit );
386
387                // fix ObjectDecl - replaces ConstructorInit nodes
388                DUMP( ctorinitp, std::move( transUnit ) );
389
390                // Currently not working due to unresolved issues with UniqueExpr
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
392
393                PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
394                PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
395                PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp );
396
397                // Needs to happen before tuple types are expanded.
398                PASS( "Convert Specializations",  GenPoly::convertSpecializations, transUnit );
399
400                PASS( "Expand Tuples", Tuples::expandTuples, transUnit );
401                DUMP( tuplep, std::move( transUnit ) );
402
403                // Must come after Translate Tries.
404                PASS( "Virtual Expand Casts", Virtual::expandCasts, transUnit );
405
406                PASS( "Instantiate Generics", GenPoly::instantiateGeneric, transUnit );
407                DUMP( genericsp, std::move( transUnit ) );
408
409                PASS( "Convert L-Value", GenPoly::convertLvalue, transUnit );
410                DUMP( bboxp, std::move( transUnit ) );
411                PASS( "Box", GenPoly::box, transUnit );
412                PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit );
413
414                // Code has been lowered to C, now we can start generation.
415
416                DUMP( bcodegenp, std::move( transUnit ) );
417
418                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
419                        output = new ofstream( argv[ optind ] );
420                } // if
421
422                PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false );
423                CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() );
424
425                if ( output != &cout ) {
426                        delete output;
427                } // if
428        } catch ( SemanticErrorException & e ) {
429                if ( errorp ) {
430                        cerr << "---AST at error:---" << endl;
431                        dump( std::move( transUnit ), cerr );
432                        cerr << endl << "---End of AST, begin error message:---\n" << endl;
433                } // if
434                e.print();
435                if ( output != &cout ) {
436                        delete output;
437                } // if
438                return EXIT_FAILURE;
439        } catch ( std::bad_alloc & ) {
440                cerr << "*cfa-cpp compilation error* std::bad_alloc" << endl;
441                backtrace( 1 );
442                abort();
443        } catch ( ... ) {
444                exception_ptr eptr = current_exception();
445                try {
446                        if (eptr) {
447                                rethrow_exception(eptr);
448                        } else {
449                                cerr << "*cfa-cpp compilation error* exception uncaught and unknown" << endl;
450                        } // if
451                } catch( const exception & e ) {
452                        cerr << "*cfa-cpp compilation error* uncaught exception \"" << e.what() << "\"\n";
453                } // try
454                return EXIT_FAILURE;
455        } // try
456
457        Stats::print();
458        return EXIT_SUCCESS;
459} // main
460
461
462static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:";
463
464enum { PreludeDir = 128 };
465static struct option long_opts[] = {
466        { "colors", required_argument, nullptr, 'c' },
467        { "gdb", no_argument, nullptr, 'g' },
468        { "help", no_argument, nullptr, 'h' },
469        { "invariant", no_argument, nullptr, 'i' },
470        { "libcfa", no_argument, nullptr, 'l' },
471        { "linemarks", no_argument, nullptr, 'L' },
472        { "no-main", no_argument, nullptr, 'm' },
473        { "no-linemarks", no_argument, nullptr, 'N' },
474        { "no-prelude", no_argument, nullptr, 'n' },
475        { "prototypes", no_argument, nullptr, 'p' },
476        { "deterministic-out", no_argument, nullptr, 'd' },
477        { "print", required_argument, nullptr, 'P' },
478        { "prelude-dir", required_argument, nullptr, PreludeDir },
479        { "statistics", required_argument, nullptr, 'S' },
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[] = {
488        "diagnostic color: never, always, auto",                        // -c
489        "wait for gdb to attach",                                                       // -g
490        "print translator help message",                                        // -h
491        "invariant checking during AST passes",                         // -i
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
497        "do not generate prelude prototypes => prelude not printed", // -p
498        "only print deterministic output",                  // -d
499        "print",                                                                                        // -P
500        "<directory> prelude directory for debug/nodebug",      // no flag
501        "<option-list> enable profiling information: counters, heap, time, all, none", // -S
502        "building cfa standard lib",                                            // -t
503        "",                                                                                                     // -w
504        "",                                                                                                     // -W
505        "",                                                                                                     // -D
506}; // description
507
508static_assert( sizeof( long_opts ) / sizeof( long_opts[0] ) - 1 == sizeof( description ) / sizeof( description[0] ), "Long opts and description must match" );
509
510static struct Printopts {
511        const char * name;
512        int & flag;
513        int val;
514        const char * descript;
515} printopts[] = {
516        { "ascodegen", codegenp, true, "print AST as codegen rather than AST" },
517        { "asterr", errorp, true, "print AST on error" },
518        { "declstats", declstatsp, true, "print code property statistics" },
519        { "parse", yydebug, true, "print yacc (parsing) debug information" },
520        { "pretty", prettycodegenp, true, "prettyprint for ascodegen flag" },
521        { "rproto", resolvprotop, true, "resolver-proto instance" },
522        { "rsteps", resolvep, true, "print resolver steps" },
523        // AST dumps
524        { "ast", astp, true, "print AST after parsing" },
525        { "excpdecl", exdeclp, true, "print AST after translating exception decls" },
526        { "symevt", symtabp, true, "print AST after symbol table events" },
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" },
531        { "ctordtor", ctorinitp, true, "print AST after ctor/dtor are replaced" },
532        { "tuple", tuplep, true, "print AST after tuple expansion" },
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" },
536};
537enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) };
538
539static void usage( char * argv[] ) {
540    cout << "Usage: " << argv[0] << " [options] [input-file (default stdin)] [output-file (default stdout)], where options are:" << endl;
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
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
559                } // if
560                if ( optstring[j + 1] == ':' ) j += 1;
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
566static void parse_cmdline( int argc, char * argv[] ) {
567        opterr = 0;                                                                                     // (global) prevent getopt from printing error messages
568
569        bool Wsuppress = false, Werror = false;
570        int c;
571        while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr )) != -1 ) {
572                switch ( c ) {
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;
582                  case 'h':                                                                             // help message
583                        usage( argv );                                                          // no return
584                        break;
585                  case 'i':                                                                             // invariant checking
586                        invariant = true;
587                        break;
588                  case 'l':                                                                             // generate libcfa.c
589                        libcfap = true;
590                        break;
591                  case 'L':                                                                             // generate line marks
592                        linemarks = true;
593                        break;
594                  case 'm':                                                                             // do not replace main
595                        nomainp = true;
596                        break;
597                  case 'N':                                                                             // do not generate line marks
598                        linemarks = false;
599                        break;
600                  case 'n':                                                                             // do not read prelude
601                        nopreludep = true;
602                        break;
603                  case 'p':                                                                             // generate prototypes for prelude functions
604                        genproto = true;
605                        break;
606                  case 'd':                                     // don't print non-deterministic output
607                        deterministic_output = true;
608                        break;
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
620                        break;
621                  case PreludeDir:                                                              // prelude directory for debug/nodebug, hidden
622                        PreludeDirector = optarg;
623                        break;
624                  case 'S':                                                                             // enable profiling information, argument comma separated list of names
625                        Stats::parse_params( optarg );
626                        break;
627                  case 't':                                                                             // building cfa stdlib
628                        treep = true;
629                        break;
630                  case 'g':                                                                             // wait for gdb
631                        waiting_for_gdb = true;
632                        break;
633                  case 'w':                                                                             // suppress all warnings, hidden
634                        Wsuppress = true;
635                        break;
636                  case 'W':                                                                             // coordinate gcc -W with CFA, hidden
637                        if ( strcmp( optarg, "all" ) == 0 ) {
638                                SemanticWarning_EnableAll();
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
650                                SemanticWarning_Set( warning, s );
651                        } // if
652                        break;
653                  case 'D':                                                                             // ignore -Dxxx, forwarded by cpp, hidden
654                        break;
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
663                        if ( optopt ) {                                                         // short option ?
664                                cout << "Missing option for -" << (char)optopt << endl;
665                        } else {
666                                cout << "Missing option for " << argv[optind - 1] << endl;
667                        } // if
668                        goto Default;
669                  Default:
670                  default:
671                        usage( argv );                                                          // no return
672                } // switch
673        } // while
674
675        if ( Werror ) {
676                SemanticWarning_WarningAsError();
677        } // if
678        if ( Wsuppress ) {
679                SemanticWarning_SuppressAll();
680        } // if
681        // for ( const auto w : WarningFormats ) {
682        //      cout << w.name << ' ' << (int)w.severity << endl;
683        // } // for
684} // parse_cmdline
685
686static bool notPrelude( ast::ptr<ast::Decl> & decl ) {
687        return !decl->linkage.is_builtin;
688}
689
690static void dump( ast::TranslationUnit && unit, std::ostream & out ) {
691        // May filter out all prelude declarations.
692        if ( genproto ) {
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        }
698
699        // May print as full dump or as code generation.
700        if ( codegenp ) {
701                CodeGen::generate( unit, out, !genproto, prettycodegenp, false, false, false );
702        } else {
703                ast::printAll( out, unit.decls );
704        }
705}
706
707// Local Variables: //
708// tab-width: 4 //
709// mode: c++ //
710// compile-command: "make install" //
711// End:  //
Note: See TracBrowser for help on using the repository browser.