Threw away the "multiple parser" infrastructure.

This commit is contained in:
John Wiegley 2009-02-07 17:45:48 -04:00
parent 9380d73646
commit 589eabd8e6
14 changed files with 236 additions and 625 deletions

View file

@ -106,7 +106,6 @@ pkginclude_HEADERS = \
src/entry.h \
src/account.h \
src/journal.h \
src/textual.h \
src/timelog.h \
src/iterators.h \
src/compare.h \
@ -222,7 +221,6 @@ libledger_python_la_SOURCES = \
python/py_scope.cc \
python/py_session.cc \
python/py_stream.cc \
python/py_textual.cc \
python/py_timelog.cc \
python/py_times.cc \
python/py_token.cc \

View file

@ -1,68 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "pyinterp.h"
#include "pyutils.h"
#include "textual.h"
#include <boost/python/exception_translator.hpp>
#include <boost/python/implicit.hpp>
#include <boost/python/args.hpp>
namespace ledger {
using namespace boost::python;
#define EXC_TRANSLATOR(type) \
void exc_translate_ ## type(const type& err) { \
PyErr_SetString(PyExc_ArithmeticError, err.what()); \
}
//EXC_TRANSLATOR(textual_error)
void export_textual()
{
#if 0
class_< textual_parser_t > ("TextualParser")
;
#endif
//register_optional_to_python<amount_t>();
//implicitly_convertible<string, amount_t>();
#define EXC_TRANSLATE(type) \
register_exception_translator<type>(&exc_translate_ ## type);
//EXC_TRANSLATE(textual_error);
}
} // namespace ledger

View file

@ -65,7 +65,6 @@ void export_report();
void export_scope();
void export_session();
void export_stream();
void export_textual();
void export_timelog();
void export_times();
void export_token();
@ -103,7 +102,6 @@ void initialize_for_python()
export_scope();
export_session();
export_stream();
export_textual();
export_timelog();
export_times();
export_token();

View file

