#ifndef __FST_IO_H__
#define __FST_IO_H__
// fst-io.h
// This is a copy of the OPENFST SDK application sample files ...
// except for the main functions ifdef'ed out
// 2007, 2008 Nuance Communications
//
// print-main.h compile-main.h
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// \file
// Classes and functions to compile a binary Fst from textual input.
// Includes helper function for fstcompile.cc that templates the main
// on the arc type to support multiple and extensible arc types.
#include <fstream>
#include <sstream>
#include "fst/lib/fst.h"
#include "fst/lib/fstlib.h"
#include "fst/lib/fst-decl.h"
#include "fst/lib/vector-fst.h"
#include "fst/lib/arcsort.h"
#include "fst/lib/invert.h"
namespace fst {
template <class A> class FstPrinter {
public:
typedef A Arc;
typedef typename A::StateId StateId;
typedef typename A::Label Label;
typedef typename A::Weight Weight;
FstPrinter(const Fst<A> &fst,
const SymbolTable *isyms,
const SymbolTable *osyms,
const SymbolTable *ssyms,
bool accep)
: fst_(fst), isyms_(isyms), osyms_(osyms), ssyms_(ssyms),
accep_(accep && fst.Properties(kAcceptor, true)), ostrm_(0) {}
// Print Fst to an output strm
void Print(ostream *ostrm, const string &dest) {
ostrm_ = ostrm;
dest_ = dest;
StateId start = fst_.Start();
if (start == kNoStateId)
return;
// initial state first
PrintState(start);
for (StateIterator< Fst<A> > siter(fst_);
!siter.Done();
siter.Next()) {
StateId s = siter.Value();
if (s != start)
PrintState(s);
}
}
private:
// Maximum line length in text file.
static const int kLineLen = 8096;
void PrintId(int64 id, const SymbolTable *syms,
const char *name) const {
if (syms) {
string symbol = syms->Find(id);
if (symbol == "") {
LOG(ERROR) << "FstPrinter: Integer " << id
<< " is not mapped to any textual symbol"
<< ", symbol table = " << syms->Name()
<< ", destination = " << dest_;
exit(1);
}
*ostrm_ << symbol;
} else {
*ostrm_ << id;
}
}
void PrintStateId(StateId s) const {
PrintId(s, ssyms_, "state ID");
}
void PrintILabel(Label l) const {
PrintId(l, isyms_, "arc input label");
}
void PrintOLabel(Label l) const {
PrintId(l, osyms_, "arc output label");
}
void PrintState(StateId s) const {
bool output = false;
for (ArcIterator< Fst<A> > aiter(fst_, s);
!aiter.Done();
aiter.Next()) {
Arc arc = aiter.Value();
PrintStateId(s);
*ostrm_ << "\t";
PrintStateId(arc.nextstate);
*ostrm_ << "\t";
PrintILabel(arc.ilabel);
if (!accep_) {
*ostrm_ << "\t";
PrintOLabel(arc.olabel);
}
if (arc.weight != Weight::One())
*ostrm_ << "\t" << arc.weight;
*ostrm_ << "\n";
output = true;
}
Weight final = fst_.Final(s);
if (final != Weight::Zero() || !output) {
PrintStateId(s);
if (final != Weight::One()) {
*ostrm_ << "\t" << final;
}
*ostrm_ << "\n";
}
}
const Fst<A> &fst_;
const SymbolTable *isyms_; // ilabel symbol table
const SymbolTable *osyms_; // olabel symbol table
const SymbolTable *ssyms_; // slabel symbol table
bool accep_; // print as acceptor when possible
ostream *ostrm_; // binary FST destination
string dest_; // binary FST destination name
DISALLOW_EVIL_CONSTRUCTORS(FstPrinter);
};
#if 0
// Main function for fstprint templated on the arc type.
template <class Arc>
int PrintMain(int argc, char **argv, istream &istrm,
const FstReadOptions &opts) {
Fst<Arc> *fst = Fst<Arc>::Read(istrm, opts);
if (!fst) return 1;
string dest = "standard output";
ostream *ostrm = &std::cout;
if (argc == 3) {
dest = argv[2];
ostrm = new ofstream(argv[2]);
if (!*ostrm) {
LOG(ERROR) << argv[0] << ": Open failed, file = " << argv[2];
return 0;
}
}
ostrm->precision(9);
const SymbolTable *isyms = 0, *osyms = 0, *ssyms = 0;
if (!FLAGS_isymbols.empty() && !FLAGS_numeric) {
isyms = SymbolTable::ReadText(FLAGS_isymbols);
if (!isyms) exit(1);
}
if (!FLAGS_osymbols.empty() && !FLAGS_numeric) {
osyms = SymbolTable::ReadText(FLAGS_osymbols);
if (!osyms) exit(1);
}
if (!FLAGS_ssymbols.empty() && !FLAGS_numeric) {
ssyms = SymbolTable::ReadText(FLAGS_ssymbols);
if (!ssyms) exit(1);
}
if (!isyms && !FLAGS_numeric)
isyms = fst->InputSymbols();
if (!osyms && !FLAGS_numeric)
osyms = fst->OutputSymbols();
FstPrinter<Arc> fstprinter(*fst, isyms, osyms, ssyms, FLAGS_acceptor);
fstprinter.Print(ostrm, dest);
if (isyms && !FLAGS_save_isymbols.empty())
isyms->WriteText(FLAGS_save_isymbols);
if (osyms && !FLAGS_save_osymbols.empty())
osyms->WriteText(FLAGS_save_osymbols);
if (ostrm != &std::cout)
delete ostrm;
return 0;
}
#endif
template <class A> class FstReader {
public:
typedef A Arc;
typedef typename A::StateId StateId;
typedef typename A::Label Label;
typedef typename A::Weight Weight;
FstReader(istream &istrm, const string &source,
const SymbolTable *isyms, const SymbolTable *osyms,
const SymbolTable *ssyms, bool accep, bool ikeep,
bool okeep, bool nkeep)
: nline_(0), source_(source),
isyms_(isyms), osyms_(osyms), ssyms_(ssyms),
nstates_(0), keep_state_numbering_(nkeep) {
char line[kLineLen];
while (istrm.getline(line, kLineLen)) {
++nline_;
vector<char *> col;
SplitToVector(line, "\n\t ", &col, true);
if (col.size() == 0 || col[0][0] == '\0') // empty line
continue;
if (col.size() > 5 ||
col.size() > 4 && accep ||
col.size() == 3 && !accep) {
LOG(ERROR) << "FstReader: Bad number of columns, source = " << source_
<< ", line = " << nline_;
exit(1);
}
StateId s = StrToStateId(col[0]);
while (s >= fst_.NumStates())
fst_.AddState();
if (nline_ == 1)
fst_.SetStart(s);
Arc arc;
StateId d = s;
switch (col.size()) {
case 1:
fst_.SetFinal(s, Weight::One());
break;
case 2:
fst_.SetFinal(s, StrToWeight(col[1], true));
break;
case 3:
arc.nextstate = d = StrToStateId(col[1]);
arc.ilabel = StrToILabel(col[2]);
arc.olabel = arc.ilabel;
arc.weight = Weight::One();
fst_.AddArc(s, arc);
break;
case 4:
arc.nextstate = d = StrToStateId(col[1]);
arc.ilabel = StrToILabel(col[2]);
if (accep) {
arc.olabel = arc.ilabel;
arc.weight = StrToWeight(col[3], false);
} else {
arc.olabel = StrToOLabel(col[3]);
arc.weight = Weight::One();
}
fst_.AddArc(s, arc);
break;
case 5:
arc.nextstate = d = StrToStateId(col[1]);
arc.ilabel = StrToILabel(col[2]);
arc.olabel = StrToOLabel(col[3]);
arc.weight = StrToWeight(col[4], false);
fst_.AddArc(s, arc);
}
while (d >= fst_.NumStates())
fst_.AddState();
}
if (ikeep)
fst_.SetInputSymbols(isyms);
if (okeep)
fst_.SetOutputSymbols(osyms);
}
const VectorFst<A> &Fst() const { return fst_; }
private:
// Maximum line length in text file.
static const int kLineLen = 8096;
int64 StrToId(const char *s, const SymbolTable *syms,
const char *name) const {
int64 n;
if (syms) {
n = syms->Find(s);
if (n < 0) {
LOG(ERROR) << "FstReader: Symbol \"" << s
<< "\" is not mapped to any integer " << name
<< ", symbol table = " << syms->Name()
<< ", source = " << source_ << ", line = " << nline_;
exit(1);
}
} else {
char *p;
n = strtoll(s, &p, 10);
if (p < s + strlen(s) || n < 0) {
LOG(ERROR) << "FstReader: Bad " << name << " integer = \"" << s
<< "\", source = " << source_ << ", line = " << nline_;
exit(1);
}
}
return n;
}
StateId StrToStateId(const char *s) {
StateId n = StrToId(s, ssyms_, "state ID");
if (keep_state_numbering_)
return n;
// remap state IDs to make dense set
typename hash_map<StateId, StateId>::const_iterator it = states_.find(n);
if (it == states_.end()) {
states_[n] = nstates_;
return nstates_++;
} else {
return it->second;
}
}
StateId StrToILabel(const char *s) const {
return StrToId(s, isyms_, "arc ilabel");
}
StateId StrToOLabel(const char *s) const {
return StrToId(s, osyms_, "arc olabel");
}
Weight StrToWeight(const char *s, bool allow_zero) const {
Weight w;
istringstream strm(s);
strm >> w;
if (strm.fail() || !allow_zero && w == Weight::Zero()) {
LOG(ERROR) << "FstReader: Bad weight = \"" << s
<< "\", source = " << source_ << ", line = " << nline_;
exit(1);
}
return w;
}
VectorFst<A> fst_;
size_t nline_;
string source_; // text FST source name
const SymbolTable *isyms_; // ilabel symbol table
const SymbolTable *osyms_; // olabel symbol table
const SymbolTable *ssyms_; // slabel symbol table
hash_map<StateId, StateId> states_; // state ID map
StateId nstates_; // number of seen states
bool keep_state_numbering_;
DISALLOW_EVIL_CONSTRUCTORS(FstReader);
};
#if 0
// Main function for fstcompile templated on the arc type. Last two
// arguments unneeded since fstcompile passes the arc type as a flag
// unlike the other mains, which infer the arc type from an input Fst.
template <class Arc>
int CompileMain(int argc, char **argv, istream& /* strm */,
const FstReadOptions & /* opts */) {
char *ifilename = "standard input";
istream *istrm = &std::cin;
if (argc > 1 && strcmp(argv[1], "-") != 0) {
ifilename = argv[1];
istrm = new ifstream(ifilename);
if (!*istrm) {
LOG(ERROR) << argv[0] << ": Open failed, file = " << ifilename;
return 1;
}
}
const SymbolTable *isyms = 0, *osyms = 0, *ssyms = 0;
if (!FLAGS_isymbols.empty()) {
isyms = SymbolTable::ReadText(FLAGS_isymbols);
if (!isyms) exit(1);
}
if (!FLAGS_osymbols.empty()) {
osyms = SymbolTable::ReadText(FLAGS_osymbols);
if (!osyms) exit(1);
}
if (!FLAGS_ssymbols.empty()) {
ssyms = SymbolTable::ReadText(FLAGS_ssymbols);
if (!ssyms) exit(1);
}
FstReader<Arc> fstreader(*istrm, ifilename, isyms, osyms, ssyms,
FLAGS_acceptor, FLAGS_keep_isymbols,
FLAGS_keep_osymbols, FLAGS_keep_state_numbering);
const Fst<Arc> *fst = &fstreader.Fst();
if (FLAGS_fst_type != "vector") {
fst = Convert<Arc>(*fst, FLAGS_fst_type);
if (!fst) return 1;
}
fst->Write(argc > 2 ? argv[2] : "");
if (istrm != &std::cin)
delete istrm;
return 0;
}
#endif
} // namespace fst
#endif /* __FST_IO_H__ */