1 //===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
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.
8 //===----------------------------------------------------------------------===//
10 // This file implements the parsing of configuration files for the LLVM Compiler
13 //===------------------------------------------------------------------------===
15 #include "ConfigData.h"
16 #include "ConfigLexer.h"
17 #include "CompilerDriver.h"
18 #include "Support/CommandLine.h"
19 #include "Support/StringExtras.h"
26 ConfigLexerInfo ConfigLexerState;
27 InputProvider* ConfigLexerInput = 0;
29 InputProvider::~InputProvider() {}
30 void InputProvider::error(const std::string& msg) {
31 std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " <<
36 void InputProvider::checkErrors() {
38 std::cerr << name << " had " << errCount << " errors. Terminating.\n";
47 class FileInputProvider : public InputProvider {
49 FileInputProvider(const std::string & fname)
50 : InputProvider(fname)
52 ConfigLexerInput = this;
54 virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
55 virtual unsigned read(char *buffer, unsigned max_size) {
57 F.read(buffer,max_size);
58 if ( F.gcount() ) return F.gcount() - 1;
63 bool okay() { return F.good(); }
68 cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden, cl::init(false),
69 cl::desc("Dump lexical tokens (debug use only)."));
77 ConfigLexerState.lineNum = 1;
78 ConfigLexerState.in_value = false;
79 ConfigLexerState.StringVal.clear();
80 ConfigLexerState.IntegerVal = 0;
83 ConfigLexerTokens token;
84 InputProvider* provider;
85 CompilerDriver::ConfigData* confDat;
90 std::cerr << token << "\n";
96 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
99 void eatLineRemnant() {
100 while (next_is_real()) ;
103 void error(const std::string& msg, bool skip = true) {
104 provider->error(msg);
109 std::string parseName() {
111 if (next() == EQUALS) {
112 while (next_is_real()) {
116 result += ConfigLexerState.StringVal + " ";
119 error("Invalid name");
124 error("Name exepected");
126 result.erase(result.size()-1,1);
132 bool parseBoolean() {
134 if (next() == EQUALS) {
135 if (next() == FALSETOK) {
137 } else if (token != TRUETOK) {
138 error("Expecting boolean value");
141 if (next() != EOLTOK && token != 0) {
142 error("Extraneous tokens after boolean");
146 error("Expecting '='");
150 bool parseSubstitution(CompilerDriver::StringVector& optList) {
152 case IN_SUBST: optList.push_back("@in@"); break;
153 case OUT_SUBST: optList.push_back("@out@"); break;
154 case TIME_SUBST: optList.push_back("@time@"); break;
155 case STATS_SUBST: optList.push_back("@stats@"); break;
156 case OPT_SUBST: optList.push_back("@opt@"); break;
157 case TARGET_SUBST: optList.push_back("@target@"); break;
164 void parseOptionList(CompilerDriver::StringVector& optList ) {
165 if (next() == EQUALS) {
166 while (next_is_real()) {
167 if (token == STRING || token == OPTION)
168 optList.push_back(ConfigLexerState.StringVal);
169 else if (!parseSubstitution(optList)) {
170 error("Expecting a program argument or substitution", false);
175 error("Expecting '='");
181 confDat->langName = parseName();
184 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
187 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
190 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
193 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
197 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
200 error("Expecting 'name' or 'optN' after 'lang.'");
205 void parseCommand(CompilerDriver::Action& action) {
206 if (next() == EQUALS) {
207 if (next() == EOLTOK) {
209 action.program.clear();
212 if (token == STRING || token == OPTION) {
213 action.program = ConfigLexerState.StringVal;
215 error("Expecting a program name");
217 while (next_is_real()) {
218 if (token == STRING || token == OPTION) {
219 action.args.push_back(ConfigLexerState.StringVal);
220 } else if (!parseSubstitution(action.args)) {
221 error("Expecting a program argument or substitution", false);
229 void parsePreprocessor() {
232 parseCommand(confDat->PreProcessor);
236 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
238 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
241 error("Expecting 'command' or 'required'");
246 void parseTranslator() {
249 parseCommand(confDat->Translator);
253 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
255 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
259 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
261 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
265 confDat->Translator.set(CompilerDriver::OPTIMIZES_FLAG);
267 confDat->Translator.clear(CompilerDriver::OPTIMIZES_FLAG);
271 confDat->Translator.set(CompilerDriver::GROKS_DASH_O_FLAG);
273 confDat->Translator.clear(CompilerDriver::GROKS_DASH_O_FLAG);
277 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
279 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
283 error("Expecting 'command', 'required', 'preprocesses', "
284 "'groks_dash_O' or 'optimizes'");
289 void parseOptimizer() {
292 parseCommand(confDat->Optimizer);
296 confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
298 confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
302 confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
304 confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
308 confDat->Optimizer.set(CompilerDriver::GROKS_DASH_O_FLAG);
310 confDat->Optimizer.clear(CompilerDriver::GROKS_DASH_O_FLAG);
314 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
316 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
319 error("Expecting 'command' or 'groks_dash_O'");
324 void parseAssembler() {
327 parseCommand(confDat->Assembler);
330 error("Expecting 'command'");
338 parseCommand(confDat->Linker);
342 confDat->Linker.set(CompilerDriver::GROKS_DASH_O_FLAG);
344 confDat->Linker.clear(CompilerDriver::GROKS_DASH_O_FLAG);
347 error("Expecting 'command'");
352 void parseAssignment() {
354 case LANG: parseLang(); break;
355 case PREPROCESSOR: parsePreprocessor(); break;
356 case TRANSLATOR: parseTranslator(); break;
357 case OPTIMIZER: parseOptimizer(); break;
358 case ASSEMBLER: parseAssembler(); break;
359 case LINKER: parseLinker(); break;
360 case EOLTOK: break; // just ignore
363 error("Invalid top level configuration item");
369 while ( next() != EOFTOK ) {
370 if (token == ERRORTOK)
371 error("Invalid token");
372 else if (token != EOLTOK)
375 provider->checkErrors();
380 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
383 p.provider = &provider;
384 p.confDat = &confDat;
389 CompilerDriver::ConfigData*
390 LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
391 CompilerDriver::ConfigData* result = 0;
392 if (configDir.empty()) {
393 FileInputProvider fip( std::string("/etc/llvm/") + ftype );
395 fip.error("Configuration for '" + ftype + "' is not available.");
399 result = new CompilerDriver::ConfigData();
400 ParseConfigData(fip,*result);
403 FileInputProvider fip( configDir + "/" + ftype );
405 fip.error("Configuration for '" + ftype + "' is not available.");
409 result = new CompilerDriver::ConfigData();
410 ParseConfigData(fip,*result);
416 LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
420 Configurations.clear();
423 LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
425 ConfigDataMap::iterator cIt = Configurations.begin();
426 while (cIt != Configurations.end()) {
427 CompilerDriver::ConfigData* cd = cIt->second;
431 Configurations.clear();
434 CompilerDriver::ConfigData*
435 LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
436 CompilerDriver::ConfigData* result = 0;
437 if (!Configurations.empty()) {
438 ConfigDataMap::iterator cIt = Configurations.find(filetype);
439 if ( cIt != Configurations.end() ) {
440 // We found one in the case, return it.
441 result = cIt->second;
445 // The configuration data doesn't exist, we have to go read it.
446 result = ReadConfigData(filetype);
447 // If we got one, cache it
449 Configurations.insert(std::make_pair(filetype,result));
451 return result; // Might return 0
454 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab