/*
- * Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
*/
/* This file is part of Ragel.
#include <fcntl.h>
#include <errno.h>
-#ifndef WIN32
-#include <sys/wait.h>
-#else
+#ifdef _WIN32
#include <windows.h>
#include <psapi.h>
+#include <time.h>
+#include <io.h>
+#include <process.h>
+
+#if _MSC_VER
+#define S_IRUSR _S_IREAD
+#define S_IWUSR _S_IWRITE
+#endif
#endif
/* Parsing. */
#include "vector.h"
#include "version.h"
#include "common.h"
+#include "inputdata.h"
using std::istream;
using std::ostream;
MinimizeOpt minimizeOpt = MinimizeMostOps;
/* Graphviz dot file generation. */
-char *machineSpec = 0, *machineName = 0;
+const char *machineSpec = 0, *machineName = 0;
bool machineSpecFound = false;
+bool wantDupsRemoved = true;
bool printStatistics = false;
-bool frontendOnly = false;
+bool generateXML = false;
bool generateDot = false;
-typedef Vector<const char *> ArgsVector;
-ArgsVector frontendArgs;
-ArgsVector backendArgs;
+/* Target language and output style. */
+CodeStyle codeStyle = GenTables;
+
+int numSplitPartitions = 0;
+bool noLineDirectives = false;
+
+bool displayPrintables = false;
+
+/* Target ruby impl */
+RubyImplEnum rubyImpl = MRI;
/* Print a summary of the options. */
void usage()
" -v, --version Print version information and exit\n"
" -o <file> Write output to <file>\n"
" -s Print some statistics on stderr\n"
+" -d Do not remove duplicates from action lists\n"
+" -I <dir> Add <dir> to the list of directories to search\n"
+" for included an imported files\n"
+"error reporting format:\n"
+" --error-format=gnu file:line:column: message (default)\n"
+" --error-format=msvc file(line,column): message\n"
"fsm minimization:\n"
" -n Do not perform minimization\n"
" -m Minimize at the end of the compilation\n"
" -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"
-"line direcives: (C/D only)\n"
+" -A The host language is C#\n"
+"line direcives: (C/D/C#)\n"
" -L Inhibit writing of #line directives\n"
-"code style: (C/Ruby 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 only)\n"
+"code style: (C/D/C#)\n"
" -G0 Goto-driven FSM\n"
" -G1 Faster goto-driven FSM\n"
+"code style: (C/D)\n"
" -G2 Really fast goto-driven FSM\n"
" -P<N> N-Way Split really fast goto-driven FSM\n"
;
+
+ exit(0);
}
-/* Print version information. */
+/* Print version information and exit. */
void version()
{
cout << "Ragel State Machine Compiler version " VERSION << " " PUBDATE << endl <<
- "Copyright (c) 2001-2007 by Adrian Thurston" << endl;
+ "Copyright (c) 2001-2009 by Adrian Thurston" << endl;
+ exit(0);
+}
+
+/* Error reporting format. */
+ErrorFormat errorFormat = ErrorFormatGNU;
+
+InputLoc makeInputLoc( const char *fileName, int line, int col)
+{
+ InputLoc loc = { fileName, line, col };
+ return loc;
+}
+
+ostream &operator<<( ostream &out, const InputLoc &loc )
+{
+ assert( loc.fileName != 0 );
+ switch ( errorFormat ) {
+ case ErrorFormatMSVC:
+ out << loc.fileName << "(" << loc.line;
+ if ( loc.col )
+ out << "," << loc.col;
+ out << ")";
+ break;
+
+ default:
+ out << loc.fileName << ":" << loc.line;
+ if ( loc.col )
+ out << ":" << loc.col;
+ break;
+ }
+ return out;
}
/* Total error count. */
/* Print the opening to a warning in the input, then return the error ostream. */
ostream &warning( const InputLoc &loc )
{
- assert( loc.fileName != 0 );
- cerr << loc.fileName << ":" << loc.line << ":" <<
- loc.col << ": warning: ";
+ cerr << loc << ": warning: ";
return cerr;
}
ostream &error( const InputLoc &loc )
{
gblErrorCount += 1;
- assert( loc.fileName != 0 );
- cerr << loc.fileName << ":" << loc.line << ": ";
+ cerr << loc << ": ";
return cerr;
}
}
}
-void processArgs( int argc, char **argv, char *&inputFileName, char *&outputFileName )
+void processArgs( int argc, const char **argv, InputData &id )
{
- ParamCheck pc("xo:nmleabjkS:M:CDJRvHh?-:sT:F:G:P:LpV", argc, argv);
+ ParamCheck pc("xo:dnmleabjkS:M:I:CDJRAvHh?-:sT:F:G:P:LpV", argc, argv);
+
+ /* FIXME: Need to check code styles VS langauge. */
while ( pc.check() ) {
switch ( pc.state ) {
break;
case 'x':
- frontendOnly = true;
+ generateXML = true;
break;
/* Output. */
case 'o':
- if ( *pc.parameterArg == 0 )
+ 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.parameterArg;
+ id.outputFileName = pc.paramArg;
}
break;
+ /* Flag for turning off duplicate action removal. */
+ case 'd':
+ wantDupsRemoved = false;
+ break;
+
/* Minimization, mostly hidden options. */
case 'n':
minimizeOpt = MinimizeNone;
- frontendArgs.append( "-n" );
break;
case 'm':
minimizeOpt = MinimizeEnd;
- frontendArgs.append( "-m" );
break;
case 'l':
minimizeOpt = MinimizeMostOps;
- frontendArgs.append( "-l" );
break;
case 'e':
minimizeOpt = MinimizeEveryOp;
- frontendArgs.append( "-e" );
break;
case 'a':
minimizeLevel = MinimizeApprox;
- frontendArgs.append( "-a" );
break;
case 'b':
minimizeLevel = MinimizeStable;
- frontendArgs.append( "-b" );
break;
case 'j':
minimizeLevel = MinimizePartition1;
- frontendArgs.append( "-j" );
break;
case 'k':
minimizeLevel = MinimizePartition2;
- frontendArgs.append( "-k" );
break;
/* Machine spec. */
case 'S':
- if ( *pc.parameterArg == 0 )
+ if ( *pc.paramArg == 0 )
error() << "please specify an argument to -S" << endl;
else if ( machineSpec != 0 )
error() << "more than one -S argument was given" << endl;
else {
/* Ok, remember the path to the machine to generate. */
- machineSpec = pc.parameterArg;
- frontendArgs.append( "-S" );
- frontendArgs.append( pc.parameterArg );
+ machineSpec = pc.paramArg;
}
break;
/* Machine path. */
case 'M':
- if ( *pc.parameterArg == 0 )
+ if ( *pc.paramArg == 0 )
error() << "please specify an argument to -M" << endl;
else if ( machineName != 0 )
error() << "more than one -M argument was given" << endl;
else {
/* Ok, remember the machine name to generate. */
- machineName = pc.parameterArg;
- frontendArgs.append( "-M" );
- frontendArgs.append( pc.parameterArg );
+ machineName = pc.paramArg;
+ }
+ break;
+
+ case 'I':
+ if ( *pc.paramArg == 0 )
+ error() << "please specify an argument to -I" << endl;
+ else {
+ id.includePaths.append( pc.paramArg );
}
break;
/* Host language types. */
case 'C':
hostLang = &hostLangC;
- frontendArgs.append( "-C" );
break;
case 'D':
hostLang = &hostLangD;
- frontendArgs.append( "-D" );
break;
case 'J':
hostLang = &hostLangJava;
- frontendArgs.append( "-J" );
break;
case 'R':
hostLang = &hostLangRuby;
- frontendArgs.append( "-R" );
+ break;
+ case 'A':
+ hostLang = &hostLangCSharp;
break;
/* Version and help. */
case 'v':
version();
- exit(0);
+ break;
case 'H': case 'h': case '?':
usage();
- exit(0);
+ break;
case 's':
printStatistics = true;
- frontendArgs.append( "-s" );
break;
- case '-':
- if ( strcasecmp(pc.parameterArg, "help") == 0 ) {
+ case '-': {
+ char *arg = strdup( pc.paramArg );
+ char *eq = strchr( arg, '=' );
+
+ if ( eq != 0 )
+ *eq++ = 0;
+
+ if ( strcmp( arg, "help" ) == 0 )
usage();
- exit(0);
- }
- else if ( strcasecmp(pc.parameterArg, "version") == 0 ) {
+ else if ( strcmp( arg, "version" ) == 0 )
version();
- exit(0);
+ else if ( strcmp( arg, "error-format" ) == 0 ) {
+ if ( eq == 0 )
+ error() << "expecting '=value' for error-format" << endl;
+ else if ( strcmp( eq, "gnu" ) == 0 )
+ errorFormat = ErrorFormatGNU;
+ else if ( strcmp( eq, "msvc" ) == 0 )
+ errorFormat = ErrorFormatMSVC;
+ else
+ error() << "invalid value for error-format" << endl;
}
+ else if ( strcmp( arg, "rbx" ) == 0 )
+ rubyImpl = Rubinius;
else {
- error() << "--" << pc.parameterArg <<
+ error() << "--" << pc.paramArg <<
" is an invalid argument" << endl;
}
+ free( arg );
+ break;
+ }
/* Passthrough args. */
case 'T':
- backendArgs.append( "-T" );
- backendArgs.append( pc.parameterArg );
+ if ( pc.paramArg[0] == '0' )
+ codeStyle = GenTables;
+ else if ( pc.paramArg[0] == '1' )
+ codeStyle = GenFTables;
+ else {
+ error() << "-T" << pc.paramArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
break;
case 'F':
- backendArgs.append( "-F" );
- backendArgs.append( pc.parameterArg );
+ if ( pc.paramArg[0] == '0' )
+ codeStyle = GenFlat;
+ else if ( pc.paramArg[0] == '1' )
+ codeStyle = GenFFlat;
+ else {
+ error() << "-F" << pc.paramArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
break;
case 'G':
- backendArgs.append( "-G" );
- backendArgs.append( pc.parameterArg );
+ if ( pc.paramArg[0] == '0' )
+ codeStyle = GenGoto;
+ else if ( pc.paramArg[0] == '1' )
+ codeStyle = GenFGoto;
+ else if ( pc.paramArg[0] == '2' )
+ codeStyle = GenIpGoto;
+ else {
+ error() << "-G" << pc.paramArg[0] <<
+ " is an invalid argument" << endl;
+ exit(1);
+ }
break;
case 'P':
- backendArgs.append( "-P" );
- backendArgs.append( pc.parameterArg );
+ codeStyle = GenSplit;
+ numSplitPartitions = atoi( pc.paramArg );
break;
+
case 'p':
- backendArgs.append( "-p" );
+ displayPrintables = true;
break;
+
case 'L':
- backendArgs.append( "-L" );
+ noLineDirectives = true;
break;
}
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;
}
}
}
-int frontend( char *inputFileName, char *outputFileName )
+void process( InputData &id )
{
/* Open the input file for reading. */
- assert( inputFileName != 0 );
- ifstream *inFile = new ifstream( inputFileName );
- istream *inStream = inFile;
+ 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;
- if ( machineSpec == 0 && machineName == 0 )
- hostData << "<host line=\"1\" col=\"1\">";
+ /* 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;
+ id.inputItems.append( firstInputItem );
- Scanner scanner( inputFileName, *inStream, hostData, 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 )
- return 1;
-
+ exit(1);
+
/* Now send EOF to all parsers. */
- terminateAllParsers();
+ id.terminateAllParsers();
- /* Finished, final check for errors.. */
+ /* Bail on above error. */
if ( gblErrorCount > 0 )
- return 1;
+ exit(1);
- if ( machineSpec == 0 && machineName == 0 )
- hostData << "</host>\n";
+ /* Locate the backend program */
+ /* Compiles machines. */
+ id.prepareMachineGen();
if ( gblErrorCount > 0 )
- return 1;
-
- ostream *outputFile = 0;
- if ( outputFileName != 0 )
- outputFile = new ofstream( outputFileName );
- else
- outputFile = &cout;
-
- /* Write the machines, then the surrounding code. */
- writeMachines( *outputFile, hostData.str(), inputFileName );
-
- /* Close the intermediate file. */
- if ( outputFileName != 0 )
- delete outputFile;
-
- return gblErrorCount > 0;
-}
-
-char *makeIntermedTemplate( char *baseFileName )
-{
- char *result = 0;
- const char *templ = "ragel-XXXXXX.xml";
- char *lastSlash = strrchr( baseFileName, '/' );
- if ( lastSlash == 0 ) {
- result = new char[strlen(templ)+1];
- strcpy( result, templ );
- }
- else {
- int baseLen = lastSlash - baseFileName + 1;
- result = new char[baseLen + strlen(templ) + 1];
- memcpy( result, baseFileName, baseLen );
- strcpy( result+baseLen, templ );
- }
- return result;
-};
-
-char *openIntermed( char *inputFileName, char *outputFileName )
-{
- srand(time(0));
- char *result = 0;
-
- /* Which filename do we use as the base? */
- char *baseFileName = outputFileName != 0 ? outputFileName : inputFileName;
-
- /* The template for the intermediate file name. */
- 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;
-}
+ exit(1);
+ id.makeOutputStream();
-void cleanExit( char *intermed, int status )
-{
- unlink( intermed );
- exit( status );
-}
+ /* Generates the reduced machine, which we use to write output. */
+ if ( !generateXML ) {
+ id.generateReduced();
-#ifndef WIN32
-
-/* If any forward slash is found in argv0 then it is assumed that the path is
- * explicit and the path to the backend executable should be derived from
- * that. Whe check that location and also go up one then inside a directory of
- * the same name in case we are executing from the source tree. If no forward
- * slash is found it is assumed the file is being run from the installed
- * location. The PREFIX supplied during configuration is used. */
-char **makePathChecksUnix( const char *argv0, const char *progName )
-{
- char **result = new char*[3];
- const char *lastSlash = strrchr( argv0, '/' );
- int numChecks = 0;
-
- if ( lastSlash != 0 ) {
- char *path = strdup( argv0 );
- int givenPathLen = (lastSlash - argv0) + 1;
- path[givenPathLen] = 0;
-
- int progNameLen = strlen(progName);
- int length = givenPathLen + progNameLen + 1;
- char *check = new char[length];
- sprintf( check, "%s%s", path, progName );
- result[numChecks++] = check;
-
- length = givenPathLen + 3 + progNameLen + 1 + progNameLen + 1;
- check = new char[length];
- sprintf( check, "%s../%s/%s", path, progName, progName );
- result[numChecks++] = check;
+ if ( gblErrorCount > 0 )
+ exit(1);
}
- else {
- int prefixLen = strlen(PREFIX);
- int progNameLen = strlen(progName);
- int length = prefixLen + 5 + progNameLen + 1;
- char *check = new char[length];
- sprintf( check, PREFIX "/bin/%s", progName );
- result[numChecks++] = check;
- }
-
- result[numChecks] = 0;
- return result;
-}
+ id.verifyWritesHaveData();
+ if ( gblErrorCount > 0 )
+ exit(1);
+ /*
+ * From this point on we should not be reporting any errors.
+ */
-void forkAndExec( const char *progName, char **pathChecks,
- ArgsVector &args, char *intermed )
-{
- pid_t pid = fork();
- if ( pid < 0 ) {
- /* Error, no child created. */
- error() << "failed to fork for " << progName << endl;
- cleanExit( intermed, 1 );
- }
- else if ( pid == 0 ) {
- /* child */
- while ( *pathChecks != 0 ) {
- /* Execv does not modify argv, it just uses the const form that is
- * compatible with the most code. Ours not included. */
- execv( *pathChecks, (char *const*) args.data );
- pathChecks += 1;
- }
- error() << "failed to exec " << progName << endl;
- cleanExit( intermed, 1 );
- }
+ id.openOutput();
+ id.writeOutput();
- /* Parent process, wait for the child. */
- int status;
- wait( &status );
+ /* Close the input and the intermediate file. */
+ delete inFile;
- /* What happened with the child. */
- if ( ! WIFEXITED( status ) ) {
- error() << progName << " did not exit normally" << endl;
- cleanExit( intermed, 1 );
+ /* If writing to a file, delete the ostream, causing it to flush.
+ * Standard out is flushed automatically. */
+ if ( id.outputFileName != 0 ) {
+ delete id.outStream;
+ delete id.outFilter;
}
-
- if ( WEXITSTATUS(status) != 0 )
- cleanExit( intermed, WEXITSTATUS(status) );
-}
-
-#else
-/* GetModuleFileNameEx is used to find out where the the current process's
- * binary is. That location is searched first. If that fails then we go up one
- * directory and look for the executable inside a directory of the same name
- * in case we are executing from the source tree.
- * */
-char **makePathChecksWin( const char *progName )
-{
- int len = 1024;
- char *imageFileName = new char[len];
- HANDLE h = GetCurrentProcess();
- len = GetModuleFileNameEx( h, NULL, imageFileName, len );
- imageFileName[len] = 0;
-
- char **result = new char*[3];
- const char *lastSlash = strrchr( imageFileName, '\\' );
- int numChecks = 0;
-
- assert( lastSlash != 0 );
- char *path = strdup( imageFileName );
- int givenPathLen = (lastSlash - imageFileName) + 1;
- path[givenPathLen] = 0;
-
- int progNameLen = strlen(progName);
- int length = givenPathLen + progNameLen + 1;
- char *check = new char[length];
- sprintf( check, "%s%s", path, progName );
- result[numChecks++] = check;
-
- length = givenPathLen + 3 + progNameLen + 1 + progNameLen + 1;
- check = new char[length];
- sprintf( check, "%s..\\%s\\%s", path, progName, progName );
- result[numChecks++] = check;
-
- result[numChecks] = 0;
- return result;
+ assert( gblErrorCount == 0 );
}
-void spawn( const char *progName, char **pathChecks,
- ArgsVector &args, char *intermed )
+char *makeIntermedTemplate( const char *baseFileName )
{
- int result = 0;
- while ( *pathChecks != 0 ) {
- //cerr << "trying to execute " << *pathChecks << endl;
- result = _spawnv( _P_WAIT, *pathChecks, args.data );
- if ( result >= 0 || errno != ENOENT )
- break;
- pathChecks += 1;
- }
-
- if ( result < 0 ) {
- error() << "failed to spawn " << progName << endl;
- cleanExit( intermed, 1 );
+ char *result = 0;
+ const char *templ = "ragel-XXXXXX.xml";
+ const char *lastSlash = strrchr( baseFileName, '/' );
+ if ( lastSlash == 0 ) {
+ result = new char[strlen(templ)+1];
+ strcpy( result, templ );
}
-
- if ( result > 0 )
- cleanExit( intermed, 1 );
-}
-
-#endif
-
-void execFrontend( const char *argv0, char *inputFileName, char *intermed )
-{
- /* The frontend program name. */
- const char *progName = "ragel";
-
- frontendArgs.insert( 0, progName );
- frontendArgs.insert( 1, "-x" );
- frontendArgs.append( "-o" );
- frontendArgs.append( intermed );
- frontendArgs.append( inputFileName );
- frontendArgs.append( 0 );
-
-#ifndef WIN32
- char **pathChecks = makePathChecksUnix( argv0, progName );
- forkAndExec( progName, pathChecks, frontendArgs, intermed );
-#else
- char **pathChecks = makePathChecksWin( progName );
- spawn( progName, pathChecks, frontendArgs, intermed );
-#endif
-}
-
-void execBackend( const char *argv0, char *intermed, char *outputFileName )
-{
- /* Locate the backend program */
- const char *progName = 0;
- if ( generateDot )
- progName = "rlgen-dot";
else {
- switch ( hostLang->lang ) {
- case HostLang::C:
- case HostLang::D:
- progName = "rlgen-cd";
- break;
- case HostLang::Java:
- progName = "rlgen-java";
- break;
- case HostLang::Ruby:
- progName = "rlgen-ruby";
- break;
- }
- }
-
- backendArgs.insert( 0, progName );
- if ( outputFileName != 0 ) {
- backendArgs.append( "-o" );
- backendArgs.append( outputFileName );
+ int baseLen = lastSlash - baseFileName + 1;
+ result = new char[baseLen + strlen(templ) + 1];
+ memcpy( result, baseFileName, baseLen );
+ strcpy( result+baseLen, templ );
}
- backendArgs.append( intermed );
- backendArgs.append( 0 );
-
-#ifndef WIN32
- char **pathChecks = makePathChecksUnix( argv0, progName );
- forkAndExec( progName, pathChecks, backendArgs, intermed );
-#else
- char **pathChecks = makePathChecksWin( progName );
- spawn( progName, pathChecks, backendArgs, intermed );
-#endif
-}
+ return result;
+};
/* Main, process args and call yyparse to start scanning input. */
-int main(int argc, char **argv)
+int main( int argc, const char **argv )
{
- char *inputFileName = 0;
- char *outputFileName = 0;
+ InputData id;
- processArgs( argc, argv, inputFileName, outputFileName );
-
- /* 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;
- }
+ 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;
}
- if ( frontendOnly )
- return frontend( inputFileName, outputFileName );
-
- char *intermed = openIntermed( inputFileName, outputFileName );
-
- /* From here on in the cleanExit function should be used to exit. */
-
- /* Run the frontend, then the backend processes. */
- execFrontend( argv[0], inputFileName, intermed );
- execBackend( argv[0], intermed, outputFileName );
-
- /* Clean up the intermediate. */
- cleanExit( intermed, 0 );
+ process( id );
return 0;
}