// ---------------------------------------------------------------------------
// - Scanner.cpp -
// - afnix:txt module - scanner object 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 "Vector.hpp"
#include "Scanner.hpp"
#include "Integer.hpp"
#include "Runnable.hpp"
#include "QuarkZone.hpp"
#include "Exception.hpp"
#include "OutputTerm.hpp"
namespace afnix {
// -------------------------------------------------------------------------
// - private section -
// -------------------------------------------------------------------------
// scanner context
struct s_sctx {
// the status flag
bool d_status;
// the scanned string
String d_lexeme;
// simple constructor
s_sctx (void) {
reset ();
}
// reset this context
void reset (void) {
d_status = false;
d_lexeme = "";
}
// return true if the context is valid
bool isvalid (void) const {
return d_status;
}
// return the lexeme value
String getlval (void) const {
return d_status ? d_lexeme : "";
}
// scan an input stream
void scan (Input& is, const String& ps, const Pattern& pat) {
reset ();
d_lexeme = pat.match (&is, ps);
if (d_lexeme.length () > 0) d_status = true;
}
};
// -------------------------------------------------------------------------
// - class section -
// -------------------------------------------------------------------------
// create a default scanner
Scanner::Scanner (void) {
d_mmin = false;
}
// return the class name
String Scanner::repr (void) const {
return "Scanner";
}
// return the scanner length
long Scanner::length (void) const {
rdlock ();
long result = d_vpat.length ();
unlock ();
return result;
}
// add a pattern to the scanner
void Scanner::add (Pattern* pat) {
wrlock ();
try {
// get the append index
long index = d_vpat.length ();
pat->settag (index);
d_vpat.append (pat);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// return a pattern by index
Pattern* Scanner::get (const long index) const {
rdlock ();
Pattern* pat = nilp;
try {
Object* obj = d_vpat.get (index);
pat = dynamic_cast <Pattern*> (obj);
unlock ();
} catch (...) {
unlock ();
throw;
}
return pat;
}
// check a string with the scanner
Lexeme* Scanner::check (const String& s) const {
rdlock ();
try {
// iterate with the patterns
long len = length ();
for (long i = 0; i < len; i++) {
// get the pattern
Pattern* pat = get (i);
if (pat == nilp) continue;
// check the regex against the string
if (pat->check (s) == false) continue;
// build a lexeme since we have a match
Lexeme* lexm = new Lexeme (s, pat->gettag ());
unlock ();
return lexm;
}
} catch (...) {
unlock ();
throw;
}
unlock ();
return nilp;
}
// scan an input stream and return a lexeme
Lexeme* Scanner::scan (Input& is) const {
wrlock ();
// check for patterns
long slen = length ();
if (slen == 0) {
unlock ();
return nilp;
}
// create a scanner context
s_sctx* sctx = new s_sctx[slen];
try {
// the lexeme index
long lidx = -1;
for (long i = 0; i < slen; i++) {
// get the pattern
Pattern* pat = get (i);
if (pat == nilp) continue;
// get the initial value
String init = (lidx == -1) ? "" : sctx[lidx].getlval ();
// scan for good value
sctx[i].scan (is, init, *pat);
if (sctx[i].isvalid () == true) {
lidx = i;
if (d_mmin == true) break;
}
}
// if a lexeme was found, the value is the index
Lexeme* lexm = nilp;
if (lidx != -1) {
String lval = sctx[lidx].getlval ();
long ltag = get(lidx)->gettag ();
lexm = new Lexeme (lval, ltag);
}
// no match found
delete [] sctx;
unlock ();
return lexm;
} catch (...) {
delete [] sctx;
unlock ();
throw;
}
}
// -------------------------------------------------------------------------
// - object section -
// -------------------------------------------------------------------------
// the quark zone
static const long QUARK_ZONE_LENGTH = 5;
static QuarkZone zone (QUARK_ZONE_LENGTH);
// the scanner supported quarks
static const long QUARK_ADD = zone.intern ("add");
static const long QUARK_GET = zone.intern ("get");
static const long QUARK_SCAN = zone.intern ("scan");
static const long QUARK_CHECK = zone.intern ("check");
static const long QUARK_LENGTH = zone.intern ("length");
// create a new object in a generic way
Object* Scanner::mknew (Vector* argv) {
long argc = (argv == nilp) ? 0 : argv->length ();
// check for 0 argument
if (argc == 0) return new Scanner;
throw Exception ("argument-error", "too many arguments with scanner");
}
// return true if the given quark is defined
bool Scanner::isquark (const long quark, const bool hflg) const {
rdlock ();
if (zone.exists (quark) == true) {
unlock ();
return true;
}
bool result = hflg ? Object::isquark (quark, hflg) : false;
unlock ();
return result;
}
// apply this object with a set of arguments and a quark
Object* Scanner::apply (Runnable* robj, Nameset* nset, const long quark,
Vector* argv) {
// get the number of arguments
long argc = (argv == nilp) ? 0 : argv->length ();
// process generic quark
if (quark == QUARK_ADD) {
for (long i = 0; i < argc; i++) {
Object* obj = argv->get (i);
Pattern* pat = dynamic_cast <Pattern*> (obj);
if (pat == nilp) {
throw Exception ("type-error", "invalid object to add ",
Object::repr (obj));
}
add (pat);
}
return nilp;
}
// dispatch 0 argument
if (argc == 0) {
if (quark == QUARK_LENGTH) return new Integer (length ());
}
// dispatch 1 argument
if (argc == 1) {
if (quark == QUARK_GET) {
rdlock ();
try {
long index = argv->getint (0);
Pattern* pat = get (index);
robj->post (pat);
unlock ();
return pat;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_CHECK) {
rdlock ();
try {
String sval = argv->getstring (0);
Lexeme* lexm = check (sval);
robj->post (lexm);
unlock ();
return lexm;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_SCAN) {
Object* obj = argv->get (0);
Input* is = dynamic_cast <Input*> (obj);
if (is == nilp) {
throw Exception ("type-error", "invalid object to scan ",
Object::repr (obj));
}
rdlock ();
try {
Lexeme* lexm = scan (*is);
robj->post (lexm);
unlock ();
return lexm;
} catch (...) {
unlock ();
throw;
}
}
}
// call the object method
return Object::apply (robj, nset, quark, argv);
}
}
syntax highlighted by Code2HTML, v. 0.9.1