* Activated UTF-8 in Lisp parser
[supertux.git] / src / lisp / parser.cpp
1 //  $Id$
2 //
3 //  TuxKart - a fun racing game with go-kart
4 //  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
5 //  code in this file based on lispreader from Mark Probst
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 #include <config.h>
21
22 #include <sstream>
23 #include <stdexcept>
24 #include <fstream>
25 #include <cassert>
26 #include <iostream>
27
28 #include "tinygettext/tinygettext.h"
29 #include "parser.h"
30 #include "lisp.h"
31 #include "file_system.h"
32
33 namespace lisp
34 {
35
36 Parser::Parser(bool translate)
37   : lexer(0), dictionary_manager(0), dictionary(0)
38 {
39   if(translate) {
40     dictionary_manager = new TinyGetText::DictionaryManager();
41     dictionary_manager->set_charset("UTF-8");
42   }
43 }
44
45 Parser::~Parser()
46 {
47   delete lexer;
48   delete dictionary_manager;
49 }
50
51 Lisp*
52 Parser::parse(const std::string& filename)
53 {
54   std::ifstream in(filename.c_str());
55   if(!in.good()) {
56     std::stringstream msg;
57     msg << "Parser problem: Couldn't open file '" << filename << "'.";
58     throw std::runtime_error(msg.str());
59   }
60
61   if(dictionary_manager) {
62     dictionary_manager->add_directory(FileSystem::dirname(filename));
63     dictionary = & (dictionary_manager->get_dictionary());
64   }
65   
66   return parse(in);
67 }
68
69 Lisp*
70 Parser::parse(std::istream& stream)
71 {
72   delete lexer;
73   lexer = new Lexer(stream);
74
75   token = lexer->getNextToken();
76   Lisp* result = new Lisp(Lisp::TYPE_CONS);
77   result->v.cons.car = read();
78   result->v.cons.cdr = 0;
79   
80   delete lexer;
81   lexer = 0;
82
83   return result;    
84 }
85
86 Lisp*
87 Parser::read()
88 {
89   Lisp* result;
90   switch(token) {
91     case Lexer::TOKEN_EOF: {
92       std::stringstream msg;
93       msg << "Parse Error at line " << lexer->getLineNumber() << ": "
94         << "Unexpected EOF.";
95       throw std::runtime_error(msg.str());
96     }
97     case Lexer::TOKEN_CLOSE_PAREN: {
98       std::stringstream msg;
99       msg << "Parse Error at line " << lexer->getLineNumber() << ": "
100         << "Unexpected ')'.";
101       throw std::runtime_error(msg.str());
102     }
103     case Lexer::TOKEN_OPEN_PAREN: {
104       result = new Lisp(Lisp::TYPE_CONS);
105       
106       token = lexer->getNextToken();
107       if(token == Lexer::TOKEN_CLOSE_PAREN) {
108         result->v.cons.car = 0;
109         result->v.cons.cdr = 0;
110         break;
111       }
112
113       if(token == Lexer::TOKEN_SYMBOL &&
114           strcmp(lexer->getString(), "_") == 0) {
115         // evaluate translation function (_ str) in place here
116         token = lexer->getNextToken();
117         if(token != Lexer::TOKEN_STRING)
118           throw new std::runtime_error("Expected string after '(_'");
119         
120         result = new Lisp(Lisp::TYPE_STRING);
121         if(dictionary) {
122           std::string translation = dictionary->translate(lexer->getString());
123           result->v.string = new char[translation.size()+1];
124           memcpy(result->v.string, translation.c_str(), translation.size()+1);
125         } else {
126           size_t len = strlen(lexer->getString()) + 1;                                
127           result->v.string = new char[len];
128           memcpy(result->v.string, lexer->getString(), len);
129         }
130         token = lexer->getNextToken();
131         if(token != Lexer::TOKEN_CLOSE_PAREN)
132           throw new std::runtime_error("Expected ')' after '(_ string'");
133         break;
134       }
135
136       Lisp* cur = result;
137       do {
138         cur->v.cons.car = read();
139         if(token == Lexer::TOKEN_CLOSE_PAREN) {
140           cur->v.cons.cdr = 0;
141           break;
142         }
143         cur->v.cons.cdr = new Lisp(Lisp::TYPE_CONS);
144         cur = cur->v.cons.cdr;
145       } while(1);
146
147       break;
148     }
149     case Lexer::TOKEN_SYMBOL: {
150       result = new Lisp(Lisp::TYPE_SYMBOL);
151       size_t len = strlen(lexer->getString()) + 1;
152       result->v.string = new char[len];
153       memcpy(result->v.string, lexer->getString(), len);
154       break;
155     }
156     case Lexer::TOKEN_STRING: {
157       result = new Lisp(Lisp::TYPE_STRING);
158       size_t len = strlen(lexer->getString()) + 1;
159       result->v.string = new char[len];
160       memcpy(result->v.string, lexer->getString(), len);
161       break;
162     }
163     case Lexer::TOKEN_INTEGER:
164       result = new Lisp(Lisp::TYPE_INTEGER);
165       sscanf(lexer->getString(), "%d", &result->v.integer);
166       break;
167     case Lexer::TOKEN_REAL:
168       result = new Lisp(Lisp::TYPE_REAL);
169       sscanf(lexer->getString(), "%f", &result->v.real);
170       break;
171     case Lexer::TOKEN_TRUE:
172       result = new Lisp(Lisp::TYPE_BOOLEAN);
173       result->v.boolean = true;
174       break;
175     case Lexer::TOKEN_FALSE:
176       result = new Lisp(Lisp::TYPE_BOOLEAN);
177       result->v.boolean = false;
178       break;
179
180     default:
181       // this should never happen
182       assert(false);
183   }
184
185   token = lexer->getNextToken();
186   return result;
187 }
188
189 } // end of namespace lisp