src/lisp/parser.cpp

Go to the documentation of this file.
00001 //  SuperTux
00002 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
00003 //
00004 //  This program is free software: you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation, either version 3 of the License, or
00007 //  (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
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         // evaluate translation function (_ str) in place here
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       // this should never happen
00212       result = NULL;
00213       assert(false);
00214   }
00215 
00216   token = lexer->getNextToken();
00217   return result;
00218 }
00219 
00220 } // end of namespace lisp
00221 
00222 /* EOF */

Generated on Mon Jun 9 03:38:18 2014 for SuperTux by  doxygen 1.5.1