blob: d2e788bf12b9bba6271e76792a2dbab515b4d7c3 [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 Spencer68fb37a2004-08-14 09:37:15 +000024extern int ::Configlex();
25
26namespace llvm {
27 ConfigLexerInfo ConfigLexerData;
28 InputProvider* ConfigLexerInput = 0;
29 unsigned ConfigLexerLine = 1;
30
31 InputProvider::~InputProvider() {}
32 void InputProvider::error(const std::string& msg) {
33 std::cerr << name << ":" << ConfigLexerLine << ": Error: " << msg << "\n";
34 errCount++;
35 }
36
37 void InputProvider::checkErrors() {
38 if (errCount > 0) {
39 std::cerr << name << " had " << errCount << " errors. Terminating.\n";
40 exit(errCount);
41 }
42 }
43
44}
45
Reid Spencer2594c9a2004-08-13 20:21:22 +000046namespace {
47
Reid Spencer68fb37a2004-08-14 09:37:15 +000048 class FileInputProvider : public InputProvider {
49 public:
50 FileInputProvider(const std::string & fname)
51 : InputProvider(fname)
52 , F(fname.c_str()) {
53 ConfigLexerInput = this;
54 }
55 virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
56 virtual unsigned read(char *buffer, unsigned max_size) {
57 if (F.good()) {
58 F.read(buffer,max_size);
59 if ( F.gcount() ) return F.gcount() - 1;
60 }
61 return 0;
62 }
Reid Spencer2594c9a2004-08-13 20:21:22 +000063
Reid Spencer68fb37a2004-08-14 09:37:15 +000064 bool okay() { return F.good(); }
65 private:
66 std::ifstream F;
67 };
Reid Spencer2594c9a2004-08-13 20:21:22 +000068
Reid Spencer68fb37a2004-08-14 09:37:15 +000069 struct ParseContext
70 {
71 int token;
72 InputProvider* provider;
73 CompilerDriver::ConfigData* confDat;
74 CompilerDriver::Action* action;
Reid Spencer2594c9a2004-08-13 20:21:22 +000075
Reid Spencer68fb37a2004-08-14 09:37:15 +000076 int next() { return token = Configlex(); }
77
78 bool next_is_real() {
79 token = Configlex();
80 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
Reid Spencer2594c9a2004-08-13 20:21:22 +000081 }
82
Reid Spencer68fb37a2004-08-14 09:37:15 +000083 void eatLineRemnant() {
84 while (next_is_real()) ;
Reid Spencer2594c9a2004-08-13 20:21:22 +000085 }
86
Reid Spencer68fb37a2004-08-14 09:37:15 +000087 void error(const std::string& msg, bool skip = true) {
88 provider->error(msg);
89 if (skip)
90 eatLineRemnant();
91 }
Reid Spencer2594c9a2004-08-13 20:21:22 +000092
Reid Spencer68fb37a2004-08-14 09:37:15 +000093 std::string parseName() {
94 std::string result;
95 if (next() == EQUALS) {
96 while (next_is_real()) {
97 switch (token ) {
98 case STRING :
99 case OPTION :
100 result += ConfigLexerData.StringVal + " ";
101 break;
102 default:
103 error("Invalid name");
104 break;
105 }
106 }
107 if (result.empty())
108 error("Name exepected");
109 else
110 result.erase(result.size()-1,1);
111 } else
112 error("= expected");
113 return result;
114 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000115
Reid Spencer68fb37a2004-08-14 09:37:15 +0000116 bool parseBoolean() {
117 bool result = true;
118 if (next() == EQUALS) {
119 if (next() == FALSETOK) {
120 result = false;
121 } else if (token != TRUETOK) {
122 error("Expecting boolean value");
123 return false;
124 }
125 if (next() != EOLTOK && token != 0) {
126 error("Extraneous tokens after boolean");
127 }
128 }
129 else
130 error("Expecting '='");
131 return result;
132 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000133
Reid Spencer68fb37a2004-08-14 09:37:15 +0000134 void parseLang() {
135 if ( next() == NAME ) {
136 confDat->langName = parseName();
137 } else if (token == TRANSLATOR) {
138 switch (next()) {
139 case PREPROCESSES:
140 confDat->TranslatorPreprocesses = parseBoolean();
141 break;
142 case OPTIMIZES:
143 confDat->TranslatorOptimizes = parseBoolean();
144 break;
145 case GROKS_DASH_O:
146 confDat->TranslatorGroksDashO = parseBoolean();
147 break;
148 default:
149 error("Invalid lang.translator identifier");
150 break;
151 }
152 }
153 else if (token == PREPROCESSOR) {
154 if (next() == NEEDED)
155 confDat->PreprocessorNeeded = parseBoolean();
156 }
157 else {
158 error("Expecting valid identifier after 'lang.'");
159 }
160 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000161
Reid Spencer68fb37a2004-08-14 09:37:15 +0000162 void parseCommand(CompilerDriver::Action& action) {
163 if (next() == EQUALS) {
164 next();
165 if (token == EOLTOK) {
166 // no value (valid)
167 action.program.clear();
168 action.args.clear();
169 action.inputAt = 0;
170 action.outputAt = 0;
171 } else {
172 if (token == STRING || token == OPTION) {
173 action.program = ConfigLexerData.StringVal;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000174 } else {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000175 error("Expecting a program name");
176 }
177 while (next_is_real()) {
178 if (token == STRING || token == OPTION)
179 action.args.push_back(ConfigLexerData.StringVal);
180 else if (token == IN_SUBST) {
181 action.inputAt = action.args.size();
182 action.args.push_back("in");
183 } else if (token == OUT_SUBST) {
184 action.outputAt = action.args.size();
185 action.args.push_back("out");
186 } else
187 error("Expecting a program argument", false);
Reid Spencer2594c9a2004-08-13 20:21:22 +0000188 }
189 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000190 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000191 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000192
193 void parsePreProcessor() {
194 if (next() != COMMAND) {
195 error("Expecting 'command'");
196 return;
197 }
198 parseCommand(confDat->PreProcessor);
199 }
200
201 void parseTranslator() {
202 if (next() != COMMAND) {
203 error("Expecting 'command'");
204 return;
205 }
206 parseCommand(confDat->Translator);
207 }
208
209 void parseOptimizer() {
210 if (next() != COMMAND) {
211 error("Expecting 'command'");
212 return;
213 }
214 parseCommand(confDat->Optimizer);
215 }
216
217 void parseAssembler() {
218 if (next() != COMMAND) {
219 error("Expecting 'command'");
220 return;
221 }
222 parseCommand(confDat->Assembler);
223 }
224
225 void parseLinker() {
226 if (next() != COMMAND) {
227 error("Expecting 'command'");
228 return;
229 }
230 parseCommand(confDat->Linker);
231 }
232
233 void parseAssignment() {
234 switch (token) {
235 case LANG: return parseLang();
236 case PREPROCESSOR: return parsePreProcessor();
237 case TRANSLATOR: return parseTranslator();
238 case OPTIMIZER: return parseOptimizer();
239 case ASSEMBLER: return parseAssembler();
240 case LINKER: return parseLinker();
241 case EOLTOK: break; // just ignore
242 case ERRORTOK:
243 default:
244 error("Invalid top level configuration item identifier");
245 }
246 }
247
248 void parseFile() {
249 while ( next() != 0 ) {
250 parseAssignment();
251 }
252 provider->checkErrors();
253 }
254 };
255
256 void
257 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
258 ParseContext ctxt;
259 ctxt.token = 0;
260 ctxt.provider = &provider;
261 ctxt.confDat = &confDat;
262 ctxt.action = 0;
263 ctxt.parseFile();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000264 }
265}
266
267CompilerDriver::ConfigData*
Reid Spencer68fb37a2004-08-14 09:37:15 +0000268LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
269 CompilerDriver::ConfigData* result = 0;
270 if (configDir.empty()) {
271 FileInputProvider fip( std::string("/etc/llvm/") + ftype );
272 if (!fip.okay()) {
273 fip.error("Configuration for '" + ftype + "' is not available.");
274 fip.checkErrors();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000275 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000276 else {
277 result = new CompilerDriver::ConfigData();
278 ParseConfigData(fip,*result);
279 }
280 } else {
281 FileInputProvider fip( configDir + "/" + ftype );
282 if (!fip.okay()) {
283 fip.error("Configuration for '" + ftype + "' is not available.");
284 fip.checkErrors();
285 }
286 else {
287 result = new CompilerDriver::ConfigData();
288 ParseConfigData(fip,*result);
289 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000290 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000291 return result;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000292}
293
294LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
295 : Configurations()
296 , configDir()
297{
298 Configurations.clear();
299}
300
301LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
302{
303 ConfigDataMap::iterator cIt = Configurations.begin();
304 while (cIt != Configurations.end()) {
305 CompilerDriver::ConfigData* cd = cIt->second;
306 ++cIt;
307 delete cd;
308 }
309 Configurations.clear();
310}
311
312CompilerDriver::ConfigData*
313LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
314 CompilerDriver::ConfigData* result = 0;
315 if (!Configurations.empty()) {
316 ConfigDataMap::iterator cIt = Configurations.find(filetype);
317 if ( cIt != Configurations.end() ) {
318 // We found one in the case, return it.
319 result = cIt->second;
320 }
321 }
322 if (result == 0) {
323 // The configuration data doesn't exist, we have to go read it.
324 result = ReadConfigData(filetype);
325 // If we got one, cache it
326 if ( result != 0 )
327 Configurations.insert(std::make_pair(filetype,result));
328 }
329 return result; // Might return 0
330}
331
332// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab