#include "vector.h"
#include "version.h"
#include "common.h"
-#include "xmlparse.h"
+#include "inputdata.h"
using std::istream;
using std::ostream;
bool wantDupsRemoved = true;
bool printStatistics = false;
-bool frontendOnly = false;
+bool generateXML = false;
bool generateDot = false;
/* Target language and output style. */
-CodeStyleEnum codeStyle = GenTables;
+CodeStyle codeStyle = GenTables;
int numSplitPartitions = 0;
bool noLineDirectives = false;
bool displayPrintables = false;
-bool graphvizDone = false;
/* Target ruby impl */
RubyImplEnum rubyImpl = MRI;
-ArgsVector includePaths;
-
-istream *inStream = 0;
-ostream *outStream = 0;
-output_filter *outFilter = 0;
-const char *outputFileName = 0;
-
/* Print a summary of the options. */
void usage()
{
" -x Run the frontend only: emit XML intermediate format\n"
" -V Generate a dot file for Graphviz\n"
" -p Display printable characters on labels\n"
-" -S <spec> FSM specification to output (for rlgen-dot)\n"
-" -M <machine> Machine definition/instantiation to output (for rlgen-dot)\n"
+" -S <spec> FSM specification to output (for graphviz output)\n"
+" -M <machine> Machine definition/instantiation to output (for graphviz output)\n"
"host language:\n"
" -C The host language is C, C++, Obj-C or Obj-C++ (default)\n"
" -D The host language is D\n"
" -J The host language is Java\n"
" -R The host language is Ruby\n"
" -A The host language is C#\n"
-"line direcives: (C/D/C# only)\n"
+"line direcives: (C/D/C#)\n"
" -L Inhibit writing of #line directives\n"
-"code style: (C/Ruby/C# only)\n"
+"code style: (C/D/Java/Ruby/C#)\n"
" -T0 Table driven FSM (default)\n"
+"code style: (C/D/Ruby/C#)\n"
" -T1 Faster table driven FSM\n"
" -F0 Flat table driven FSM\n"
" -F1 Faster flat table-driven FSM\n"
-"code style: (C/C# only)\n"
+"code style: (C/D/C#)\n"
" -G0 Goto-driven FSM\n"
" -G1 Faster goto-driven FSM\n"
-"code style: (C only)\n"
+"code style: (C/D)\n"
" -G2 Really fast goto-driven FSM\n"
" -P<N> N-Way Split really fast goto-driven FSM\n"
;
void version()
{
cout << "Ragel State Machine Compiler version " VERSION << " " PUBDATE << endl <<
- "Copyright (c) 2001-2008 by Adrian Thurston" << endl;
+ "Copyright (c) 2001-2009 by Adrian Thurston" << endl;
exit(0);
}
}
}
-void processArgs( int argc, const char **argv, const char *&inputFileName )
+void processArgs( int argc, const char **argv, InputData &id )
{
ParamCheck pc("xo:dnmleabjkS:M:I:CDJRAvHh?-:sT:F:G:P:LpV", argc, argv);
break;
case 'x':
- frontendOnly = true;
+ generateXML = true;
break;
/* Output. */
case 'o':
if ( *pc.paramArg == 0 )
error() << "a zero length output file name was given" << endl;
- else if ( outputFileName != 0 )
+ else if ( id.outputFileName != 0 )
error() << "more than one output file name was given" << endl;
else {
/* Ok, remember the output file name. */
- outputFileName = pc.paramArg;
+ id.outputFileName = pc.paramArg;
}
break;
if ( *pc.paramArg == 0 )
error() << "please specify an argument to -I" << endl;
else {
- includePaths.append( pc.paramArg );
+ id.includePaths.append( pc.paramArg );
}
break;
printStatistics = true;
break;
case '-': {
- char *eq = strchr( pc.paramArg, '=' );
+ char *arg = strdup( pc.paramArg );
+ char *eq = strchr( arg, '=' );
if ( eq != 0 )
*eq++ = 0;
- if ( strcmp( pc.paramArg, "help" ) == 0 )
+ if ( strcmp( arg, "help" ) == 0 )
usage();
- else if ( strcmp( pc.paramArg, "version" ) == 0 )
+ else if ( strcmp( arg, "version" ) == 0 )
version();
- else if ( strcmp( pc.paramArg, "error-format" ) == 0 ) {
+ else if ( strcmp( arg, "error-format" ) == 0 ) {
if ( eq == 0 )
error() << "expecting '=value' for error-format" << endl;
else if ( strcmp( eq, "gnu" ) == 0 )
else
error() << "invalid value for error-format" << endl;
}
- else if ( strcmp( pc.paramArg, "rbx" ) == 0 )
+ else if ( strcmp( arg, "rbx" ) == 0 )
rubyImpl = Rubinius;
else {
error() << "--" << pc.paramArg <<
" is an invalid argument" << endl;
}
+ free( arg );
break;
}
/* It is interpreted as an input file. */
if ( *pc.curArg == 0 )
error() << "a zero length input file name was given" << endl;
- else if ( inputFileName != 0 )
+ else if ( id.inputFileName != 0 )
error() << "more than one input file name was given" << endl;
else {
/* OK, Remember the filename. */
- inputFileName = pc.curArg;
+ id.inputFileName = pc.curArg;
}
break;
}
}
}
-void process( const char *inputFileName, const char *intermed )
+void process( InputData &id )
{
- const char *xmlFileName = intermed;
- bool wantComplete = true;
- bool outputActive = true;
-
/* Open the input file for reading. */
- assert( inputFileName != 0 );
- ifstream *inFile = new ifstream( inputFileName );
+ assert( id.inputFileName != 0 );
+ ifstream *inFile = new ifstream( id.inputFileName );
if ( ! inFile->is_open() )
- error() << "could not open " << inputFileName << " for reading" << endp;
+ error() << "could not open " << id.inputFileName << " for reading" << endp;
/* Used for just a few things. */
std::ostringstream hostData;
/* Make the first input item. */
InputItem *firstInputItem = new InputItem;
firstInputItem->type = InputItem::HostData;
+ firstInputItem->loc.fileName = id.inputFileName;
firstInputItem->loc.line = 1;
firstInputItem->loc.col = 1;
- inputItems.append( firstInputItem );
+ id.inputItems.append( firstInputItem );
- Scanner scanner( inputFileName, *inFile, 0, 0, 0, false );
+ Scanner scanner( id, id.inputFileName, *inFile, 0, 0, 0, false );
scanner.do_scan();
/* Finished, final check for errors.. */
if ( gblErrorCount > 0 )
exit(1);
-
- /* Now send EOF to all parsers. */
- terminateAllParsers();
- /* Finished, final check for errors.. */
- if ( gblErrorCount > 0 )
- exit(1);
+ /* Now send EOF to all parsers. */
+ id.terminateAllParsers();
/* Bail on above error. */
if ( gblErrorCount > 0 )
exit(1);
/* Locate the backend program */
- if ( generateDot ) {
- wantComplete = false;
- outputActive = false;
- }
+ /* Compiles machines. */
+ id.prepareMachineGen();
- XmlScanner xmlScanner( xmlFileName, cin );
- XmlParser xmlParser( inputFileName, xmlFileName, outputActive, wantComplete );
- xmlParser.init();
+ if ( gblErrorCount > 0 )
+ exit(1);
- xmlParser.openOutput();
+ id.makeOutputStream();
- /* Write the machines, then the surrounding code. */
- generate( xmlParser );
+ /* Generates the reduced machine, which we use to write output. */
+ if ( !generateXML ) {
+ id.generateReduced();
- /* Close the input and the intermediate file. */
- delete inFile;
+ if ( gblErrorCount > 0 )
+ exit(1);
+ }
- /* Bail on above error. */
+ id.verifyWritesHaveData();
if ( gblErrorCount > 0 )
exit(1);
-// xml_parse( *xmlInFile, xmlFileName,
-// outputActive, wantComplete,
-// xmlScanner, xmlParser );
+ /*
+ * From this point on we should not be reporting any errors.
+ */
+
+ id.openOutput();
+ id.writeOutput();
+
+ /* Close the input and the intermediate file. */
+ delete inFile;
/* If writing to a file, delete the ostream, causing it to flush.
* Standard out is flushed automatically. */
- if ( outputFileName != 0 ) {
- delete outStream;
- delete outFilter;
+ if ( id.outputFileName != 0 ) {
+ delete id.outStream;
+ delete id.outFilter;
}
- /* Finished, final check for errors.. */
- if ( gblErrorCount > 0 ) {
- /* If we opened an output file, remove it. */
- if ( outputFileName != 0 )
- unlink( outputFileName );
- exit(1);
- }
+ assert( gblErrorCount == 0 );
}
char *makeIntermedTemplate( const char *baseFileName )
{
char *result = 0;
const char *templ = "ragel-XXXXXX.xml";
- char *lastSlash = strrchr( baseFileName, '/' );
+ const char *lastSlash = strrchr( baseFileName, '/' );
if ( lastSlash == 0 ) {
result = new char[strlen(templ)+1];
strcpy( result, templ );
return result;
};
-const char *openIntermed( const char *inputFileName, const char *outputFileName )
-{
- srand(time(0));
- const char *result = 0;
-
- /* Which filename do we use as the base? */
- const char *baseFileName = outputFileName != 0 ? outputFileName : inputFileName;
-
- /* The template for the intermediate file name. */
- const char *intermedFileName = makeIntermedTemplate( baseFileName );
-
- /* Randomize the name and try to open. */
- char fnChars[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- char *firstX = strrchr( intermedFileName, 'X' ) - 5;
- for ( int tries = 0; tries < 20; tries++ ) {
- /* Choose a random name. */
- for ( int x = 0; x < 6; x++ )
- firstX[x] = fnChars[rand() % 52];
-
- /* Try to open the file. */
- int fd = ::open( intermedFileName, O_WRONLY|O_EXCL|O_CREAT, S_IRUSR|S_IWUSR );
-
- if ( fd > 0 ) {
- /* Success. Close the file immediately and return the name for use
- * by the child processes. */
- ::close( fd );
- result = intermedFileName;
- break;
- }
-
- if ( errno == EACCES ) {
- error() << "failed to open temp file " << intermedFileName <<
- ", access denied" << endp;
- }
- }
-
- if ( result == 0 )
- error() << "abnormal error: cannot find unique name for temp file" << endp;
-
- return result;
-}
-
-
-void cleanExit( const char *intermed, int status )
-{
- //unlink( intermed );
- exit( status );
-}
-
/* Main, process args and call yyparse to start scanning input. */
int main( int argc, const char **argv )
{
- const char *inputFileName = 0;
- processArgs( argc, argv, inputFileName );
-
- /* If -M or -S are given and we're not generating a dot file then invoke
- * the frontend. These options are not useful with code generators. */
- if ( machineName != 0 || machineSpec != 0 ) {
- if ( !generateDot )
- frontendOnly = true;
- }
+ InputData id;
+
+ processArgs( argc, argv, id );
/* Require an input file. If we use standard in then we won't have a file
* name on which to base the output. */
- if ( inputFileName == 0 )
+ if ( id.inputFileName == 0 )
error() << "no input file given" << endl;
/* Bail on argument processing errors. */
exit(1);
/* Make sure we are not writing to the same file as the input file. */
- if ( inputFileName != 0 && outputFileName != 0 &&
- strcmp( inputFileName, outputFileName ) == 0 )
+ if ( id.inputFileName != 0 && id.outputFileName != 0 &&
+ strcmp( id.inputFileName, id.outputFileName ) == 0 )
{
- error() << "output file \"" << outputFileName <<
+ error() << "output file \"" << id.outputFileName <<
"\" is the same as the input file" << endp;
}
- const char *intermed = 0; //openIntermed( inputFileName, outputFileName );
- process( inputFileName, intermed );
-
- /* Clean up the intermediate. */
- cleanExit( intermed, 0 );
+ process( id );
return 0;
}