@ -51,19 +51,15 @@ entry_t * derive_new_entry(report_t& report,
mask_t regexp(*i++);
journals_iterator iter(session);
entries_list::reverse_iterator j;
for (journal_t * journal = iter(); journal; journal = iter()) {
for (j = journal->entries.rbegin();
j != journal->entries.rend();
j++) {
if (regexp.match((*j)->payee)) {
matching = *j;
break;
}
for (j = report.session.journal->entries.rbegin();
j != report.session.journal->entries.rend();
j++) {
if (regexp.match((*j)->payee)) {
matching = *j;
break;
}
if (matching) break;
}
added->payee = matching ? matching->payee : regexp.expr.str();

View file

@ -34,7 +34,6 @@
#include "compare.h"
#include "session.h"
#include "format.h"
#include "textual.h"
namespace ledger {

View file

@ -85,9 +85,9 @@ void global_scope_t::read_init()
ifstream init(init_file);
journal_t temp;
if (session().read_journal(temp, init_file) > 0 ||
temp.auto_entries.size() > 0 || temp.period_entries.size() > 0) {
if (session().read_journal(init_file) > 0 ||
session().journal->auto_entries.size() > 0 ||
session().journal->period_entries.size() > 0) {
throw_(parse_error,
"Entries found in initialization file '" << init_file << "'");
}
@ -105,8 +105,7 @@ void global_scope_t::read_journal_files()
if (session().HANDLED(account_))
master_account = session().HANDLER(account_).str();
std::size_t count = session().read_data(*session().create_journal(),
master_account);
std::size_t count = session().read_data(master_account);
if (count == 0)
throw_(parse_error, "Failed to locate any journal entries; "
"did you specify a valid file with -f?");

View file

@ -37,37 +37,23 @@ namespace ledger {
void entries_iterator::reset(session_t& session)
{
journals_i = session.journals.begin();
journals_end = session.journals.end();
journals_uninitialized = false;
if (journals_i != journals_end) {
entries_i = (*journals_i).entries.begin();
entries_end = (*journals_i).entries.end();
entries_uninitialized = false;
} else {
entries_uninitialized = true;
}
entries_i = session.journal->entries.begin();
entries_end = session.journal->entries.end();
entries_uninitialized = false;
}
entry_t * entries_iterator::operator()()
{
if (entries_i == entries_end) {
journals_i++;
if (journals_i == journals_end)
return NULL;
entries_i = (*journals_i).entries.begin();
entries_end = (*journals_i).entries.end();
}
return *entries_i++;
if (entries_i != entries_end)
return *entries_i++;
else
return NULL;
}
void session_xacts_iterator::reset(session_t& session)
{
entries.reset(session);
entry_t * entry = entries();
if (entry != NULL)
xacts.reset(*entry);
@ -139,19 +125,6 @@ account_t * sorted_accounts_iterator::operator()()
return account;
}
void journals_iterator::reset(session_t& session)
{
journals_i = session.journals.begin();
journals_end = session.journals.end();
}
journal_t * journals_iterator::operator()()
{
if (journals_i == journals_end)
return NULL;
return &(*journals_i++);
}
#if 0
// jww (2008-08-03): This needs to be changed into a commodities->xacts
// iterator.

View file

@ -110,23 +110,16 @@ public:
*/
class entries_iterator : public noncopyable
{
ptr_list<journal_t>::iterator journals_i;
ptr_list<journal_t>::iterator journals_end;
bool journals_uninitialized;
entries_list::iterator entries_i;
entries_list::iterator entries_end;
entries_list::iterator entries_i;
entries_list::iterator entries_end;
bool entries_uninitialized;
public:
entries_iterator()
: journals_uninitialized(true), entries_uninitialized(true) {
entries_iterator() : entries_uninitialized(true) {
TRACE_CTOR(entries_iterator, "");
}
entries_iterator(session_t& session)
: journals_uninitialized(true), entries_uninitialized(true) {
entries_iterator(session_t& session) : entries_uninitialized(true) {
TRACE_CTOR(entries_iterator, "session_t&");
reset(session);
}
@ -250,33 +243,6 @@ public:
virtual account_t * operator()();
};
/**
* @brief Brief
*
* Long.
*/
class journals_iterator : public noncopyable
{
ptr_list<journal_t>::iterator journals_i;
ptr_list<journal_t>::iterator journals_end;
public:
journals_iterator() {
TRACE_CTOR(journals_iterator, "");
}
journals_iterator(session_t& session) {
TRACE_CTOR(journals_iterator, "session_t&");
reset(session);
}
virtual ~journals_iterator() throw() {
TRACE_DTOR(journals_iterator);
}
void reset(session_t& session);
virtual journal_t * operator()();
};
} // namespace ledger
#endif // _ITERATORS_H

View file

@ -65,14 +65,12 @@ class account_t;
class journal_t : public noncopyable
{
public:
account_t * master;
account_t * basket;
entries_list entries;
paths_list sources;
optional<path> price_db;
account_t * master;
account_t * basket;
entries_list entries;
auto_entries_list auto_entries;
period_entries_list period_entries;
auto_entries_list auto_entries;
period_entries_list period_entries;
hooks_t<entry_finalizer_t, entry_t> entry_finalize_hooks;
@ -98,33 +96,10 @@ public:
entry_finalize_hooks.remove_hook(finalizer);
}
/**
* @brief Provides an abstract interface for writing journal parsers.
*
* Any data format for Ledger data is possible, as long as it can be parsed
* into a journal_t data tree. This class provides the basic interface which
* must be implemented by every such journal parser.
*/
class parser_t : public noncopyable
{
public:
parser_t() {
TRACE_CTOR(journal_t::parser_t, "");
}
virtual ~parser_t() {
TRACE_DTOR(journal_t::parser_t);
}
#if defined(TEST_FOR_PARSER)
virtual bool test(std::istream& in) const = 0;
#endif
virtual std::size_t parse(std::istream& in,
session_t& session,
journal_t& journal,
account_t * master = NULL,
const path * original_file = NULL) = 0;
};
std::size_t parse(std::istream& in,
session_t& session,
account_t * master,
const path * original_file);
bool valid() const;
};

View file

@ -75,7 +75,6 @@
#include <expr.h>
#include <journal.h>
#include <textual.h>
#include <iterators.h>
#include <compare.h>

View file

@ -33,7 +33,6 @@
#include "report.h"
#include "iterators.h"
#include "filters.h"
#include "textual.h"
namespace ledger {
@ -61,7 +60,8 @@ session_t::session_t()
current_year(CURRENT_DATE().year()),
commodity_pool(new commodity_pool_t),
master(new account_t(NULL, ""))
master(new account_t(NULL, "")),
journal(new journal_t(master.get()))
{
TRACE_CTOR(session_t, "");
@ -70,8 +70,6 @@ session_t::session_t()
else
HANDLER(price_db_).on(path("./.pricedb").string());
register_parser(new textual_parser_t);
// Add time commodity conversions, so that timelog's may be parsed
// in terms of seconds, but reported as minutes or hours.
if (commodity_t * commodity = commodity_pool->create("s"))
@ -80,58 +78,26 @@ session_t::session_t()
assert(false);
}
journal_t * session_t::create_journal()
{
journal_t * journal = new journal_t(master.get());
journals.push_back(journal);
return journal;
}
void session_t::close_journal(journal_t * journal)
{
for (ptr_list<journal_t>::iterator i = journals.begin();
i != journals.end();
i++)
if (&*i == journal) {
journals.erase(i);
return;
}
assert(false);
checked_delete(journal);
}
std::size_t session_t::read_journal(journal_t& journal,
std::istream& in,
std::size_t session_t::read_journal(std::istream& in,
const path& pathname,
account_t * master)
{
if (! master)
master = journal.master;
foreach (journal_t::parser_t& parser, parsers)
#if defined(TEST_FOR_PARSER)
if (parser.test(in))
#endif
return parser.parse(in, *this, journal, master, &pathname);
return 0;
master = journal->master;
return journal->parse(in, *this, master, &pathname);
}
std::size_t session_t::read_journal(journal_t& journal,
const path& pathname,
std::size_t session_t::read_journal(const path& pathname,
account_t * master)
{
journal.sources.push_back(pathname);
if (! exists(pathname))
throw_(std::logic_error, "Cannot read file" << pathname);
ifstream stream(pathname);
return read_journal(journal, stream, pathname, master);
return read_journal(stream, pathname, master);
}
std::size_t session_t::read_data(journal_t& journal,
const string& master_account)
std::size_t session_t::read_data(const string& master_account)
{
if (HANDLER(file_).data_files.empty())
throw_(parse_error, "No journal file was specified (please use -f)");
@ -139,24 +105,18 @@ std::size_t session_t::read_data(journal_t& journal,
std::size_t entry_count = 0;
if (entry_count == 0) {
account_t * acct = journal.master;
account_t * acct = journal->master;
if (! master_account.empty())
acct = journal.find_account(master_account);
acct = journal->find_account(master_account);
journal.price_db = HANDLER(price_db_).str();
if (journal.price_db && exists(*journal.price_db)) {
if (read_journal(journal, *journal.price_db)) {
if (HANDLED(price_db_) && exists(path(HANDLER(price_db_).str()))) {
if (read_journal(HANDLER(price_db_).str()))
throw_(parse_error, "Entries not allowed in price history file");
} else {
journal.sources.pop_back();
}
}
foreach (const path& pathname, HANDLER(file_).data_files) {
if (pathname == "-") {
journal.sources.push_back("/dev/stdin");
// To avoid problems with stdin and pipes, etc., we read the entire
// file in beforehand into a memory buffer, and then parcel it out
// from there.
@ -172,12 +132,10 @@ std::size_t session_t::read_data(journal_t& journal,
std::istringstream buf_in(buffer.str());
entry_count += read_journal(journal, buf_in, "/dev/stdin", acct);
entry_count += read_journal(buf_in, "/dev/stdin", acct);
}
else if (exists(pathname)) {
entry_count += read_journal(journal, pathname, acct);
if (journal.price_db)
journal.sources.push_back(*journal.price_db);
entry_count += read_journal(pathname, acct);
}
else {
throw_(parse_error, "Could not open journal file '" << pathname << "'");
@ -185,25 +143,11 @@ std::size_t session_t::read_data(journal_t& journal,
}
}
VERIFY(journal.valid());
VERIFY(journal->valid());
return entry_count;
}
void session_t::unregister_parser(journal_t::parser_t * parser)
{
for (ptr_list<journal_t::parser_t>::iterator i = parsers.begin();
i != parsers.end();
i++) {
if (&*i == parser) {
parsers.erase(i);
return;
}
}
assert(false);
checked_delete(parser);
}
void session_t::clean_xacts()
{
session_xacts_iterator walker(*this);
@ -223,38 +167,6 @@ void session_t::clean_accounts()
master->clear_xdata();
}
#if 0
value_t session_t::resolve(const string& name, expr_t::scope_t& locals)
{
const char * p = name.c_str();
switch (*p) {
case 'd':
#if 0
if (name == "date_format") {
// jww (2007-04-18): What to do here?
return string_value(moment_t::output_format);
}
#endif
break;
case 'n':
switch (*++p) {
case 'o':
if (name == "now")
return value_t(now);
break;
}
break;
case 'r':
if (name == "register_format")
return string_value(register_format);
break;
}
return expr_t::scope_t::resolve(name, locals);
}
#endif
option_t<session_t> * session_t::lookup_option(const char * p)
{
switch (*p) {

View file

@ -66,10 +66,9 @@ public:
bool flush_on_next_data_file;
int current_year;
shared_ptr<commodity_pool_t> commodity_pool;
ptr_list<journal_t::parser_t> parsers;
ptr_list<journal_t> journals;
scoped_ptr<account_t> master;
shared_ptr<commodity_pool_t> commodity_pool;
scoped_ptr<account_t> master;
scoped_ptr<journal_t> journal;
explicit session_t();
virtual ~session_t() {
@ -80,24 +79,13 @@ public:
flush_on_next_data_file = true;
}
journal_t * create_journal();
void close_journal(journal_t * journal);
std::size_t read_journal(journal_t& journal,
std::istream& in,
std::size_t read_journal(std::istream& in,
const path& pathname,
account_t * master = NULL);
std::size_t read_journal(journal_t& journal,
const path& pathname,
std::size_t read_journal(const path& pathname,
account_t * master = NULL);
std::size_t read_data(journal_t& journal,
const string& master_account = "");
void register_parser(journal_t::parser_t * parser) {
parsers.push_back(parser);
}
void unregister_parser(journal_t::parser_t * parser);
std::size_t read_data(const string& master_account = "");
void clean_xacts();
void clean_xacts(entry_t& entry);

View file

@ -29,94 +29,107 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(__GNUG__) && __GNUG__ < 3
#define _XOPEN_SOURCE
#endif
#include "textual.h"
#include "session.h"
#include "journal.h"
#if defined(TIMELOG_SUPPORT)
#include "timelog.h"
#endif
#include "parser.h"
#include "session.h"
namespace ledger {
#if defined(TEST_FOR_PARSER)
bool textual_parser_t::test(std::istream& in) const
{
char buf[12];
char * p;
in.read(buf, 11);
if (utf8::is_bom(buf))
p = &buf[3];
else
p = buf;
if (std::strncmp(p, "<?xml", 5) == 0)
throw_(parse_error,
"Ledger file contains XML data, but format was not recognized");
in.clear();
in.seekg(0, std::ios::beg);
assert(in.good());
return true;
}
#endif // TEST_FOR_PARSER
std::size_t textual_parser_t::parse(std::istream& in,
session_t& session,
journal_t& journal,
account_t * master,
const path * original_file)
{
TRACE_START(parsing_total, 1, "Total time spent parsing text:");
std::list<account_t *> account_stack;
#if defined(TIMELOG_SUPPORT)
time_log_t timelog(journal);
#endif
instance_t parsing_instance(account_stack,
#if defined(TIMELOG_SUPPORT)
timelog,
#endif
in, session, journal, master,
original_file);
parsing_instance.parse();
session.clean_accounts(); // remove calculated totals
TRACE_STOP(parsing_total, 1);
// These tracers were started in textual.cc
TRACE_FINISH(entry_text, 1);
TRACE_FINISH(entry_details, 1);
TRACE_FINISH(entry_xacts, 1);
TRACE_FINISH(entries, 1);
TRACE_FINISH(instance_parse, 1); // report per-instance timers
TRACE_FINISH(parsing_total, 1);
if (parsing_instance.errors > 0)
throw static_cast<int>(parsing_instance.errors);
return parsing_instance.count;
}
namespace {
#if defined(STORE_XACT_EXPRS)
optional<expr_t>
#else
void
class instance_t : public noncopyable, public scope_t
{
static const std::size_t MAX_LINE = 1024;
public:
std::list<account_t *>& account_stack;
#if defined(TIMELOG_SUPPORT)
time_log_t& timelog;
#endif
parse_amount_expr(session_t& session,
std::istream& in,
amount_t& amount,
xact_t * xact,
uint_least8_t flags = 0)
instance_t * parent;
std::istream& in;
session_t& session;
journal_t& journal;
account_t * master;
const path * original_file;
accounts_map account_aliases;
path pathname;
char linebuf[MAX_LINE + 1];
std::size_t linenum;
istream_pos_type line_beg_pos;
istream_pos_type curr_pos;
std::size_t count;
std::size_t errors;
scoped_ptr<auto_entry_finalizer_t> auto_entry_finalizer;
instance_t(std::list<account_t *>& _account_stack,
#if defined(TIMELOG_SUPPORT)
time_log_t& _timelog,
#endif
std::istream& _in,
session_t& _session,
journal_t& _journal,
account_t * _master = NULL,
const path * _original_file = NULL,
instance_t * _parent = NULL);
~instance_t();
void parse();
std::streamsize read_line(char *& line);
bool peek_whitespace_line() {
return (in.good() && ! in.eof() &&
(in.peek() == ' ' || in.peek() == '\t'));
}
void read_next_directive();
#if defined(TIMELOG_SUPPORT)
void clock_in_directive(char * line, bool capitalized);
void clock_out_directive(char * line, bool capitalized);
#endif
void default_commodity_directive(char * line);
void default_account_directive(char * line);
void price_conversion_directive(char * line);
void price_entry_directive(char * line);
void nomarket_directive(char * line);
void year_directive(char * line);
void option_directive(char * line);
void automated_entry_directive(char * line);
void period_entry_directive(char * line);
void entry_directive(char * line, std::streamsize len);
void include_directive(char * line);
void account_directive(char * line);
void end_directive(char * line);
void alias_directive(char * line);
void define_directive(char * line);
void general_directive(char * line);
xact_t * parse_xact(char * line,
std::streamsize len,
account_t * account,
entry_t * entry);
bool parse_xacts(account_t * account,
entry_base_t& entry,
const string& kind);
entry_t * parse_entry(char * line,
std::streamsize len,
account_t * account);
virtual expr_t::ptr_op_t lookup(const string& name);
};
void parse_amount_expr(session_t& session,
std::istream& in,
amount_t& amount,
xact_t * xact,
uint_least8_t flags = 0)
{
expr_t expr(in, flags | static_cast<uint_least8_t>(expr_t::PARSE_PARTIAL));
@ -140,47 +153,42 @@ namespace {
amount = result.as_amount();
DEBUG("textual.parse", "The transaction amount is " << amount);
#if defined(STORE_XACT_EXPRS)
return expr;
#endif
}
#if defined(STORE_XACT_EXPRS)
return none;
#endif
}
}
textual_parser_t::instance_t::instance_t
(std::list<account_t *>& _account_stack,
instance_t::instance_t(std::list<account_t *>& _account_stack,
#if defined(TIMELOG_SUPPORT)
time_log_t& _timelog,
time_log_t& _timelog,
#endif
std::istream& _in,
session_t& _session,
journal_t& _journal,
account_t * _master,
const path * _original_file,
instance_t * _parent)
std::istream& _in,
session_t& _session,
journal_t& _journal,
account_t * _master,
const path * _original_file,
instance_t * _parent)
: account_stack(_account_stack),
#if defined(TIMELOG_SUPPORT)
timelog(_timelog),
#endif
parent(_parent), in(_in), session(_session),
journal(_journal), master(_master),
original_file(_original_file)
parent(_parent), in(_in), session(_session), journal(_journal),
master(_master), original_file(_original_file)
{
TRACE_CTOR(textual_parser_t::instance_t, "...");
TRACE_CTOR(instance_t, "...");
if (! master)
master = journal.master;
account_stack.push_front(master);
pathname = journal.sources.back();
if (_original_file)
pathname = *_original_file;
else
pathname = "/dev/stdin";
}
textual_parser_t::instance_t::~instance_t()
instance_t::~instance_t()
{
TRACE_DTOR(textual_parser_t::instance_t);
TRACE_DTOR(instance_t);
account_stack.pop_front();
@ -188,7 +196,7 @@ textual_parser_t::instance_t::~instance_t()
journal.remove_entry_finalizer(auto_entry_finalizer.get());
}
void textual_parser_t::instance_t::parse()
void instance_t::parse()
{
INFO("Parsing file '" << pathname.string() << "'");
@ -241,13 +249,15 @@ void textual_parser_t::instance_t::parse()
TRACE_STOP(instance_parse, 1);
}
std::streamsize textual_parser_t::instance_t::read_line(char *& line)
std::streamsize instance_t::read_line(char *& line)
{
assert(in.good());
assert(! in.eof()); // no one should call us in that case
line_beg_pos = curr_pos;
check_for_signal();
in.getline(linebuf, MAX_LINE);
std::streamsize len = in.gcount();
@ -270,7 +280,7 @@ std::streamsize textual_parser_t::instance_t::read_line(char *& line)
return 0;
}
void textual_parser_t::instance_t::read_next_directive()
void instance_t::read_next_directive()
{
char * line;
std::streamsize len = read_line(line);
@ -369,8 +379,8 @@ void textual_parser_t::instance_t::read_next_directive()
#if defined(TIMELOG_SUPPORT)
void textual_parser_t::instance_t::clock_in_directive(char * line,
bool capitalized)
void instance_t::clock_in_directive(char * line,
bool capitalized)
{
string date(line, 2, 19);
@ -381,8 +391,8 @@ void textual_parser_t::instance_t::clock_in_directive(char * line,
account_stack.front()->find_account(p), n ? n : "");
}
void textual_parser_t::instance_t::clock_out_directive(char * line,
bool capitalized)
void instance_t::clock_out_directive(char * line,
bool capitalized)
{
string date(line, 2, 19);
@ -395,19 +405,19 @@ void textual_parser_t::instance_t::clock_out_directive(char * line,
}
#endif // TIMELOG_SUPPORT
void textual_parser_t::instance_t::default_commodity_directive(char * line)
void instance_t::default_commodity_directive(char * line)
{
amount_t amt(skip_ws(line + 1));
assert(amt.valid());
amount_t::current_pool->default_commodity = &amt.commodity();
}
void textual_parser_t::instance_t::default_account_directive(char * line)
void instance_t::default_account_directive(char * line)
{
journal.basket = account_stack.front()->find_account(skip_ws(line + 1));
}
void textual_parser_t::instance_t::price_conversion_directive(char * line)
void instance_t::price_conversion_directive(char * line)
{
if (char * p = std::strchr(line + 1, '=')) {
*p++ = '\0';
@ -440,7 +450,7 @@ namespace {
}
}
void textual_parser_t::instance_t::price_entry_directive(char * line)
void instance_t::price_entry_directive(char * line)
{
char * date_field_ptr = skip_ws(line + 1);
char * time_field_ptr = next_element(date_field_ptr);
@ -470,7 +480,7 @@ void textual_parser_t::instance_t::price_entry_directive(char * line)
commodity->add_price(datetime, price);
}
void textual_parser_t::instance_t::nomarket_directive(char * line)
void instance_t::nomarket_directive(char * line)
{
char * p = skip_ws(line + 1);
string symbol;
@ -481,12 +491,12 @@ void textual_parser_t::instance_t::nomarket_directive(char * line)
commodity->add_flags(COMMODITY_NOMARKET);
}
void textual_parser_t::instance_t::year_directive(char * line)
void instance_t::year_directive(char * line)
{
session.current_year = std::atoi(skip_ws(line + 1));
}
void textual_parser_t::instance_t::option_directive(char * line)
void instance_t::option_directive(char * line)
{
char * p = next_element(line);
if (! p) {
@ -497,7 +507,7 @@ void textual_parser_t::instance_t::option_directive(char * line)
process_option(line + 2, session, p, line);
}
void textual_parser_t::instance_t::automated_entry_directive(char * line)
void instance_t::automated_entry_directive(char * line)
{
if (! auto_entry_finalizer.get()) {
auto_entry_finalizer.reset(new auto_entry_finalizer_t(&journal));
@ -525,7 +535,7 @@ void textual_parser_t::instance_t::automated_entry_directive(char * line)
}
}
void textual_parser_t::instance_t::period_entry_directive(char * line)
void instance_t::period_entry_directive(char * line)
{
std::auto_ptr<period_entry_t> pe(new period_entry_t(skip_ws(line + 1)));
if (! pe->period)
@ -553,7 +563,7 @@ void textual_parser_t::instance_t::period_entry_directive(char * line)
}
}
void textual_parser_t::instance_t::entry_directive(char * line, std::streamsize len)
void instance_t::entry_directive(char * line, std::streamsize len)
{
TRACE_START(entries, 1, "Time spent handling entries:");
@ -574,7 +584,7 @@ void textual_parser_t::instance_t::entry_directive(char * line, std::streamsize
TRACE_STOP(entries, 1);
}
void textual_parser_t::instance_t::include_directive(char * line)
void instance_t::include_directive(char * line)
{
path filename(next_element(line));
@ -606,7 +616,7 @@ void textual_parser_t::instance_t::include_directive(char * line)
count += instance.count;
}
void textual_parser_t::instance_t::account_directive(char * line)
void instance_t::account_directive(char * line)
{
if (account_t * acct =
account_stack.front()->find_account(next_element(line)))
@ -615,12 +625,12 @@ void textual_parser_t::instance_t::account_directive(char * line)
assert(! "Failed to create account");
}
void textual_parser_t::instance_t::end_directive(char * line)
void instance_t::end_directive(char * line)
{
account_stack.pop_front();
}
void textual_parser_t::instance_t::alias_directive(char * line)
void instance_t::alias_directive(char * line)
{
char * b = skip_ws(line + 1);
if (char * e = std::strchr(b, '=')) {
@ -641,13 +651,13 @@ void textual_parser_t::instance_t::alias_directive(char * line)
}
}
void textual_parser_t::instance_t::define_directive(char * line)
void instance_t::define_directive(char * line)
{
expr_t def(skip_ws(line + 1));
def.compile(session); // causes definitions to be established
}
void textual_parser_t::instance_t::general_directive(char * line)
void instance_t::general_directive(char * line)
{
char * p = next_element(line);
string word(line + 1);
@ -698,10 +708,10 @@ void textual_parser_t::instance_t::general_directive(char * line)
}
}
xact_t * textual_parser_t::instance_t::parse_xact(char * line,
std::streamsize len,
account_t * account,
entry_t * entry)
xact_t * instance_t::parse_xact(char * line,
std::streamsize len,
account_t * account,
entry_t * entry)
{
TRACE_START(xact_details, 1, "Time spent parsing transactions:");
@ -992,9 +1002,9 @@ xact_t * textual_parser_t::instance_t::parse_xact(char * line,
}
}
bool textual_parser_t::instance_t::parse_xacts(account_t * account,
entry_base_t& entry,
const string& kind)
bool instance_t::parse_xacts(account_t * account,
entry_base_t& entry,
const string& kind)
{
TRACE_START(entry_xacts, 1, "Time spent parsing transactions:");
@ -1016,9 +1026,9 @@ bool textual_parser_t::instance_t::parse_xacts(account_t * account,
return added;
}
entry_t * textual_parser_t::instance_t::parse_entry(char * line,
std::streamsize len,
account_t * account)
entry_t * instance_t::parse_entry(char * line,
std::streamsize len,
account_t * account)
{
TRACE_START(entry_text, 1, "Time spent parsing entry text:");
@ -1120,9 +1130,46 @@ entry_t * textual_parser_t::instance_t::parse_entry(char * line,
return curr.release();
}
expr_t::ptr_op_t textual_parser_t::instance_t::lookup(const string& name)
expr_t::ptr_op_t instance_t::lookup(const string& name)
{
return session.lookup(name);
}
std::size_t journal_t::parse(std::istream& in,
session_t& session,
account_t * master,
const path * original_file)
{
TRACE_START(parsing_total, 1, "Total time spent parsing text:");
std::list<account_t *> account_stack;
#if defined(TIMELOG_SUPPORT)
time_log_t timelog(*this);
#endif
instance_t parsing_instance(account_stack,
#if defined(TIMELOG_SUPPORT)
timelog,
#endif
in, session, *this, master, original_file);
parsing_instance.parse();
session.clean_accounts(); // remove calculated totals
TRACE_STOP(parsing_total, 1);
// These tracers were started in textual.cc
TRACE_FINISH(entry_text, 1);
TRACE_FINISH(entry_details, 1);
TRACE_FINISH(entry_xacts, 1);
TRACE_FINISH(entries, 1);
TRACE_FINISH(instance_parse, 1); // report per-instance timers
TRACE_FINISH(parsing_total, 1);
if (parsing_instance.errors > 0)
throw static_cast<int>(parsing_instance.errors);
return parsing_instance.count;
}
} // namespace ledger

View file

@ -1,171 +0,0 @@
/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @defgroup parse Parsers
*/
/**
* @file textual.h
* @author John Wiegley
*
* @ingroup parse
*
* @brief Brief
*
* Long.
*/
#ifndef _TEXTUAL_H
#define _TEXTUAL_H
#include "journal.h"
#include "account.h"
namespace ledger {
#define TIMELOG_SUPPORT 1
#if defined(TIMELOG_SUPPORT)
class time_log_t;
#endif
/**
* @brief Brief
*
* Long.
*/
class textual_parser_t : public journal_t::parser_t
{
public:
#if defined(TEST_FOR_PARSER)
virtual bool test(std::istream& in) const;
#endif
virtual std::size_t parse(std::istream& in,
session_t& session,
journal_t& journal,
account_t * master = NULL,
const path * original_file = NULL);
protected:
class instance_t : public noncopyable, public scope_t
{
static const std::size_t MAX_LINE = 1024;
public:
std::list<account_t *>& account_stack;
#if defined(TIMELOG_SUPPORT)
time_log_t& timelog;
#endif
instance_t * parent;
std::istream& in;
session_t& session;
journal_t& journal;
account_t * master;
const path * original_file;
accounts_map account_aliases;
path pathname;
char linebuf[MAX_LINE + 1];
std::size_t linenum;
istream_pos_type line_beg_pos;
istream_pos_type curr_pos;
std::size_t count;
std::size_t errors;
scoped_ptr<auto_entry_finalizer_t> auto_entry_finalizer;
instance_t(std::list<account_t *>& _account_stack,
#if defined(TIMELOG_SUPPORT)
time_log_t& _timelog,
#endif
std::istream& _in,
session_t& _session,
journal_t& _journal,
account_t * _master = NULL,
const path * _original_file = NULL,
instance_t * _parent = NULL);
~instance_t();
void parse();
std::streamsize read_line(char *& line);
bool peek_whitespace_line() {
return (in.good() && ! in.eof() &&
(in.peek() == ' ' || in.peek() == '\t'));
}
void read_next_directive();
#if defined(TIMELOG_SUPPORT)
void clock_in_directive(char * line, bool capitalized);
void clock_out_directive(char * line, bool capitalized);
#endif
void default_commodity_directive(char * line);
void default_account_directive(char * line);
void price_conversion_directive(char * line);
void price_entry_directive(char * line);
void nomarket_directive(char * line);
void year_directive(char * line);
void option_directive(char * line);
void automated_entry_directive(char * line);
void period_entry_directive(char * line);
void entry_directive(char * line, std::streamsize len);
void include_directive(char * line);
void account_directive(char * line);
void end_directive(char * line);
void alias_directive(char * line);
void define_directive(char * line);
void general_directive(char * line);
xact_t * parse_xact(char * line,
std::streamsize len,
account_t * account,
entry_t * entry);
bool parse_xacts(account_t * account,
entry_base_t& entry,
const string& kind);
entry_t * parse_entry(char * line,
std::streamsize len,
account_t * account);
virtual expr_t::ptr_op_t lookup(const string& name);
};
friend class instance_t;
};
} // namespace ledger
#endif // _TEXTUAL_H