For PR495:
[oota-llvm.git] / tools / llvmc / Configuration.cpp
1 //===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Reid Spencer and is distributed under the
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the parsing of configuration files for the LLVM Compiler
11 // Driver (llvmc).
12 //
13 //===------------------------------------------------------------------------===
14
15 #include "Configuration.h"
16 #include "ConfigLexer.h"
17 #include "CompilerDriver.h"
18 #include "llvm/Config/config.h"
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include <iostream>
22 #include <fstream>
23
24 using namespace llvm;
25
26 namespace sys {
27   // From CompilerDriver.cpp (for now)
28   extern bool FileIsReadable(const std::string& fname);
29 }
30
31 namespace llvm {
32   ConfigLexerInfo ConfigLexerState;
33   InputProvider* ConfigLexerInput = 0;
34
35   InputProvider::~InputProvider() {}
36   void InputProvider::error(const std::string& msg) {
37     std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " <<
38       msg << "\n";
39     errCount++;
40   }
41
42   void InputProvider::checkErrors() {
43     if (errCount > 0) {
44       std::cerr << name << " had " << errCount << " errors. Terminating.\n";
45       exit(errCount);
46     }
47   }
48
49 }
50
51 namespace {
52
53   class FileInputProvider : public InputProvider {
54     public:
55       FileInputProvider(const std::string & fname)
56         : InputProvider(fname)
57         , F(fname.c_str()) {
58         ConfigLexerInput = this;
59       }
60       virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
61       virtual unsigned read(char *buffer, unsigned max_size) {
62         if (F.good()) {
63           F.read(buffer,max_size);
64           if ( F.gcount() ) return F.gcount() - 1;
65         }
66         return 0;
67       }
68
69       bool okay() { return F.good(); }
70     private:
71       std::ifstream F;
72   };
73
74   cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden,
75     cl::init(false), cl::desc("Dump lexical tokens (debug use only)."));
76
77   struct Parser
78   {
79     Parser() {
80       token = EOFTOK;
81       provider = 0;
82       confDat = 0;
83       ConfigLexerState.lineNum = 1;
84       ConfigLexerState.in_value = false;
85       ConfigLexerState.StringVal.clear();
86       ConfigLexerState.IntegerVal = 0;
87     };
88
89     ConfigLexerTokens token;
90     InputProvider* provider;
91     CompilerDriver::ConfigData* confDat;
92
93     inline int next() {
94       token = Configlex();
95       if (DumpTokens)
96         std::cerr << token << "\n";
97       return token;
98     }
99
100     inline bool next_is_real() {
101       next();
102       return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
103     }
104
105     inline void eatLineRemnant() {
106       while (next_is_real()) ;
107     }
108
109     void error(const std::string& msg, bool skip = true) {
110       provider->error(msg);
111       if (skip)
112         eatLineRemnant();
113     }
114
115     bool parseCompleteItem(std::string& result) {
116       result.clear();
117       while (next_is_real()) {
118         switch (token ) {
119           case STRING :
120           case OPTION :
121             result += ConfigLexerState.StringVal;
122             break;
123           case SEPARATOR:
124             result += ".";
125             break;
126           case SPACE:
127             return true;
128           default:
129             return false;
130         }
131       }
132       return false;
133     }
134
135     std::string parseName() {
136       std::string result;
137       if (next() == EQUALS) {
138         if (parseCompleteItem(result))
139           eatLineRemnant();
140         if (result.empty())
141           error("Name exepected");
142       } else
143         error("Expecting '='");
144       return result;
145     }
146
147     bool parseBoolean() {
148       bool result = true;
149       if (next() == EQUALS) {
150         if (next() == SPACE)
151           next();
152         if (token == FALSETOK) {
153           result = false;
154         } else if (token != TRUETOK) {
155           error("Expecting boolean value");
156           return false;
157         }
158         if (next() != EOLTOK && token != 0) {
159           error("Extraneous tokens after boolean");
160         }
161       }
162       else
163         error("Expecting '='");
164       return result;
165     }
166
167     bool parseSubstitution(CompilerDriver::StringVector& optList) {
168       switch (token) {
169         case ARGS_SUBST:        optList.push_back("%args%"); break;
170         case BINDIR_SUBST:      optList.push_back("%bindir%"); break;
171         case DEFS_SUBST:        optList.push_back("%defs%"); break;
172         case IN_SUBST:          optList.push_back("%in%"); break;
173         case INCLS_SUBST:       optList.push_back("%incls%"); break;
174         case LIBDIR_SUBST:      optList.push_back("%libdir%"); break;
175         case LIBS_SUBST:        optList.push_back("%libs%"); break;
176         case OPT_SUBST:         optList.push_back("%opt%"); break;
177         case OUT_SUBST:         optList.push_back("%out%"); break;
178         case TARGET_SUBST:      optList.push_back("%target%"); break;
179         case STATS_SUBST:       optList.push_back("%stats%"); break;
180         case TIME_SUBST:        optList.push_back("%time%"); break;
181         case VERBOSE_SUBST:     optList.push_back("%verbose%"); break;
182         case FOPTS_SUBST:       optList.push_back("%fOpts%"); break;
183         case MOPTS_SUBST:       optList.push_back("%Mopts%"); break;
184         case WOPTS_SUBST:       optList.push_back("%Wopts%"); break;
185         default:
186           return false;
187       }
188       return true;
189     }
190
191     void parseOptionList(CompilerDriver::StringVector& optList ) {
192       if (next() == EQUALS) {
193         while (next_is_real()) {
194           if (token == STRING || token == OPTION)
195             optList.push_back(ConfigLexerState.StringVal);
196           else if (!parseSubstitution(optList)) {
197             error("Expecting a program argument or substitution", false);
198             break;
199           }
200         }
201       } else
202         error("Expecting '='");
203     }
204
205     void parseVersion() {
206       if (next() != EQUALS)
207         error("Expecting '='");
208       while (next_is_real()) {
209         if (token == STRING || token == OPTION)
210           confDat->version = ConfigLexerState.StringVal;
211         else
212           error("Expecting a version string");
213       }
214     }
215
216     void parseLibs() {
217       if (next() != EQUALS)
218         error("Expecting '='");
219       std::string lib;
220       while (parseCompleteItem(lib)) {
221         if (!lib.empty()) {
222           confDat->libpaths.push_back(lib);
223         }
224       }
225     }
226
227     void parseLang() {
228       if (next() != SEPARATOR)
229         error("Expecting '.'");
230       switch (next() ) {
231         case LIBS:
232           parseLibs();
233           break;
234         case NAME:
235           confDat->langName = parseName();
236           break;
237         case OPT1:
238           parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
239           break;
240         case OPT2:
241           parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
242           break;
243         case OPT3:
244           parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
245           break;
246         case OPT4:
247           parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
248           break;
249         case OPT5:
250           parseOptionList(
251             confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
252           break;
253         default:
254           error("Expecting 'name' or 'optN' after 'lang.'");
255           break;
256       }
257     }
258
259     bool parseProgramName(std::string& str) {
260       str.clear();
261       do {
262         switch (token) {
263           case OPTION:
264           case STRING:
265           case ARGS_SUBST:
266           case DEFS_SUBST:
267           case IN_SUBST:
268           case INCLS_SUBST:
269           case LIBS_SUBST:
270           case OPT_SUBST:
271           case OUT_SUBST:
272           case STATS_SUBST:
273           case TARGET_SUBST:
274           case TIME_SUBST:
275           case VERBOSE_SUBST:
276           case FOPTS_SUBST:
277           case MOPTS_SUBST:
278           case WOPTS_SUBST:
279             str += ConfigLexerState.StringVal;
280             break;
281           case SEPARATOR:
282             str += ".";
283             break;
284           case ASSEMBLY:
285             str += "assembly";
286             break;
287           case BYTECODE:
288             str += "bytecode";
289             break;
290           case TRUETOK:
291             str += "true";
292             break;
293           case FALSETOK:
294             str += "false";
295             break;
296           default:
297             break;
298         }
299         next();
300       } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
301                token != ERRORTOK);
302       return !str.empty();
303     }
304
305     void parseCommand(CompilerDriver::Action& action) {
306       if (next() != EQUALS)
307         error("Expecting '='");
308       switch (next()) {
309         case EOLTOK:
310           // no value (valid)
311           action.program.clear();
312           action.args.clear();
313           break;
314         case SPACE:
315           next();
316           /* FALL THROUGH */
317         default:
318         {
319           std::string progname;
320           if (parseProgramName(progname))
321             action.program.set(progname);
322           else
323             error("Expecting a program name");
324
325           // Get the options
326           std::string anOption;
327           while (next_is_real()) {
328             switch (token) {
329               case STRING:
330               case OPTION:
331                 anOption += ConfigLexerState.StringVal;
332                 break;
333               case ASSEMBLY:
334                 anOption += "assembly";
335                 break;
336               case BYTECODE:
337                 anOption += "bytecode";
338                 break;
339               case TRUETOK:
340                 anOption += "true";
341                 break;
342               case FALSETOK:
343                 anOption += "false";
344                 break;
345               case SEPARATOR:
346                 anOption += ".";
347                 break;
348               case SPACE:
349                 action.args.push_back(anOption);
350                 anOption.clear();
351                 break;
352               default:
353                 if (!parseSubstitution(action.args))
354                   error("Expecting a program argument or substitution", false);
355                 break;
356             }
357           }
358         }
359       }
360     }
361
362     void parsePreprocessor() {
363       if (next() != SEPARATOR)
364         error("Expecting '.'");
365       switch (next()) {
366         case COMMAND:
367           parseCommand(confDat->PreProcessor);
368           break;
369         case REQUIRED:
370           if (parseBoolean())
371             confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
372           else
373             confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
374           break;
375         default:
376           error("Expecting 'command' or 'required' but found '" +
377               ConfigLexerState.StringVal);
378           break;
379       }
380     }
381
382     bool parseOutputFlag() {
383       if (next() == EQUALS) {
384         if (next() == SPACE)
385           next();
386         if (token == ASSEMBLY) {
387           return true;
388         } else if (token == BYTECODE) {
389           return false;
390         } else {
391           error("Expecting output type value");
392           return false;
393         }
394         if (next() != EOLTOK && token != 0) {
395           error("Extraneous tokens after output value");
396         }
397       }
398       else
399         error("Expecting '='");
400       return false;
401     }
402
403     void parseTranslator() {
404       if (next() != SEPARATOR)
405         error("Expecting '.'");
406       switch (next()) {
407         case COMMAND:
408           parseCommand(confDat->Translator);
409           break;
410         case REQUIRED:
411           if (parseBoolean())
412             confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
413           else
414             confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
415           break;
416         case PREPROCESSES:
417           if (parseBoolean())
418             confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
419           else
420             confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
421           break;
422         case OUTPUT:
423           if (parseOutputFlag())
424             confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
425           else
426             confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
427           break;
428
429         default:
430           error("Expecting 'command', 'required', 'preprocesses', or "
431                 "'output' but found '" + ConfigLexerState.StringVal +
432                 "' instead");
433           break;
434       }
435     }
436
437     void parseOptimizer() {
438       if (next() != SEPARATOR)
439         error("Expecting '.'");
440       switch (next()) {
441         case COMMAND:
442           parseCommand(confDat->Optimizer);
443           break;
444         case PREPROCESSES:
445           if (parseBoolean())
446             confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
447           else
448             confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
449           break;
450         case TRANSLATES:
451           if (parseBoolean())
452             confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
453           else
454             confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
455           break;
456         case REQUIRED:
457           if (parseBoolean())
458             confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
459           else
460             confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
461           break;
462         case OUTPUT:
463           if (parseOutputFlag())
464             confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
465           else
466             confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
467           break;
468         default:
469           error(std::string("Expecting 'command', 'preprocesses', "
470               "'translates' or 'output' but found '") +
471               ConfigLexerState.StringVal + "' instead");
472           break;
473       }
474     }
475
476     void parseAssembler() {
477       if (next() != SEPARATOR)
478         error("Expecting '.'");
479       switch(next()) {
480         case COMMAND:
481           parseCommand(confDat->Assembler);
482           break;
483         default:
484           error("Expecting 'command'");
485           break;
486       }
487     }
488
489     void parseLinker() {
490       if (next() != SEPARATOR)
491         error("Expecting '.'");
492       switch(next()) {
493         case LIBS:
494           break; //FIXME
495         case LIBPATHS:
496           break; //FIXME
497         default:
498           error("Expecting 'libs' or 'libpaths'");
499           break;
500       }
501     }
502
503     void parseAssignment() {
504       switch (token) {
505         case VERSION_TOK:   parseVersion(); break;
506         case LANG:          parseLang(); break;
507         case PREPROCESSOR:  parsePreprocessor(); break;
508         case TRANSLATOR:    parseTranslator(); break;
509         case OPTIMIZER:     parseOptimizer(); break;
510         case ASSEMBLER:     parseAssembler(); break;
511         case LINKER:        parseLinker(); break;
512         case EOLTOK:        break; // just ignore
513         case ERRORTOK:
514         default:
515           error("Invalid top level configuration item");
516           break;
517       }
518     }
519
520     void parseFile() {
521       while ( next() != EOFTOK ) {
522         if (token == ERRORTOK)
523           error("Invalid token");
524         else if (token != EOLTOK)
525           parseAssignment();
526       }
527       provider->checkErrors();
528     }
529   };
530
531 void
532 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
533   Parser p;
534   p.token = EOFTOK;
535   p.provider = &provider;
536   p.confDat = &confDat;
537   p.parseFile();
538   }
539
540 }
541
542 CompilerDriver::ConfigData*
543 LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
544   CompilerDriver::ConfigData* result = 0;
545   sys::Path confFile;
546   if (configDir.isEmpty()) {
547     // Try the environment variable
548     const char* conf = getenv("LLVM_CONFIG_DIR");
549     if (conf) {
550       confFile.set(conf);
551       confFile.appendComponent(ftype);
552       if (!confFile.canRead())
553         throw std::string("Configuration file for '") + ftype +
554                           "' is not available.";
555     } else {
556       // Try the user's home directory
557       confFile = sys::Path::GetUserHomeDirectory();
558       if (!confFile.isEmpty()) {
559         confFile.appendComponent(".llvm");
560         confFile.appendComponent("etc");
561         confFile.appendComponent(ftype);
562         if (!confFile.canRead())
563           confFile.clear();
564       }
565       if (confFile.isEmpty()) {
566         // Okay, try the LLVM installation directory
567         confFile = sys::Path::GetLLVMConfigDir();
568         confFile.appendComponent(ftype);
569         if (!confFile.canRead()) {
570           // Okay, try the "standard" place
571           confFile = sys::Path::GetLLVMDefaultConfigDir();
572           confFile.appendComponent(ftype);
573           if (!confFile.canRead()) {
574             throw std::string("Configuration file for '") + ftype +
575                               "' is not available.";
576           }
577         }
578       }
579     }
580   } else {
581     confFile = configDir;
582     confFile.appendComponent(ftype);
583     if (!confFile.canRead())
584       throw std::string("Configuration file for '") + ftype +
585                         "' is not available.";
586   }
587   FileInputProvider fip( confFile.toString() );
588   if (!fip.okay()) {
589     throw std::string("Configuration file for '") + ftype +
590                       "' is not available.";
591   }
592   result = new CompilerDriver::ConfigData();
593   ParseConfigData(fip,*result);
594   return result;
595 }
596
597 LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
598 {
599   ConfigDataMap::iterator cIt = Configurations.begin();
600   while (cIt != Configurations.end()) {
601     CompilerDriver::ConfigData* cd = cIt->second;
602     ++cIt;
603     delete cd;
604   }
605   Configurations.clear();
606 }
607
608 CompilerDriver::ConfigData*
609 LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
610   CompilerDriver::ConfigData* result = 0;
611   if (!Configurations.empty()) {
612     ConfigDataMap::iterator cIt = Configurations.find(filetype);
613     if ( cIt != Configurations.end() ) {
614       // We found one in the case, return it.
615       result = cIt->second;
616     }
617   }
618   if (result == 0) {
619     // The configuration data doesn't exist, we have to go read it.
620     result = ReadConfigData(filetype);
621     // If we got one, cache it
622     if (result != 0)
623       Configurations.insert(std::make_pair(filetype,result));
624   }
625   return result; // Might return 0
626 }