00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <sstream>
00018 #include <stdexcept>
00019 #include <tinygettext/tinygettext.hpp>
00020 #include <physfs.h>
00021
00022 #include "lisp/lisp.hpp"
00023 #include "lisp/parser.hpp"
00024 #include "util/obstackpp.hpp"
00025 #include "physfs/ifile_stream.hpp"
00026 #include "physfs/ifile_streambuf.hpp"
00027 #include "supertux/globals.hpp"
00028
00029 #include "supertux/gameconfig.hpp"
00030
00031 namespace lisp {
00032
00033 Parser::Parser(bool translate) :
00034 lexer(0),
00035 filename(),
00036 dictionary_manager(0),
00037 dictionary(0),
00038 token(),
00039 obst()
00040 {
00041 if(translate) {
00042 dictionary_manager = new tinygettext::DictionaryManager();
00043 dictionary_manager->set_charset("UTF-8");
00044 if (g_config && (g_config->locale != ""))
00045 dictionary_manager->set_language(tinygettext::Language::from_name(g_config->locale));
00046 }
00047
00048 obstack_init(&obst);
00049 }
00050
00051 Parser::~Parser()
00052 {
00053 obstack_free(&obst, NULL);
00054 delete lexer;
00055 delete dictionary_manager;
00056 }
00057
00058 static std::string dirname(const std::string& filename)
00059 {
00060 std::string::size_type p = filename.find_last_of('/');
00061 if(p == std::string::npos)
00062 return "";
00063
00064 return filename.substr(0, p+1);
00065 }
00066
00067 const Lisp*
00068 Parser::parse(const std::string& filename)
00069 {
00070 IFileStreambuf ins(filename);
00071 std::istream in(&ins);
00072
00073 if(!in.good()) {
00074 std::stringstream msg;
00075 msg << "Parser problem: Couldn't open file '" << filename << "'.";
00076 throw std::runtime_error(msg.str());
00077 }
00078
00079 if(dictionary_manager) {
00080 std::string rel_dir = dirname (filename);
00081 char **searchpath = PHYSFS_getSearchPath();
00082 for(char** i = searchpath; *i != NULL; i++)
00083 {
00084 std::string abs_dir = std::string (*i) + PHYSFS_getDirSeparator () + rel_dir;
00085 dictionary_manager->add_directory (abs_dir);
00086 }
00087 dictionary = & (dictionary_manager->get_dictionary());
00088 }
00089
00090 return parse(in, filename);
00091 }
00092
00093 const Lisp*
00094 Parser::parse(std::istream& stream, const std::string& sourcename)
00095 {
00096 delete lexer;
00097 lexer = new Lexer(stream);
00098
00099 this->filename = sourcename;
00100 token = lexer->getNextToken();
00101
00102 Lisp* result = new(obst) Lisp(Lisp::TYPE_CONS);
00103 result->v.cons.car = read();
00104 result->v.cons.cdr = 0;
00105
00106 delete lexer;
00107 lexer = 0;
00108
00109 return result;
00110 }
00111
00112 void
00113 Parser::parse_error(const char* msg) const
00114 {
00115 std::stringstream emsg;
00116 emsg << "Parse Error at '" << filename << "' line " << lexer->getLineNumber()
00117 << ": " << msg;
00118 throw std::runtime_error(emsg.str());
00119 }
00120
00121 const Lisp*
00122 Parser::read()
00123 {
00124 Lisp* result;
00125 switch(token) {
00126 case Lexer::TOKEN_EOF: {
00127 parse_error("Unexpected EOF.");
00128 }
00129 case Lexer::TOKEN_CLOSE_PAREN: {
00130 parse_error("Unexpected ')'.");
00131 }
00132 case Lexer::TOKEN_OPEN_PAREN: {
00133 result = new(obst) Lisp(Lisp::TYPE_CONS);
00134
00135 token = lexer->getNextToken();
00136 if(token == Lexer::TOKEN_CLOSE_PAREN) {
00137 result->v.cons.car = 0;
00138 result->v.cons.cdr = 0;
00139 break;
00140 }
00141
00142 if(token == Lexer::TOKEN_SYMBOL &&
00143 strcmp(lexer->getString(), "_") == 0) {
00144
00145 token = lexer->getNextToken();
00146 if(token != Lexer::TOKEN_STRING)
00147 parse_error("Expected string after '(_'");
00148
00149 result = new(obst) Lisp(Lisp::TYPE_STRING);
00150 if(dictionary) {
00151 std::string translation = dictionary->translate(lexer->getString());
00152 result->v.string = new(obst) char[translation.size()+1];
00153 memcpy(result->v.string, translation.c_str(), translation.size()+1);
00154 } else {
00155 size_t len = strlen(lexer->getString()) + 1;
00156 result->v.string = new(obst) char[len];
00157 memcpy(result->v.string, lexer->getString(), len);
00158 }
00159 token = lexer->getNextToken();
00160 if(token != Lexer::TOKEN_CLOSE_PAREN)
00161 parse_error("Expected ')' after '(_ string'");
00162 break;
00163 }
00164
00165 Lisp* cur = result;
00166 do {
00167 cur->v.cons.car = read();
00168 if(token == Lexer::TOKEN_CLOSE_PAREN) {
00169 cur->v.cons.cdr = 0;
00170 break;
00171 }
00172 Lisp *newcur = new(obst) Lisp(Lisp::TYPE_CONS);
00173 cur->v.cons.cdr = newcur;
00174 cur = newcur;
00175 } while(1);
00176
00177 break;
00178 }
00179 case Lexer::TOKEN_SYMBOL: {
00180 result = new(obst) Lisp(Lisp::TYPE_SYMBOL);
00181 size_t len = strlen(lexer->getString()) + 1;
00182 result->v.string = new(obst) char[len];
00183 memcpy(result->v.string, lexer->getString(), len);
00184 break;
00185 }
00186 case Lexer::TOKEN_STRING: {
00187 result = new(obst) Lisp(Lisp::TYPE_STRING);
00188 size_t len = strlen(lexer->getString()) + 1;
00189 result->v.string = new(obst) char[len];
00190 memcpy(result->v.string, lexer->getString(), len);
00191 break;
00192 }
00193 case Lexer::TOKEN_INTEGER:
00194 result = new(obst) Lisp(Lisp::TYPE_INTEGER);
00195 sscanf(lexer->getString(), "%d", &result->v.integer);
00196 break;
00197 case Lexer::TOKEN_REAL:
00198 result = new(obst) Lisp(Lisp::TYPE_REAL);
00199 sscanf(lexer->getString(), "%f", &result->v.real);
00200 break;
00201 case Lexer::TOKEN_TRUE:
00202 result = new(obst) Lisp(Lisp::TYPE_BOOLEAN);
00203 result->v.boolean = true;
00204 break;
00205 case Lexer::TOKEN_FALSE:
00206 result = new(obst) Lisp(Lisp::TYPE_BOOLEAN);
00207 result->v.boolean = false;
00208 break;
00209
00210 default:
00211
00212 result = NULL;
00213 assert(false);
00214 }
00215
00216 token = lexer->getNextToken();
00217 return result;
00218 }
00219
00220 }
00221
00222