diff options
Diffstat (limited to 'libfsm/reducer.cc')
-rw-r--r-- | libfsm/reducer.cc | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/libfsm/reducer.cc b/libfsm/reducer.cc new file mode 100644 index 00000000..592dcfe1 --- /dev/null +++ b/libfsm/reducer.cc @@ -0,0 +1,230 @@ +/* + * Copyright 2015-2018 Adrian Thurston <thurston@colm.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * 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 + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "reducer.h" + +#include <colm/colm.h> +#include <colm/tree.h> + +#include <errno.h> + +using std::endl; +using std::ifstream; + +void TopLevel::loadMachineName( string data ) +{ + /* Make/get the priority key. The name may have already been referenced + * and therefore exist. */ + PriorDictEl *priorDictEl; + if ( pd->priorDict.insert( data, pd->fsmCtx->nextPriorKey, &priorDictEl ) ) + pd->fsmCtx->nextPriorKey += 1; + pd->curDefPriorKey = priorDictEl->value; + + /* Make/get the local error key. */ + LocalErrDictEl *localErrDictEl; + if ( pd->localErrDict.insert( data, pd->nextLocalErrKey, &localErrDictEl ) ) + pd->nextLocalErrKey += 1; + pd->curDefLocalErrKey = localErrDictEl->value; +} + +void TopLevel::tryMachineDef( const InputLoc &loc, std::string name, + MachineDef *machineDef, bool isInstance ) +{ + GraphDictEl *newEl = pd->graphDict.insert( name ); + if ( newEl != 0 ) { + /* New element in the dict, all good. */ + newEl->value = new VarDef( name, machineDef ); + newEl->isInstance = isInstance; + newEl->loc = loc; + newEl->value->isExport = exportContext[exportContext.length()-1]; + + /* It it is an instance, put on the instance list. */ + if ( isInstance ) + pd->instanceList.append( newEl ); + } + else { + // Recover by ignoring the duplicate. + pd->id->error(loc) << "fsm \"" << name << "\" previously defined" << endl; + } +} + +long TopLevel::tryLongScan( const InputLoc &loc, const char *data ) +{ + /* Convert the priority number to a long. Check for overflow. */ + long priorityNum; + errno = 0; + + long aug = strtol( data, 0, 10 ); + if ( errno == ERANGE && aug == LONG_MAX ) { + /* Priority number too large. Recover by setting the priority to 0. */ + pd->id->error(loc) << "priority number " << data << + " overflows" << endl; + priorityNum = 0; + } + else if ( errno == ERANGE && aug == LONG_MIN ) { + /* Priority number too large in the neg. Recover by using 0. */ + pd->id->error(loc) << "priority number " << data << + " underflows" << endl; + priorityNum = 0; + } + else { + /* No overflow or underflow. */ + priorityNum = aug; + } + + return priorityNum; +} + +void TopLevel::include( const InputLoc &incLoc, bool fileSpecified, string fileName, string machine ) +{ + /* Stash the current section name and pd. */ + string sectionName = pd->sectionName; + ParseData *pd0 = pd; + + const char **includeChecks = 0; + long found = 0; + + const char *inclSectionName = machine.c_str(); + + /* Default the section name to the current section name. */ + if ( inclSectionName == 0 ) + inclSectionName = sectionName.c_str(); + + /* Build the include checks. */ + if ( fileSpecified ) + includeChecks = pd->id->makeIncludePathChecks( curFileName, fileName.c_str() ); + else { + char *test = new char[strlen(curFileName)+1]; + strcpy( test, curFileName ); + + includeChecks = new const char*[2]; + + includeChecks[0] = test; + includeChecks[1] = 0; + } + + /* Try to find the file. */ + ifstream *inFile = pd->id->tryOpenInclude( includeChecks, found ); + if ( inFile == 0 ) { + id->error(incLoc) << "include: failed to locate file" << endl; + const char **tried = includeChecks; + while ( *tried != 0 ) + id->error(incLoc) << "include: attempted: \"" << *tried++ << '\"' << endl; + + return; + } + + delete inFile; + +// /* Don't include anything that's already been included. */ +// if ( !pd->duplicateInclude( includeChecks[found], inclSectionName ) ) { +// pd->includeHistory.push_back( IncludeHistoryItem( +// includeChecks[found], inclSectionName ) ); +// +// /* Either we are not in the lib, or a file was specifed, use the +// * file-based include pass. */ +// includePass.reduceFile( includeChecks[found], id->hostLang ); +// } + + const char *targetMachine0 = targetMachine; + const char *searchMachine0 = searchMachine; + + includeDepth += 1; + pd = 0; + + targetMachine = sectionName.c_str(); + searchMachine = machine.c_str(); + + // reduceFile( includeChecks[found] ); + +// if ( includePass.incItems.length() == 0 ) { +// pd->id->error(incLoc) << "could not find machine " << machine << +// " in " << fileName << endp; +// } +// else { +// /* Load the data into include el. Save in the dict. */ +// loadIncludeData( el, includePass, includeChecks[found] ); +// id->includeDict.insert( el ); +// includePass.incItems.empty(); +// } + + pd = pd0; + includeDepth -= 1; + + targetMachine = targetMachine0; + searchMachine = searchMachine0; +} + +void TopLevel::import( const InputLoc &loc, std::string name, Literal *literal ) +{ + MachineDef *machineDef = new MachineDef( + new Join( + new Expression( + new Term( + new FactorWithAug( + new FactorWithRep( + new FactorWithNeg( new Factor( literal ) ) + ) + ) + ) + ) + ) + ); + + /* Generic creation of machine for instantiation and assignment. */ + tryMachineDef( loc, name, machineDef, false ); + machineDef->join->loc = loc; +} + +void TopLevel::reduceFile( const char *cmd, const char *inputFileName ) +{ + const int baseN = 2; + const char **argv = new const char*[baseN + id->includePaths.length() + 1]; + argv[0] = cmd; + argv[1] = inputFileName; + for ( int i = 0; i < id->includePaths.length(); i++ ) + argv[baseN + i] = id->includePaths.data[i]; + argv[baseN + id->includePaths.length()] = 0; + + const char *prevCurFileName = curFileName; + curFileName = inputFileName; + + colm_program *program = colm_new_program( frontendSections ); + colm_set_debug( program, 0 ); + colm_set_reduce_clean( program, 0 ); + colm_set_reduce_ctx( program, this ); + colm_run_program( program, baseN + id->includePaths.length(), argv ); + id->streamFileNames.append( colm_extract_fns( program ) ); + + int length = 0; + const char *err = colm_error( program, &length ); + if ( err != 0 ) { + // std::cout << "error" << std::endl; + id->error_plain() << string( err, length ) << std::endl; + } + + colm_delete_program( program ); + + curFileName = prevCurFileName; + + delete[] argv; +} |