-// $Id$
-//
// SuperTux
// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
-#include <config.h>
+#include "lisp/lexer.hpp"
+#include <string.h>
#include <sstream>
#include <stdexcept>
-#include <iostream>
-
-#include "lexer.hpp"
-
-namespace lisp
+#include <stdio.h>
+
+namespace lisp {
+
+Lexer::Lexer(std::istream& newstream) :
+ stream(newstream),
+ eof(false),
+ linenumber(0),
+ bufend(),
+ bufpos(),
+ c(),
+ token_length()
{
-
-class EOFException
-{
-};
-
-Lexer::Lexer(std::istream& newstream)
- : stream(newstream), eof(false), linenumber(0)
-{
- try {
- // trigger a refill of the buffer
- c = 0;
- bufend = 0;
- nextChar();
- } catch(EOFException& e) {
- }
+ // trigger a refill of the buffer
+ bufpos = NULL;
+ bufend = NULL;
+ nextChar();
}
Lexer::~Lexer()
void
Lexer::nextChar()
{
- ++c;
- if(c >= bufend) {
- if(eof)
- throw EOFException();
+ if(bufpos >= bufend) {
+ if(eof) {
+ c = EOF;
+ return;
+ }
stream.read(buffer, BUFFER_SIZE);
size_t bytes_read = stream.gcount();
- c = buffer;
+ bufpos = buffer;
bufend = buffer + bytes_read;
// the following is a hack that appends an additional ' ' at the end of
++bufend;
}
}
+ c = *bufpos++;
+ if(c == '\n')
+ ++linenumber;
+}
+
+void
+Lexer::addChar()
+{
+ if(token_length < MAX_TOKEN_LENGTH)
+ token_string[token_length++] = c;
+ nextChar();
}
Lexer::TokenType
{
static const char* delims = "\"();";
- try {
- while(isspace(*c)) {
- if(*c == '\n')
- ++linenumber;
- nextChar();
- };
+ while(isspace(c)) {
+ nextChar();
+ }
- token_length = 0;
+ token_length = 0;
- switch(*c) {
- case ';': // comment
- while(true) {
- nextChar();
- if(*c == '\n') {
- ++linenumber;
- break;
- }
- }
- return getNextToken(); // and again
- case '(':
+ switch(c) {
+ case ';': // comment
+ while(c != '\n') {
nextChar();
- return TOKEN_OPEN_PAREN;
- case ')':
+ }
+ return getNextToken(); // and again
+ case '(':
+ nextChar();
+ return TOKEN_OPEN_PAREN;
+ case ')':
+ nextChar();
+ return TOKEN_CLOSE_PAREN;
+ case '"': { // string
+ int startline = linenumber;
+ while(1) {
nextChar();
- return TOKEN_CLOSE_PAREN;
- case '"': { // string
- int startline = linenumber;
- try {
- while(1) {
+ switch(c) {
+ case '"':
+ nextChar();
+ goto string_finished;
+ case '\r':
+ continue;
+ case '\n':
+ break;
+ case '\\':
nextChar();
- if(*c == '"')
- break;
- else if (*c == '\r') // XXX this breaks with pure \r EOL
- continue;
- else if(*c == '\n')
- linenumber++;
- else if(*c == '\\') {
- nextChar();
- switch(*c) {
- case 'n':
- *c = '\n';
- break;
- case 't':
- *c = '\t';
- break;
- }
+ switch(c) {
+ case 'n':
+ c = '\n';
+ break;
+ case 't':
+ c = '\t';
+ break;
}
- if(token_length < MAX_TOKEN_LENGTH)
- token_string[token_length++] = *c;
+ break;
+ case EOF: {
+ std::stringstream msg;
+ msg << "Parse error in line " << startline << ": "
+ << "EOF while parsing string.";
+ throw std::runtime_error(msg.str());
}
- token_string[token_length] = 0;
- } catch(EOFException& ) {
- std::stringstream msg;
- msg << "Parse error in line " << startline << ": "
- << "EOF while parsing string.";
- throw std::runtime_error(msg.str());
+ default:
+ break;
}
- nextChar();
- return TOKEN_STRING;
+ if(token_length < MAX_TOKEN_LENGTH)
+ token_string[token_length++] = c;
}
- case '#': // constant
- try {
- nextChar();
-
- while(isalnum(*c) || *c == '_') {
- if(token_length < MAX_TOKEN_LENGTH)
- token_string[token_length++] = *c;
- nextChar();
- }
- token_string[token_length] = 0;
- } catch(EOFException& ) {
- std::stringstream msg;
- msg << "Parse Error in line " << linenumber << ": "
- << "EOF while parsing constant.";
- throw std::runtime_error(msg.str());
- }
+ string_finished:
+ token_string[token_length] = 0;
+ return TOKEN_STRING;
+ }
+ case '#': // constant
+ nextChar();
- if(strcmp(token_string, "t") == 0)
- return TOKEN_TRUE;
- if(strcmp(token_string, "f") == 0)
- return TOKEN_FALSE;
+ while(isalnum(c) || c == '_') {
+ addChar();
+ }
+ token_string[token_length] = 0;
- // we only handle #t and #f constants at the moment...
+ if(strcmp(token_string, "t") == 0)
+ return TOKEN_TRUE;
+ if(strcmp(token_string, "f") == 0)
+ return TOKEN_FALSE;
- {
- std::stringstream msg;
- msg << "Parse Error in line " << linenumber << ": "
+ // we only handle #t and #f constants at the moment...
+ {
+ std::stringstream msg;
+ msg << "Parse Error in line " << linenumber << ": "
<< "Unknown constant '" << token_string << "'.";
- throw std::runtime_error(msg.str());
- }
+ throw std::runtime_error(msg.str());
+ }
- default:
- if(isdigit(*c) || *c == '-') {
- bool have_nondigits = false;
- bool have_digits = false;
- int have_floating_point = 0;
+ case EOF:
+ return TOKEN_EOF;
- do {
- if(isdigit(*c))
- have_digits = true;
- else if(*c == '.')
- ++have_floating_point;
- else if(isalnum(*c) || *c == '_')
- have_nondigits = true;
+ default:
+ if(isdigit(c) || c == '-') {
+ bool have_nondigits = false;
+ bool have_digits = false;
+ int have_floating_point = 0;
- if(token_length < MAX_TOKEN_LENGTH)
- token_string[token_length++] = *c;
+ do {
+ if(isdigit(c))
+ have_digits = true;
+ else if(c == '.')
+ ++have_floating_point;
+ else if(isalnum(c) || c == '_')
+ have_nondigits = true;
- nextChar();
- } while(!isspace(*c) && !strchr(delims, *c));
-
- token_string[token_length] = 0;
-
- // no nextChar
-
- if(have_nondigits || !have_digits || have_floating_point > 1)
- return TOKEN_SYMBOL;
- else if(have_floating_point == 1)
- return TOKEN_REAL;
- else
- return TOKEN_INTEGER;
- } else {
- do {
- if(token_length < MAX_TOKEN_LENGTH)
- token_string[token_length++] = *c;
- nextChar();
- } while(!isspace(*c) && !strchr(delims, *c));
- token_string[token_length] = 0;
+ addChar();
+ } while(!isspace(c) && !strchr(delims, c));
- // no nextChar
+ token_string[token_length] = 0;
+ // no nextChar
+
+ if(have_nondigits || !have_digits || have_floating_point > 1)
return TOKEN_SYMBOL;
- }
- }
- } catch(EOFException& ) {
- return TOKEN_EOF;
+ else if(have_floating_point == 1)
+ return TOKEN_REAL;
+ else
+ return TOKEN_INTEGER;
+ } else {
+ do {
+ addChar();
+ } while(!isspace(c) && !strchr(delims, c));
+ token_string[token_length] = 0;
+
+ // no nextChar
+
+ return TOKEN_SYMBOL;
+ }
}
}
} // end of namespace lisp
+
+/* EOF */