source: src/main.cc @ 5c27b6a

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