3 // Copyright (C) 2004 Matthias Braun <matze@braunis.de>
4 // code in this file based on lispreader from Mark Probst
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 Lexer::Lexer(std::istream& newstream)
34 : stream(newstream), eof(false), linenumber(0)
37 // trigger a refill of the buffer
41 } catch(EOFException& e) {
56 std::streamsize n = stream.readsome(buffer, BUFFER_SIZE);
61 // the following is a hack that appends an additional ' ' at the end of
62 // the file to avoid problems when parsing symbols/elements and a sudden
63 // EOF. This is faster than relying on unget and IMO also nicer.
64 if(n == 0 || stream.eof()) {
75 static const char* delims = "\"();";
88 while(!stream.eof()) {
95 return getNextToken(); // and again
98 return TOKEN_OPEN_PAREN;
101 return TOKEN_CLOSE_PAREN;
102 case '"': { // string
103 int startline = linenumber;
107 std::stringstream msg;
108 msg << "Parse Error in line " << startline << ": "
109 << "Couldn't find end of string.";
110 throw std::runtime_error(msg.str());
117 else if(*c == '\\') {
128 if(token_length < MAX_TOKEN_LENGTH)
129 token_string[token_length++] = *c;
131 token_string[token_length] = 0;
132 } catch(EOFException& ) {
133 std::stringstream msg;
134 msg << "Parse error in line " << startline << ": "
135 << "EOF while parsing string.";
136 throw std::runtime_error(msg.str());
141 case '#': // constant
145 while(isalnum(*c) || *c == '_') {
146 if(token_length < MAX_TOKEN_LENGTH)
147 token_string[token_length++] = *c;
150 token_string[token_length] = 0;
151 } catch(EOFException& ) {
152 std::stringstream msg;
153 msg << "Parse Error in line " << linenumber << ": "
154 << "EOF while parsing constant.";
155 throw std::runtime_error(msg.str());
158 if(strcmp(token_string, "t") == 0)
160 if(strcmp(token_string, "f") == 0)
163 // we only handle #t and #f constants at the moment...
166 std::stringstream msg;
167 msg << "Parse Error in line " << linenumber << ": "
168 << "Unknown constant '" << token_string << "'.";
169 throw std::runtime_error(msg.str());
173 if(isdigit(*c) || *c == '-') {
174 bool have_nondigits = false;
175 bool have_digits = false;
176 int have_floating_point = 0;
182 ++have_floating_point;
183 else if(isalnum(*c) || *c == '_')
184 have_nondigits = true;
186 if(token_length < MAX_TOKEN_LENGTH)
187 token_string[token_length++] = *c;
190 } while(!isspace(*c) && !strchr(delims, *c));
192 token_string[token_length] = 0;
196 if(have_nondigits || !have_digits || have_floating_point > 1)
198 else if(have_floating_point == 1)
201 return TOKEN_INTEGER;
204 if(token_length < MAX_TOKEN_LENGTH)
205 token_string[token_length++] = *c;
207 } while(!isspace(*c) && !strchr(delims, *c));
208 token_string[token_length] = 0;
215 } catch(EOFException& ) {
220 } // end of namespace lisp