Added C++ version of the tab-program

This commit is contained in:
Frank B. Brokken 2014-09-22 14:00:32 +02:00
parent 3ec8c904d4
commit 87bb986b23
22 changed files with 1416 additions and 0 deletions

View file

@ -0,0 +1,3 @@
#define AUTHOR "Frank B. Brokken (f.b.brokken@rug.nl)"
#define VERSION "2.00.00"
#define YEARS "1999-2014"

View file

@ -0,0 +1,47 @@
#include "main.ih"
bool arguments(int argc, char **argv)
{
if (argc == 1)
{
string progname(argv[0]);
size_t pos = progname.find_last_of('/');
if (pos != string::npos)
progname.erase(0, pos + 1);
usage(progname);
return false;
}
while (true)
{
switch (getopt(argc, argv, "c:des:q"))
{
case 'e':
g_entab = true;
break;
case 's':
g_minSpaces = stoul(optarg);
break;
case 'c':
g_tabPos = stoul(optarg);
break;
case 'q':
g_quiet = true;
break;
default:
return true;
}
}
}

View file

@ -0,0 +1,7 @@
#include "main.ih"
bool g_entab = false;
bool g_quiet = false;
size_t g_minSpaces = 4;
size_t g_tabPos = 8;

View file

@ -0,0 +1,12 @@
#ifndef INCLUDED_GLOBALS_H_
#define INCLUDED_GLOBALS_H_
#include <cstddef>
extern size_t g_minSpaces;
extern size_t g_tabPos;
extern bool g_entab;
extern bool g_quiet;
#endif

View file

@ -0,0 +1,123 @@
// Inspect the following #defines. Change them to taste. If you don't
// need a particular option, change its value into an empty string
// For more information about this file: 'man 7 icmconf'
// define any additional libraries the program may need:
#define ADD_LIBRARIES ""
// define any additional paths (other than the standard paths) the
// additional libraries are located in:
#define ADD_LIBRARY_PATHS ""
// Uncomment to clear the screen just before starting the compilation
// process
//#define CLS
// The compiler to use. Define CC instead if a C compiler should be used.
#define CXX "g++"
//#define CC "gcc"
// The compiler options to use. Define CFLAGS instead if a C compiler is
// used.
#define CXXFLAGS " --std=c++0x -Wall -g -O2"
//#define CFLAGS " -Wall -g -O2"
// Options passed to the linker:
#define LDFLAGS ""
// Uncomment to construct a library. Optionally use another name (don't
// use lib or an extension like .a)
//#define LIBRARY "modules"
// The source containing main():
#define MAIN "main.cc"
// The extension of object modules:
#define OBJ_EXT ".o"
// If a parser must be generated define the subdirectory containing the
// parser's specification file
#define PARSER_DIR ""
// Specify additional grammar specification files using patterns
// these files are (in)directly included by PARSSPEC. Specify patterns
// relative to PARSER_DIR
//#define PARSFILES ""
// Flags to provide PARSGEN with:
#define PARSFLAGS "-V"
// What is the program generating a parser?
#define PARSGEN "bisonc++"
// Name of the file generated by the parser generator containing the
// parser function
#define PARSOUT "parse.cc"
// What is the grammar specification file?
#define PARSSPEC "grammar"
// Uncomment to relink the binary, even when no sources were changed
//#define REFRESH
// If a lexical scanner must be generated: the subdirectory containing
// the scanner's specification file.
#define SCANNER_DIR "scanner"
// Specify additional lexer specification files using patterns
// these files are (in)directly included by SCANSPEC
//#define SCANFILES ""
// Flags to provide SCANGEN with:
#define SCANFLAGS ""
// What is the program generating the lexical scanner?
#define SCANGEN "flexc++"
// Name of the file generated by the lexical scanner
#define SCANOUT "lex.cc"
// Name of the lexical scanner specification file
#define SCANSPEC "lexer"
// Uncomment to construct a shared library
//#define SHARED
// When creating a shared library:
// Specify the names of any libraries and library paths that are required
// by the shared library. E.g., if a library is found in /usr/lib/special
// use "-L/usr/lib/special -lspecial" if the name of the library is
// libspecial.so
// The /lib and /usr/lib paths are usually predefined and need not be
// specified
#define SHAREDREQ ""
// The pattern locating sources in a directory:
#define SOURCES "*.cc"
// Directory below this directory to contain temporary results
#define TMP_DIR "tmp"
// Uncomment to use the ALL facility and a class dependency setup in the
// CLASSES file. When a directory contains a file ALL (optionally rename
// this filename by providing an alternative name) then all its sources
// and all sources of all classes depending on it are also compiled.
// Class dependencies are indicated by the class name (as the first
// word on a line) optionally followed by additional class names, which
// are the classes directly depending on the line's first class name.
//#define USE_ALL "a"
// should commands be echoed (ON) or not (OFF) ?
#define USE_ECHO ON
// Use the VERSION file
#define USE_VERSION
// #define DEFCOM "program" (or "library") may be added (by, e.g.,
// icmstart)
#define DEFCOM "program"

