1 /** Aesalon, a tool to visualize program behaviour in real time.
2 Copyright (C) 2009-2011, Aesalon development team.
4 Aesalon is distributed under the terms of the GNU GPLv3. See
5 the included file LICENSE for more information.
7 @file src/config/Parser.cpp
16 #include "config/Parser.h"
17 #include "util/StreamAsString.h"
18 #include "util/MessageSystem.h"
23 void Parser::parse(Vault
*vault
, const std::string
&configFile
) {
24 std::string currentModule
;
28 if(!m_stream
->is_open()) return;
32 std::string token
= nextToken(tokenType
);
33 if(tokenType
== END_OF_FILE
) break;
35 //std::cout << '"' << token << '"' << " of type " << nameOf(tokenType) << std::endl;
37 if(tokenType
== WORD
&& token
== "include") {
38 Parser().parse(vault
, expectNextToken(QUOTED_WORD
));
39 expectNextSymbol(";");
41 else if(tokenType
== WORD
&& token
== "module") {
42 currentModule
= expectNextToken(WORD
);
43 expectNextSymbol("{");
45 else if(tokenType
== WORD
&& token
== "search") {
46 char *dirpath
= strdup(configFile
.c_str());
47 dirpath
= dirname(dirpath
);
49 std::string dirname
= expectNextToken(QUOTED_WORD
);
51 if(dirname
[0] != '/' && dirname
[0] != '~') {
52 dirname
= Util::StreamAsString() << dirpath
<< "/" << dirname
;
55 Parser().parseDirectory(vault
, dirname
);
57 expectNextSymbol(";");
60 else if(tokenType
== SYMBOL
&& token
== "}") {
61 if(currentModule
!= "") {
64 else Message(Fatal
, "Extra \"}\" in config file.");
66 else if(tokenType
== WORD
&& token
== "use") {
67 /*std::cout << "Parser: Using module \"" << expectNextToken(WORD) << "\"\n";*/
68 std::string moduleName
= expectNextToken(WORD
);
70 vault
->set("::modules", moduleName
);
72 expectNextSymbol(";");
74 else if(tokenType
== WORD
) {
75 std::string op
= expectNextToken(SYMBOL
);
77 if(op
== "=") vault
->clear(token
);
81 std::string next
= nextToken(nextType
);
83 //if(nextType == SYMBOL && next == ";") break;
85 if(nextType
== WORD
|| nextType
== QUOTED_WORD
) {
86 if(currentModule
!= "") vault
->set(
87 Util::StreamAsString() << currentModule
<< ":" << token
, next
);
89 else vault
->set(token
, next
);
91 /*std::cout << "Set \"" << currentModule << "::" << token << "\" to \""
92 << next << "\" with operator " << op << std::endl;*/
94 else Message(Fatal
, "Invalid RHS");
96 std::string sym
= expectNextToken(SYMBOL
);
98 else if(sym
== ",") {}
100 Message(Fatal
, "Expected \",\" or \";\", got \"" << sym
<< "\"");
105 Message(Fatal
, "Syntax error at token \"" << token
<< "\"");
107 //std::cout << "\"" << token << "\"\n";
113 void Parser::parseDirectory(Vault
*vault
, const std::string
&directory
) {
114 DIR *dir
= opendir(directory
.c_str());
115 if(dir
== NULL
) return;
117 vault
->clear("::directory");
118 vault
->set("::directory", directory
);
122 while((dent
= readdir(dir
)) != NULL
) {
123 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, "..")) continue;
124 std::string possible
= directory
+ "/";
125 possible
+= dent
->d_name
;
128 if(stat(possible
.c_str(), &s
) != 0) {
129 /* Cannot stat file, probably don't have access permissions. */
135 if(S_ISDIR(s
.st_mode
)) {
136 parse(vault
, possible
+ AesalonModuleConfigFileName
);
137 std::string path
= dent
->d_name
;
140 vault
->set(path
, possible
);
147 void Parser::openFile(const std::string
&configFile
) {
148 m_stream
= new std::ifstream(configFile
.c_str());
151 std::string
Parser::nextToken(TokenType
&type
) {
152 std::ifstream
&stream
= *m_stream
;
161 if(stream
.peek() == '#') {
163 std::getline(stream
, line
);
164 return nextToken(type
);
166 else if(stream
.peek() == '"') {
167 stream
.get(); // skip "
170 while(stream
.peek() != '"') {
171 word
+= stream
.get();
174 stream
.get(); // skip "
179 else if(std::isalnum(stream
.peek())) {
181 while(std::isalnum(stream
.peek())) {
182 word
+= stream
.get();
188 else if(stream
.peek() == '+') {
189 stream
.get(); // skip '+'
190 if(stream
.peek() == '=') {
191 stream
.get(); // skip '='
199 Message(Fatal
, "Unrecognized token: \"+" << rest
<< "\"");
200 return ""; // Never reached.
204 token
+= stream
.get();
211 std::string
Parser::expectNextToken(TokenType expected
) {
213 std::string token
= nextToken(actual
);
215 if(actual
!= expected
) {
217 "Expected " << nameOf(expected
) << " token, found " << nameOf(actual
)
218 << " token: \"" << token
<< "\"");
224 void Parser::expectNextSymbol(const std::string
&symbol
) {
225 std::string s
= expectNextToken(SYMBOL
);
227 Message(Fatal
, "Expected token \"" << symbol
<< "\", got \"" << s
<< "\"");
231 void Parser::skipWhitespace() {
232 std::ifstream
&stream
= *m_stream
;
234 while(!stream
.fail() && std::isspace(stream
.peek())) {
239 void Parser::closeFile() {
244 const char *Parser::nameOf(TokenType type
) const {
245 static const char *name
[] = {
255 } // namespace Config