Continued working on configuration system.
[aesalon.git] / monitor / src / config / Parser.cpp
blob8415292db0e5b8eddff85aff6aa84565cb47d5e0
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>
17 #include <sys/stat.h>
18 #include <stdlib.h>
20 #include "config/Parser.h"
21 #include "common/ParsingException.h"
22 #include "common/StreamAsString.h"
23 #include "common/PathSanitizer.h"
24 #include "config/ConcreteVault.h"
26 namespace Monitor {
27 namespace Config {
29 void Parser::parse(ConcreteVault *vault, const std::string &configFile) {
30 std::string currentModule;
32 std::vector<std::string> paths;
33 vault->get("PATH", paths);
35 openFile(Common::PathSanitizer::sanitize(configFile, paths));
37 if(!m_stream->is_open()) return;
39 for(;;) {
40 TokenType tokenType;
41 std::string token = nextToken(tokenType);
42 if(tokenType == END_OF_FILE) break;
44 //std::cout << '"' << token << '"' << " of type " << nameOf(tokenType) << std::endl;
46 if(tokenType == WORD && token == "include") {
47 Parser().parse(vault, expectNextToken(QUOTED_WORD));
48 expectNextSymbol(";");
50 else if(tokenType == WORD && token == "module") {
51 currentModule = expectNextToken(WORD);
52 expectNextSymbol("{");
54 else if(tokenType == SYMBOL && token == "}") {
55 if(currentModule != "") {
56 currentModule = "";
58 else throw Common::ParsingException("Extra \"}\"");
60 else if(tokenType == WORD && token == "use") {
61 /*std::cout << "Parser: Using module \"" << expectNextToken(WORD) << "\"\n";*/
62 std::string moduleName = expectNextToken(WORD);
64 Parser().parse(vault, Common::PathSanitizer::sanitize(moduleName + "/module.conf", paths));
66 expectNextSymbol(";");
68 else if(tokenType == WORD) {
69 std::string op = expectNextToken(SYMBOL);
71 if(op == "=") vault->clear(token);
73 do {
74 TokenType nextType;
75 std::string next = nextToken(nextType);
77 //if(nextType == SYMBOL && next == ";") break;
79 if(nextType == WORD || nextType == QUOTED_WORD) {
80 if(currentModule != "") vault->set(
81 Common::StreamAsString() << currentModule << ":" << token, next);
83 else vault->set(token, next);
85 /*std::cout << "Set \"" << currentModule << "::" << token << "\" to \""
86 << next << "\" with operator " << op << std::endl;*/
88 else throw Common::ParsingException("Invalid RHS");
90 std::string sym = expectNextToken(SYMBOL);
91 if(sym == ";") break;
92 else if(sym == ",") {}
93 else {
94 throw Common::ParsingException(Common::StreamAsString()
95 << "Expected \",\" or \";\", got \"" << sym << "\"");
97 } while(true);
99 else {
100 throw Common::ParsingException(Common::StreamAsString()
101 << "Syntax error at token \"" << token << "\"");
103 //std::cout << "\"" << token << "\"\n";
106 closeFile();
109 void Parser::openFile(const std::string &configFile) {
110 m_stream = new std::ifstream(configFile.c_str());
113 std::string Parser::nextToken(TokenType &type) {
114 std::ifstream &stream = *m_stream;
116 skipWhitespace();
118 if(stream.eof()) {
119 type = END_OF_FILE;
120 return "";
123 if(stream.peek() == '#') {
124 std::string line;
125 std::getline(stream, line);
126 return nextToken(type);
128 else if(stream.peek() == '"') {
129 stream.get(); // skip "
131 std::string word;
132 while(stream.peek() != '"') {
133 word += stream.get();
136 stream.get(); // skip "
138 type = QUOTED_WORD;
139 return word;
141 else if(std::isalnum(stream.peek())) {
142 std::string word;
143 while(std::isalnum(stream.peek())) {
144 word += stream.get();
147 type = WORD;
148 return word;
150 else if(stream.peek() == '+') {
151 stream.get(); // skip '+'
152 if(stream.peek() == '=') {
153 stream.get(); // skip '='
154 type = SYMBOL;
155 return "+=";
158 std::string rest;
159 stream >> rest;
161 throw Common::ParsingException(Common::StreamAsString()
162 << "Unrecognized token: \"+" << rest << "\"");
164 else {
165 std::string token;
166 token += stream.get();
168 type = SYMBOL;
169 return token;
173 std::string Parser::expectNextToken(TokenType expected) {
174 TokenType actual;
175 std::string token = nextToken(actual);
177 if(actual != expected) {
178 throw Common::ParsingException(Common::StreamAsString()
179 << "Expected " << nameOf(expected) << " token, found " << nameOf(actual)
180 << " token: \"" << token << "\"");
183 return token;
186 void Parser::expectNextSymbol(const std::string &symbol) {
187 std::string s = expectNextToken(SYMBOL);
188 if(symbol != s) {
189 throw Common::ParsingException(Common::StreamAsString()
190 << "Expected token \"" << symbol << "\", got \"" << s << "\"");
194 void Parser::skipWhitespace() {
195 std::ifstream &stream = *m_stream;
197 while(!stream.fail() && std::isspace(stream.peek())) {
198 stream.get();
202 void Parser::closeFile() {
203 delete m_stream;
204 m_stream = NULL;
207 const char *Parser::nameOf(TokenType type) const {
208 static const char *name[] = {
209 "WORD",
210 "QUOTED_WORD",
211 "SYMBOL",
212 "END_OF_FILE"
215 return name[type];
218 } // namespace Config
219 } // namespace Monitor