View file

@ -0,0 +1,23 @@
#include "main.ih"
int main(int argc, char **argv)
try
{
if (not arguments(argc, argv))
return 0;
argv += optind;
argc -= optind;
Scanner scanner;
if (argv[0][0] == '-')
scanner.lex();
if (not process(argv, scanner))
return 1;
}
catch (...)
{
return 1;
}

View file

@ -0,0 +1,25 @@
#include <iostream>
#include <string>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "globals.h"
#include "scanner/scanner.h"
namespace Icmbuild
{
extern char version[];
extern char years[];
extern char author[];
};
bool arguments(int argc, char **argv);
void usage(std::string const &progname);
bool normalFile(char const *fileName);
bool process(char **argv, Scanner &scanner);
using namespace std;

View file

@ -0,0 +1,16 @@
#include "main.ih"
bool normalFile(char const *fileName)
{
struct stat fileInfo;
if (lstat(fileName, &fileInfo))
{
cout << "Can't stat `" << fileName << "': skipping\n";
return false;
}
return S_ISREG(fileInfo.st_mode);
}

View file

@ -0,0 +1,29 @@
#include "main.ih"
bool process(char **argv, Scanner &scanner)
{
char tempfile[] = "tab.tmp";
for (; *argv; ++argv)
{
if (not normalFile(*argv))
continue;
if (!g_quiet)
cout << "processing `" << *argv << "'\n";
unlink(tempfile);
if (rename(*argv, tempfile))
{
cout << "can't rename `" << *argv << "'\n";
return false;
}
scanner.switchStreams(tempfile, *argv);
scanner.lex();
}
unlink(tempfile);
return true;
}

View file

@ -0,0 +1,9 @@
#include "scanner.ih"
void Scanner::anyChar()
{
if (g_entab)
processSpaces();
++d_column;
out().put(matched()[0]);
}

View file

@ -0,0 +1,10 @@
#include "scanner.ih"
void Scanner::blank()
{
++d_column;
++d_nSpaces;
if (not g_entab)
out().put(' ');
}

View file

@ -0,0 +1,5 @@
#include "scanner.ih"
void Scanner::
{
}

View file

