Started to improve the configuration system a bit more.
[aesalon.git] / monitor / src / config / Parser.cpp
blob0773501ae172a50a3b14c648fd753cc37d837941
1 /**
2 Aesalon, a tool to visualize a program's behaviour at run-time.
3 Copyright (C) 2010, Aesalon Development Team.
5 Aesalon is distributed under the terms of the GNU GPLv3. For more
6 licensing information, see the file LICENSE included with the distribution.
8 @file monitor/src/config/Parser.cpp
12 #include <iostream> // for debugging
13 #include <sstream>
14 #include <fstream>
15 #include <string>
16 #include <cctype>
18 #include "config/Parser.h"
19 #include "common/ParsingException.h"
20 #include "common/StreamAsString.h"
21 #include "config/ConcreteVault.h"
23 namespace Monitor {
24 namespace Config {
26 void Parser::parse(ConcreteVault *vault, const std::string &configFile) {
27 std::string currentModule;
29 openFile(configFile);
31 for(;;) {
32 TokenType tokenType;
33 std::string token = nextToken(tokenType);
34 if(tokenType == END_OF_FILE) break;
36 //std::cout << '"' << token << '"' << " of type " << nameOf(tokenType) << std::endl;
38 if(tokenType == WORD && token == "include") {
39 Parser().parse(vault, expectNextToken(QUOTED_WORD));
40 expectNextSymbol(";");
42 else if(tokenType == WORD && token == "module") {
43 currentModule = expectNextToken(WORD);
44 expectNextSymbol("{");
46 else if(tokenType == SYMBOL && token == "}") {
47 if(currentModule != "") {
48 currentModule = "";
50 else throw Common::ParsingException("Extra \"}\"");
52 else if(tokenType == WORD && token == "use") {
53 /*std::cout << "Parser: Using module \"" << expectNextToken(WORD) << "\"\n";*/
54 vault->set("LD_PRELOAD", expectNextToken(WORD));
55 expectNextSymbol(";");
57 else if(tokenType == WORD) {
58 std::string op = expectNextToken(SYMBOL);
60 if(op == "=") vault->clear(token);
62 do {
63 TokenType nextType;
64 std::string next = nextToken(nextType);
66 //if(nextType == SYMBOL && next == ";") break;
68 if(nextType == WORD || nextType == QUOTED_WORD) {
69 if(currentModule != "") vault->set(
70 Common::StreamAsString() << currentModule << ":" << token, next);
72 else vault->set(token, next);
74 std::cout << "Set \"" << currentModule << "::" << token << "\" to \""
75 << next << "\" with operator " << op << std::endl;
77 else throw Common::ParsingException("Invalid RHS");
79 std::string sym = expectNextToken(SYMBOL);
80 if(sym == ";") break;
81 else if(sym == ",") {}
82 else {
83 throw Common::ParsingException(Common::StreamAsString()
84 << "Expected \",\" or \";\", got \"" << sym << "\"");
86 } while(true);
88 else {
89 throw Common::ParsingException(Common::StreamAsString()
90 << "Syntax error at token \"" << token << "\"");
92 //std::cout << "\"" << token << "\"\n";
95 closeFile();
98 void Parser::openFile(const std::string &configFile) {
99 m_stream = new std::ifstream(configFile.c_str());
100 if(!m_stream->is_open()) {
101 std::cout << "Error opening config file \"" << configFile << "\"\n";
105 std::string Parser::nextToken(TokenType &type) {
106 std::ifstream &stream = *m_stream;
108 skipWhitespace();
110 if(stream.eof()) {
111 type = END_OF_FILE;
112 return "";
115 if(stream.peek() == '#') {
116 std::string line;
117 std::getline(stream, line);
118 return nextToken(type);
120 else if(stream.peek() == '"') {
121 stream.get(); // skip "
123 std::string word;
124 while(stream.peek() != '"') {
125 word += stream.get();
128 stream.get(); // skip "
130 type = QUOTED_WORD;
131 return word;
133 else if(std::isalnum(stream.peek())) {
134 std::string word;
135 while(std::isalnum(stream.peek())) {
136 word += stream.get();
139 type = WORD;
140 return word;
142 else if(stream.peek() == '+') {
143 stream.get(); // skip '+'
144 if(stream.peek() == '=') {
145 stream.get(); // skip '='
146 type = SYMBOL;
147 return "+=";
150 std::string rest;
151 stream >> rest;
153 throw Common::ParsingException(Common::StreamAsString()
154 << "Unrecognized token: \"+" << rest << "\"");
156 else {
157 std::string token;
158 token += stream.get();
160 type = SYMBOL;
161 return token;
165 std::string Parser::expectNextToken(TokenType expected) {
166 TokenType actual;
167 std::string token = nextToken(actual);
169 if(actual != expected) {
170 throw Common::ParsingException(Common::StreamAsString()
171 << "Expected " << nameOf(expected) << " token, found " << nameOf(actual)
172 << " token: \"" << token << "\"");
175 return token;
178 void Parser::expectNextSymbol(const std::string &symbol) {
179 std::string s = expectNextToken(SYMBOL);
180 if(symbol != s) {
181 throw Common::ParsingException(Common::StreamAsString()
182 << "Expected token \"" << symbol << "\", got \"" << s << "\"");
186 void Parser::skipWhitespace() {
187 std::ifstream &stream = *m_stream;
189 while(!stream.fail() && std::isspace(stream.peek())) {
190 stream.get();
194 void Parser::closeFile() {
195 delete m_stream;
196 m_stream = NULL;
199 const char *Parser::nameOf(TokenType type) const {
200 static const char *name[] = {
201 "WORD",
202 "QUOTED_WORD",
203 "SYMBOL",
204 "END_OF_FILE"
207 return name[type];
210 } // namespace Config
211 } // namespace Monitor