2 * Copyright 2008 Adrian Thurston <thurston@complang.org>
5 /* This file is part of Ragel.
7 * Ragel is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Ragel is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Ragel; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "inputdata.h"
25 #include "parsedata.h"
28 #include "dotcodegen.h"
35 /* Invoked by the parser when the root element is opened. */
36 void InputData::cdDefaultFileName( const char *inputFile )
38 /* If the output format is code and no output file name is given, then
40 if ( outputFileName == 0 ) {
41 const char *ext = findFileExtension( inputFile );
42 if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
43 outputFileName = fileNameFromStem( inputFile, ".h" );
45 const char *defExtension = 0;
46 switch ( hostLang->lang ) {
47 case HostLang::C: defExtension = ".c"; break;
48 case HostLang::D: defExtension = ".d"; break;
51 outputFileName = fileNameFromStem( inputFile, defExtension );
56 /* Invoked by the parser when the root element is opened. */
57 void InputData::javaDefaultFileName( const char *inputFile )
59 /* If the output format is code and no output file name is given, then
61 if ( outputFileName == 0 )
62 outputFileName = fileNameFromStem( inputFile, ".java" );
65 /* Invoked by the parser when the root element is opened. */
66 void InputData::rubyDefaultFileName( const char *inputFile )
68 /* If the output format is code and no output file name is given, then
70 if ( outputFileName == 0 )
71 outputFileName = fileNameFromStem( inputFile, ".rb" );
74 /* Invoked by the parser when the root element is opened. */
75 void InputData::csharpDefaultFileName( const char *inputFile )
77 /* If the output format is code and no output file name is given, then
79 if ( outputFileName == 0 ) {
80 const char *ext = findFileExtension( inputFile );
81 if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
82 outputFileName = fileNameFromStem( inputFile, ".h" );
84 outputFileName = fileNameFromStem( inputFile, ".cs" );
88 void InputData::makeOutputStream()
90 if ( ! generateDot && ! generateXML ) {
91 switch ( hostLang->lang ) {
94 cdDefaultFileName( inputFileName );
97 javaDefaultFileName( inputFileName );
100 rubyDefaultFileName( inputFileName );
102 case HostLang::CSharp:
103 csharpDefaultFileName( inputFileName );
108 /* Make sure we are not writing to the same file as the input file. */
109 if ( outputFileName != 0 ) {
110 if ( strcmp( inputFileName, outputFileName ) == 0 ) {
111 error() << "output file \"" << outputFileName <<
112 "\" is the same as the input file" << endl;
115 /* Create the filter on the output and open it. */
116 outFilter = new output_filter( outputFileName );
118 /* Open the output stream, attaching it to the filter. */
119 outStream = new ostream( outFilter );
122 /* Writing out ot std out. */
127 void InputData::openOutput()
129 if ( outFilter != 0 ) {
130 outFilter->open( outputFileName, ios::out|ios::trunc );
131 if ( !outFilter->is_open() ) {
132 error() << "error opening " << outputFileName << " for writing" << endl;
138 void InputData::prepareMachineGen()
141 /* Locate a machine spec to generate dot output for. We can only emit.
142 * Dot takes one graph at a time. */
143 if ( machineSpec != 0 ) {
144 /* Machine specified. */
145 ParserDictEl *pdEl = parserDict.find( machineSpec );
147 error() << "could not locate machine specified with -S and/or -M" << endp;
148 dotGenParser = pdEl->value;
151 /* No machine spec given, just use the first one. */
152 if ( parserList.length() == 0 )
153 error() << "no machine specification to generate graphviz output" << endp;
155 dotGenParser = parserList.head;
158 GraphDictEl *gdEl = 0;
160 if ( machineName != 0 ) {
161 gdEl = dotGenParser->pd->graphDict.find( machineName );
163 error() << "machine definition/instantiation not found" << endp;
166 /* We are using the whole machine spec. Need to make sure there
167 * are instances in the spec. */
168 if ( dotGenParser->pd->instanceList.length() == 0 )
169 error() << "no machine instantiations to generate graphviz output" << endp;
172 dotGenParser->pd->prepareMachineGen( gdEl );
175 /* No machine spec or machine name given. Generate everything. */
176 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
177 ParseData *pd = parser->value->pd;
178 if ( pd->instanceList.length() > 0 )
179 pd->prepareMachineGen( 0 );
184 void InputData::generateReduced()
187 dotGenParser->pd->generateReduced( *this );
189 for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
190 ParseData *pd = parser->value->pd;
191 if ( pd->instanceList.length() > 0 )
192 pd->generateReduced( *this );
197 /* Send eof to all parsers. */
198 void InputData::terminateAllParsers( )
200 /* FIXME: a proper token is needed here. Suppose we should use the
201 * location of EOF in the last file that the parser was referenced in. */
203 loc.fileName = "<EOF>";
206 for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
207 pdel->value->token( loc, Parser_tk_eof, 0, 0 );
211 void InputData::writeOutput()
214 writeXML( *outStream );
216 else if ( generateDot )
217 static_cast<GraphvizDotGen*>(dotGenParser->pd->cgd)->writeDotFile();
219 for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
220 if ( ii->type == InputItem::Write ) {
221 CodeGenData *cgd = ii->pd->cgd;
222 ::keyOps = &cgd->thisKeyOps;
224 cgd->writeStatement( ii->loc, ii->writeArgs.length()-1, ii->writeArgs.data );
228 lineDirective( *outStream, inputFileName, ii->loc.line );
229 *outStream << ii->data.str();