@ -0,0 +1,502 @@
// Generated by Flexc++ V2.01.00 on Mon, 22 Sep 2014 12:51:12 +0200
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdexcept>
// $insert class_ih
#include "scanner.ih"
// s_ranges__: use (unsigned) characters as index to obtain
// that character's range-number.
// The range for EOF is defined in a constant in the
// class header file
size_t const ScannerBase::s_ranges__[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5,
};
// s_dfa__ contains the rows of *all* DFAs ordered by start state. The
// enum class StartCondition__ is defined in the baseclass header
// StartCondition__::INITIAL is always 0. Each entry defines the row to
// transit to if the column's character range was sensed. Row numbers are
// relative to the used DFA, and d_dfaBase__ is set to the first row of
// the subset to use. The row's final two values are respectively the
// rule that may be matched at this state, and the rule's FINAL flag. If
// the final value equals FINAL (= 1) then, if there's no continuation,
// the rule is matched. If the BOL flag (8) is also set (so FINAL + BOL (=
// 9) is set) then the rule only matches when d_atBOL is also true.
int const ScannerBase::s_dfa__[][9] =
{
// INITIAL
{-1, 1, 2, 3, 4, 3,-1, -1, -1}, // 0
{-1,-1,-1,-1,-1,-1,-1, 1, -1}, // 1
{-1,-1,-1,-1,-1,-1,-1, 2, -1}, // 2
{-1,-1,-1,-1,-1,-1,-1, 3, -1}, // 3
{-1,-1,-1,-1,-1,-1,-1, 0, -1}, // 4
};
int const (*ScannerBase::s_dfaBase__[])[9] =
{
s_dfa__ + 0,
};
size_t ScannerBase::s_istreamNr = 0;
// $insert inputImplementation
ScannerBase::Input::Input()
:
d_in(0),
d_lineNr(1)
{}
ScannerBase::Input::Input(std::istream *iStream, size_t lineNr)
:
d_in(iStream),
d_lineNr(lineNr)
{}
size_t ScannerBase::Input::get()
{
switch (size_t ch = next()) // get the next input char
{
case '\n':
++d_lineNr;
// FALLING THROUGH
default:
return ch;
}
}
size_t ScannerBase::Input::next()
{
size_t ch;
if (d_deque.empty()) // deque empty: next char fm d_in
{
if (d_in == 0)
return AT_EOF;
ch = d_in->get();
return *d_in ? ch : static_cast<size_t>(AT_EOF);
}
ch = d_deque.front();
d_deque.pop_front();
return ch;
}
void ScannerBase::Input::reRead(size_t ch)
{
if (ch < 0x100)
{
if (ch == '\n')
--d_lineNr;
d_deque.push_front(ch);
}
}
void ScannerBase::Input::reRead(std::string const &str, size_t fm)
{
for (size_t idx = str.size(); idx-- > fm; )
reRead(str[idx]);
}
ScannerBase::ScannerBase(std::istream &in, std::ostream &out)
:
d_filename("-"),
d_out(new std::ostream(out.rdbuf())),
// $insert interactiveInit
d_in(0),
d_input(new std::istream(in.rdbuf())),
d_dfaBase__(s_dfa__)
{}
void ScannerBase::switchStream__(std::istream &in, size_t lineNr)
{
d_input.close();
d_input = Input(new std::istream(in.rdbuf()), lineNr);
}
ScannerBase::ScannerBase(std::string const &infilename, std::string const &outfilename)
:
d_filename(infilename),
d_out(outfilename == "-" ? new std::ostream(std::cout.rdbuf()) :
outfilename == "" ? new std::ostream(std::cerr.rdbuf()) :
new std::ofstream(outfilename)),
d_input(new std::ifstream(infilename)),
d_dfaBase__(s_dfa__)
{}
void ScannerBase::switchStreams(std::istream &in, std::ostream &out)
{
switchStream__(in, 1);
switchOstream(out);
}
void ScannerBase::switchOstream(std::ostream &out)
{
*d_out << std::flush;
d_out.reset(new std::ostream(out.rdbuf()));
}
// $insert debugFunctions
void ScannerBase::setDebug(bool onOff)
{}
bool ScannerBase::debug() const
{
return false;
}
void ScannerBase::redo(size_t nChars)
{
size_t from = nChars >= length() ? 0 : length() - nChars;
d_input.reRead(d_matched, from);
d_matched.resize(from);
}
void ScannerBase::switchOstream(std::string const &outfilename)
{
*d_out << std::flush;
d_out.reset(
outfilename == "-" ? new std::ostream(std::cout.rdbuf()) :
outfilename == "" ? new std::ostream(std::cerr.rdbuf()) :
new std::ofstream(outfilename));
}
void ScannerBase::switchIstream(std::string const &infilename)
{
d_input.close();
d_filename = infilename;
d_input = Input(new std::ifstream(infilename));
d_atBOL = true;
}
void ScannerBase::switchStreams(std::string const &infilename,
std::string const &outfilename)
{
switchOstream(outfilename);
switchIstream(infilename);
}
void ScannerBase::pushStream(std::istream &istr)
{
std::istream *streamPtr = new std::istream(istr.rdbuf());
p_pushStream("(istream)", streamPtr);
}
void ScannerBase::pushStream(std::string const &name)
{
std::istream *streamPtr = new std::ifstream(name);
if (!*streamPtr)
{
delete streamPtr;
throw std::runtime_error("Cannot read " + name);
}
p_pushStream(name, streamPtr);
}
void ScannerBase::p_pushStream(std::string const &name, std::istream *streamPtr)
{
if (d_streamStack.size() == s_maxSizeofStreamStack__)
{
delete streamPtr;
throw std::length_error("Max stream stack size exceeded");
}
d_streamStack.push_back(StreamStruct{d_filename, d_input});
d_filename = name;
d_input = Input(streamPtr);
d_atBOL = true;
}
bool ScannerBase::popStream()
{
d_input.close();
if (d_streamStack.empty())
return false;
StreamStruct &top = d_streamStack.back();
d_input = top.pushedInput;
d_filename = top.pushedName;
d_streamStack.pop_back();
return true;
}
// See the manual's section `Run-time operations' section for an explanation
// of this member.
ScannerBase::ActionType__ ScannerBase::actionType__(size_t range)
{
d_nextState = d_dfaBase__[d_state][range];
if (d_nextState != -1) // transition is possible
return ActionType__::CONTINUE;
if (knownFinalState()) // FINAL state reached
return ActionType__::MATCH;
if (d_matched.size())
return ActionType__::ECHO_FIRST; // no match, echo the 1st char
return range != s_rangeOfEOF__ ?
ActionType__::ECHO_CH
:
ActionType__::RETURN;
}
void ScannerBase::accept(size_t nChars) // old name: less
{
if (nChars < d_matched.size())
{
d_input.reRead(d_matched, nChars);
d_matched.resize(nChars);
}
}
void ScannerBase::setMatchedSize(size_t length)
{
d_input.reRead(d_matched, length); // reread the tail section
d_matched.resize(length); // return what's left
}
// At this point a rule has been matched. The next character is not part of
// the matched rule and is sent back to the input. The final match length
// is determined, the index of the matched rule is determined, and then
// d_atBOL is updated. Finally the rule's index is returned.
// The numbers behind the finalPtr assignments are explained in the
// manual's `Run-time operations' section.
size_t ScannerBase::matched__(size_t ch)
{
d_input.reRead(ch);
FinalData *finalPtr;
if (not d_atBOL) // not at BOL
finalPtr = &d_final.std; // then use the std rule (3, 4)
// at BOL
else if (not available(d_final.std.rule)) // only a BOL rule avail.
finalPtr = &d_final.bol; // use the BOL rule (6)
else if (not available(d_final.bol.rule)) // only a std rule is avail.
finalPtr = &d_final.std; // use the std rule (7)
else if ( // Both are available (8)
d_final.bol.length != // check lengths of matched texts
d_final.std.length // unequal lengths, use the rule
) // having the longer match length
finalPtr =
d_final.bol.length > d_final.std.length ?
&d_final.bol
:
&d_final.std;
else // lengths are equal: use 1st rule
finalPtr =
d_final.bol.rule < d_final.std.rule ?
&d_final.bol
:
&d_final.std;
setMatchedSize(finalPtr->length);
d_atBOL = d_matched.back() == '\n';
return finalPtr->rule;
}
size_t ScannerBase::getRange__(int ch) // using int to prevent casts
{
return ch == AT_EOF ? as<size_t>(s_rangeOfEOF__) : s_ranges__[ch];
}
// At this point d_nextState contains the next state and continuation is
// possible. The just read char. is appended to d_match
void ScannerBase::continue__(int ch)
{
d_state = d_nextState;
if (ch != AT_EOF)
d_matched += ch;
}
void ScannerBase::echoCh__(size_t ch)
{
*d_out << as<char>(ch);
d_atBOL = ch == '\n';
}
// At this point there is no continuation. The last character is
// pushed back into the input stream as well as all but the first char. in
// the buffer. The first char. in the buffer is echoed to stderr.
// If there isn't any 1st char yet then the current char doesn't fit any
// rules and that char is then echoed
void ScannerBase::echoFirst__(size_t ch)
{
d_input.reRead(ch);
d_input.reRead(d_matched, 1);
echoCh__(d_matched[0]);
}
// Update the rules associated with the current state, do this separately
// for BOL and std rules.
// If a rule was set, update the rule index and the current d_matched
// length.
void ScannerBase::updateFinals__()
{
size_t len = d_matched.size();
int const *rf = d_dfaBase__[d_state] + s_finIdx__;
if (rf[0] != -1) // update to the latest std rule
{
d_final.std = FinalData { as<size_t>(rf[0]), len };
}
if (rf[1] != -1) // update to the latest bol rule
{
d_final.bol = FinalData { as<size_t>(rf[1]), len };
}
}
void ScannerBase::reset__()
{
d_final = Final{
FinalData{s_unavailable, 0},
FinalData {s_unavailable, 0}
};
d_state = 0;
d_return = true;
if (!d_more)
d_matched.clear();
d_more = false;
}
int Scanner::executeAction__(size_t ruleIdx)
try
{
switch (ruleIdx)
{
// $insert actions
case 0:
{
#line 8 "lexer"
blank();
}
break;
case 1:
{
#line 10 "lexer"
tab();
}
break;
case 2:
{
#line 12 "lexer"
newline();
}
break;
case 3:
{
#line 14 "lexer"
anyChar();
}
break;
}
noReturn__();
return 0;
}
catch (Leave__ value)
{
return static_cast<int>(value);
}
int Scanner::lex__()
{
reset__();
preCode();
while (true)
{
size_t ch = get__(); // fetch next char
size_t range = getRange__(ch); // determine the range
updateFinals__(); // update the state's Final info
switch (actionType__(range)) // determine the action
{
case ActionType__::CONTINUE:
continue__(ch);
continue;
case ActionType__::MATCH:
{
d_token__ = executeAction__(matched__(ch));
if (return__())
{
print();
postCode(PostEnum__::RETURN);
return d_token__;
}
break;
}
case ActionType__::ECHO_FIRST:
echoFirst__(ch);
break;
case ActionType__::ECHO_CH:
echoCh__(ch);
break;
case ActionType__::RETURN:
if (!popStream())
{
postCode(PostEnum__::END);
return 0;
}
postCode(PostEnum__::POP);
continue;
} // switch
postCode(PostEnum__::WIP);
reset__();
preCode();
} // while
}
void ScannerBase::print__() const
{
}

