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
&& token
== "output") {
75 std::string spec
= expectNextToken(QUOTED_WORD
);
77 vault
->set("::output", spec
);
79 expectNextSymbol(";");
81 else if(tokenType
== WORD
) {
82 std::string op
= expectNextToken(SYMBOL
);
84 if(op
== "=") vault
->clear(token
);
88 std::string next
= nextToken(nextType
);
90 //if(nextType == SYMBOL && next == ";") break;
92 if(nextType
== WORD
|| nextType
== QUOTED_WORD
) {
93 if(currentModule
!= "") vault
->set(
94 Util::StreamAsString() << currentModule
<< ":" << token
, next
);
96 else vault
->set(token
, next
);
98 /*std::cout << "Set \"" << currentModule << "::" << token << "\" to \""
99 << next << "\" with operator " << op << std::endl;*/
101 else Message(Fatal
, "Invalid RHS");
103 std::string sym
= expectNextToken(SYMBOL
);
104 if(sym
== ";") break;
105 else if(sym
== ",") {}
107 Message(Fatal
, "Expected \",\" or \";\", got \"" << sym
<< "\"");
112 Message(Fatal
, "Syntax error at token \"" << token
<< "\"");
114 //std::cout << "\"" << token << "\"\n";
120 void Parser::parseDirectory(Vault
*vault
, const std::string
&directory
) {
121 DIR *dir
= opendir(directory
.c_str());
122 if(dir
== NULL
) return;
124 vault
->clear("::directory");
125 vault
->set("::directory", directory
);
129 while((dent
= readdir(dir
)) != NULL
) {
130 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, "..")) continue;
131 std::string possible
= directory
+ "/";
132 possible
+= dent
->d_name
;
135 if(stat(possible
.c_str(), &s
) != 0) {
136 /* Cannot stat file, probably don't have access permissions. */
142 if(S_ISDIR(s
.st_mode
)) {
143 parse(vault
, possible
+ AesalonModuleConfigFileName
);
144 std::string path
= dent
->d_name
;
147 vault
->set(path
, possible
);
154 void Parser::openFile(const std::string
&configFile
) {
155 m_stream
= new std::ifstream(configFile
.c_str());
158 std::string
Parser::nextToken(TokenType
&type
) {
159 std::ifstream
&stream
= *m_stream
;
168 if(stream
.peek() == '#') {
170 std::getline(stream
, line
);
171 return nextToken(type
);
173 else if(stream
.peek() == '"') {
174 stream
.get(); // skip "
177 while(stream
.peek() != '"') {
178 word
+= stream
.get();
181 stream
.get(); // skip "
186 else if(std::isalnum(stream
.peek())) {
188 while(std::isalnum(stream
.peek())) {
189 word
+= stream
.get();
195 else if(stream
.peek() == '+') {
196 stream
.get(); // skip '+'
197 if(stream
.peek() == '=') {
198 stream
.get(); // skip '='
206 Message(Fatal
, "Unrecognized token: \"+" << rest
<< "\"");
207 return ""; // Never reached.
211 token
+= stream
.get();
218 std::string
Parser::expectNextToken(TokenType expected
) {
220 std::string token
= nextToken(actual
);
222 if(actual
!= expected
) {
224 "Expected " << nameOf(expected
) << " token, found " << nameOf(actual
)
225 << " token: \"" << token
<< "\"");
231 void Parser::expectNextSymbol(const std::string
&symbol
) {
232 std::string s
= expectNextToken(SYMBOL
);
234 Message(Fatal
, "Expected token \"" << symbol
<< "\", got \"" << s
<< "\"");
238 void Parser::skipWhitespace() {
239 std::ifstream
&stream
= *m_stream
;
241 while(!stream
.fail() && std::isspace(stream
.peek())) {
246 void Parser::closeFile() {
251 const char *Parser::nameOf(TokenType type
) const {
252 static const char *name
[] = {
262 } // namespace Config