// ---------------------------------------------------------------------------
// - Reader.cpp -
// - afnix engine - reader class implementation -
// ---------------------------------------------------------------------------
// - This program is free software; you can redistribute it and/or modify -
// - it provided that this copyright notice is kept intact. -
// - -
// - This program is distributed in the hope that it will be useful, but -
// - without any warranty; without even the implied warranty of -
// - merchantability or fitness for a particular purpose. In no event shall -
// - the copyright holder be liable for any direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software. -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2007 amaury darsch -
// ---------------------------------------------------------------------------
#include "Reader.hpp"
#include "Terminal.hpp"
#include "Exception.hpp"
namespace afnix {
// -------------------------------------------------------------------------
// - private section -
// -------------------------------------------------------------------------
// this procedure sets a line and eventually feeds the input stream
static inline void readline (Input* is, bool pflag) {
Terminal* term = dynamic_cast <Terminal*> (is);
if (term == nilp) return;
String line = term->readline (pflag);
is->pushback (line);
}
// -------------------------------------------------------------------------
// - class section -
// -------------------------------------------------------------------------
// create a new reader class
Reader::Reader (Input* is) {
Object::iref (p_is = is);
p_lex = new Lexer (p_is);
}
// destroy this reader
Reader::~Reader (void) {
Object::dref (p_is);
delete p_lex;
}
// return the class name
String Reader::repr (void) const {
return "Reader";
}
// parse the input stream and return a cons cell
Form* Reader::parse (void) {
wrlock ();
try {
Form* result = nilp;
// read a line from the top
readline (p_is, true);
// loop until we have an eol or eof
while (true) {
Token token = p_lex->get ();
switch (token.gettid ()) {
case Token::ERROR:
delete result;
throw Exception ("syntax-error", "illegal token found",
token.getval ());
case Token::EOL:
if (result == nilp) {
readline (p_is, true);
continue;
}
unlock ();
return result;
case Token::EOF:
unlock ();
return result;
case Token::RFB:
if (result == nilp) {
long lnum = getlnum ();
result = new Form (rform (true));
result->setinfo (d_fname, lnum);
} else result->append (rform (true));
continue;
case Token::BFB:
if (result == nilp) {
long lnum = getlnum ();
result = new Form (bform (true));
result->setinfo (d_fname, lnum);
} else result->append (bform (true));
continue;
case Token::REAL:
case Token::REGEX:
case Token::STRING:
case Token::LEXICAL:
case Token::INTEGER:
case Token::RELATIF:
case Token::QUALIFIED:
case Token::CHARACTER:
if (result == nilp) {
long lnum = getlnum ();
result = new Form (token.getobj ());
result->setinfo (d_fname, lnum);
} else result->append (token.getobj ());
continue;
default:
delete result;
throw Exception ("syntax-error", "illegal token found",
token.getval ());
}
}
// if we are here , an error append
delete result;
throw Exception ("internal-error", "reader loop error");
} catch (...) {
unlock ();
throw;
}
}
// read a form and return a cons cell - the rfb charcter is consumed
Form* Reader::rform (bool pflag) {
wrlock ();
try {
Form* result = nilp;
// loop until we have a rfe
while (true) {
Token token = p_lex->get ();
switch (token.gettid ()) {
case Token::ERROR:
delete result;
throw Exception ("syntax-error", "illegal token found",
token.getval ());
case Token::EOL:
readline (p_is, false);
continue;
case Token::EOF:
delete result;
throw Exception ("eof-error", "eof unexpected while parsing form");
case Token::RFB:
if (result == nilp) {
long lnum = getlnum ();
result = new Form (rform (pflag));
result->setinfo (d_fname, lnum);
} else result->append (rform (pflag));
continue;
case Token::BFB:
if (result == nilp) {
long lnum = getlnum ();
result = new Form (bform (pflag));
result->setinfo (d_fname, lnum);
} else result->append (bform (pflag));
continue;
case Token::RFE:
unlock ();
return result;
case Token::BFE:
delete result;
throw Exception ("reader-error", "illegal character } in form");
default:
if (result == nilp) {
long lnum = getlnum ();
result = new Form (token.getobj ());
result->setinfo (d_fname, lnum);
} else result->append (token.getobj ());
continue;
}
}
// if we are here , an error append
delete result;
throw Exception ("internal-error", "reader loop error");
} catch (...) {
unlock ();
throw;
}
}
// read a block form and return a cons cell - the bfb character is consumed
Form* Reader::bform (bool pflag) {
wrlock ();
try {
Form* form = nilp;
Form* result = new Form (Form::BLOCK, getlnum ());
// loop until we have a bfe
while (true) {
Token token = p_lex->get ();
switch (token.gettid ()) {
case Token::ERROR:
delete form;
delete result;
throw Exception ("syntax-error", "illegal token found",
token.getval ());
case Token::EOL:
if (form == nilp) {
readline (p_is, false);
continue;
}
result->append (form);
form = nilp;
readline (p_is, false);
continue;
case Token::EOF:
delete result;
delete form;
throw Exception ("eof-error", "eof unexpected while parsing form");
case Token::RFB:
if (form == nilp) {
long lnum = getlnum ();
form = new Form (rform (pflag));
form->setinfo (d_fname, lnum);
} else form->append (rform (pflag));
continue;
case Token::BFB:
if (form == nilp)
form = bform (pflag);
else
form->append (bform (pflag));
continue;
case Token::BFE:
if (form != nilp) result->append (form);
form = nilp;
unlock ();
return result;
case Token::RFE:
delete result;
throw Exception ("reader-error", "illegal character in block form");
default:
if (form == nilp) {
long lnum = getlnum ();
form = new Form (token.getobj ());
form->setinfo (d_fname, lnum);
} else form->append (token.getobj ());
continue;
}
}
// if we are here , an error append
delete result;
throw Exception ("internal-error", "reader loop error");
} catch (...) {
unlock ();
throw;
}
}
// set the reader file name
void Reader::setfname (const String& fname) {
wrlock ();
d_fname = fname;
unlock ();
}
// return the lexer line number
long Reader::getlnum (void) const {
rdlock ();
long result = p_lex->getlnum ();
unlock ();
return result;
}
}
syntax highlighted by Code2HTML, v. 0.9.1