source: src/main.cc @ d18540f

ADTast-experimental
Last change on this file since d18540f was cbd1ba8, checked in by Andrew Beach <ajbeach@…>, 17 months ago

Moved parsing code out of main into the parsing directly, as an organizational improvement. The new files use the new naming convention, and should be converted to the new AST.

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