source: src/main.cc@ 0f4c513

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