/*
- * Copyright 2001-2005 Adrian Thurston <thurston@cs.queensu.ca>
+ * Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
*/
/* This file is part of Ragel.
using std::cerr;
using std::endl;
-/* Target language and output style. */
-OutputFormat outputFormat = OutCode;
-CodeStyleEnum codeStyle = GenTables;
-
/* Io globals. */
-istream *inStream = 0;
-ostream *outStream = 0;
-output_filter *outFilter = 0;
-char *outputFileName = 0;
-
-/* Graphviz dot file generation. */
-bool graphvizDone = false;
+extern istream *inStream;
+extern ostream *outStream;
+extern output_filter *outFilter;
+extern const char *outputFileName;
-int numSplitPartitions = 0;
-bool printPrintables = false;
+extern int numSplitPartitions;
/* Print a summary of the options. */
-void usage()
+void java_usage()
{
cout <<
-"usage: rlcodegen-java [options] file\n"
+"usage: " PROGNAME " [options] file\n"
"general:\n"
" -h, -H, -?, --help Print this usage and exit\n"
" -v, --version Print version information and exit\n"
" -o <file> Write output to <file>\n"
-"output:\n"
-" -V Generate a Graphviz dotfile instead of code\n"
-" -p Print printable characters in Graphviz output\n"
-"generated code style:\n"
-" -T0 Table driven FSM (default)\n"
-" -T1 Faster table driven FSM\n"
-" -F0 Flat table driven FSM\n"
-" -F1 Faster flat table-driven FSM\n"
-" -G0 Goto-driven FSM\n"
-" -G1 Faster goto-driven FSM\n"
-" -G2 Really fast goto-driven FSM\n"
-" -P<N> N-Way Split really fast goto-driven FSM\n"
;
}
/* Print version information. */
-void version()
+void java_version()
{
- cout << "Ragel Code Generator version " VERSION << " " PUBDATE << endl <<
- "Copyright (c) 2001-2006 by Adrian Thurston" << endl;
-}
-
-/* Scans a string looking for the file extension. If there is a file
- * extension then pointer returned points to inside the string
- * passed in. Otherwise returns null. */
-char *findFileExtension( char *stemFile )
-{
- char *ppos = stemFile + strlen(stemFile) - 1;
-
- /* Scan backwards from the end looking for the first dot.
- * If we encounter a '/' before the first dot, then stop the scan. */
- while ( 1 ) {
- /* If we found a dot or got to the beginning of the string then
- * we are done. */
- if ( ppos == stemFile || *ppos == '.' )
- break;
-
- /* If we hit a / then there is no extension. Done. */
- if ( *ppos == '/' ) {
- ppos = stemFile;
- break;
- }
- ppos--;
- }
-
- /* If we got to the front of the string then bail we
- * did not find an extension */
- if ( ppos == stemFile )
- ppos = 0;
-
- return ppos;
+ cout << "Ragel Code Generator for Java" << endl <<
+ "Version " VERSION << ", " PUBDATE << endl <<
+ "Copyright (c) 2001-2007 by Adrian Thurston" << endl;
}
-/* Make a file name from a stem. Removes the old filename suffix and
- * replaces it with a new one. Returns a newed up string. */
-char *fileNameFromStem( char *stemFile, char *suffix )
-{
- int len = strlen( stemFile );
- assert( len > 0 );
-
- /* Get the extension. */
- char *ppos = findFileExtension( stemFile );
-
- /* If an extension was found, then shorten what we think the len is. */
- if ( ppos != 0 )
- len = ppos - stemFile;
-
- /* Make the return string from the stem and the suffix. */
- char *retVal = new char[ len + strlen( suffix ) + 1 ];
- strncpy( retVal, stemFile, len );
- strcpy( retVal + len, suffix );
-
- return retVal;
-}
-
-/* Total error count. */
-int gblErrorCount = 0;
-
-ostream &error()
+ostream &java_error()
{
gblErrorCount += 1;
cerr << PROGNAME ": ";
return cerr;
}
-/* Counts newlines before sending sync. */
-int output_filter::sync( )
-{
- line += 1;
- return std::filebuf::sync();
-}
-
-/* Counts newlines before sending data out to file. */
-std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
-{
- for ( int i = 0; i < n; i++ ) {
- if ( s[i] == '\n' )
- line += 1;
- }
- return std::filebuf::xsputn( s, n );
-}
-
-void escapeLineDirectivePath( std::ostream &out, char *path )
-{
- for ( char *pc = path; *pc != 0; pc++ ) {
- if ( *pc == '\\' )
- out << "\\\\";
- else
- out << *pc;
- }
-}
-
/*
* Callbacks invoked by the XML data parser.
*/
/* Invoked by the parser when the root element is opened. */
-ostream *openOutput( char *inputFile, char *language )
+ostream *javaOpenOutput( char *inputFile )
{
- if ( strcmp( language, "C" ) == 0 ) {
- hostLangType = CCode;
- hostLang = &hostLangC;
- }
- else if ( strcmp( language, "D" ) == 0 ) {
- hostLangType = DCode;
- hostLang = &hostLangD;
- }
- else if ( strcmp( language, "Java" ) == 0 ) {
- hostLangType = JavaCode;
- hostLang = &hostLangJava;
- }
-
- /* Eventually more types will be supported. */
- if ( hostLangType == JavaCode && codeStyle != GenTables ) {
- error() << "java: only the table code style -T0 is "
- "currently supported" << endl;
+ if ( hostLang->lang != HostLang::Java ) {
+ java_error() << "this code generator is for Java only" << endl;
+ exit(1);
}
/* If the output format is code and no output file name is given, then
* make a default. */
- if ( outputFormat == OutCode && outputFileName == 0 ) {
+ if ( outputFileName == 0 ) {
char *ext = findFileExtension( inputFile );
if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
outputFileName = fileNameFromStem( inputFile, ".h" );
- else {
- char *defExtension = 0;
- switch ( hostLangType ) {
- case CCode: defExtension = ".c"; break;
- case DCode: defExtension = ".d"; break;
- case JavaCode: defExtension = ".java"; break;
- }
- outputFileName = fileNameFromStem( inputFile, defExtension );
- }
+ else
+ outputFileName = fileNameFromStem( inputFile, ".java" );
}
/* Make sure we are not writing to the same file as the input file. */
if ( outputFileName != 0 && strcmp( inputFile, outputFileName ) == 0 ) {
- error() << "output file \"" << outputFileName <<
+ java_error() << "output file \"" << outputFileName <<
"\" is the same as the input file" << endl;
}
outFilter = new output_filter( outputFileName );
outFilter->open( outputFileName, ios::out|ios::trunc );
if ( !outFilter->is_open() ) {
- error() << "error opening " << outputFileName << " for writing" << endl;
+ java_error() << "error opening " << outputFileName << " for writing" << endl;
exit(1);
}
}
/* Invoked by the parser when a ragel definition is opened. */
-CodeGenData *makeCodeGen( char *sourceFileName, char *fsmName,
+CodeGenData *javaMakeCodeGen( char *sourceFileName, char *fsmName,
ostream &out, bool wantComplete )
{
CodeGenData *codeGen = new JavaTabCodeGen(out);
}
/* Main, process args and call yyparse to start scanning input. */
-int main(int argc, char **argv)
+int java_main( const char *xmlInputFileName )
{
- ParamCheck pc("o:VpT:F:G:vHh?-:P:", argc, argv);
- char *xmlInputFileName = 0;
-
- while ( pc.check() ) {
- switch ( pc.state ) {
- case ParamCheck::match:
- switch ( pc.parameter ) {
- /* Output. */
- case 'o':
- if ( *pc.parameterArg == 0 )
- error() << "a zero length output file name was given" << endl;
- else if ( outputFileName != 0 )
- error() << "more than one output file name was given" << endl;
- else {
- /* Ok, remember the output file name. */
- outputFileName = pc.parameterArg;
- }
- break;
-
- /* Output formats. */
- case 'V':
- outputFormat = OutGraphvizDot;
- break;
-
- case 'p':
- printPrintables = true;
- break;
-
- /* Code style. */
- case 'T':
- if ( pc.parameterArg[0] == '0' )
- codeStyle = GenTables;
- else if ( pc.parameterArg[0] == '1' )
- codeStyle = GenFTables;
- else {
- error() << "-T" << pc.parameterArg[0] <<
- " is an invalid argument" << endl;
- exit(1);
- }
- break;
- case 'F':
- if ( pc.parameterArg[0] == '0' )
- codeStyle = GenFlat;
- else if ( pc.parameterArg[0] == '1' )
- codeStyle = GenFFlat;
- else {
- error() << "-F" << pc.parameterArg[0] <<
- " is an invalid argument" << endl;
- exit(1);
- }
- break;
- case 'G':
- if ( pc.parameterArg[0] == '0' )
- codeStyle = GenGoto;
- else if ( pc.parameterArg[0] == '1' )
- codeStyle = GenFGoto;
- else if ( pc.parameterArg[0] == '2' )
- codeStyle = GenIpGoto;
- else {
- error() << "-G" << pc.parameterArg[0] <<
- " is an invalid argument" << endl;
- exit(1);
- }
- break;
- case 'P':
- codeStyle = GenSplit;
- numSplitPartitions = atoi( pc.parameterArg );
- break;
-
- /* Version and help. */
- case 'v':
- version();
- exit(0);
- case 'H': case 'h': case '?':
- usage();
- exit(0);
- case '-':
- if ( strcasecmp(pc.parameterArg, "help") == 0 ) {
- usage();
- exit(0);
- }
- else if ( strcasecmp(pc.parameterArg, "version") == 0 ) {
- version();
- exit(0);
- }
- else {
- error() << "--" << pc.parameterArg <<
- " is an invalid argument" << endl;
- break;
- }
- }
- break;
-
- case ParamCheck::invalid:
- error() << "-" << pc.parameter << " is an invalid argument" << endl;
- break;
-
- case ParamCheck::noparam:
- if ( *pc.curArg == 0 )
- error() << "a zero length input file name was given" << endl;
- else if ( xmlInputFileName != 0 )
- error() << "more than one input file name was given" << endl;
- else {
- /* OK, Remember the filename. */
- xmlInputFileName = pc.curArg;
- }
- break;
- }
- }
-
- /* Bail on above errors. */
- if ( gblErrorCount > 0 )
- exit(1);
-
/* Open the input file for reading. */
- if ( xmlInputFileName != 0 ) {
- /* Open the input file for reading. */
- ifstream *inFile = new ifstream( xmlInputFileName );
- inStream = inFile;
- if ( ! inFile->is_open() )
- error() << "could not open " << xmlInputFileName << " for reading" << endl;
- }
- else {
- xmlInputFileName = "<stdin>";
- inStream = &cin;
- }
+ ifstream *inFile = new ifstream( xmlInputFileName );
+ inStream = inFile;
+ if ( ! inFile->is_open() )
+ java_error() << "could not open " << xmlInputFileName << " for reading" << endl;
/* Bail on above errors. */
if ( gblErrorCount > 0 )
exit(1);
- bool wantComplete = outputFormat != OutGraphvizDot;
- bool outputActive = outputFormat == OutCode;
+ bool wantComplete = true;
+ bool outputActive = true;
/* Parse the input! */
xml_parse( *inStream, xmlInputFileName, outputActive, wantComplete );