push bytecode decompressor out through APIs. Now the bytecode reader
[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 LLVMGCCDIR_SUBST:
120         case LLVMGCCARCH_SUBST:
121           case STRING :
122           case OPTION :
123             result += ConfigLexerState.StringVal;
124             break;
125           case SEPARATOR:
126             result += ".";
127             break;
128           case SPACE:
129             return true;
130           default:
131             return false;
132         }
133       }
134       return false;
135     }
136
137     std::string parseName() {
138       std::string result;
139       if (next() == EQUALS) {
140         if (parseCompleteItem(result))
141           eatLineRemnant();
142         if (result.empty())
143           error("Name exepected");
144       } else
145         error("Expecting '='");
146       return result;
147     }
148
149     bool parseBoolean() {
150       bool result = true;
151       if (next() == EQUALS) {
152         if (next() == SPACE)
153           next();
154         if (token == FALSETOK) {
155           result = false;
156         } else if (token != TRUETOK) {
157           error("Expecting boolean value");
158           return false;
159         }
160         if (next() != EOLTOK && token != 0) {
161           error("Extraneous tokens after boolean");
162         }
163       }
164       else
165         error("Expecting '='");
166       return result;
167     }
168
169     bool parseSubstitution(CompilerDriver::StringVector& optList) {
170       switch (token) {
171         case ARGS_SUBST:        optList.push_back("%args%"); break;
172         case BINDIR_SUBST:      optList.push_back("%bindir%"); break;
173         case DEFS_SUBST:        optList.push_back("%defs%"); break;
174         case IN_SUBST:          optList.push_back("%in%"); break;
175         case INCLS_SUBST:       optList.push_back("%incls%"); break;
176         case LIBDIR_SUBST:      optList.push_back("%libdir%"); break;
177         case LIBS_SUBST:        optList.push_back("%libs%"); break;
178         case OPT_SUBST:         optList.push_back("%opt%"); break;
179         case OUT_SUBST:         optList.push_back("%out%"); break;
180         case TARGET_SUBST:      optList.push_back("%target%"); break;
181         case STATS_SUBST:       optList.push_back("%stats%"); break;
182         case TIME_SUBST:        optList.push_back("%time%"); break;
183         case VERBOSE_SUBST:     optList.push_back("%verbose%"); break;
184         case FOPTS_SUBST:       optList.push_back("%fOpts%"); break;
185         case MOPTS_SUBST:       optList.push_back("%Mopts%"); break;
186         case WOPTS_SUBST:       optList.push_back("%Wopts%"); break;
187         default:
188           return false;
189       }
190       return true;
191     }
192
193     void parseOptionList(CompilerDriver::StringVector& optList ) {
194       if (next() == EQUALS) {
195         while (next_is_real()) {
196           if (token == STRING || token == OPTION)
197             optList.push_back(ConfigLexerState.StringVal);
198           else if (!parseSubstitution(optList)) {
199             error("Expecting a program argument or substitution", false);
200             break;
201           }
202         }
203       } else
204         error("Expecting '='");
205     }
206
207     void parseVersion() {
208       if (next() != EQUALS)
209         error("Expecting '='");
210       while (next_is_real()) {
211         if (token == STRING || token == OPTION)
212           confDat->version = ConfigLexerState.StringVal;
213         else
214           error("Expecting a version string");
215       }
216     }
217
218     void parseLibs() {
219       if (next() != EQUALS)
220         error("Expecting '='");
221       std::string lib;
222       while (parseCompleteItem(lib)) {
223         if (!lib.empty()) {
224           confDat->libpaths.push_back(lib);
225         }
226       }
227     }
228
229     void parseLang() {
230       if (next() != SEPARATOR)
231         error("Expecting '.'");
232       switch (next() ) {
233         case LIBS:
234           parseLibs();
235           break;
236         case NAME:
237           confDat->langName = parseName();
238           break;
239         case OPT1:
240           parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
241           break;
242         case OPT2:
243           parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
244           break;
245         case OPT3:
246           parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
247           break;
248         case OPT4:
249           parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
250           break;
251         case OPT5:
252           parseOptionList(
253             confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
254           break;
255         default:
256           error("Expecting 'name' or 'optN' after 'lang.'");
257           break;
258       }
259     }
260
261     bool parseProgramName(std::string& str) {
262       str.clear();
263       do {
264         switch (token) {
265         case BINDIR_SUBST:
266         case LLVMGCC_SUBST:
267         case LLVMGXX_SUBST:
268         case LLVMCC1_SUBST:
269         case LLVMCC1PLUS_SUBST:
270           case OPTION:
271           case STRING:
272           case ARGS_SUBST:
273           case DEFS_SUBST:
274           case IN_SUBST:
275           case INCLS_SUBST:
276           case LIBS_SUBST:
277           case OPT_SUBST:
278           case OUT_SUBST:
279           case STATS_SUBST:
280           case TARGET_SUBST:
281           case TIME_SUBST:
282           case VERBOSE_SUBST:
283           case FOPTS_SUBST:
284           case MOPTS_SUBST:
285           case WOPTS_SUBST:
286             str += ConfigLexerState.StringVal;
287             break;
288           case SEPARATOR:
289             str += ".";
290             break;
291           case ASSEMBLY:
292             str += "assembly";
293             break;
294           case BYTECODE:
295             str += "bytecode";
296             break;
297           case TRUETOK:
298             str += "true";
299             break;
300           case FALSETOK:
301             str += "false";
302             break;
303           default:
304             break;
305         }
306         next();
307       } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
308                token != ERRORTOK);
309       return !str.empty();
310     }
311
312     void parseCommand(CompilerDriver::Action& action) {
313       if (next() != EQUALS)
314         error("Expecting '='");
315       switch (next()) {
316         case EOLTOK:
317           // no value (valid)
318           action.program.clear();
319           action.args.clear();
320           break;
321         case SPACE:
322           next();
323           /* FALL THROUGH */
324         default:
325         {
326           std::string progname;
327           if (parseProgramName(progname))
328             action.program.set(progname);
329           else
330             error("Expecting a program name");
331
332           // Get the options
333           std::string anOption;
334           while (next_is_real()) {
335             switch (token) {
336               case STRING:
337               case OPTION:
338                 anOption += ConfigLexerState.StringVal;
339                 break;
340               case ASSEMBLY:
341                 anOption += "assembly";
342                 break;
343               case BYTECODE:
344                 anOption += "bytecode";
345                 break;
346               case TRUETOK:
347                 anOption += "true";
348                 break;
349               case FALSETOK:
350                 anOption += "false";
351                 break;
352               case SEPARATOR:
353                 anOption += ".";
354                 break;
355               case SPACE:
356                 action.args.push_back(anOption);
357                 anOption.clear();
358                 break;
359               default:
360                 if (!parseSubstitution(action.args))
361                   error("Expecting a program argument or substitution", false);
362                 break;
363             }
364           }
365         }
366       }
367     }
368
369     void parsePreprocessor() {
370       if (next() != SEPARATOR)
371         error("Expecting '.'");
372       switch (next()) {
373         case COMMAND:
374           parseCommand(confDat->PreProcessor);
375           break;
376         case REQUIRED:
377           if (parseBoolean())
378             confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
379           else
380             confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
381           break;
382         default:
383           error("Expecting 'command' or 'required' but found '" +
384               ConfigLexerState.StringVal);
385           break;
386       }
387     }
388
389     bool parseOutputFlag() {
390       if (next() == EQUALS) {
391         if (next() == SPACE)
392           next();
393         if (token == ASSEMBLY) {
394           return true;
395         } else if (token == BYTECODE) {
396           return false;
397         } else {
398           error("Expecting output type value");
399           return false;
400         }
401         if (next() != EOLTOK && token != 0) {
402           error("Extraneous tokens after output value");
403         }
404       }
405       else
406         error("Expecting '='");
407       return false;
408     }
409
410     void parseTranslator() {
411       if (next() != SEPARATOR)
412         error("Expecting '.'");
413       switch (next()) {
414         case COMMAND:
415           parseCommand(confDat->Translator);
416           break;
417         case REQUIRED:
418           if (parseBoolean())
419             confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
420           else
421             confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
422           break;
423         case PREPROCESSES:
424           if (parseBoolean())
425             confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
426           else
427             confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
428           break;
429         case OUTPUT:
430           if (parseOutputFlag())
431             confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
432           else
433             confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
434           break;
435
436         default:
437           error("Expecting 'command', 'required', 'preprocesses', or "
438                 "'output' but found '" + ConfigLexerState.StringVal +
439                 "' instead");
440           break;
441       }
442     }
443
444     void parseOptimizer() {
445       if (next() != SEPARATOR)
446         error("Expecting '.'");
447       switch (next()) {
448         case COMMAND:
449           parseCommand(confDat->Optimizer);
450           break;
451         case PREPROCESSES:
452           if (parseBoolean())
453             confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
454           else
455             confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
456           break;
457         case TRANSLATES:
458           if (parseBoolean())
459             confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
460           else
461             confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
462           break;
463         case REQUIRED:
464           if (parseBoolean())
465             confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
466           else
467             confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
468           break;
469         case OUTPUT:
470           if (parseOutputFlag())
471             confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
472           else
473             confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
474           break;
475         default:
476           error(std::string("Expecting 'command', 'preprocesses', "
477               "'translates' or 'output' but found '") +
478               ConfigLexerState.StringVal + "' instead");
479           break;
480       }
481     }
482
483     void parseAssembler() {
484       if (next() != SEPARATOR)
485         error("Expecting '.'");
486       switch(next()) {
487         case COMMAND:
488           parseCommand(confDat->Assembler);
489           break;
490         default:
491           error("Expecting 'command'");
492           break;
493       }
494     }
495
496     void parseLinker() {
497       if (next() != SEPARATOR)
498         error("Expecting '.'");
499       switch(next()) {
500         case LIBS:
501           break; //FIXME
502         case LIBPATHS:
503           break; //FIXME
504         default:
505           error("Expecting 'libs' or 'libpaths'");
506           break;
507       }
508     }
509
510     void parseAssignment() {
511       switch (token) {
512         case VERSION_TOK:   parseVersion(); break;
513         case LANG:          parseLang(); break;
514         case PREPROCESSOR:  parsePreprocessor(); break;
515         case TRANSLATOR:    parseTranslator(); break;
516         case OPTIMIZER:     parseOptimizer(); break;
517         case ASSEMBLER:     parseAssembler(); break;
518         case LINKER:        parseLinker(); break;
519         case EOLTOK:        break; // just ignore
520         case ERRORTOK:
521         default:
522           error("Invalid top level configuration item");
523           break;
524       }
525     }
526
527     void parseFile() {
528       while ( next() != EOFTOK ) {
529         if (token == ERRORTOK)
530           error("Invalid token");
531         else if (token != EOLTOK)
532           parseAssignment();
533       }
534       provider->checkErrors();
535     }
536   };
537
538 void
539 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
540   Parser p;
541   p.token = EOFTOK;
542   p.provider = &provider;
543   p.confDat = &confDat;
544   p.parseFile();
545   }
546
547 }
548
549 CompilerDriver::ConfigData*
550 LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
551   CompilerDriver::ConfigData* result = 0;
552   sys::Path confFile;
553   if (configDir.isEmpty()) {
554     // Try the environment variable
555     const char* conf = getenv("LLVM_CONFIG_DIR");
556     if (conf) {
557       confFile.set(conf);
558       confFile.appendComponent(ftype);
559       if (!confFile.canRead())
560         throw std::string("Configuration file for '") + ftype +
561                           "' is not available.";
562     } else {
563       // Try the user's home directory
564       confFile = sys::Path::GetUserHomeDirectory();
565       if (!confFile.isEmpty()) {
566         confFile.appendComponent(".llvm");
567         confFile.appendComponent("etc");
568         confFile.appendComponent(ftype);
569         if (!confFile.canRead())
570           confFile.clear();
571       }
572       if (confFile.isEmpty()) {
573         // Okay, try the LLVM installation directory
574         confFile = sys::Path::GetLLVMConfigDir();
575         confFile.appendComponent(ftype);
576         if (!confFile.canRead()) {
577           // Okay, try the "standard" place
578           confFile = sys::Path::GetLLVMDefaultConfigDir();
579           confFile.appendComponent(ftype);
580           if (!confFile.canRead()) {
581             throw std::string("Configuration file for '") + ftype +
582                               "' is not available.";
583           }
584         }
585       }
586     }
587   } else {
588     confFile = configDir;
589     confFile.appendComponent(ftype);
590     if (!confFile.canRead())
591       throw std::string("Configuration file for '") + ftype +
592                         "' is not available.";
593   }
594   FileInputProvider fip( confFile.toString() );
595   if (!fip.okay()) {
596     throw std::string("Configuration file for '") + ftype +
597                       "' is not available.";
598   }
599   result = new CompilerDriver::ConfigData();
600   ParseConfigData(fip,*result);
601   return result;
602 }
603
604 LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
605 {
606   ConfigDataMap::iterator cIt = Configurations.begin();
607   while (cIt != Configurations.end()) {
608     CompilerDriver::ConfigData* cd = cIt->second;
609     ++cIt;
610     delete cd;
611   }
612   Configurations.clear();
613 }
614
615 CompilerDriver::ConfigData*
616 LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
617   CompilerDriver::ConfigData* result = 0;
618   if (!Configurations.empty()) {
619     ConfigDataMap::iterator cIt = Configurations.find(filetype);
620     if ( cIt != Configurations.end() ) {
621       // We found one in the case, return it.
622       result = cIt->second;
623     }
624   }
625   if (result == 0) {
626     // The configuration data doesn't exist, we have to go read it.
627     result = ReadConfigData(filetype);
628     // If we got one, cache it
629     if (result != 0)
630       Configurations.insert(std::make_pair(filetype,result));
631   }
632   return result; // Might return 0
633 }