View file

@ -0,0 +1,14 @@
%filenames scanner
//%interactive
//%debug
%%
[ ] blank();
\t tab();
\n newline();
. anyChar();

View file

@ -0,0 +1,8 @@
#include "scanner.ih"
void Scanner::newline()
{
out().put('\n');
d_column = 0;
d_nSpaces = 0;
}

View file

@ -0,0 +1,23 @@
#include "scanner.ih"
void Scanner::processSpaces()
{
size_t nTabs;
if (d_nSpaces >= g_minSpaces)
{
nTabs = d_column / g_tabPos - (d_column - d_nSpaces) / g_tabPos;
if (nTabs > 0)
{
d_nSpaces = d_column % g_tabPos;
for (; nTabs; nTabs--)
out().put('\t');
}
}
if (d_nSpaces != 0)
out() << setw(d_nSpaces) << ' ';
d_nSpaces = 0;
}

View file

@ -0,0 +1,78 @@
// Generated by Flexc++ V2.01.00 on Mon, 22 Sep 2014 12:29:41 +0200
#ifndef Scanner_H_INCLUDED_
#define Scanner_H_INCLUDED_
// $insert baseclass_h
#include "scannerbase.h"
// $insert classHead
class Scanner: public ScannerBase
{
size_t d_column = 0;
size_t d_nSpaces = 0;
public:
explicit Scanner(std::istream &in = std::cin,
std::ostream &out = std::cout);
Scanner(std::string const &infile, std::string const &outfile);
// $insert lexFunctionDecl
int lex();
private:
void blank();
void tab();
void processSpaces();
void newline();
void anyChar();
int lex__();
int executeAction__(size_t ruleNr);
void print();
void preCode(); // re-implement this function for code that must
// be exec'ed before the patternmatching starts
void postCode(PostEnum__ type);
// re-implement this function for code that must
// be exec'ed after the rules's actions.
};
// $insert scannerConstructors
inline Scanner::Scanner(std::istream &in, std::ostream &out)
:
ScannerBase(in, out)
{}
inline Scanner::Scanner(std::string const &infile, std::string const &outfile)
:
ScannerBase(infile, outfile)
{}
// $insert inlineLexFunction
inline int Scanner::lex()
{
return lex__();
}
inline void Scanner::preCode()
{
// optionally replace by your own code
}
inline void Scanner::postCode(PostEnum__ type)
{
// optionally replace by your own code
}
inline void Scanner::print()
{
print__();
}
#endif // Scanner_H_INCLUDED_

