summaryrefslogtreecommitdiff
path: root/ragel/inputdata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ragel/inputdata.cpp')
-rw-r--r--ragel/inputdata.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/ragel/inputdata.cpp b/ragel/inputdata.cpp
new file mode 100644
index 0000000..7d8322f
--- /dev/null
+++ b/ragel/inputdata.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2008 Adrian Thurston <thurston@complang.org>
+ */
+
+/* This file is part of Ragel.
+ *
+ * Ragel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Ragel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Ragel; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ragel.h"
+#include "common.h"
+#include "inputdata.h"
+#include "parsedata.h"
+#include "rlparse.h"
+#include <iostream>
+#include "dotcodegen.h"
+
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ios;
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::cdDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 ) {
+ const char *ext = findFileExtension( inputFile );
+ if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".h" );
+ else {
+ const char *defExtension = 0;
+ switch ( hostLang->lang ) {
+ case HostLang::C: defExtension = ".c"; break;
+ case HostLang::D: defExtension = ".d"; break;
+ case HostLang::D2: defExtension = ".d"; break;
+ default: break;
+ }
+ outputFileName = fileNameFromStem( inputFile, defExtension );
+ }
+ }
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::goDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".go" );
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::javaDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".java" );
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::rubyDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".rb" );
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::csharpDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 ) {
+ const char *ext = findFileExtension( inputFile );
+ if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".h" );
+ else
+ outputFileName = fileNameFromStem( inputFile, ".cs" );
+ }
+}
+
+/* Invoked by the parser when the root element is opened. */
+void InputData::ocamlDefaultFileName( const char *inputFile )
+{
+ /* If the output format is code and no output file name is given, then
+ * make a default. */
+ if ( outputFileName == 0 )
+ outputFileName = fileNameFromStem( inputFile, ".ml" );
+}
+
+void InputData::makeOutputStream()
+{
+ if ( ! generateDot && ! generateXML ) {
+ switch ( hostLang->lang ) {
+ case HostLang::C:
+ case HostLang::D:
+ case HostLang::D2:
+ cdDefaultFileName( inputFileName );
+ break;
+ case HostLang::Java:
+ javaDefaultFileName( inputFileName );
+ break;
+ case HostLang::Go:
+ goDefaultFileName( inputFileName );
+ break;
+ case HostLang::Ruby:
+ rubyDefaultFileName( inputFileName );
+ break;
+ case HostLang::CSharp:
+ csharpDefaultFileName( inputFileName );
+ break;
+ case HostLang::OCaml:
+ ocamlDefaultFileName( inputFileName );
+ break;
+ }
+ }
+
+ /* Make sure we are not writing to the same file as the input file. */
+ if ( outputFileName != 0 ) {
+ if ( strcmp( inputFileName, outputFileName ) == 0 ) {
+ error() << "output file \"" << outputFileName <<
+ "\" is the same as the input file" << endl;
+ }
+
+ /* Create the filter on the output and open it. */
+ outFilter = new output_filter( outputFileName );
+
+ /* Open the output stream, attaching it to the filter. */
+ outStream = new ostream( outFilter );
+ }
+ else {
+ /* Writing out ot std out. */
+ outStream = &cout;
+ }
+}
+
+void InputData::openOutput()
+{
+ if ( outFilter != 0 ) {
+ outFilter->open( outputFileName, ios::out|ios::trunc );
+ if ( !outFilter->is_open() ) {
+ error() << "error opening " << outputFileName << " for writing" << endl;
+ exit(1);
+ }
+ }
+}
+
+void InputData::prepareMachineGen()
+{
+ if ( generateDot ) {
+ /* Locate a machine spec to generate dot output for. We can only emit.
+ * Dot takes one graph at a time. */
+ if ( machineSpec != 0 ) {
+ /* Machine specified. */
+ ParserDictEl *pdEl = parserDict.find( machineSpec );
+ if ( pdEl == 0 )
+ error() << "could not locate machine specified with -S and/or -M" << endp;
+ dotGenParser = pdEl->value;
+ }
+ else {
+ /* No machine spec given, just use the first one. */
+ if ( parserList.length() == 0 )
+ error() << "no machine specification to generate graphviz output" << endp;
+
+ dotGenParser = parserList.head;
+ }
+
+ GraphDictEl *gdEl = 0;
+
+ if ( machineName != 0 ) {
+ gdEl = dotGenParser->pd->graphDict.find( machineName );
+ if ( gdEl == 0 )
+ error() << "machine definition/instantiation not found" << endp;
+ }
+ else {
+ /* We are using the whole machine spec. Need to make sure there
+ * are instances in the spec. */
+ if ( dotGenParser->pd->instanceList.length() == 0 )
+ error() << "no machine instantiations to generate graphviz output" << endp;
+ }
+
+ dotGenParser->pd->prepareMachineGen( gdEl );
+ }
+ else {
+ /* No machine spec or machine name given. Generate everything. */
+ for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
+ ParseData *pd = parser->value->pd;
+ if ( pd->instanceList.length() > 0 )
+ pd->prepareMachineGen( 0 );
+ }
+ }
+}
+
+void InputData::generateReduced()
+{
+ if ( generateDot )
+ dotGenParser->pd->generateReduced( *this );
+ else {
+ for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
+ ParseData *pd = parser->value->pd;
+ if ( pd->instanceList.length() > 0 )
+ pd->generateReduced( *this );
+ }
+ }
+}
+
+/* Send eof to all parsers. */
+void InputData::terminateAllParsers( )
+{
+ /* FIXME: a proper token is needed here. Suppose we should use the
+ * location of EOF in the last file that the parser was referenced in. */
+ InputLoc loc;
+ loc.fileName = "<EOF>";
+ loc.line = 0;
+ loc.col = 0;
+ for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
+ pdel->value->token( loc, Parser_tk_eof, 0, 0 );
+}
+
+void InputData::verifyWritesHaveData()
+{
+ if ( !generateXML && !generateDot ) {
+ for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
+ if ( ii->type == InputItem::Write ) {
+ if ( ii->pd->cgd == 0 )
+ error( ii->loc ) << "no machine instantiations to write" << endl;
+ }
+ }
+ }
+}
+
+void InputData::writeOutput()
+{
+ if ( generateXML )
+ writeXML( *outStream );
+ else if ( generateDot )
+ static_cast<GraphvizDotGen*>(dotGenParser->pd->cgd)->writeDotFile();
+ else {
+ bool hostLineDirective = true;
+ for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
+ if ( ii->type == InputItem::Write ) {
+ CodeGenData *cgd = ii->pd->cgd;
+ ::keyOps = &cgd->thisKeyOps;
+
+ hostLineDirective = cgd->writeStatement( ii->loc,
+ ii->writeArgs.length()-1, ii->writeArgs.data );
+ }
+ else {
+ if ( hostLineDirective ) {
+ /* Write statements can turn off host line directives for
+ * host sections that follow them. */
+ *outStream << '\n';
+ lineDirective( *outStream, inputFileName, ii->loc.line );
+ }
+ *outStream << ii->data.str();
+ hostLineDirective = true;
+ }
+ }
+ }
+}
+