2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <tinygettext/tinygettext.hpp>
21 #include "lisp/lisp.hpp"
22 #include "lisp/parser.hpp"
23 #include "util/obstackpp.hpp"
24 #include "physfs/ifile_stream.hpp"
25 #include "physfs/ifile_streambuf.hpp"
26 #include "supertux/globals.hpp"
28 #include "supertux/gameconfig.hpp"
32 Parser::Parser(bool translate) :
35 dictionary_manager(0),
41 dictionary_manager = new tinygettext::DictionaryManager();
42 dictionary_manager->set_charset("UTF-8");
43 if (g_config && (g_config->locale != ""))
44 dictionary_manager->set_language(tinygettext::Language::from_name(g_config->locale));
52 obstack_free(&obst, NULL);
54 delete dictionary_manager;
57 static std::string dirname(const std::string& filename)
59 std::string::size_type p = filename.find_last_of('/');
60 if(p == std::string::npos)
63 return filename.substr(0, p+1);
67 Parser::parse(const std::string& filename)
69 IFileStreambuf ins(filename);
70 std::istream in(&ins);
73 std::stringstream msg;
74 msg << "Parser problem: Couldn't open file '" << filename << "'.";
75 throw std::runtime_error(msg.str());
78 if(dictionary_manager) {
79 dictionary_manager->add_directory(dirname(filename));
80 dictionary = & (dictionary_manager->get_dictionary());
83 return parse(in, filename);
87 Parser::parse(std::istream& stream, const std::string& sourcename)
90 lexer = new Lexer(stream);
92 this->filename = sourcename;
93 token = lexer->getNextToken();
95 Lisp* result = new(obst) Lisp(Lisp::TYPE_CONS);
96 result->v.cons.car = read();
97 result->v.cons.cdr = 0;
106 Parser::parse_error(const char* msg) const
108 std::stringstream emsg;
109 emsg << "Parse Error at '" << filename << "' line " << lexer->getLineNumber()
111 throw std::runtime_error(emsg.str());
119 case Lexer::TOKEN_EOF: {
120 parse_error("Unexpected EOF.");
122 case Lexer::TOKEN_CLOSE_PAREN: {
123 parse_error("Unexpected ')'.");
125 case Lexer::TOKEN_OPEN_PAREN: {
126 result = new(obst) Lisp(Lisp::TYPE_CONS);
128 token = lexer->getNextToken();
129 if(token == Lexer::TOKEN_CLOSE_PAREN) {
130 result->v.cons.car = 0;
131 result->v.cons.cdr = 0;
135 if(token == Lexer::TOKEN_SYMBOL &&
136 strcmp(lexer->getString(), "_") == 0) {
137 // evaluate translation function (_ str) in place here
138 token = lexer->getNextToken();
139 if(token != Lexer::TOKEN_STRING)
140 parse_error("Expected string after '(_'");
142 result = new(obst) Lisp(Lisp::TYPE_STRING);
144 std::string translation = dictionary->translate(lexer->getString());
145 result->v.string = new(obst) char[translation.size()+1];
146 memcpy(result->v.string, translation.c_str(), translation.size()+1);
148 size_t len = strlen(lexer->getString()) + 1;
149 result->v.string = new(obst) char[len];
150 memcpy(result->v.string, lexer->getString(), len);
152 token = lexer->getNextToken();
153 if(token != Lexer::TOKEN_CLOSE_PAREN)
154 parse_error("Expected ')' after '(_ string'");
160 cur->v.cons.car = read();
161 if(token == Lexer::TOKEN_CLOSE_PAREN) {
165 Lisp *newcur = new(obst) Lisp(Lisp::TYPE_CONS);
166 cur->v.cons.cdr = newcur;
172 case Lexer::TOKEN_SYMBOL: {
173 result = new(obst) Lisp(Lisp::TYPE_SYMBOL);
174 size_t len = strlen(lexer->getString()) + 1;
175 result->v.string = new(obst) char[len];
176 memcpy(result->v.string, lexer->getString(), len);
179 case Lexer::TOKEN_STRING: {
180 result = new(obst) Lisp(Lisp::TYPE_STRING);
181 size_t len = strlen(lexer->getString()) + 1;
182 result->v.string = new(obst) char[len];
183 memcpy(result->v.string, lexer->getString(), len);
186 case Lexer::TOKEN_INTEGER:
187 result = new(obst) Lisp(Lisp::TYPE_INTEGER);
188 sscanf(lexer->getString(), "%d", &result->v.integer);
190 case Lexer::TOKEN_REAL:
191 result = new(obst) Lisp(Lisp::TYPE_REAL);
192 sscanf(lexer->getString(), "%f", &result->v.real);
194 case Lexer::TOKEN_TRUE:
195 result = new(obst) Lisp(Lisp::TYPE_BOOLEAN);
196 result->v.boolean = true;
198 case Lexer::TOKEN_FALSE:
199 result = new(obst) Lisp(Lisp::TYPE_BOOLEAN);
200 result->v.boolean = false;
204 // this should never happen
209 token = lexer->getNextToken();
213 } // end of namespace lisp