source: src/main.cc@ d0bdb18

ADT ast-experimental
Last change on this file since d0bdb18 was cbd1ba8, checked in by Andrew Beach <ajbeach@…>, 3 years 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.