lisp/parser.cpp: Remove a forgotten debug message.
[supertux.git] / src / lisp / parser.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
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.
8 //
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.
13 //
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/>.
16
17 #include <sstream>
18 #include <stdexcept>
19 #include <tinygettext/tinygettext.hpp>
20 #include <physfs.h>
21
22 #include "lisp/lisp.hpp"
23 #include "lisp/parser.hpp"
24 #include "util/obstackpp.hpp"
25 #include "physfs/ifile_stream.hpp"
26 #include "physfs/ifile_streambuf.hpp"
27 #include "supertux/globals.hpp"
28
29 #include "supertux/gameconfig.hpp"
30
31 namespace lisp {
32
33 Parser::Parser(bool translate) :
34   lexer(0), 
35   filename(),
36   dictionary_manager(0), 
37   dictionary(0),
38   token(),
39   obst()
40 {
41   if(translate) {
42     dictionary_manager = new tinygettext::DictionaryManager();
43     dictionary_manager->set_charset("UTF-8");
44     if (g_config && (g_config->locale != "")) 
45       dictionary_manager->set_language(tinygettext::Language::from_name(g_config->locale));
46   }
47
48   obstack_init(&obst);
49 }
50
51 Parser::~Parser()
52 {
53   obstack_free(&obst, NULL);
54   delete lexer;
55   delete dictionary_manager;
56 }
57
58 static std::string dirname(const std::string& filename)
59 {
60   std::string::size_type p = filename.find_last_of('/');
61   if(p == std::string::npos)
62     return "";
63
64   return filename.substr(0, p+1);
65 }
66
67 const Lisp*
68 Parser::parse(const std::string& filename)
69 {
70   IFileStreambuf ins(filename);
71   std::istream in(&ins);
72
73   if(!in.good()) {
74     std::stringstream msg;
75     msg << "Parser problem: Couldn't open file '" << filename << "'.";
76     throw std::runtime_error(msg.str());
77   }
78
79   if(dictionary_manager) {
80     std::string rel_dir = dirname (filename);
81     char **searchpath = PHYSFS_getSearchPath();
82     for(char** i = searchpath; *i != NULL; i++)
83     {
84       std::string abs_dir = std::string (*i) + PHYSFS_getDirSeparator () + rel_dir;
85       dictionary_manager->add_directory (abs_dir);
86     }
87     dictionary = & (dictionary_manager->get_dictionary());
88   }
89
90   return parse(in, filename);
91 }
92
93 const Lisp*
94 Parser::parse(std::istream& stream, const std::string& sourcename)
95 {
96   delete lexer;
97   lexer = new Lexer(stream);
98
99   this->filename = sourcename;
100   token = lexer->getNextToken();
101
102   Lisp* result = new(obst) Lisp(Lisp::TYPE_CONS);
103   result->v.cons.car = read();
104   result->v.cons.cdr = 0;
105
106   delete lexer;
107   lexer = 0;
108
109   return result;
110 }
111
112 void
113 Parser::parse_error(const char* msg) const
114 {
115   std::stringstream emsg;
116   emsg << "Parse Error at '" << filename << "' line " << lexer->getLineNumber()
117        << ": " << msg;
118   throw std::runtime_error(emsg.str());
119 }
120
121 const Lisp*
122 Parser::read()
123 {
124   Lisp* result;
125   switch(token) {
126     case Lexer::TOKEN_EOF: {
127       parse_error("Unexpected EOF.");
128     }
129     case Lexer::TOKEN_CLOSE_PAREN: {
130       parse_error("Unexpected ')'.");
131     }
132     case Lexer::TOKEN_OPEN_PAREN: {
133       result = new(obst) Lisp(Lisp::TYPE_CONS);
134
135       token = lexer->getNextToken();
136       if(token == Lexer::TOKEN_CLOSE_PAREN) {
137         result->v.cons.car = 0;
138         result->v.cons.cdr = 0;
139         break;
140       }
141
142       if(token == Lexer::TOKEN_SYMBOL &&
143          strcmp(lexer->getString(), "_") == 0) {
144         // evaluate translation function (_ str) in place here
145         token = lexer->getNextToken();
146         if(token != Lexer::TOKEN_STRING)
147           parse_error("Expected string after '(_'");
148
149         result = new(obst) Lisp(Lisp::TYPE_STRING);
150         if(dictionary) {
151           std::string translation = dictionary->translate(lexer->getString());
152           result->v.string = new(obst) char[translation.size()+1];
153           memcpy(result->v.string, translation.c_str(), translation.size()+1);
154         } else {
155           size_t len = strlen(lexer->getString()) + 1;
156           result->v.string = new(obst) char[len];
157           memcpy(result->v.string, lexer->getString(), len);
158         }
159         token = lexer->getNextToken();
160         if(token != Lexer::TOKEN_CLOSE_PAREN)
161           parse_error("Expected ')' after '(_ string'");
162         break;
163       }
164
165       Lisp* cur = result;
166       do {
167         cur->v.cons.car = read();
168         if(token == Lexer::TOKEN_CLOSE_PAREN) {
169           cur->v.cons.cdr = 0;
170           break;
171         }
172         Lisp *newcur = new(obst) Lisp(Lisp::TYPE_CONS);
173         cur->v.cons.cdr = newcur;
174         cur = newcur;
175       } while(1);
176
177       break;
178     }
179     case Lexer::TOKEN_SYMBOL: {
180       result = new(obst) Lisp(Lisp::TYPE_SYMBOL);
181       size_t len = strlen(lexer->getString()) + 1;
182       result->v.string = new(obst) char[len];
183       memcpy(result->v.string, lexer->getString(), len);
184       break;
185     }
186     case Lexer::TOKEN_STRING: {
187       result = new(obst) Lisp(Lisp::TYPE_STRING);
188       size_t len = strlen(lexer->getString()) + 1;
189       result->v.string = new(obst) char[len];
190       memcpy(result->v.string, lexer->getString(), len);
191       break;
192     }
193     case Lexer::TOKEN_INTEGER:
194       result = new(obst) Lisp(Lisp::TYPE_INTEGER);
195       sscanf(lexer->getString(), "%d", &result->v.integer);
196       break;
197     case Lexer::TOKEN_REAL:
198       result = new(obst) Lisp(Lisp::TYPE_REAL);
199       sscanf(lexer->getString(), "%f", &result->v.real);
200       break;
201     case Lexer::TOKEN_TRUE:
202       result = new(obst) Lisp(Lisp::TYPE_BOOLEAN);
203       result->v.boolean = true;
204       break;
205     case Lexer::TOKEN_FALSE:
206       result = new(obst) Lisp(Lisp::TYPE_BOOLEAN);
207       result->v.boolean = false;
208       break;
209
210     default:
211       // this should never happen
212       result = NULL;
213       assert(false);
214   }
215
216   token = lexer->getNextToken();
217   return result;
218 }
219
220 } // end of namespace lisp
221
222 /* EOF */