View file

@ -0,0 +1,15 @@
// Declare here
// what's only used in the Scanner class
// and let Scanner's sources include "scanner.ih"
#include <iomanip>
#include "../globals.h"
#include "scanner.h"
using namespace std;
// end of scanner.ih

View file

@ -0,0 +1,394 @@
// Generated by Flexc++ V2.01.00 on Mon, 22 Sep 2014 12:51:12 +0200
#ifndef ScannerBASE_H_INCLUDED
#define ScannerBASE_H_INCLUDED
#include <limits>
#include <iostream>
#include <deque>
#include <string>
#include <vector>
#include <memory>
class ScannerBase
{
// idx: rule, value: tail length (NO_INCREMENTS if no tail)
typedef std::vector<int> VectorInt;
static size_t const s_unavailable = std::numeric_limits<size_t>::max();
enum
{
AT_EOF = -1
};
protected:
enum Leave__
{};
enum class ActionType__
{
CONTINUE, // transition succeeded, go on
ECHO_CH, // echo ch itself (d_matched empty)
ECHO_FIRST, // echo d_matched[0], push back the rest
MATCH, // matched a rule
RETURN, // no further continuation, lex returns 0.
};
enum class PostEnum__
{
END, // postCode called when lex__() ends
POP, // postCode called after switching files
RETURN, // postCode called when lex__() returns
WIP // postCode called when a non-returning rule
// was matched
};
public:
enum class StartCondition__ {
// $insert startCondNames
INITIAL,
};
private:
struct FinalData
{
size_t rule;
size_t length;
};
struct Final
{
FinalData std;
FinalData bol;
};
// class Input encapsulates all input operations.
// Its member get() returns the next input character
// $insert inputInterface
class Input
{
std::deque<unsigned char> d_deque; // pending input chars
std::istream *d_in; // ptr for easy streamswitching
size_t d_lineNr; // line count
public:
Input();
// iStream: dynamically allocated
Input(std::istream *iStream, size_t lineNr = 1);
size_t get(); // the next range
void reRead(size_t ch); // push back 'ch' (if < 0x100)
// push back str from idx 'fmIdx'
void reRead(std::string const &str, size_t fmIdx);
size_t lineNr() const
{
return d_lineNr;
}
size_t nPending() const
{
return d_deque.size();
}
void setPending(size_t size)
{
d_deque.erase(d_deque.begin(), d_deque.end() - size);
}
void close() // force closing the stream
{
delete d_in;
d_in = 0; // switchStreams also closes
}
private:
size_t next(); // obtain the next character
};
protected:
struct StreamStruct
{
std::string pushedName;
Input pushedInput;
};
private:
std::vector<StreamStruct> d_streamStack;
std::string d_filename; // name of the currently processed
static size_t s_istreamNr; // file. With istreams it receives
// the name "<istream #>", where
// # is the sequence number of the
// istream (starting at 1)
int d_startCondition = 0;
int d_lopSC = 0;
size_t d_state = 0;
int d_nextState;
std::shared_ptr<std::ostream> d_out;
bool d_atBOL = true; // the matched text starts at BOL
Final d_final;
// only used interactively:
std::istream *d_in; // points to the input stream
std::shared_ptr<std::istringstream> d_line; // holds line fm d_in
Input d_input;
std::string d_matched; // matched characters
std::string d_lopMatched; // matched lop-rule characters
std::string::iterator d_lopIter;
std::string::iterator d_lopTail;
std::string::iterator d_lopEnd;
size_t d_lopPending; // # pending input chars at lop1__
bool d_return; // return after a rule's action
bool d_more = false; // set to true by more()
size_t (ScannerBase::*d_get)() = &ScannerBase::getInput;
protected:
std::istream *d_in__;
int d_token__; // returned by lex__
int const (*d_dfaBase__)[9];
static int const s_dfa__[][9];
static int const (*s_dfaBase__[])[9];
enum: bool { s_interactive__ = false };
enum: size_t {
s_rangeOfEOF__ = 6,
s_finIdx__ = 7,
s_nRules__ = 4,
s_maxSizeofStreamStack__ = 10
};
static size_t const s_ranges__[];
static size_t const s_rf__[][2];
public:
ScannerBase(ScannerBase const &other) = delete;
ScannerBase &operator=(ScannerBase const &rhs) = delete;
bool debug() const;
std::string const &filename() const;
std::string const &matched() const;
size_t length() const;
size_t lineNr() const;
void setDebug(bool onOff);
void switchOstream(std::ostream &out);
void switchOstream(std::string const &outfilename);
void switchStreams(std::istream &in,
std::ostream &out = std::cout);
void switchIstream(std::string const &infilename);
void switchStreams(std::string const &infilename,
std::string const &outfilename);
// $insert interactiveDecl
protected:
ScannerBase(std::istream &in, std::ostream &out);
ScannerBase(std::string const &infilename, std::string const &outfilename);
StartCondition__ startCondition() const; // current start condition
bool popStream();
std::ostream &out();
void begin(StartCondition__ startCondition);
void echo() const;
void leave(int retValue) const;
// `accept(n)' returns all but the first `n' characters of the current
// token back to the input stream, where they will be rescanned when the
// scanner looks for the next match.
// So, it matches n of the characters in the input buffer, and so it accepts
// n characters, rescanning the rest.
void accept(size_t nChars = 0); // former: less
void redo(size_t nChars = 0); // rescan the last nChar
// characters, reducing
// length() by nChars
void more();
void push(size_t ch); // push char to Input
void push(std::string const &txt); // same: chars
std::vector<StreamStruct> const &streamStack() const;
void pushStream(std::istream &curStream);
void pushStream(std::string const &curName);
void setFilename(std::string const &name);
void setMatched(std::string const &text);
static std::string istreamName__();
// members used by lex__(): they end in __ and should not be used
// otherwise.
ActionType__ actionType__(size_t range); // next action
bool return__(); // 'return' from codeblock
size_t matched__(size_t ch); // handles a matched rule
size_t getRange__(int ch); // convert char to range
size_t get__(); // next character
size_t state__() const; // current state
void continue__(int ch); // handles a transition
void echoCh__(size_t ch); // echoes ch, sets d_atBOL
void echoFirst__(size_t ch); // handles unknown input
void updateFinals__(); // update a state's Final info
void noReturn__(); // d_return to false
void print__() const; // optionally print token
void pushFront__(size_t ch); // return char to Input
void reset__(); // prepare for new cycle
// next input stream:
void switchStream__(std::istream &in, size_t lineNr);
void lopf__(size_t tail); // matched fixed size tail
void lop1__(int lopSC); // matched ab for a/b
void lop2__(); // matches the LOP's b tail
void lop3__(); // catch-all while matching b
void lop4__(); // matches the LOP's a head
private:
size_t getInput();
size_t getLOP();
void p_pushStream(std::string const &name, std::istream *streamPtr);
void setMatchedSize(size_t length);
bool knownFinalState();
template <typename ReturnType, typename ArgType>
static ReturnType constexpr as(ArgType value);
static bool constexpr available(size_t value);
static StartCondition__ constexpr SC(int sc);
static int constexpr SC(StartCondition__ sc);
};
template <typename ReturnType, typename ArgType>
inline ReturnType constexpr ScannerBase::as(ArgType value)
{
return static_cast<ReturnType>(value);
}
inline bool ScannerBase::knownFinalState()
{
return (d_atBOL && available(d_final.bol.rule)) ||
available(d_final.std.rule);
}
inline bool constexpr ScannerBase::available(size_t value)
{
return value != std::numeric_limits<size_t>::max();
}
inline ScannerBase::StartCondition__ constexpr ScannerBase::SC(int sc)
{
return as<StartCondition__>(sc);
}
inline int constexpr ScannerBase::SC(StartCondition__ sc)
{
return as<int>(sc);
}
inline std::ostream &ScannerBase::out()
{
return *d_out;
}
inline void ScannerBase::push(size_t ch)
{
d_input.reRead(ch);
}
inline void ScannerBase::push(std::string const &str)
{
d_input.reRead(str, 0);
}
inline void ScannerBase::setFilename(std::string const &name)
{
d_filename = name;
}
inline void ScannerBase::setMatched(std::string const &text)
{
d_matched = text;
}
inline std::string const &ScannerBase::matched() const
{
return d_matched;
}
inline ScannerBase::StartCondition__ ScannerBase::startCondition() const
{
return SC(d_startCondition);
}
inline std::string const &ScannerBase::filename() const
{
return d_filename;
}
inline void ScannerBase::echo() const
{
*d_out << d_matched;
}
inline size_t ScannerBase::length() const
{
return d_matched.size();
}
inline void ScannerBase::leave(int retValue) const
{
throw as<Leave__>(retValue);
}
inline size_t ScannerBase::lineNr() const
{
return d_input.lineNr();
}
inline void ScannerBase::more()
{
d_more = true;
}
inline void ScannerBase::begin(StartCondition__ startCondition)
{
// d_state is reset to 0 by reset__()
d_dfaBase__ = s_dfaBase__[d_startCondition = SC(startCondition)];
}
inline size_t ScannerBase::state__() const
{
return d_state;
}
inline size_t ScannerBase::get__()
{
return (this->*d_get)();
}
inline size_t ScannerBase::getInput()
{
return d_input.get();
}
inline bool ScannerBase::return__()
{
return d_return;
}
inline void ScannerBase::noReturn__()
{
d_return = false;
}
#endif // ScannerBASE_H_INCLUDED

