summaryrefslogtreecommitdiff
path: root/libfsm/reducer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libfsm/reducer.cc')
-rw-r--r--libfsm/reducer.cc230
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;
+}