source: src/main.cc @ 2261bcc

Last change on this file since 2261bcc was 1ee0a4da, checked in by Andrew Beach <ajbeach@…>, 9 months ago

Translated the box pass to the new AST. This includes direct as possible translations of the existing passes are two fix in passes which correct AST problems the direct translation causes. Outside the box pass there have already been many changes, ad there is another in Instantiate Generics, which disconnects designators instead of leaving them connected to the original polymorphic type, which breaks the invarants once the fields are removed in the Eraser sub-pass. There was also a change that was made and un-made in one commit. If translate from the new-AST to the old-AST part way you must, where possible, sort the TypeEnvKey? values by string comparison. However, it now passes over that so it would be just extra complexity and run time, so I removed it. I stand at the exit from a great woods, just shy of a year from when I entered it. It has been a difficult and tiring journey. The path has been long and at times comically winding; but most often it was invisible, hidden under an impenetrable canopy and I spend days looking for it. All for a short jog forward before getting lost again. In front of me is another woods. It looks smaller, but I can't see the other side. Anyways, time to keep walking.

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