View file

@ -0,0 +1,18 @@
#include "scanner.ih"
void Scanner::tab()
{
if (g_entab)
{
processSpaces();
out().put('\t');
}
else
{
do
out().put(' ');
while (++d_column % g_tabPos != 0);
}
d_column = 0; // as we are at a tab-position
}

View file

@ -0,0 +1,27 @@
// usage.cc
#include "main.ih"
void usage(std::string const &progname)
{
cout << '\n' <<
progname << " by " << Icmbuild::author << "\n" <<
progname << " V" << Icmbuild::version << " " << Icmbuild::years << "\n"
"Copyright (c) GPL " << Icmbuild::years << ". All rights reserved.\n"
"\n"
"Usage: %s [-d | -e | -snnn | -cnnn]* file(s)\n"
"Where:\n"
" -c - entab at / detab to multiples of nnn columns "
"(default: 8)\n"
" -d - tabs in file(s) are removed (detab)\n"
" (default action)\n"
" -e - spaces in file(s) are changed into tabs (entab)\n"
" -q - quiet: less output than otherwise\n"
" -s - entab/detab a minimum number of nnn spaces "
"(default: 4)\n"
" file(s) - file(s) to entab/detab (are overwritten)\n"
" use - to filter stdin to stdout\n"
" non-regular files (e.g. symbolic links) are "
"skipped.\n"
"\n";
}

View file

@ -0,0 +1,28 @@
// version.cc
#include "main.ih"
#include "icmconf"
#ifdef USE_VERSION
#include "VERSION"
#endif
#ifndef AUTHOR
#define AUTHOR ""
#endif
#ifndef VERSION
#define VERSION "0.00.00"
#endif
#ifndef YEARS
#define YEARS "2012"
#endif
namespace Icmbuild
{
char version[] = VERSION;
char years[] = YEARS;
char author[] = AUTHOR;
}