7e89968f531404f13ebaa89cca2b2684b59e7c3c
[external/ragel.git] / rlgen-ruby / main.cpp
1 /*
2  *  Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3  *  Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
4  */
5
6 /*  This file is part of Ragel.
7  *
8  *  Ragel is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  * 
13  *  Ragel is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  * 
18  *  You should have received a copy of the GNU General Public License
19  *  along with Ragel; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <iostream>
27 #include <fstream>
28 #include <unistd.h>
29
30 #include "xmlparse.h"
31 #include "pcheck.h"
32 #include "vector.h"
33 #include "version.h"
34 #include "common.h"
35 #include "rlgen-ruby.h"
36 #include "ruby-tabcodegen.h"
37 #include "ruby-ftabcodegen.h"
38 #include "ruby-flatcodegen.h"
39 #include "ruby-fflatcodegen.h"
40 #include "rbx-gotocodegen.h"
41
42 using std::istream;
43 using std::ifstream;
44 using std::ostream;
45 using std::ios;
46 using std::cin;
47 using std::cout;
48 using std::cerr;
49 using std::endl;
50
51 /* Target ruby impl */
52 extern RubyImplEnum rubyImpl;
53
54 /* Target language and output style. */
55 extern CodeStyleEnum codeStyle;
56
57 /* Io globals. */
58 extern istream *inStream;
59 extern ostream *outStream;
60 extern output_filter *outFilter;
61 extern const char *outputFileName;
62
63 /* Graphviz dot file generation. */
64 extern bool graphvizDone;
65
66 extern int numSplitPartitions;
67
68 /* Print a summary of the options. */
69 void ruby_usage()
70 {
71         cout <<
72 "usage: " PROGNAME " [options] file\n"
73 "general:\n"
74 "   -h, -H, -?, --help    Print this usage and exit\n"
75 "   -v, --version         Print version information and exit\n"
76 "   -o <file>             Write output to <file>\n"
77 "   --rbx                 Allow to use Rubinius asm features\n"
78 "generated code style:\n"
79 "   -T0                   Table driven FSM (default)\n"
80 "   -T1                   Faster table driven FSM\n"
81 "   -F0                   Flat table driven FSM\n"
82 "   -F1                   Faster flat table-driven FSM\n"
83 "   -G0                   Goto-driven FSM\n"
84         ;       
85 }
86
87 /* Print version information. */
88 void ruby_version()
89 {
90         cout << "Ragel Code Generator for Ruby" << endl <<
91                         "Version " VERSION << ", " PUBDATE << endl <<
92                         "Copyright (c) 2001-2007 by Adrian Thurston" << endl <<
93                         "Copyright (c) 2007 by Victor Hugo Borja" << endl;
94 }
95
96 ostream &ruby_error()
97 {
98         gblErrorCount += 1;
99         cerr << PROGNAME ": ";
100         return cerr;
101 }
102
103 /*
104  * Callbacks invoked by the XML data parser.
105  */
106
107 /* Invoked by the parser when the root element is opened. */
108 ostream *rubyOpenOutput( char *inputFile )
109 {
110         if ( hostLang->lang != HostLang::Ruby ) {
111                 ruby_error() << "this code generator is for Ruby only" << endl;
112                 exit(1);
113         }
114
115         /* If the output format is code and no output file name is given, then
116          * make a default. */
117         if ( outputFileName == 0 ) {
118                 char *ext = findFileExtension( inputFile );
119                 if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
120                         outputFileName = fileNameFromStem( inputFile, ".h" );
121                 else
122                         outputFileName = fileNameFromStem( inputFile, ".rb" );
123         }
124
125         /* Make sure we are not writing to the same file as the input file. */
126         if ( outputFileName != 0 && strcmp( inputFile, outputFileName  ) == 0 ) {
127                 ruby_error() << "output file \"" << outputFileName  << 
128                                 "\" is the same as the input file" << endl;
129         }
130
131         if ( outputFileName != 0 ) {
132                 /* Create the filter on the output and open it. */
133                 outFilter = new output_filter( outputFileName );
134                 outFilter->open( outputFileName, ios::out|ios::trunc );
135                 if ( !outFilter->is_open() ) {
136                         ruby_error() << "error opening " << outputFileName << " for writing" << endl;
137                         exit(1);
138                 }
139
140                 /* Open the output stream, attaching it to the filter. */
141                 outStream = new ostream( outFilter );
142         }
143         else {
144                 /* Writing out ot std out. */
145                 outStream = &cout;
146         }
147         return outStream;
148 }
149
150 /* Invoked by the parser when a ragel definition is opened. */
151 CodeGenData *rubyMakeCodeGen( char *sourceFileName, char *fsmName, 
152                 ostream &out, bool wantComplete )
153 {
154         CodeGenData *codeGen = 0;
155         switch ( codeStyle ) {
156                 case GenTables: 
157                         codeGen = new RubyTabCodeGen(out);
158                         break;
159                 case GenFTables:
160                         codeGen = new RubyFTabCodeGen(out);
161                         break;
162                 case GenFlat:
163                         codeGen = new RubyFlatCodeGen(out);
164                         break;
165                 case GenFFlat:
166                         codeGen = new RubyFFlatCodeGen(out);
167                         break;
168                 case GenGoto:
169                         if ( rubyImpl == Rubinius ) {
170                                 codeGen = new RbxGotoCodeGen(out);
171                         } else {
172                                 cout << "Goto style is still _very_ experimental " 
173                                         "and only supported using Rubinius.\n"
174                                         "You may want to enable the --rbx flag "
175                                         " to give it a try.\n";
176                                 exit(1);
177                         }
178                         break;
179                 default:
180                         cout << "Invalid code style\n";
181                         exit(1);
182                         break;
183         }
184         codeGen->sourceFileName = sourceFileName;
185         codeGen->fsmName = fsmName;
186         codeGen->wantComplete = wantComplete;
187
188         return codeGen;
189 }
190
191 /* Main, process args and call yyparse to start scanning input. */
192 int ruby_main( const char *xmlInputFileName )
193 {
194         /* Open the input file for reading. */
195         ifstream *inFile = new ifstream( xmlInputFileName );
196         inStream = inFile;
197         if ( ! inFile->is_open() )
198                 ruby_error() << "could not open " << xmlInputFileName << " for reading" << endl;
199
200         /* Bail on above errors. */
201         if ( gblErrorCount > 0 )
202                 exit(1);
203
204         bool wantComplete = true;
205         bool outputActive = true;
206
207         /* Parse the input! */
208         xml_parse( *inStream, xmlInputFileName, outputActive, wantComplete );
209
210         /* If writing to a file, delete the ostream, causing it to flush.
211          * Standard out is flushed automatically. */
212         if ( outputFileName != 0 ) {
213                 delete outStream;
214                 delete outFilter;
215         }
216
217         /* Finished, final check for errors.. */
218         if ( gblErrorCount > 0 ) {
219                 /* If we opened an output file, remove it. */
220                 if ( outputFileName != 0 )
221                         unlink( outputFileName );
222                 exit(1);
223         }
224         return 0;
225 }
226
227 /*
228  * Local Variables:
229  * mode: c++
230  * indent-tabs-mode: 1
231  * c-file-style: "bsd"
232  * End:
233  */