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
17 #include <sys/types.h>
23 #include "config/Parser.h"
24 #include "common/ParsingException.h"
25 #include "common/StreamAsString.h"
26 #include "common/PathSanitizer.h"
27 #include "config/ConcreteVault.h"
28 #include "common/Config.h"
33 void Parser::parse(ConcreteVault
*vault
, const std::string
&configFile
) {
34 std::string currentModule
;
38 if(!m_stream
->is_open()) return;
42 std::string token
= nextToken(tokenType
);
43 if(tokenType
== END_OF_FILE
) break;
45 //std::cout << '"' << token << '"' << " of type " << nameOf(tokenType) << std::endl;
47 if(tokenType
== WORD
&& token
== "include") {
48 Parser().parse(vault
, expectNextToken(QUOTED_WORD
));
49 expectNextSymbol(";");
51 else if(tokenType
== WORD
&& token
== "module") {
52 currentModule
= expectNextToken(WORD
);
53 expectNextSymbol("{");
55 else if(tokenType
== WORD
&& token
== "search") {
56 char *dirpath
= strdup(configFile
.c_str());
57 dirpath
= dirname(dirpath
);
59 std::string dirname
= expectNextToken(QUOTED_WORD
);
61 if(dirname
[0] != '/' && dirname
[0] != '~') {
62 dirname
= Common::StreamAsString() << dirpath
<< "/" << dirname
;
65 Parser().parseDirectory(vault
, dirname
);
67 expectNextSymbol(";");
70 else if(tokenType
== SYMBOL
&& token
== "}") {
71 if(currentModule
!= "") {
74 else throw Common::ParsingException("Extra \"}\"");
76 else if(tokenType
== WORD
&& token
== "use") {
77 /*std::cout << "Parser: Using module \"" << expectNextToken(WORD) << "\"\n";*/
78 std::string moduleName
= expectNextToken(WORD
);
80 vault
->set("::modules", moduleName
);
82 expectNextSymbol(";");
84 else if(tokenType
== WORD
) {
85 std::string op
= expectNextToken(SYMBOL
);
87 if(op
== "=") vault
->clear(token
);
91 std::string next
= nextToken(nextType
);
93 //if(nextType == SYMBOL && next == ";") break;
95 if(nextType
== WORD
|| nextType
== QUOTED_WORD
) {
96 if(currentModule
!= "") vault
->set(
97 Common::StreamAsString() << currentModule
<< ":" << token
, next
);
99 else vault
->set(token
, next
);
101 /*std::cout << "Set \"" << currentModule << "::" << token << "\" to \""
102 << next << "\" with operator " << op << std::endl;*/
104 else throw Common::ParsingException("Invalid RHS");
106 std::string sym
= expectNextToken(SYMBOL
);
107 if(sym
== ";") break;
108 else if(sym
== ",") {}
110 throw Common::ParsingException(Common::StreamAsString()
111 << "Expected \",\" or \";\", got \"" << sym
<< "\"");
116 throw Common::ParsingException(Common::StreamAsString()
117 << "Syntax error at token \"" << token
<< "\"");
119 //std::cout << "\"" << token << "\"\n";
125 void Parser::parseDirectory(ConcreteVault
*vault
, const std::string
&directory
) {
126 DIR *dir
= opendir(directory
.c_str());
127 if(dir
== NULL
) return;
129 vault
->clear("::directory");
130 vault
->set("::directory", directory
);
134 while((dent
= readdir(dir
)) != NULL
) {
135 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, "..")) continue;
136 std::string possible
= directory
+ "/";
137 possible
+= dent
->d_name
;
140 if(stat(possible
.c_str(), &s
) != 0) {
141 /* Cannot stat file, probably don't have access permissions. */
147 if(S_ISDIR(s
.st_mode
)) {
148 parse(vault
, possible
+ AesalonModuleConfigFileName
);
149 std::string path
= dent
->d_name
;
152 vault
->set(path
, possible
);
159 void Parser::openFile(const std::string
&configFile
) {
160 m_stream
= new std::ifstream(configFile
.c_str());
163 std::string
Parser::nextToken(TokenType
&type
) {
164 std::ifstream
&stream
= *m_stream
;
173 if(stream
.peek() == '#') {
175 std::getline(stream
, line
);
176 return nextToken(type
);
178 else if(stream
.peek() == '"') {
179 stream
.get(); // skip "
182 while(stream
.peek() != '"') {
183 word
+= stream
.get();
186 stream
.get(); // skip "
191 else if(std::isalnum(stream
.peek())) {
193 while(std::isalnum(stream
.peek())) {
194 word
+= stream
.get();
200 else if(stream
.peek() == '+') {
201 stream
.get(); // skip '+'
202 if(stream
.peek() == '=') {
203 stream
.get(); // skip '='
211 throw Common::ParsingException(Common::StreamAsString()
212 << "Unrecognized token: \"+" << rest
<< "\"");
216 token
+= stream
.get();
223 std::string
Parser::expectNextToken(TokenType expected
) {
225 std::string token
= nextToken(actual
);
227 if(actual
!= expected
) {
228 throw Common::ParsingException(Common::StreamAsString()
229 << "Expected " << nameOf(expected
) << " token, found " << nameOf(actual
)
230 << " token: \"" << token
<< "\"");
236 void Parser::expectNextSymbol(const std::string
&symbol
) {
237 std::string s
= expectNextToken(SYMBOL
);
239 throw Common::ParsingException(Common::StreamAsString()
240 << "Expected token \"" << symbol
<< "\", got \"" << s
<< "\"");
244 void Parser::skipWhitespace() {
245 std::ifstream
&stream
= *m_stream
;
247 while(!stream
.fail() && std::isspace(stream
.peek())) {
252 void Parser::closeFile() {
257 const char *Parser::nameOf(TokenType type
) const {
258 static const char *name
[] = {
268 } // namespace Config
269 } // namespace Monitor