inputdata.cc (ragel-7.0.0.10) | : | inputdata.cc (ragel-7.0.0.11) | ||
---|---|---|---|---|
/* | /* | |||
* Copyright 2008-2016 Adrian Thurston <thurston@colm.net> | * Copyright 2008-2018 Adrian Thurston <thurston@colm.net> | |||
* | * | |||
* Permission is hereby granted, free of charge, to any person obtaining a copy | * Permission is hereby granted, free of charge, to any person obtaining a copy | |||
* of this software and associated documentation files (the "Software"), to | * of this software and associated documentation files (the "Software"), to | |||
* deal in the Software without restriction, including without limitation the | * deal in the Software without restriction, including without limitation the | |||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |||
* sell copies of the Software, and to permit persons to whom the Software is | * sell copies of the Software, and to permit persons to whom the Software is | |||
* furnished to do so, subject to the following conditions: | * furnished to do so, subject to the following conditions: | |||
* | * | |||
* The above copyright notice and this permission notice shall be included in al l | * The above copyright notice and this permission notice shall be included in al l | |||
* copies or substantial portions of the Software. | * copies or substantial portions of the Software. | |||
skipping to change at line 30 | skipping to change at line 30 | |||
* SOFTWARE. | * SOFTWARE. | |||
*/ | */ | |||
#include "ragel.h" | #include "ragel.h" | |||
#include "common.h" | #include "common.h" | |||
#include "inputdata.h" | #include "inputdata.h" | |||
#include "parsedata.h" | #include "parsedata.h" | |||
#include "load.h" | #include "load.h" | |||
#include "rlscan.h" | #include "rlscan.h" | |||
#include "reducer.h" | #include "reducer.h" | |||
#include "version.h" | ||||
#include "pcheck.h" | ||||
#include <colm/colm.h> | ||||
#include <stdlib.h> | ||||
#include <string.h> | ||||
#include <stdio.h> | ||||
#include <iostream> | #include <iostream> | |||
#include <iomanip> | ||||
#include <fstream> | ||||
#include <unistd.h> | #include <unistd.h> | |||
#include <sstream> | ||||
#include <sys/types.h> | ||||
#include <sys/stat.h> | ||||
#include <fcntl.h> | ||||
#include <errno.h> | ||||
#include <sys/wait.h> | ||||
#ifdef _WIN32 | ||||
#include <windows.h> | ||||
#include <psapi.h> | ||||
#include <time.h> | ||||
#include <io.h> | ||||
#include <process.h> | ||||
#if _MSC_VER | ||||
#define S_IRUSR _S_IREAD | ||||
#define S_IWUSR _S_IWRITE | ||||
#endif | ||||
#endif | ||||
using std::istream; | using std::istream; | |||
using std::ifstream; | using std::ifstream; | |||
using std::ofstream; | ||||
using std::stringstream; | using std::stringstream; | |||
using std::ostream; | using std::ostream; | |||
using std::endl; | using std::endl; | |||
using std::ios; | using std::ios; | |||
InputData::~InputData() | InputData::~InputData() | |||
{ | { | |||
inputItems.empty(); | inputItems.empty(); | |||
parseDataList.empty(); | parseDataList.empty(); | |||
sectionList.empty(); | sectionList.empty(); | |||
skipping to change at line 69 | skipping to change at line 97 | |||
if ( histogramFn != 0 ) | if ( histogramFn != 0 ) | |||
::free( (void*)histogramFn ); | ::free( (void*)histogramFn ); | |||
if ( histogram != 0 ) | if ( histogram != 0 ) | |||
delete[] histogram; | delete[] histogram; | |||
for ( ArgsVector::Iter bl = breadthLabels; bl.lte(); bl++ ) | for ( ArgsVector::Iter bl = breadthLabels; bl.lte(); bl++ ) | |||
free( (void*) *bl ); | free( (void*) *bl ); | |||
} | } | |||
/* Invoked by the parser when the root element is opened. */ | ||||
void InputData::cDefaultFileName( 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; | ||||
default: break; | ||||
} | ||||
outputFileName = fileNameFromStem( inputFile, defExtensio | ||||
n ); | ||||
} | ||||
} | ||||
} | ||||
void InputData::asmDefaultFileName( const char *inputFile ) | ||||
{ | ||||
if ( outputFileName == 0 ) | ||||
outputFileName = fileNameFromStem( inputFile, ".s" ); | ||||
} | ||||
void InputData::makeDefaultFileName() | void InputData::makeDefaultFileName() | |||
{ | { | |||
switch ( hostLang->lang ) { | if ( outputFileName == 0 ) | |||
case HostLang::C: | outputFileName = (hostLang->defaultOutFn)( inputFileName ); | |||
cDefaultFileName( inputFileName ); | ||||
break; | ||||
case HostLang::Asm: | ||||
asmDefaultFileName( inputFileName ); | ||||
break; | ||||
} | ||||
} | } | |||
bool InputData::isBreadthLabel( const string &label ) | bool InputData::isBreadthLabel( const string &label ) | |||
{ | { | |||
for ( ArgsVector::Iter bl = breadthLabels; bl.lte(); bl++ ) { | for ( ArgsVector::Iter bl = breadthLabels; bl.lte(); bl++ ) { | |||
if ( label == *bl ) | if ( label == *bl ) | |||
return true; | return true; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
skipping to change at line 232 | skipping to change at line 228 | |||
void InputData::writeOutput( InputItem *ii ) | void InputData::writeOutput( InputItem *ii ) | |||
{ | { | |||
switch ( ii->type ) { | switch ( ii->type ) { | |||
case InputItem::Write: { | case InputItem::Write: { | |||
CodeGenData *cgd = ii->pd->cgd; | CodeGenData *cgd = ii->pd->cgd; | |||
cgd->writeStatement( ii->loc, ii->writeArgs.size(), | cgd->writeStatement( ii->loc, ii->writeArgs.size(), | |||
ii->writeArgs, generateDot, hostLang ); | ii->writeArgs, generateDot, hostLang ); | |||
break; | break; | |||
} | } | |||
case InputItem::HostData: { | case InputItem::HostData: { | |||
if ( hostLang->lang == HostLang::C ) { | switch ( hostLang->backend ) { | |||
if ( ii->loc.fileName != 0 ) { | case Direct: | |||
if ( !noLineDirectives ) { | if ( hostLang->_lang == HostLang::C ) { | |||
*outStream << "\n#line " << ii->l | if ( ii->loc.fileName != 0 ) { | |||
oc.line << | if ( !noLineDirectives ) | |||
" \"" << ii->loc. | { | |||
fileName << "\"\n"; | *outStream << "\n | |||
#line " << ii->loc.line << | ||||
" | ||||
\"" << ii->loc.fileName << "\"\n"; | ||||
} | ||||
} | ||||
} | } | |||
} | ||||
} | ||||
*outStream << ii->data.str(); | *outStream << ii->data.str(); | |||
break; | ||||
case Translated: | ||||
openHostBlock( '@', this, *outStream, inp | ||||
utFileName, ii->loc.line ); | ||||
translatedHostData( *outStream, ii->data. | ||||
str() ); | ||||
*outStream << "}@"; | ||||
break; | ||||
} | ||||
break; | break; | |||
} | } | |||
case InputItem::EndSection: { | case InputItem::EndSection: { | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
void InputData::writeOutput() | void InputData::writeOutput() | |||
{ | { | |||
skipping to change at line 396 | skipping to change at line 401 | |||
while ( lastFlush != 0 ) { | while ( lastFlush != 0 ) { | |||
/* Flush out. */ | /* Flush out. */ | |||
writeOutput( lastFlush ); | writeOutput( lastFlush ); | |||
lastFlush = lastFlush->next; | lastFlush = lastFlush->next; | |||
} | } | |||
} | } | |||
void InputData::makeTranslateOutputFileName() | void InputData::makeTranslateOutputFileName() | |||
{ | { | |||
if ( false ) { | origOutputFileName = outputFileName; | |||
origOutputFileName = outputFileName; | outputFileName = fileNameFromStem( outputFileName, ".ri" ); | |||
outputFileName = fileNameFromStem( inputFileName, ".ri" ); | genOutputFileName = outputFileName; | |||
genOutputFileName = outputFileName; | ||||
} | ||||
} | } | |||
#ifdef WITH_RAGEL_KELBT | #ifdef WITH_RAGEL_KELBT | |||
void InputData::parseKelbt() | void InputData::parseKelbt() | |||
{ | { | |||
/* | /* | |||
* Ragel Parser from ragel 6. | * Ragel Parser from ragel 6. | |||
*/ | */ | |||
ifstream *inFileStream; | ifstream *inFileStream; | |||
stringstream *inStringStream; | ||||
istream *inStream; | istream *inStream; | |||
if ( inLibRagel ) { | /* Open the input file for reading. */ | |||
/* Open the input file for reading. */ | assert( inputFileName != 0 ); | |||
assert( inputFileName != 0 ); | inFileStream = new ifstream( inputFileName ); | |||
inStringStream = new stringstream( string( input ) ); | if ( ! inFileStream->is_open() ) | |||
inStream = inStringStream; | error() << "could not open " << inputFileName << " for reading" < | |||
} | < endp; | |||
else { | inStream = inFileStream; | |||
/* Open the input file for reading. */ | ||||
assert( inputFileName != 0 ); | ||||
inFileStream = new ifstream( inputFileName ); | ||||
if ( ! inFileStream->is_open() ) | ||||
error() << "could not open " << inputFileName << " for re | ||||
ading" << endp; | ||||
inStream = inFileStream; | ||||
} | ||||
makeFirstInputItem(); | makeFirstInputItem(); | |||
Scanner scanner( this, inputFileName, *inStream, 0, 0, 0, false ); | Scanner scanner( this, inputFileName, *inStream, 0, 0, 0, false ); | |||
scanner.sectionPass = true; | scanner.sectionPass = true; | |||
scanner.do_scan(); | scanner.do_scan(); | |||
inStream->clear(); | inStream->clear(); | |||
inStream->seekg( 0, std::ios::beg ); | inStream->seekg( 0, std::ios::beg ); | |||
skipping to change at line 451 | skipping to change at line 445 | |||
scanner.do_scan(); | scanner.do_scan(); | |||
/* Finished, final check for errors.. */ | /* Finished, final check for errors.. */ | |||
if ( errorCount > 0 ) | if ( errorCount > 0 ) | |||
abortCompile( 1 ); | abortCompile( 1 ); | |||
/* Bail on above error. */ | /* Bail on above error. */ | |||
if ( errorCount > 0 ) | if ( errorCount > 0 ) | |||
abortCompile( 1 ); | abortCompile( 1 ); | |||
if ( inLibRagel ) | delete inFileStream; | |||
delete inStringStream; | ||||
else | ||||
delete inFileStream; | ||||
} | } | |||
void InputData::processKelbt() | void InputData::processKelbt() | |||
{ | { | |||
/* With the kelbt version we implement two parse passes. The first is use d | /* With the kelbt version we implement two parse passes. The first is use d | |||
* to identify the last time that any given machine is referenced by a | * to identify the last time that any given machine is referenced by a | |||
* ragel section. In the second pass we parse, compile, and emit as far | * ragel section. In the second pass we parse, compile, and emit as far | |||
* forward as possible when we encounter the last reference to a machine. | * forward as possible when we encounter the last reference to a machine. | |||
* */ | * */ | |||
if ( generateDot ) { | if ( generateDot ) { | |||
parseKelbt(); | parseKelbt(); | |||
terminateAllParsers(); | terminateAllParsers(); | |||
processDot(); | processDot(); | |||
} | } | |||
else { | else { | |||
makeDefaultFileName(); | ||||
makeTranslateOutputFileName(); | ||||
createOutputStream(); | createOutputStream(); | |||
openOutput(); | openOutput(); | |||
parseKelbt(); | parseKelbt(); | |||
flushRemaining(); | flushRemaining(); | |||
closeOutput(); | closeOutput(); | |||
} | } | |||
assert( errorCount == 0 ); | assert( errorCount == 0 ); | |||
} | } | |||
#endif | #endif | |||
skipping to change at line 511 | skipping to change at line 500 | |||
} | } | |||
if ( errorCount ) | if ( errorCount ) | |||
return false; | return false; | |||
makeFirstInputItem(); | makeFirstInputItem(); | |||
curItem = inputItems.head; | curItem = inputItems.head; | |||
lastFlush = inputItems.head; | lastFlush = inputItems.head; | |||
topLevel->reduceFile( inputFileName, false ); | topLevel->reduceFile( "rlparse", inputFileName ); | |||
if ( errorCount ) | if ( errorCount ) | |||
return false; | return false; | |||
bool success = topLevel->success; | bool success = topLevel->success; | |||
delete topLevel; | delete topLevel; | |||
return success; | return success; | |||
} | } | |||
bool InputData::processReduce() | bool InputData::processReduce() | |||
{ | { | |||
if ( generateDot ) { | if ( generateDot ) { | |||
parseReduce(); | parseReduce(); | |||
processDot(); | processDot(); | |||
return true; | return true; | |||
} | } | |||
else { | else { | |||
makeDefaultFileName(); | ||||
makeTranslateOutputFileName(); | ||||
createOutputStream(); | createOutputStream(); | |||
openOutput(); | openOutput(); | |||
bool success = parseReduce(); | bool success = parseReduce(); | |||
if ( success ) | if ( success ) | |||
flushRemaining(); | flushRemaining(); | |||
closeOutput(); | closeOutput(); | |||
if ( !success && outputFileName != 0 ) | if ( !success && outputFileName != 0 ) | |||
unlink( outputFileName ); | unlink( outputFileName ); | |||
return success; | return success; | |||
} | } | |||
} | } | |||
bool InputData::process() | bool InputData::process() | |||
{ | { | |||
switch ( frontend ) { | switch ( frontend ) { | |||
case KelbtBased: { | case KelbtBased: { | |||
#ifdef WITH_RAGEL_KELBT | #ifdef WITH_RAGEL_KELBT | |||
processKelbt(); | processKelbt(); | |||
#endif | #endif | |||
return true; | return true; | |||
} | } | |||
case ReduceBased: { | case ReduceBased: { | |||
return processReduce(); | return processReduce(); | |||
} | } | |||
} | } | |||
return false; | return false; | |||
} | } | |||
/* Print a summary of the options. */ | ||||
void InputData::usage() | ||||
{ | ||||
info() << | ||||
"usage: ragel [options] file\n" | ||||
"general:\n" | ||||
" -h, -H, -?, --help Print this usage and exit\n" | ||||
" -v, --version Print version information and exit\n" | ||||
" -o <file> Write output to <file>\n" | ||||
" -s Print some statistics and compilation info to stderr\n" | ||||
" -d Do not remove duplicates from action lists\n" | ||||
" -I <dir> Add <dir> to the list of directories to search\n" | ||||
" for included an imported files\n" | ||||
" --rlhc Show the rlhc command used to compile\n" | ||||
" --save-temps Do not delete intermediate file during compilation\n" | ||||
" --no-intermediate Disable call to rlhc, leave behind intermediate\n" | ||||
"error reporting format:\n" | ||||
" --error-format=gnu file:line:column: message (default)\n" | ||||
" --error-format=msvc file(line,column): message\n" | ||||
"fsm minimization:\n" | ||||
" -n Do not perform minimization\n" | ||||
" -m Minimize at the end of the compilation\n" | ||||
" -l Minimize after most operations (default)\n" | ||||
" -e Minimize after every operation\n" | ||||
"visualization:\n" | ||||
" -V Generate a dot file for Graphviz\n" | ||||
" -p Display printable characters on labels\n" | ||||
" -S <spec> FSM specification to output (for graphviz output)\n" | ||||
" -M <machine> Machine definition/instantiation to output (for\n" | ||||
" graphviz output)\n" | ||||
"host language:\n" | ||||
" -C C, C++, Obj-C or Obj-C++ (default)\n" | ||||
" All code styles supported.\n" | ||||
" --asm --gas-x86-64-sys-v\n" | ||||
" GNU AS, x86_64, System V ABI.\n" | ||||
" Generated in a code style equivalent to -G2\n" | ||||
" -D D All code styles supported\n" | ||||
" -Z Go All code styles supported\n" | ||||
" -A C# -T0 -T1 -F0 -F1 -G0 -G1\n" | ||||
" -J Java -T0 -T1 -F0 -F1\n" | ||||
" -R Ruby -T0 -T1 -F0 -F1\n" | ||||
" -O OCaml -T0 -T1 -F0 -F1\n" | ||||
" -U Rust -T0 -T1 -F0 -F1\n" | ||||
" -Y Julia -T0 -T1 -F0 -F1\n" | ||||
" -K Crack -T0 -T1 -F0 -F1\n" | ||||
" -P JavaScript -T0 -T1 -F0 -F1\n" | ||||
"line directives:\n" | ||||
" -L Inhibit writing of #line directives\n" | ||||
"code style:\n" | ||||
" -T0 Binary search (default)\n" | ||||
" -T1 Binary search with expanded actions \n" | ||||
" -F0 Flat table\n" | ||||
" -F1 Flat table with expanded actions\n" | ||||
" -G0 Switch-driven\n" | ||||
" -G1 Switch-driven with expanded actions\n" | ||||
" -G2 Goto-driven with expanded actions\n" | ||||
"large machines:\n" | ||||
" --integral-tables Use integers for table data (default)\n" | ||||
" --string-tables Encode table data into strings for faster host lang\n" | ||||
" compilation\n" | ||||
"analysis:\n" | ||||
" --prior-interaction Search for condition-based general repetitions\ | ||||
n" | ||||
" that will not function properly due to state mo | ||||
d\n" | ||||
" overlap and must be NFA reps. \n" | ||||
" --conds-depth=D Search for high-cost conditions inside a prefix | ||||
\n" | ||||
" of the machine (depth D from start state).\n" | ||||
" --state-limit=L Report fail if number of states exceeds this\n" | ||||
" during compilation.\n" | ||||
" --breadth-check=E1,E2,.. Report breadth cost of named entry points and\n | ||||
" | ||||
" the start state.\n" | ||||
" --input-histogram=FN Input char histogram for breadth check. If\n" | ||||
" unspecified a flat histogram is used.\n" | ||||
"testing:\n" | ||||
" --kelbt-frontend Compile using original ragel + kelbt frontend\n" | ||||
" Requires ragel be built with ragel + kelbt support\n | ||||
" | ||||
" --colm-frontend Compile using a colm-based recursive descent\n" | ||||
" frontend\n" | ||||
" --reduce-frontend Compile using a colm-based reducer (default)\n" | ||||
" --direct-backend Use the direct backend for supported langs (default) | ||||
\n" | ||||
" --colm-backend Use the translation backed for C\n" | ||||
" --var-backend Use the variable-based backend for langs that\n" | ||||
" support goto-based\n" | ||||
" --goto-backend Use the goto-based backend for supported langs\n" | ||||
" (default)\n" | ||||
" --supported-host-langs Show supported host languages by command line arg\n" | ||||
" --supported-frontends Show supported frontends\n" | ||||
" --supported-backends Show supported backends\n" | ||||
" --force-libragel Cause mainline to behave like libragel\n" | ||||
; | ||||
abortCompile( 0 ); | ||||
} | ||||
/* Print version information and exit. */ | ||||
void InputData::version() | ||||
{ | ||||
info() << "Ragel State Machine Compiler version " VERSION << " " PUBDATE | ||||
<< endl << | ||||
"Copyright (c) 2001-2018 by Adrian Thurston" << endl; | ||||
abortCompile( 0 ); | ||||
} | ||||
void InputData::showHostLangNames() | ||||
{ | ||||
ostream &out = info(); | ||||
for ( int i = 0; i < numHostLangs; i++ ) { | ||||
if ( i > 0 ) | ||||
out << " "; | ||||
out << hostLangs[i]->name; | ||||
} | ||||
out << endl; | ||||
abortCompile( 0 ); | ||||
} | ||||
void InputData::showHostLangArgs() | ||||
{ | ||||
ostream &out = info(); | ||||
for ( int i = 0; i < numHostLangs; i++ ) { | ||||
if ( i > 0 ) | ||||
out << " "; | ||||
out << hostLangs[i]->arg; | ||||
} | ||||
out << endl; | ||||
abortCompile( 0 ); | ||||
} | ||||
void InputData::showFrontends() | ||||
{ | ||||
ostream &out = info(); | ||||
out << "--colm-frontend"; | ||||
out << " --reduce-frontend"; | ||||
#ifdef WITH_RAGEL_KELBT | ||||
out << " --kelbt-frontend"; | ||||
#endif | ||||
out << endl; | ||||
abortCompile( 0 ); | ||||
} | ||||
void InputData::showBackends() | ||||
{ | ||||
info() << | ||||
"--direct-backend --colm-backend" << endl; | ||||
abortCompile( 0 ); | ||||
} | ||||
InputLoc makeInputLoc( const char *fileName, int line, int col ) | ||||
{ | ||||
InputLoc loc( fileName, line, col ); | ||||
return loc; | ||||
} | ||||
void escapeLineDirectivePath( std::ostream &out, char *path ) | ||||
{ | ||||
for ( char *pc = path; *pc != 0; pc++ ) { | ||||
if ( *pc == '\\' ) | ||||
out << "\\\\"; | ||||
else | ||||
out << *pc; | ||||
} | ||||
} | ||||
void InputData::parseArgs( int argc, const char **argv ) | ||||
{ | ||||
ParamCheck pc( "r:o:dnmleabjkS:M:I:CEJZRAOKUYvHh?-:sT:F:G:LpV", argc, arg | ||||
v ); | ||||
/* Decide if we were invoked using a path variable, or with an explicit p | ||||
ath. */ | ||||
const char *lastSlash = strrchr( argv[0], '/' ); | ||||
if ( lastSlash == 0 ) { | ||||
/* Defualt to the the binary install location. */ | ||||
dirName = BINDIR; | ||||
} | ||||
else { | ||||
/* Compute dirName from argv0. */ | ||||
dirName = string( argv[0], lastSlash - argv[0] ); | ||||
} | ||||
/* FIXME: Need to check code styles VS langauge. */ | ||||
while ( pc.check() ) { | ||||
switch ( pc.state ) { | ||||
case ParamCheck::match: | ||||
switch ( pc.parameter ) { | ||||
case 'V': | ||||
generateDot = true; | ||||
break; | ||||
/* Output. */ | ||||
case 'o': | ||||
if ( *pc.paramArg == 0 ) | ||||
error() << "a zero length output file nam | ||||
e was given" << endl; | ||||
else if ( outputFileName != 0 ) | ||||
error() << "more than one output file nam | ||||
e was given" << endl; | ||||
else { | ||||
/* Ok, remember the output file name. */ | ||||
outputFileName = new char[strlen(pc.param | ||||
Arg)+1]; | ||||
strcpy( (char*)outputFileName, pc.paramAr | ||||
g ); | ||||
} | ||||
break; | ||||
/* Flag for turning off duplicate action removal. */ | ||||
case 'd': | ||||
wantDupsRemoved = false; | ||||
break; | ||||
/* Minimization, mostly hidden options. */ | ||||
case 'n': | ||||
minimizeOpt = MinimizeNone; | ||||
break; | ||||
case 'm': | ||||
minimizeOpt = MinimizeEnd; | ||||
break; | ||||
case 'l': | ||||
minimizeOpt = MinimizeMostOps; | ||||
break; | ||||
case 'e': | ||||
minimizeOpt = MinimizeEveryOp; | ||||
break; | ||||
case 'a': | ||||
#ifdef TO_UPGRADE_CONDS | ||||
minimizeLevel = MinimizeApprox; | ||||
#else | ||||
error() << "minimize approx (-a) unsupported in t | ||||
his version" << endp; | ||||
#endif | ||||
break; | ||||
case 'b': | ||||
#ifdef TO_UPGRADE_CONDS | ||||
minimizeLevel = MinimizeStable; | ||||
#else | ||||
error() << "minimize stable (-b) unsupported in t | ||||
his version" << endp; | ||||
#endif | ||||
break; | ||||
case 'j': | ||||
minimizeLevel = MinimizePartition1; | ||||
break; | ||||
case 'k': | ||||
minimizeLevel = MinimizePartition2; | ||||
break; | ||||
/* Machine spec. */ | ||||
case 'S': | ||||
if ( *pc.paramArg == 0 ) | ||||
error() << "please specify an argument to | ||||
-S" << endl; | ||||
else if ( machineSpec != 0 ) | ||||
error() << "more than one -S argument was | ||||
given" << endl; | ||||
else { | ||||
/* Ok, remember the path to the machine t | ||||
o generate. */ | ||||
machineSpec = pc.paramArg; | ||||
} | ||||
break; | ||||
/* Machine path. */ | ||||
case 'M': | ||||
if ( *pc.paramArg == 0 ) | ||||
error() << "please specify an argument to | ||||
-M" << endl; | ||||
else if ( machineName != 0 ) | ||||
error() << "more than one -M argument was | ||||
given" << endl; | ||||
else { | ||||
/* Ok, remember the machine name to gener | ||||
ate. */ | ||||
machineName = pc.paramArg; | ||||
} | ||||
break; | ||||
case 'I': | ||||
if ( *pc.paramArg == 0 ) | ||||
error() << "please specify an argument to | ||||
-I" << endl; | ||||
else { | ||||
includePaths.append( pc.paramArg ); | ||||
} | ||||
break; | ||||
/* Host language types. */ | ||||
case 'C': | ||||
hostLang = &hostLangC; | ||||
break; | ||||
// case 'D': | ||||
// hostLang = &hostLangD; | ||||
// break; | ||||
// case 'Z': | ||||
// hostLang = &hostLangGo; | ||||
// break; | ||||
// case 'J': | ||||
// hostLang = &hostLangJava; | ||||
// break; | ||||
// case 'R': | ||||
// hostLang = &hostLangRuby; | ||||
// break; | ||||
// case 'A': | ||||
// hostLang = &hostLangCSharp; | ||||
// break; | ||||
// case 'O': | ||||
// hostLang = &hostLangOCaml; | ||||
// break; | ||||
// case 'K': | ||||
// hostLang = &hostLangCrack; | ||||
// break; | ||||
// case 'U': | ||||
// hostLang = &hostLangRust; | ||||
// break; | ||||
// case 'Y': | ||||
// hostLang = &hostLangJulia; | ||||
// break; | ||||
// case 'P': | ||||
// hostLang = &hostLangJS; | ||||
// break; | ||||
/* Version and help. */ | ||||
case 'v': | ||||
version(); | ||||
break; | ||||
case 'H': case 'h': case '?': | ||||
usage(); | ||||
break; | ||||
case 's': | ||||
printStatistics = true; | ||||
break; | ||||
case '-': { | ||||
char *arg = strdup( pc.paramArg ); | ||||
char *eq = strchr( arg, '=' ); | ||||
if ( eq != 0 ) | ||||
*eq++ = 0; | ||||
if ( strcmp( arg, "help" ) == 0 ) | ||||
usage(); | ||||
else if ( strcmp( arg, "version" ) == 0 ) | ||||
version(); | ||||
else if ( strcmp( arg, "error-format" ) == 0 ) { | ||||
if ( eq == 0 ) | ||||
error() << "expecting '=value' fo | ||||
r error-format" << endl; | ||||
else if ( strcmp( eq, "gnu" ) == 0 ) | ||||
errorFormat = ErrorFormatGNU; | ||||
else if ( strcmp( eq, "msvc" ) == 0 ) | ||||
errorFormat = ErrorFormatMSVC; | ||||
else | ||||
error() << "invalid value for err | ||||
or-format" << endl; | ||||
} | ||||
else if ( strcmp( arg, "rbx" ) == 0 ) | ||||
rubyImpl = Rubinius; | ||||
else if ( strcmp( arg, "rlhc" ) == 0 ) | ||||
rlhc = true; | ||||
else if ( strcmp( arg, "no-intermediate" ) == 0 ) | ||||
noIntermediate = true; | ||||
#ifdef WITH_RAGEL_KELBT | ||||
else if ( strcmp( arg, "kelbt-frontend" ) == 0 ) | ||||
{ | ||||
frontend = KelbtBased; | ||||
frontendSpecified = true; | ||||
} | ||||
#else | ||||
else if ( strcmp( arg, "kelbt-frontend" ) == 0 ) | ||||
{ | ||||
error() << "--kelbt-frontend specified bu | ||||
t, " | ||||
"ragel not built with rag | ||||
el+kelbt support" << endp; | ||||
} | ||||
#endif | ||||
else if ( strcmp( arg, "reduce-frontend" ) == 0 ) | ||||
{ | ||||
frontend = ReduceBased; | ||||
frontendSpecified = true; | ||||
} | ||||
else if ( strcmp( arg, "string-tables" ) == 0 ) | ||||
stringTables = true; | ||||
else if ( strcmp( arg, "integral-tables" ) == 0 ) | ||||
stringTables = false; | ||||
else if ( strcmp( arg, "host-lang-names" ) == 0 ) | ||||
showHostLangNames(); | ||||
else if ( strcmp( arg, "host-lang-args" ) == 0 || | ||||
strcmp( arg, "supported-host-lang | ||||
s" ) == 0 ) | ||||
showHostLangArgs(); | ||||
else if ( strcmp( arg, "supported-frontends" ) == | ||||
0 ) | ||||
showFrontends(); | ||||
else if ( strcmp( arg, "supported-backends" ) == | ||||
0 ) | ||||
showBackends(); | ||||
else if ( strcmp( arg, "save-temps" ) == 0 ) | ||||
saveTemps = true; | ||||
else if ( strcmp( arg, "prior-interaction" ) == 0 | ||||
) | ||||
checkPriorInteraction = true; | ||||
else if ( strcmp( arg, "conds-depth" ) == 0 ) | ||||
condsCheckDepth = strtol( eq, 0, 10 ); | ||||
else if ( strcmp( arg, "state-limit" ) == 0 ) | ||||
stateLimit = strtol( eq, 0, 10 ); | ||||
else if ( strcmp( arg, "breadth-check" ) == 0 ) { | ||||
char *ptr = 0; | ||||
while ( true ) { | ||||
char *label = strtok_r( eq, ",", | ||||
&ptr ); | ||||
eq = NULL; | ||||
if ( label == NULL ) | ||||
break; | ||||
breadthLabels.append( strdup( lab | ||||
el ) ); | ||||
} | ||||
checkBreadth = true; | ||||
} | ||||
else if ( strcmp( arg, "input-histogram" ) == 0 ) | ||||
histogramFn = strdup(eq); | ||||
else if ( strcmp( arg, "force-libragel" ) == 0 ) | ||||
forceLibRagel = true; | ||||
else { | ||||
error() << "--" << pc.paramArg << | ||||
" is an invalid argument" | ||||
<< endl; | ||||
} | ||||
free( arg ); | ||||
break; | ||||
} | ||||
/* Passthrough args. */ | ||||
case 'T': | ||||
if ( pc.paramArg[0] == '0' ) | ||||
codeStyle = GenBinaryLoop; | ||||
else if ( pc.paramArg[0] == '1' ) | ||||
codeStyle = GenBinaryExp; | ||||
else { | ||||
error() << "-T" << pc.paramArg[0] << | ||||
" is an invalid argument" | ||||
<< endl; | ||||
abortCompile( 1 ); | ||||
} | ||||
break; | ||||
case 'F': | ||||
if ( pc.paramArg[0] == '0' ) | ||||
codeStyle = GenFlatLoop; | ||||
else if ( pc.paramArg[0] == '1' ) | ||||
codeStyle = GenFlatExp; | ||||
else { | ||||
error() << "-F" << pc.paramArg[0] << | ||||
" is an invalid argument" | ||||
<< endl; | ||||
abortCompile( 1 ); | ||||
} | ||||
break; | ||||
case 'G': | ||||
if ( pc.paramArg[0] == '0' ) | ||||
codeStyle = GenSwitchLoop; | ||||
else if ( pc.paramArg[0] == '1' ) | ||||
codeStyle = GenSwitchExp; | ||||
else if ( pc.paramArg[0] == '2' ) | ||||
codeStyle = GenIpGoto; | ||||
else if ( pc.paramArg[0] == 'T' && pc.paramArg[1] | ||||
== '2' ) { | ||||
codeStyle = GenIpGoto; | ||||
maxTransitions = 32; | ||||
} else { | ||||
error() << "-G" << pc.paramArg[0] << | ||||
" is an invalid argument" | ||||
<< endl; | ||||
abortCompile( 1 ); | ||||
} | ||||
break; | ||||
case 'p': | ||||
displayPrintables = true; | ||||
break; | ||||
case 'L': | ||||
noLineDirectives = true; | ||||
break; | ||||
} | ||||
break; | ||||
case ParamCheck::invalid: | ||||
error() << "-" << pc.parameter << " is an invalid argumen | ||||
t" << endl; | ||||
break; | ||||
case ParamCheck::noparam: | ||||
/* It is interpreted as an input file. */ | ||||
if ( *pc.curArg == 0 ) | ||||
error() << "a zero length input file name was giv | ||||
en" << endl; | ||||
else if ( inputFileName != 0 ) | ||||
error() << "more than one input file name was giv | ||||
en" << endl; | ||||
else { | ||||
/* OK, Remember the filename. */ | ||||
inputFileName = pc.curArg; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
void InputData::loadHistogram() | ||||
{ | ||||
const int alphsize = 256; | ||||
/* Init a default. */ | ||||
histogram = new double[alphsize]; | ||||
ifstream h( histogramFn ); | ||||
if ( !h.is_open() ) | ||||
error() << "histogram read: failed to open file: " << histogramFn | ||||
<< endp; | ||||
int i = 0; | ||||
double value; | ||||
while ( true ) { | ||||
if ( h >> value ) { | ||||
if ( i >= alphsize ) { | ||||
/* Too many items. */ | ||||
error() << "histogram read: too many histogram va | ||||
lues," | ||||
" expecting " << alphsize << " (f | ||||
or char alphabet)" << endp; | ||||
} | ||||
histogram[i] = value; | ||||
i++; | ||||
} | ||||
else { | ||||
/* Read failure. */ | ||||
if ( h.eof() ) { | ||||
if ( i < alphsize ) { | ||||
error() << "histogram read: fell short of | ||||
" << | ||||
alphsize << " items" << e | ||||
ndp; | ||||
} | ||||
break; | ||||
} | ||||
else { | ||||
error() << "histogram read: error at item " << i | ||||
<< endp; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
void InputData::defaultHistogram() | ||||
{ | ||||
/* Flat histogram. */ | ||||
const int alphsize = 256; | ||||
histogram = new double[alphsize]; | ||||
for ( int i = 0; i < alphsize; i++ ) { | ||||
histogram[i] = 1.0 / (double)alphsize; | ||||
} | ||||
} | ||||
void InputData::checkArgs() | ||||
{ | ||||
/* Require an input file. If we use standard in then we won't have a file | ||||
* name on which to base the output. */ | ||||
if ( inputFileName == 0 ) | ||||
error() << "no input file given" << endl; | ||||
/* Bail on argument processing errors. */ | ||||
if ( errorCount > 0 ) | ||||
abortCompile( 1 ); | ||||
/* Make sure we are not writing to the same file as the input file. */ | ||||
if ( inputFileName != 0 && outputFileName != 0 && | ||||
strcmp( inputFileName, outputFileName ) == 0 ) | ||||
{ | ||||
error() << "output file \"" << outputFileName << | ||||
"\" is the same as the input file" << endp; | ||||
} | ||||
if ( !frontendSpecified ) | ||||
frontend = ReduceBased; | ||||
if ( checkBreadth ) { | ||||
if ( histogramFn != 0 ) | ||||
loadHistogram(); | ||||
else | ||||
defaultHistogram(); | ||||
} | ||||
} | ||||
char *InputData::readInput( const char *inputFileName ) | ||||
{ | ||||
struct stat st; | ||||
int res = stat( inputFileName, &st ); | ||||
if ( res != 0 ) { | ||||
error() << inputFileName << ": stat failed: " << strerror(errno) | ||||
<< endl; | ||||
return 0; | ||||
} | ||||
std::ifstream in( inputFileName ); | ||||
if ( !in.is_open() ) { | ||||
error() << inputFileName << ": could not open in force-libragel m | ||||
ode"; | ||||
return 0; | ||||
} | ||||
char *input = new char[st.st_size+1]; | ||||
in.read( input, st.st_size ); | ||||
if ( in.gcount() != st.st_size ) { | ||||
error() << inputFileName << ": could not read in force-libragel m | ||||
ode"; | ||||
delete[] input; | ||||
return 0; | ||||
} | ||||
input[st.st_size] = 0; | ||||
return input; | ||||
} | ||||
int InputData::main( int argc, const char **argv ) | ||||
{ | ||||
int code = 0; | ||||
try { | ||||
parseArgs( argc, argv ); | ||||
checkArgs(); | ||||
if ( !generateDot ) | ||||
makeDefaultFileName(); | ||||
if ( !process() ) | ||||
abortCompile( 1 ); | ||||
} | ||||
catch ( const AbortCompile &ac ) { | ||||
code = ac.code; | ||||
} | ||||
return code; | ||||
} | ||||
int InputData::rlhcRun( int argc, const char **argv ) | ||||
{ | ||||
struct colm_program *prg; | ||||
int exit_status; | ||||
prg = colm_new_program( rlhcSections ); | ||||
colm_set_debug( prg, 0 ); | ||||
colm_run_program( prg, argc, argv ); | ||||
exit_status = colm_delete_program( prg ); | ||||
return exit_status; | ||||
} | ||||
int InputData::rlhcMain( int argc, const char **argv ) | ||||
{ | ||||
int status = 0; | ||||
pid_t pid = 0; | ||||
parseArgs( argc, argv ); | ||||
checkArgs(); | ||||
makeDefaultFileName(); | ||||
makeTranslateOutputFileName(); | ||||
pid = fork(); | ||||
if ( pid == 0 ) { | ||||
/* Child. */ | ||||
if ( !process() ) | ||||
abortCompile( 1 ); | ||||
exit( 0 ); | ||||
} | ||||
waitpid( pid, &status, 0 ); | ||||
pid = fork(); | ||||
if ( pid == 0 ) { | ||||
/* rlhc <input> <output> */ | ||||
const char *_argv[] = { "rlhc", | ||||
genOutputFileName.c_str(), | ||||
origOutputFileName.c_str(), 0 }; | ||||
rlhcRun( 3, _argv ); | ||||
} | ||||
waitpid( pid, &status, 0 ); | ||||
return 0; | ||||
} | ||||
End of changes. 19 change blocks. | ||||
77 lines changed or deleted | 67 lines changed or added |