blob: cfea9eb43561aed876780a1546c2c766400f8f89 [file] [log] [blame]
Reid Spencer2594c9a2004-08-13 20:21:22 +00001//===- ConfigData.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 "ConfigData.h"
Reid Spencer68fb37a2004-08-14 09:37:15 +000016#include "ConfigLexer.h"
Reid Spencer2594c9a2004-08-13 20:21:22 +000017#include "CompilerDriver.h"
18#include "Support/StringExtras.h"
19#include <iostream>
Reid Spencer68fb37a2004-08-14 09:37:15 +000020#include <fstream>
Reid Spencer2594c9a2004-08-13 20:21:22 +000021
22using namespace llvm;
23
Reid Spencerbf437722004-08-15 08:19:46 +000024extern int ::Configlineno;
Reid Spencer68fb37a2004-08-14 09:37:15 +000025
26namespace llvm {
27 ConfigLexerInfo ConfigLexerData;
28 InputProvider* ConfigLexerInput = 0;
Reid Spencer68fb37a2004-08-14 09:37:15 +000029
30 InputProvider::~InputProvider() {}
31 void InputProvider::error(const std::string& msg) {
Reid Spencerbf437722004-08-15 08:19:46 +000032 std::cerr << name << ":" << Configlineno << ": Error: " << msg << "\n";
Reid Spencer68fb37a2004-08-14 09:37:15 +000033 errCount++;
34 }
35
36 void InputProvider::checkErrors() {
37 if (errCount > 0) {
38 std::cerr << name << " had " << errCount << " errors. Terminating.\n";
39 exit(errCount);
40 }
41 }
42
43}
44
Reid Spencer2594c9a2004-08-13 20:21:22 +000045namespace {
46
Reid Spencer68fb37a2004-08-14 09:37:15 +000047 class FileInputProvider : public InputProvider {
48 public:
49 FileInputProvider(const std::string & fname)
50 : InputProvider(fname)
51 , F(fname.c_str()) {
52 ConfigLexerInput = this;
53 }
54 virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
55 virtual unsigned read(char *buffer, unsigned max_size) {
56 if (F.good()) {
57 F.read(buffer,max_size);
58 if ( F.gcount() ) return F.gcount() - 1;
59 }
60 return 0;
61 }
Reid Spencer2594c9a2004-08-13 20:21:22 +000062
Reid Spencer68fb37a2004-08-14 09:37:15 +000063 bool okay() { return F.good(); }
64 private:
65 std::ifstream F;
66 };
Reid Spencer2594c9a2004-08-13 20:21:22 +000067
Reid Spencerbf437722004-08-15 08:19:46 +000068 struct Parser
Reid Spencer68fb37a2004-08-14 09:37:15 +000069 {
Reid Spencerbf437722004-08-15 08:19:46 +000070 ConfigLexerTokens token;
Reid Spencer68fb37a2004-08-14 09:37:15 +000071 InputProvider* provider;
72 CompilerDriver::ConfigData* confDat;
73 CompilerDriver::Action* action;
Reid Spencer2594c9a2004-08-13 20:21:22 +000074
Reid Spencer68fb37a2004-08-14 09:37:15 +000075 int next() { return token = Configlex(); }
76
77 bool next_is_real() {
78 token = Configlex();
79 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
Reid Spencer2594c9a2004-08-13 20:21:22 +000080 }
81
Reid Spencer68fb37a2004-08-14 09:37:15 +000082 void eatLineRemnant() {
83 while (next_is_real()) ;
Reid Spencer2594c9a2004-08-13 20:21:22 +000084 }
85
Reid Spencer68fb37a2004-08-14 09:37:15 +000086 void error(const std::string& msg, bool skip = true) {
87 provider->error(msg);
88 if (skip)
89 eatLineRemnant();
90 }
Reid Spencer2594c9a2004-08-13 20:21:22 +000091
Reid Spencer68fb37a2004-08-14 09:37:15 +000092 std::string parseName() {
93 std::string result;
94 if (next() == EQUALS) {
95 while (next_is_real()) {
96 switch (token ) {
97 case STRING :
98 case OPTION :
99 result += ConfigLexerData.StringVal + " ";
100 break;
101 default:
102 error("Invalid name");
103 break;
104 }
105 }
106 if (result.empty())
107 error("Name exepected");
108 else
109 result.erase(result.size()-1,1);
110 } else
111 error("= expected");
112 return result;
113 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000114
Reid Spencer68fb37a2004-08-14 09:37:15 +0000115 bool parseBoolean() {
116 bool result = true;
117 if (next() == EQUALS) {
118 if (next() == FALSETOK) {
119 result = false;
120 } else if (token != TRUETOK) {
121 error("Expecting boolean value");
122 return false;
123 }
124 if (next() != EOLTOK && token != 0) {
125 error("Extraneous tokens after boolean");
126 }
127 }
128 else
129 error("Expecting '='");
130 return result;
131 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000132
Reid Spencerbf437722004-08-15 08:19:46 +0000133 void parseOptionList(CompilerDriver::StringVector& optList ) {
134 while (next_is_real()) {
135 if (token == STRING || token == OPTION)
136 optList.push_back(ConfigLexerData.StringVal);
137 else {
138 error("Expecting a program option", false);
139 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000140 }
141 }
Reid Spencerbf437722004-08-15 08:19:46 +0000142 }
143
144 void parseLang() {
145 switch (next() ) {
146 case NAME:
147 confDat->langName = parseName();
148 break;
149 case OPT1:
150 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
151 break;
152 case OPT2:
153 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
154 break;
155 case OPT3:
156 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
157 break;
158 case OPT4:
159 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
160 break;
161 case OPT5:
162 parseOptionList(
163 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
164 break;
165 default:
166 error("Expecting 'name' or 'optN' after 'lang.'");
167 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000168 }
169 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000170
Reid Spencer68fb37a2004-08-14 09:37:15 +0000171 void parseCommand(CompilerDriver::Action& action) {
172 if (next() == EQUALS) {
Reid Spencerbf437722004-08-15 08:19:46 +0000173 if (next() == EOLTOK) {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000174 // no value (valid)
175 action.program.clear();
176 action.args.clear();
177 action.inputAt = 0;
178 action.outputAt = 0;
179 } else {
180 if (token == STRING || token == OPTION) {
181 action.program = ConfigLexerData.StringVal;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000182 } else {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000183 error("Expecting a program name");
184 }
185 while (next_is_real()) {
Reid Spencerbf437722004-08-15 08:19:46 +0000186 if (token == STRING || token == OPTION) {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000187 action.args.push_back(ConfigLexerData.StringVal);
Reid Spencerbf437722004-08-15 08:19:46 +0000188 } else if (token == IN_SUBST) {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000189 action.inputAt = action.args.size();
Reid Spencerbf437722004-08-15 08:19:46 +0000190 action.args.push_back("@in@");
Reid Spencer68fb37a2004-08-14 09:37:15 +0000191 } else if (token == OUT_SUBST) {
192 action.outputAt = action.args.size();
Reid Spencerbf437722004-08-15 08:19:46 +0000193 action.args.push_back("@out@");
194 } else {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000195 error("Expecting a program argument", false);
Reid Spencerbf437722004-08-15 08:19:46 +0000196 break;
197 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000198 }
199 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000200 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000201 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000202
Reid Spencerbf437722004-08-15 08:19:46 +0000203 void parsePreprocessor() {
204 switch (next()) {
205 case COMMAND:
206 parseCommand(confDat->PreProcessor);
207 break;
208 case REQUIRED:
209 if (parseBoolean())
210 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
211 else
212 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
213 break;
214 default:
215 error("Expecting 'command' or 'required'");
216 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000217 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000218 }
219
220 void parseTranslator() {
Reid Spencerbf437722004-08-15 08:19:46 +0000221 switch (next()) {
222 case COMMAND:
223 parseCommand(confDat->Translator);
224 break;
225 case REQUIRED:
226 if (parseBoolean())
227 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
228 else
229 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
230 break;
231 case PREPROCESSES:
232 if (parseBoolean())
233 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
234 else
235 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
236 break;
237 case OPTIMIZES:
238 if (parseBoolean())
239 confDat->Translator.set(CompilerDriver::OPTIMIZES_FLAG);
240 else
241 confDat->Translator.clear(CompilerDriver::OPTIMIZES_FLAG);
242 break;
243 case GROKS_DASH_O:
244 if (parseBoolean())
245 confDat->Translator.set(CompilerDriver::GROKS_DASH_O_FLAG);
246 else
247 confDat->Translator.clear(CompilerDriver::GROKS_DASH_O_FLAG);
248 break;
249 case GROKS_O10N:
250 if (parseBoolean())
251 confDat->Translator.set(CompilerDriver::GROKS_O10N_FLAG);
252 else
253 confDat->Translator.clear(CompilerDriver::GROKS_O10N_FLAG);
254 break;
255 default:
256 error("Expecting 'command', 'required', 'preprocesses', "
257 "'groks_dash_O' or 'optimizes'");
258 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000259 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000260 }
261
262 void parseOptimizer() {
Reid Spencerbf437722004-08-15 08:19:46 +0000263 switch (next()) {
264 case COMMAND:
265 parseCommand(confDat->Optimizer);
266 break;
267 case GROKS_DASH_O:
268 if (parseBoolean())
269 confDat->Optimizer.set(CompilerDriver::GROKS_DASH_O_FLAG);
270 else
271 confDat->Optimizer.clear(CompilerDriver::GROKS_DASH_O_FLAG);
272 break;
273 case GROKS_O10N:
274 if (parseBoolean())
275 confDat->Optimizer.set(CompilerDriver::GROKS_O10N_FLAG);
276 else
277 confDat->Optimizer.clear(CompilerDriver::GROKS_O10N_FLAG);
278 break;
279 default:
280 error("Expecting 'command' or 'groks_dash_O'");
281 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000282 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000283 }
284
285 void parseAssembler() {
Reid Spencerbf437722004-08-15 08:19:46 +0000286 switch(next()) {
287 case COMMAND:
288 parseCommand(confDat->Assembler);
289 break;
290 default:
291 error("Expecting 'command'");
292 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000293 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000294 }
295
296 void parseLinker() {
Reid Spencerbf437722004-08-15 08:19:46 +0000297 switch(next()) {
298 case COMMAND:
299 parseCommand(confDat->Linker);
300 break;
301 case GROKS_DASH_O:
302 if (parseBoolean())
303 confDat->Linker.set(CompilerDriver::GROKS_DASH_O_FLAG);
304 else
305 confDat->Linker.clear(CompilerDriver::GROKS_DASH_O_FLAG);
306 break;
307 case GROKS_O10N:
308 if (parseBoolean())
309 confDat->Linker.set(CompilerDriver::GROKS_O10N_FLAG);
310 else
311 confDat->Linker.clear(CompilerDriver::GROKS_O10N_FLAG);
312 break;
313 default:
314 error("Expecting 'command'");
315 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000316 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000317 }
318
319 void parseAssignment() {
320 switch (token) {
Reid Spencerbf437722004-08-15 08:19:46 +0000321 case LANG: parseLang(); break;
322 case PREPROCESSOR: parsePreprocessor(); break;
323 case TRANSLATOR: parseTranslator(); break;
324 case OPTIMIZER: parseOptimizer(); break;
325 case ASSEMBLER: parseAssembler(); break;
326 case LINKER: parseLinker(); break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000327 case EOLTOK: break; // just ignore
328 case ERRORTOK:
329 default:
Reid Spencerbf437722004-08-15 08:19:46 +0000330 error("Invalid top level configuration item");
331 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000332 }
333 }
334
335 void parseFile() {
Reid Spencerbf437722004-08-15 08:19:46 +0000336 while ( next() != EOFTOK ) {
337 if (token == ERRORTOK)
338 error("Invalid token");
339 else if (token != EOLTOK)
340 parseAssignment();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000341 }
342 provider->checkErrors();
343 }
344 };
345
346 void
347 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
Reid Spencerbf437722004-08-15 08:19:46 +0000348 Parser p;
349 p.token = EOFTOK;
350 p.provider = &provider;
351 p.confDat = &confDat;
352 p.action = 0;
353 p.parseFile();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000354 }
355}
356
357CompilerDriver::ConfigData*
Reid Spencer68fb37a2004-08-14 09:37:15 +0000358LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
359 CompilerDriver::ConfigData* result = 0;
360 if (configDir.empty()) {
361 FileInputProvider fip( std::string("/etc/llvm/") + ftype );
362 if (!fip.okay()) {
363 fip.error("Configuration for '" + ftype + "' is not available.");
364 fip.checkErrors();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000365 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000366 else {
367 result = new CompilerDriver::ConfigData();
368 ParseConfigData(fip,*result);
369 }
370 } else {
371 FileInputProvider fip( configDir + "/" + ftype );
372 if (!fip.okay()) {
373 fip.error("Configuration for '" + ftype + "' is not available.");
374 fip.checkErrors();
375 }
376 else {
377 result = new CompilerDriver::ConfigData();
378 ParseConfigData(fip,*result);
379 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000380 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000381 return result;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000382}
383
384LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
385 : Configurations()
386 , configDir()
387{
388 Configurations.clear();
389}
390
391LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
392{
393 ConfigDataMap::iterator cIt = Configurations.begin();
394 while (cIt != Configurations.end()) {
395 CompilerDriver::ConfigData* cd = cIt->second;
396 ++cIt;
397 delete cd;
398 }
399 Configurations.clear();
400}
401
402CompilerDriver::ConfigData*
403LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
404 CompilerDriver::ConfigData* result = 0;
405 if (!Configurations.empty()) {
406 ConfigDataMap::iterator cIt = Configurations.find(filetype);
407 if ( cIt != Configurations.end() ) {
408 // We found one in the case, return it.
409 result = cIt->second;
410 }
411 }
412 if (result == 0) {
413 // The configuration data doesn't exist, we have to go read it.
414 result = ReadConfigData(filetype);
415 // If we got one, cache it
416 if ( result != 0 )
417 Configurations.insert(std::make_pair(filetype,result));
418 }
419 return result; // Might return 0
420}
421
422// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab