X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Flisp%2Fparser.cpp;h=4f7697c42b2c47207fa31d52d43f626340b482d0;hb=5667d7e94d85f968ab914bc457edd689fc907253;hp=cd74886e2d1a42604b93a458a3286442cc6bd0c1;hpb=aeec9baba33ec63d2d0fdd97d961a53ec5c1541d;p=supertux.git diff --git a/src/lisp/parser.cpp b/src/lisp/parser.cpp index cd74886e2..4f7697c42 100644 --- a/src/lisp/parser.cpp +++ b/src/lisp/parser.cpp @@ -1,8 +1,7 @@ // $Id$ // -// TuxKart - a fun racing game with go-kart -// Copyright (C) 2004 Matthias Braun -// code in this file based on lispreader from Mark Probst +// SuperTux +// Copyright (C) 2006 Matthias Braun // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -25,10 +24,13 @@ #include #include -#include "tinygettext/tinygettext.h" -#include "parser.h" -#include "lisp.h" -#include "file_system.h" +#include "tinygettext/tinygettext.hpp" +#include "physfs/physfs_stream.hpp" +#include "parser.hpp" +#include "lisp.hpp" +#include "obstack/obstackpp.hpp" + +#include "gameconfig.hpp" namespace lisp { @@ -38,20 +40,35 @@ Parser::Parser(bool translate) { if(translate) { dictionary_manager = new TinyGetText::DictionaryManager(); - dictionary_manager->set_charset("ISO8859-1"); + dictionary_manager->set_charset("UTF-8"); + if (config && (config->locale != "")) dictionary_manager->set_language(config->locale); } + + obstack_init(&obst); } Parser::~Parser() { + obstack_free(&obst, NULL); delete lexer; delete dictionary_manager; } -Lisp* +static std::string dirname(const std::string& filename) +{ + std::string::size_type p = filename.find_last_of('/'); + if(p == std::string::npos) + return ""; + + return filename.substr(0, p+1); +} + +const Lisp* Parser::parse(const std::string& filename) { - std::ifstream in(filename.c_str()); + IFileStreambuf ins(filename); + std::istream in(&ins); + if(!in.good()) { std::stringstream msg; msg << "Parser problem: Couldn't open file '" << filename << "'."; @@ -59,50 +76,55 @@ Parser::parse(const std::string& filename) } if(dictionary_manager) { - dictionary_manager->add_directory(FileSystem::dirname(filename)); + dictionary_manager->add_directory(dirname(filename)); dictionary = & (dictionary_manager->get_dictionary()); } - - return parse(in); + + return parse(in, filename); } -Lisp* -Parser::parse(std::istream& stream) +const Lisp* +Parser::parse(std::istream& stream, const std::string& sourcename) { delete lexer; lexer = new Lexer(stream); + this->filename = sourcename; token = lexer->getNextToken(); - Lisp* result = new Lisp(Lisp::TYPE_CONS); + + Lisp* result = new(obst) Lisp(Lisp::TYPE_CONS); result->v.cons.car = read(); result->v.cons.cdr = 0; - + delete lexer; lexer = 0; - return result; + return result; +} + +void +Parser::parse_error(const char* msg) const +{ + std::stringstream emsg; + emsg << "Parse Error at '" << filename << "' line " << lexer->getLineNumber() + << ": " << msg; + throw std::runtime_error(emsg.str()); } -Lisp* +const Lisp* Parser::read() { Lisp* result; switch(token) { case Lexer::TOKEN_EOF: { - std::stringstream msg; - msg << "Parse Error at line " << lexer->getLineNumber() << ": " - << "Unexpected EOF."; - throw std::runtime_error(msg.str()); + parse_error("Unexpected EOF."); } case Lexer::TOKEN_CLOSE_PAREN: { - std::stringstream msg; - msg << "Parse Error at line " << lexer->getLineNumber() << ": " - << "Unexpected ')'."; - throw std::runtime_error(msg.str()); + parse_error("Unexpected ')'."); } case Lexer::TOKEN_OPEN_PAREN: { - result = new Lisp(Lisp::TYPE_CONS); - + result = new(obst) Lisp(Lisp::TYPE_CONS); + token = lexer->getNextToken(); if(token == Lexer::TOKEN_CLOSE_PAREN) { result->v.cons.car = 0; @@ -115,21 +137,21 @@ Parser::read() // evaluate translation function (_ str) in place here token = lexer->getNextToken(); if(token != Lexer::TOKEN_STRING) - throw new std::runtime_error("Expected string after '(_'"); - - result = new Lisp(Lisp::TYPE_STRING); + parse_error("Expected string after '(_'"); + + result = new(obst) Lisp(Lisp::TYPE_STRING); if(dictionary) { std::string translation = dictionary->translate(lexer->getString()); - result->v.string = new char[translation.size()+1]; + result->v.string = new(obst) char[translation.size()+1]; memcpy(result->v.string, translation.c_str(), translation.size()+1); } else { - size_t len = strlen(lexer->getString()) + 1; - result->v.string = new char[len]; + size_t len = strlen(lexer->getString()) + 1; + result->v.string = new(obst) char[len]; memcpy(result->v.string, lexer->getString(), len); } token = lexer->getNextToken(); if(token != Lexer::TOKEN_CLOSE_PAREN) - throw new std::runtime_error("Expected ')' after '(_ string'"); + parse_error("Expected ')' after '(_ string'"); break; } @@ -140,40 +162,41 @@ Parser::read() cur->v.cons.cdr = 0; break; } - cur->v.cons.cdr = new Lisp(Lisp::TYPE_CONS); - cur = cur->v.cons.cdr; + Lisp *newcur = new(obst) Lisp(Lisp::TYPE_CONS); + cur->v.cons.cdr = newcur; + cur = newcur; } while(1); break; } case Lexer::TOKEN_SYMBOL: { - result = new Lisp(Lisp::TYPE_SYMBOL); + result = new(obst) Lisp(Lisp::TYPE_SYMBOL); size_t len = strlen(lexer->getString()) + 1; - result->v.string = new char[len]; + result->v.string = new(obst) char[len]; memcpy(result->v.string, lexer->getString(), len); break; } case Lexer::TOKEN_STRING: { - result = new Lisp(Lisp::TYPE_STRING); + result = new(obst) Lisp(Lisp::TYPE_STRING); size_t len = strlen(lexer->getString()) + 1; - result->v.string = new char[len]; + result->v.string = new(obst) char[len]; memcpy(result->v.string, lexer->getString(), len); break; } case Lexer::TOKEN_INTEGER: - result = new Lisp(Lisp::TYPE_INTEGER); + result = new(obst) Lisp(Lisp::TYPE_INTEGER); sscanf(lexer->getString(), "%d", &result->v.integer); break; case Lexer::TOKEN_REAL: - result = new Lisp(Lisp::TYPE_REAL); + result = new(obst) Lisp(Lisp::TYPE_REAL); sscanf(lexer->getString(), "%f", &result->v.real); break; case Lexer::TOKEN_TRUE: - result = new Lisp(Lisp::TYPE_BOOLEAN); + result = new(obst) Lisp(Lisp::TYPE_BOOLEAN); result->v.boolean = true; break; case Lexer::TOKEN_FALSE: - result = new Lisp(Lisp::TYPE_BOOLEAN); + result = new(obst) Lisp(Lisp::TYPE_BOOLEAN); result->v.boolean = false; break;