2 * Copyright 2007 Victor Hugo Borja <vic@rubyforge.org>
3 * Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
6 /* This file is part of Ragel.
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.
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.
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
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"
51 /* Target ruby impl */
52 RubyImplEnum rubyImpl = MRI;
54 /* Target language and output style. */
55 CodeStyleEnum codeStyle = GenTables;
58 istream *inStream = 0;
59 ostream *outStream = 0;
60 output_filter *outFilter = 0;
61 char *outputFileName = 0;
63 /* Graphviz dot file generation. */
64 bool graphvizDone = false;
66 int numSplitPartitions = 0;
67 bool printPrintables = false;
69 /* Print a summary of the options. */
73 "usage: " PROGNAME " [options] file\n"
75 " -h, -H, -?, --help Print this usage and exit\n"
76 " -v, --version Print version information and exit\n"
77 " -o <file> Write output to <file>\n"
78 " -x, --rbx Allow to use Rubinius asm features\n"
79 "generated code style:\n"
80 " -T0 Table driven FSM (default)\n"
81 " -T1 Faster table driven FSM\n"
82 " -F0 Flat table driven FSM\n"
83 " -F1 Faster flat table-driven FSM\n"
84 " -G0 Goto-driven FSM\n"
88 /* Print version information. */
91 cout << "Ragel Code Generator for Ruby" << endl <<
92 "Version " VERSION << ", " PUBDATE << endl <<
93 "Copyright (c) 2001-2007 by Adrian Thurston" << endl <<
94 "Copyright (c) 2007 by Victor Hugo Borja" << endl;
100 cerr << PROGNAME ": ";
105 * Callbacks invoked by the XML data parser.
108 /* Invoked by the parser when the root element is opened. */
109 ostream *openOutput( char *inputFile )
111 if ( hostLang->lang != HostLang::Ruby ) {
112 error() << "this code generator is for Ruby only" << endl;
116 /* If the output format is code and no output file name is given, then
118 if ( outputFileName == 0 ) {
119 char *ext = findFileExtension( inputFile );
120 if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
121 outputFileName = fileNameFromStem( inputFile, ".h" );
123 outputFileName = fileNameFromStem( inputFile, ".rb" );
126 /* Make sure we are not writing to the same file as the input file. */
127 if ( outputFileName != 0 && strcmp( inputFile, outputFileName ) == 0 ) {
128 error() << "output file \"" << outputFileName <<
129 "\" is the same as the input file" << endl;
132 if ( outputFileName != 0 ) {
133 /* Create the filter on the output and open it. */
134 outFilter = new output_filter( outputFileName );
135 outFilter->open( outputFileName, ios::out|ios::trunc );
136 if ( !outFilter->is_open() ) {
137 error() << "error opening " << outputFileName << " for writing" << endl;
141 /* Open the output stream, attaching it to the filter. */
142 outStream = new ostream( outFilter );
145 /* Writing out ot std out. */
151 /* Invoked by the parser when a ragel definition is opened. */
152 CodeGenData *makeCodeGen( char *sourceFileName, char *fsmName,
153 ostream &out, bool wantComplete )
155 CodeGenData *codeGen = 0;
156 switch ( codeStyle ) {
158 codeGen = new RubyTabCodeGen(out);
161 codeGen = new RubyFTabCodeGen(out);
164 codeGen = new RubyFlatCodeGen(out);
167 codeGen = new RubyFFlatCodeGen(out);
170 if ( rubyImpl == Rubinius ) {
171 codeGen = new RbxGotoCodeGen(out);
173 cout << "Goto style is still _very_ experimental "
174 "and only supported using Rubinius.\n"
175 "You may want to enable the --rbx flag "
176 " to give it a try.\n";
181 cout << "Invalid code style\n";
185 codeGen->sourceFileName = sourceFileName;
186 codeGen->fsmName = fsmName;
187 codeGen->wantComplete = wantComplete;
192 /* Main, process args and call yyparse to start scanning input. */
193 int main(int argc, char **argv)
195 ParamCheck pc("-:xHlh?vo:T:F:G:P:", argc, argv);
196 char *xmlInputFileName = 0;
198 while ( pc.check() ) {
199 switch ( pc.state ) {
200 case ParamCheck::match:
201 switch ( pc.parameter ) {
204 if ( *pc.parameterArg == 0 )
205 error() << "a zero length output file name was given" << endl;
206 else if ( outputFileName != 0 )
207 error() << "more than one output file name was given" << endl;
209 /* Ok, remember the output file name. */
210 outputFileName = pc.parameterArg;
216 if ( pc.parameterArg[0] == '0' )
217 codeStyle = GenTables;
218 else if ( pc.parameterArg[0] == '1' )
219 codeStyle = GenFTables;
221 error() << "-T" << pc.parameterArg[0] <<
222 " is an invalid argument" << endl;
227 if ( pc.parameterArg[0] == '0' )
229 else if ( pc.parameterArg[0] == '1' )
230 codeStyle = GenFFlat;
232 error() << "-F" << pc.parameterArg[0] <<
233 " is an invalid argument" << endl;
238 if ( pc.parameterArg[0] == '0' )
240 else if ( pc.parameterArg[0] == '1' )
241 codeStyle = GenFGoto;
242 else if ( pc.parameterArg[0] == '2' )
243 codeStyle = GenIpGoto;
245 error() << "-G" << pc.parameterArg[0] <<
246 " is an invalid argument" << endl;
251 codeStyle = GenSplit;
252 numSplitPartitions = atoi( pc.parameterArg );
259 /* Version and help. */
263 case 'H': case 'h': case '?':
268 if ( strcasecmp(pc.parameterArg, "help") == 0 ) {
272 else if ( strcasecmp(pc.parameterArg, "version") == 0 ) {
276 else if ( strcasecmp(pc.parameterArg, "rbx") == 0 ) {
280 error() << "--" << pc.parameterArg <<
281 " is an invalid argument" << endl;
287 case ParamCheck::invalid:
288 error() << "-" << pc.parameter << " is an invalid argument" << endl;
291 case ParamCheck::noparam:
292 if ( *pc.curArg == 0 )
293 error() << "a zero length input file name was given" << endl;
294 else if ( xmlInputFileName != 0 )
295 error() << "more than one input file name was given" << endl;
297 /* OK, Remember the filename. */
298 xmlInputFileName = pc.curArg;
304 /* Bail on above errors. */
305 if ( gblErrorCount > 0 )
308 /* Open the input file for reading. */
309 if ( xmlInputFileName != 0 ) {
310 /* Open the input file for reading. */
311 ifstream *inFile = new ifstream( xmlInputFileName );
313 if ( ! inFile->is_open() )
314 error() << "could not open " << xmlInputFileName << " for reading" << endl;
317 xmlInputFileName = strdup("<stdin>");
321 /* Bail on above errors. */
322 if ( gblErrorCount > 0 )
325 bool wantComplete = true;
326 bool outputActive = true;
328 /* Parse the input! */
329 xml_parse( *inStream, xmlInputFileName, outputActive, wantComplete );
331 /* If writing to a file, delete the ostream, causing it to flush.
332 * Standard out is flushed automatically. */
333 if ( outputFileName != 0 ) {
338 /* Finished, final check for errors.. */
339 if ( gblErrorCount > 0 ) {
340 /* If we opened an output file, remove it. */
341 if ( outputFileName != 0 )
342 unlink( outputFileName );
351 * indent-tabs-mode: 1
352 * c-file-style: "bsd"