inputdata.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * Copyright 2008 Adrian Thurston <thurston@complang.org>
  3. */
  4. /* This file is part of Ragel.
  5. *
  6. * Ragel is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Ragel is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Ragel; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "ragel.h"
  21. #include "common.h"
  22. #include "inputdata.h"
  23. #include "parsedata.h"
  24. #include "rlparse.h"
  25. #include <iostream>
  26. #include "dotcodegen.h"
  27. using std::cout;
  28. using std::cerr;
  29. using std::endl;
  30. using std::ios;
  31. /* Invoked by the parser when the root element is opened. */
  32. void InputData::cdDefaultFileName( const char *inputFile )
  33. {
  34. /* If the output format is code and no output file name is given, then
  35. * make a default. */
  36. if ( outputFileName == 0 ) {
  37. const char *ext = findFileExtension( inputFile );
  38. if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
  39. outputFileName = fileNameFromStem( inputFile, ".h" );
  40. else {
  41. const char *defExtension = 0;
  42. switch ( hostLang->lang ) {
  43. case HostLang::C: defExtension = ".c"; break;
  44. case HostLang::D: defExtension = ".d"; break;
  45. case HostLang::D2: defExtension = ".d"; break;
  46. default: break;
  47. }
  48. outputFileName = fileNameFromStem( inputFile, defExtension );
  49. }
  50. }
  51. }
  52. /* Invoked by the parser when the root element is opened. */
  53. void InputData::goDefaultFileName( const char *inputFile )
  54. {
  55. /* If the output format is code and no output file name is given, then
  56. * make a default. */
  57. if ( outputFileName == 0 )
  58. outputFileName = fileNameFromStem( inputFile, ".go" );
  59. }
  60. /* Invoked by the parser when the root element is opened. */
  61. void InputData::javaDefaultFileName( const char *inputFile )
  62. {
  63. /* If the output format is code and no output file name is given, then
  64. * make a default. */
  65. if ( outputFileName == 0 )
  66. outputFileName = fileNameFromStem( inputFile, ".java" );
  67. }
  68. /* Invoked by the parser when the root element is opened. */
  69. void InputData::rubyDefaultFileName( const char *inputFile )
  70. {
  71. /* If the output format is code and no output file name is given, then
  72. * make a default. */
  73. if ( outputFileName == 0 )
  74. outputFileName = fileNameFromStem( inputFile, ".rb" );
  75. }
  76. /* Invoked by the parser when the root element is opened. */
  77. void InputData::csharpDefaultFileName( const char *inputFile )
  78. {
  79. /* If the output format is code and no output file name is given, then
  80. * make a default. */
  81. if ( outputFileName == 0 ) {
  82. const char *ext = findFileExtension( inputFile );
  83. if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
  84. outputFileName = fileNameFromStem( inputFile, ".h" );
  85. else
  86. outputFileName = fileNameFromStem( inputFile, ".cs" );
  87. }
  88. }
  89. /* Invoked by the parser when the root element is opened. */
  90. void InputData::ocamlDefaultFileName( const char *inputFile )
  91. {
  92. /* If the output format is code and no output file name is given, then
  93. * make a default. */
  94. if ( outputFileName == 0 )
  95. outputFileName = fileNameFromStem( inputFile, ".ml" );
  96. }
  97. void InputData::makeOutputStream()
  98. {
  99. if ( ! generateDot && ! generateXML ) {
  100. switch ( hostLang->lang ) {
  101. case HostLang::C:
  102. case HostLang::D:
  103. case HostLang::D2:
  104. cdDefaultFileName( inputFileName );
  105. break;
  106. case HostLang::Java:
  107. javaDefaultFileName( inputFileName );
  108. break;
  109. case HostLang::Go:
  110. goDefaultFileName( inputFileName );
  111. break;
  112. case HostLang::Ruby:
  113. rubyDefaultFileName( inputFileName );
  114. break;
  115. case HostLang::CSharp:
  116. csharpDefaultFileName( inputFileName );
  117. break;
  118. case HostLang::OCaml:
  119. ocamlDefaultFileName( inputFileName );
  120. break;
  121. }
  122. }
  123. /* Make sure we are not writing to the same file as the input file. */
  124. if ( outputFileName != 0 ) {
  125. if ( strcmp( inputFileName, outputFileName ) == 0 ) {
  126. error() << "output file \"" << outputFileName <<
  127. "\" is the same as the input file" << endl;
  128. }
  129. /* Create the filter on the output and open it. */
  130. outFilter = new output_filter( outputFileName );
  131. /* Open the output stream, attaching it to the filter. */
  132. outStream = new ostream( outFilter );
  133. }
  134. else {
  135. /* Writing out ot std out. */
  136. outStream = &cout;
  137. }
  138. }
  139. void InputData::openOutput()
  140. {
  141. if ( outFilter != 0 ) {
  142. outFilter->open( outputFileName, ios::out|ios::trunc );
  143. if ( !outFilter->is_open() ) {
  144. error() << "error opening " << outputFileName << " for writing" << endl;
  145. exit(1);
  146. }
  147. }
  148. }
  149. void InputData::prepareMachineGen()
  150. {
  151. if ( generateDot ) {
  152. /* Locate a machine spec to generate dot output for. We can only emit.
  153. * Dot takes one graph at a time. */
  154. if ( machineSpec != 0 ) {
  155. /* Machine specified. */
  156. ParserDictEl *pdEl = parserDict.find( machineSpec );
  157. if ( pdEl == 0 )
  158. error() << "could not locate machine specified with -S and/or -M" << endp;
  159. dotGenParser = pdEl->value;
  160. }
  161. else {
  162. /* No machine spec given, just use the first one. */
  163. if ( parserList.length() == 0 )
  164. error() << "no machine specification to generate graphviz output" << endp;
  165. dotGenParser = parserList.head;
  166. }
  167. GraphDictEl *gdEl = 0;
  168. if ( machineName != 0 ) {
  169. gdEl = dotGenParser->pd->graphDict.find( machineName );
  170. if ( gdEl == 0 )
  171. error() << "machine definition/instantiation not found" << endp;
  172. }
  173. else {
  174. /* We are using the whole machine spec. Need to make sure there
  175. * are instances in the spec. */
  176. if ( dotGenParser->pd->instanceList.length() == 0 )
  177. error() << "no machine instantiations to generate graphviz output" << endp;
  178. }
  179. dotGenParser->pd->prepareMachineGen( gdEl );
  180. }
  181. else {
  182. /* No machine spec or machine name given. Generate everything. */
  183. for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
  184. ParseData *pd = parser->value->pd;
  185. if ( pd->instanceList.length() > 0 )
  186. pd->prepareMachineGen( 0 );
  187. }
  188. }
  189. }
  190. void InputData::generateReduced()
  191. {
  192. if ( generateDot )
  193. dotGenParser->pd->generateReduced( *this );
  194. else {
  195. for ( ParserDict::Iter parser = parserDict; parser.lte(); parser++ ) {
  196. ParseData *pd = parser->value->pd;
  197. if ( pd->instanceList.length() > 0 )
  198. pd->generateReduced( *this );
  199. }
  200. }
  201. }
  202. /* Send eof to all parsers. */
  203. void InputData::terminateAllParsers( )
  204. {
  205. /* FIXME: a proper token is needed here. Suppose we should use the
  206. * location of EOF in the last file that the parser was referenced in. */
  207. InputLoc loc;
  208. loc.fileName = "<EOF>";
  209. loc.line = 0;
  210. loc.col = 0;
  211. for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
  212. pdel->value->token( loc, Parser_tk_eof, 0, 0 );
  213. }
  214. void InputData::verifyWritesHaveData()
  215. {
  216. if ( !generateXML && !generateDot ) {
  217. for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
  218. if ( ii->type == InputItem::Write ) {
  219. if ( ii->pd->cgd == 0 )
  220. error( ii->loc ) << "no machine instantiations to write" << endl;
  221. }
  222. }
  223. }
  224. }
  225. void InputData::writeOutput()
  226. {
  227. if ( generateXML )
  228. writeXML( *outStream );
  229. else if ( generateDot )
  230. static_cast<GraphvizDotGen*>(dotGenParser->pd->cgd)->writeDotFile();
  231. else {
  232. bool hostLineDirective = true;
  233. for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
  234. if ( ii->type == InputItem::Write ) {
  235. CodeGenData *cgd = ii->pd->cgd;
  236. ::keyOps = &cgd->thisKeyOps;
  237. hostLineDirective = cgd->writeStatement( ii->loc,
  238. ii->writeArgs.length()-1, ii->writeArgs.data );
  239. }
  240. else {
  241. if ( hostLineDirective ) {
  242. /* Write statements can turn off host line directives for
  243. * host sections that follow them. */
  244. *outStream << '\n';
  245. lineDirective( *outStream, inputFileName, ii->loc.line );
  246. }
  247. *outStream << ii->data.str();
  248. hostLineDirective = true;
  249. }
  250. }
  251. }
  252. }