875a4b2011f9337ec7ecee07498a4df16b6cda1e
[supertux.git] / lib / 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 "app/setup.h"
29 #include "app/tinygettext.h"
30 #include "parser.h"
31 #include "lisp.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   }
42 }
43
44 Parser::~Parser()
45 {
46   delete lexer;
47   delete dictionary_manager;
48 }
49
50 Lisp*
51 Parser::parse(const std::string& filename)
52 {
53   std::ifstream in(filename.c_str());
54   if(!in.good()) {
55     std::stringstream msg;
56     msg << "Parser problem: Couldn't open file '" << filename << "'.";
57     throw std::runtime_error(msg.str());
58   }
59
60   if(dictionary_manager) {
61     dictionary_manager->add_directory(SuperTux::FileSystem::dirname(filename));
62     dictionary = & (dictionary_manager->get_dictionary());
63   }
64   
65   return parse(in);
66 }
67
68 Lisp*
69 Parser::parse(std::istream& stream)
70 {
71   delete lexer;
72   lexer = new Lexer(stream);
73
74   token = lexer->getNextToken();
75   Lisp* result = new Lisp(Lisp::TYPE_CONS);
76   result->v.cons.car = read();
77   result->v.cons.cdr = 0;
78   
79   delete lexer;
80   lexer = 0;
81
82   return result;    
83 }
84
85 Lisp*
86 Parser::read()
87 {
88   Lisp* result;
89   switch(token) {
90     case Lexer::TOKEN_EOF: {
91       std::stringstream msg;
92       msg << "Parse Error at line " << lexer->getLineNumber() << ": "
93         << "Unexpected EOF.";
94       throw std::runtime_error(msg.str());
95     }
96     case Lexer::TOKEN_CLOSE_PAREN: {
97       std::stringstream msg;
98       msg << "Parse Error at line " << lexer->getLineNumber() << ": "
99         << "Unexpected ')'.";
100       throw std::runtime_error(msg.str());
101     }
102     case Lexer::TOKEN_OPEN_PAREN: {
103       result = new Lisp(Lisp::TYPE_CONS);
104       
105       token = lexer->getNextToken();
106       if(token == Lexer::TOKEN_CLOSE_PAREN) {
107         result->v.cons.car = 0;
108         result->v.cons.cdr = 0;
109         break;
110       }
111
112       if(token == Lexer::TOKEN_SYMBOL &&
113           strcmp(lexer->getString(), "_") == 0) {
114         // evaluate translation function (_ str) in place here
115         token = lexer->getNextToken();
116         if(token != Lexer::TOKEN_STRING)
117           throw new std::runtime_error("Expected string after '(_'");
118         
119         result = new Lisp(Lisp::TYPE_STRING);
120         if(dictionary) {
121           std::string translation = dictionary->translate(lexer->getString());
122           std::cout << "Translated '" << lexer->getString() << "' -> '" 
123             << translation << "'\n";
124           result->v.string = new char[translation.size()+1];
125           memcpy(result->v.string, translation.c_str(), translation.size()+1);
126         } else {
127           size_t len = strlen(lexer->getString()) + 1;                                
128           result->v.string = new char[len];
129           memcpy(result->v.string, lexer->getString(), len);
130         }
131         token = lexer->getNextToken();
132         if(token != Lexer::TOKEN_CLOSE_PAREN)
133           throw new std::runtime_error("Expected ')' after '(_ string'");
134         break;
135       }
136
137       Lisp* cur = result;
138       do {
139         cur->v.cons.car = read();
140         if(token == Lexer::TOKEN_CLOSE_PAREN) {
141           cur->v.cons.cdr = 0;
142           break;
143         }
144         cur->v.cons.cdr = new Lisp(Lisp::TYPE_CONS);
145         cur = cur->v.cons.cdr;
146       } while(1);
147
148       break;
149     }
150     case Lexer::TOKEN_SYMBOL: {
151       result = new Lisp(Lisp::TYPE_SYMBOL);
152       size_t len = strlen(lexer->getString()) + 1;
153       result->v.string = new char[len];
154       memcpy(result->v.string, lexer->getString(), len);
155       break;
156     }
157     case Lexer::TOKEN_STRING: {
158       result = new Lisp(Lisp::TYPE_STRING);
159       size_t len = strlen(lexer->getString()) + 1;
160       result->v.string = new char[len];
161       memcpy(result->v.string, lexer->getString(), len);
162       break;
163     }
164     case Lexer::TOKEN_INTEGER:
165       result = new Lisp(Lisp::TYPE_INTEGER);
166       sscanf(lexer->getString(), "%d", &result->v.integer);
167       break;
168     case Lexer::TOKEN_REAL:
169       result = new Lisp(Lisp::TYPE_REAL);
170       sscanf(lexer->getString(), "%f", &result->v.real);
171       break;
172     case Lexer::TOKEN_TRUE:
173       result = new Lisp(Lisp::TYPE_BOOLEAN);
174       result->v.boolean = true;
175       break;
176     case Lexer::TOKEN_FALSE:
177       result = new Lisp(Lisp::TYPE_BOOLEAN);
178       result->v.boolean = false;
179       break;
180
181     default:
182       // this should never happen
183       assert(false);
184   }
185
186   token = lexer->getNextToken();
187   return result;
188 }
189
190 } // end of namespace lisp