<html>

<head><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- MyFirstUnitAd -->
<ins class="adsbygoogle"
     style="display:inline-block;width:970px;height:250px"
     data-ad-client="ca-pub-5778386704669218"
     data-ad-slot="1503492166"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>DFA</title>
</head>

<body>



<p align="center"><span lang="en-ca"><font size="6" color="#FF0000"><b>Reduce</b></font></span></p>

<div align="left">
  <pre><b><font color="#ff0000" size="5">A.<span lang="en-ca">First</span> Edition</font></b></pre>
</div>
<div align="left">
  <pre><b>This is <span lang="en-ca">my second edition of </span></b><span lang="en-ca"><b>Reduce, which has only a single usage to translate a NFA into regular expression.</b></span></pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">B</span>.<span lang="en-ca"><a name="problem"></a>The problem</span></font></b></pre>
</div>
<div align="left">
  <pre><b><span lang="en-ca">I feel unsatisfied with the code. It is ugly! However, I don't have enough energy to make a perfect design.</span></b></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>In order to translate the &quot;Transition Diagram&quot; into &quot;Regular Expression&quot;, you need to eliminate all nodes except</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>the start and final ones. 1. Find out all inward and outward arrows and then replace the node by combining each</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>inward starting node with each outward ending node. Their expressions should be concatenated.</b></span></pre>
</div>
<div align="left">
  <b><font color="#ff0000" size="5"><span lang="en-ca">C</span>.<span lang="en-ca">The
  </span></font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>idea of 
  program</b></font></span></div>
<pre><span lang="en-ca"><b>This edition corrects several big bugs in first one. </b></span></pre>
<pre><span lang="en-ca"><b>1. The first edition assumes that at final stage which only includes &quot;start&quot; and &quot;final&quot; and there is only arrow</b></span></pre>
<pre><span lang="en-ca"><b>from start to final&quot;. But this is not true. There can be either only one &quot;start&quot; and &quot;final&quot; state or there can</b></span></pre>
<pre><span lang="en-ca"><b>be arrows from &quot;final&quot; to &quot;start&quot;. If there is arrow from final to start, the final expression will be quite</b></span></pre>
<pre><span lang="en-ca"><b>complicated. Suppose we name loop string at start, string from start to final, string from final to start and</b></span></pre>
<pre><span lang="en-ca"><b>string looping at final state as r1, r2, r3, r4 then the correct expression is:</b></span></pre>
<pre><span lang="en-ca"><b>star(r1).r2.star(r4+r3.star(r1).r2). </b></span></pre>
<pre><span lang="en-ca"><b>2. The special case is that the start and final state are actually one state. Then we only need the looping string.</b></span></pre>
<pre><span lang="en-ca"><b>3. Another minor bug is that the first version assumes that after all eliminating operations, the final state won't</b></span></pre>
<pre><span lang="en-ca"><b>have parallel arrows. This is not always true. Suppose the initial states is only including the parallel arrows, </b></span></pre>
<pre><span lang="en-ca"><b>and since if there is no node to be eliminated, then the parallel arrows won't be combined. So, we have to check.</b></span></pre>
<pre><span lang="en-ca"><b>4. The final small special case is to remove the trap node which only has inBound arrows. </b></span></pre>
<pre><span lang="en-ca"><b>5. The string operations of star, dot, plus are boring, and I cannot return local variable. So, I defined a private</b></span></pre>
<pre><span lang="en-ca"><b>buffer to be returned as pointer.</b></span></pre>
<div align="left">
  <pre><b><font color="#ff0000" size="5">D.<span lang="en-ca"><a name="Method"></a>The </span>major functions</font></b></pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">C</span>.</font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>Further improvement</b></font></span></pre>
</div>
<div align="left">
  <pre><b><span lang="en-ca">I don't bother to check the result since it is too complicated. So, I have no idea if it is correct or not.</span></b></pre>
</div>
<pre>#include &lt;iostream&gt;
#include &lt;fstream&gt;

using namespace std;

enum States
{InBound, OutBound, IsLoop};

enum FinalArrow
{StartLoop, StartFinal, FinalStart, FinalLoop};

struct Function
{
	int domain;
	char* expr;
	int range;
	bool isStart;//means the domain is start
	bool isFinal;//means the range is final	
};

class Reduce
{
private:
	char privateBuffer[512];
	Function rules[30];
	Function temp[30];
	int tempCount;
	int size;
	int inCount;
	int outCount;
	int loopCount;
	//this record the three type arrow(inbound,outbound, loop) for a particular node
	int buffer[3][30];					  	
	bool findStates(int state);
	bool findShortCut(int state);
	void replace(int state);
	void copyFunction(Function* target, Function* source, bool toClear=false);
	void generate();
	void moveRule(int state);
//	bool notAffected(int index);
	void clearState();
	void addFunction(int index);
	void getExpr();
	void copyStr(char* target, const char* source);
	char* getFinalExpr(char str[][256]);
	char* star(const char* source);
	char* dot(char* target, const char* source);
	char* plus(char* target, const char* source);
public:
	void setParam(Function**theRule, int theSize);
	void readRules(const char* fileName);
	void beginReduce();

};

int main()
{
	Reduce R;
	//you need to copy my input file to your local C:
	R.readRules(&quot;c:\\rules.txt&quot;);
	R.beginReduce();
	
	return 0;
}


char* Reduce::star(const char* source)
{
	if (source==NULL)
	{
		return NULL;
	}
	strcpy(privateBuffer, &quot;star(&quot;);
	strcat(strcat(privateBuffer, source), &quot;)&quot;);
	return privateBuffer;
}

char* Reduce::dot(char* target, const char* source)
{
	if (source!=NULL)
	{
		if (target==NULL)
		{
			strcpy(target, source);
		}
		else
		{
			strcat(strcat(target, &quot;.&quot;), source);
		}
	}
	
	return target;
}

char* Reduce::plus(char* target, const char* source)
{
	if (source==NULL)
	{
		return target;
	}
	strcat(target, &quot;+&quot;);
	return strcat(target, source);
}


char* Reduce::getFinalExpr(char str[][256])
{
	//the formula is: star(r1).r2.star(r4+r3.star(r1).r2)
	char exp[512];
	char buf[512];
	strcpy(exp, str[FinalStart]);//r3
	dot(exp, star(str[StartLoop]));
	dot(exp, str[StartFinal]);//r3.star(r1).r2
	dot(exp, str[FinalLoop]); //exp+r4, reversed
	strcpy(buf, star(exp));
	strcpy(exp, str[StartLoop]);//exp=r1
	strcpy(exp, star(exp));//star(r1);
	dot(exp, str[StartFinal]);//exp.r2
	dot(exp, buf);
	strcpy(privateBuffer, exp);
	return privateBuffer;
}


void Reduce::copyStr(char* target, const char* source)
{
//	delete []target;
	target = new char[strlen(source)+1];
	strcpy(target, source);
}

//add a function with index of &quot;index&quot; in rules to &quot;temp&quot;
void Reduce::addFunction(int index)
{
	char str[256];
	//scan to see if there are parallel function already in temp
	for (int i=0; i&lt;tempCount; i++)
	{
		//try to union two expr, if they are parallel
		if (temp[i].domain == rules[index].domain&amp;&amp;temp[i].range==rules[index].range)
		{
			strcpy(str, &quot;(&quot;);
			strcat(str, temp[i].expr);
			strcat(strcat(str, &quot;+&quot;), rules[index].expr);
			strcat(str, &quot;)&quot;);
			delete []temp[i].expr;
			temp[i].expr = new char[strlen(str)+1];
			strcpy(temp[i].expr, str);
			//tempCount don't increment!
			return;
		}	
	}
	//if not found, copy
	copyFunction(&amp;temp[tempCount], &amp;rules[index]);
	tempCount++;
}


void Reduce::readRules(const char* fileName)
{
	ifstream f;
	int flag;
	char str[256];
	size = 0;
	f.open(fileName, ios::in);
	while (!f.eof())
	{
		f&gt;&gt;rules[size].domain&gt;&gt;str&gt;&gt;rules[size].range&gt;&gt;flag;
		rules[size].isStart = flag==1?true:false;
		f&gt;&gt;flag;
		rules[size].isFinal = flag==1?true:false;
		rules[size].expr = new char[strlen(str)+1];
		strcpy(rules[size].expr, str);
		size++;
	}
}



void Reduce::clearState()
{
	//those three type arrow should be cleared
	for (int i=0; i&lt;inCount; i++)
	{
		delete [] rules[buffer[InBound][i]].expr;
	}
	for (i=0; i&lt;outCount; i++)
	{
		delete [] rules[buffer[OutBound][i]].expr;
	}
	for (i =0; i&lt;loopCount; i++)
	{
		delete [] rules[buffer[IsLoop][i]].expr;
	}
}

void Reduce::copyFunction(Function* target, Function* source, bool toClear)
{
	target-&gt;domain = source-&gt;domain;
	target-&gt;range = source-&gt;range;
	if (toClear)
	{
		delete [] target-&gt;expr;
	}
	target-&gt;expr = new char[strlen(source-&gt;expr)+1];
	strcpy(target-&gt;expr, source-&gt;expr);
	target-&gt;isFinal = source-&gt;isFinal;
	target-&gt;isStart = source-&gt;isStart;
}

void Reduce::moveRule(int state)
{
	for (int i=0; i&lt;size; i++)
	{
		//if not affected
		if (rules[i].domain!=state&amp;&amp;rules[i].range!=state)
		{
			addFunction(i);		
		}
	}
	clearState();
	//copy back from temp to rules, in order for next
	for (i=0; i&lt;tempCount; i++)
	{
		copyFunction(&amp;rules[i], &amp;temp[i]);
	}
	size = tempCount;
}

void Reduce::setParam(Function** theRule, int theSize)
{
	size = theSize;
	for (int i=0; i&lt;size; i++)
	{
		copyFunction(&amp;rules[i], theRule[i]);
	}	
}

void Reduce::replace(int state)
{
	generate();
	moveRule(state);
}

void Reduce::generate()
{
	tempCount=0;
	char str[256];
	int in, out, loop;

	//this handles the trap situation
	if (outCount==0)
	{
		return;
	}
	
	for (int i=0; i&lt;inCount; i++)
	{		
		for (int j=0; j&lt;outCount; j++)
		{
			in = buffer[InBound][i];
			out = buffer[OutBound][j];

			temp[tempCount].domain = rules[in].domain;
			temp[tempCount].isStart = rules[in].isStart;//the start from in
			temp[tempCount].range = rules[out].range;
			temp[tempCount].isFinal = rules[out].isFinal;//final from out
			strcpy(str, rules[in].expr);
			for (int k=0; k&lt;loopCount; k++)
			{
				loop = buffer[IsLoop][k];
				if (k==0)
				{
					strcat(str, &quot;.star&quot;);
					strcat(str, &quot;(&quot;);
				}
				strcat(strcat(str, rules[loop].expr), &quot;+&quot;);
				if (k==loopCount-1)
				{
					//replace '+' with ')'
					str[strlen(str)-1]=')';
				}
			}
			strcat(str, &quot;.&quot;);
			strcat(str, rules[out].expr);
			
			temp[tempCount].expr = new char[strlen(str)+1];
			strcpy(temp[tempCount].expr, str);
			//finished one record
			tempCount++;
		}
	}
}


bool Reduce::findStates(int state)
{
	for (int i=0; i&lt;size; i++)
	{		
		if (rules[i].domain==state||rules[i].range==state)
		{
			return true;
		}
	}
	return false;
}

bool Reduce::findShortCut(int state)
{
	inCount = outCount = loopCount = 0;
	for (int i=0; i&lt;size; i++)
	{
		//exclusiveOr and this is a loop
		if (rules[i].domain==state&amp;&amp;rules[i].range==state)
		{
			//the loop 
			if (rules[i].isFinal||rules[i].isStart)
			{
				return false;
			}
			buffer[IsLoop][loopCount]=i;
			loopCount++;
		}
		else
		{			
			if (rules[i].domain==state)
			{
				//if it is start, cannot remove it.
				if (rules[i].isStart)
				{
					return false;
				}
				buffer[OutBound][outCount]=i;
				outCount++;
			}
			if (rules[i].range==state)
			{
				//if it is final, we cannot remove it
				if (rules[i].isFinal)
				{
					return false;
				}			
				buffer[InBound][inCount]=i;
				inCount++;
			}
		}
	}
	//must both have in and out, however, if there is no outBound, it
	//means it is a trap, should be removed immediately
	if (inCount==0)
	{
		cout&lt;&lt;&quot;Error! unaccessable node!\n&quot;;
		return false;
	}
	else
	{
		return true;
	}
}
			
void Reduce::getExpr()
{
	char str[4][256];	
	str[0][0]='\0';
	str[1][0]='\0';
	str[2][0]='\0';
	str[3][0]='\0';
	int startLoop =0, startFinal=0, finalStart=0, finalLoop=0, singleLoop=0;
	for (int i=0; i&lt;size; i++)
	{
		//loop at start, not at final
		if (rules[i].isStart&amp;&amp;!rules[i].isFinal&amp;&amp;rules[i].domain==rules[i].range)
		{
			//for the first one, copy &quot;star&quot;
			if (startLoop==0)
			{
				strcat(strcpy(str[StartLoop], &quot;star(&quot;), rules[i].expr);
			}
			else
			{
				//for the second or more,
				strcat(str[StartLoop], rules[i].expr);
			}
			strcat(str[StartLoop], &quot;+&quot;);
			startLoop++;
		}
		//there is two directions: one from start to final
		//the other is from final to start!!!
		//this is from start to final!
		//I wonder if there is two of such string? should not???
		//yes, it maybe! for an example, there is originally two 
		//parallel arrows between start and final and no operation has
		//ever been taken, so no merge performed.
		if (rules[i].domain!=rules[i].range&amp;&amp;rules[i].isStart&amp;&amp;rules[i].isFinal)
		{
			//the very first expr, use copy
			if (startFinal==0)
			{
				strcpy(str[StartFinal], rules[i].expr);
			}
			else
			{
				//all other use concat
				strcat(str[StartFinal], rules[i].expr);
			}
			strcat(str[StartFinal], &quot;+&quot;);
			startFinal++;
		}
		//the arrow from final to start
		if (rules[i].domain!=rules[i].range&amp;&amp;!rules[i].isStart&amp;&amp;!rules[i].isFinal)
		{
			if (finalStart==0)
			{
				strcpy(str[FinalStart], rules[i].expr);
			}
			else
			{
				strcat(str[FinalStart], rules[i].expr);
			}
			strcat(str[FinalStart], &quot;+&quot;);
			finalStart++;
		}
		//final loop, but not start loop
		if (rules[i].isFinal&amp;&amp;!rules[i].isStart&amp;&amp;rules[i].domain==rules[i].range)
		{
			//for the first one, copy &quot;star&quot;
			if (finalLoop==0)
			{
				strcat(strcpy(str[FinalLoop], &quot;star(&quot;), rules[i].expr);
			}
			else
			{
				//for the second or more,
				strcat(str[FinalLoop], rules[i].expr);
			}
			strcat(str[FinalLoop], &quot;+&quot;);
			finalLoop++;
		}
		//here is the spcial case: start and final are the same
		if (rules[i].isFinal&amp;&amp;rules[i].isStart&amp;&amp;rules[i].domain==rules[i].range)
		{
			//for the first one, copy &quot;star&quot;
			if (singleLoop==0)
			{
				//we &quot;borrow&quot; this string to express
				strcat(strcpy(str[StartLoop], &quot;star(&quot;), rules[i].expr);
			}
			else
			{
				//for the second or more,
				strcat(str[StartLoop], rules[i].expr);
			}
			strcat(str[StartLoop], &quot;+&quot;);
			singleLoop++;
		}
	}
	//overwrite &quot;+&quot; with &quot;)&quot;
	if (singleLoop&gt;0)
	{
		str[StartLoop][strlen(str[StartLoop])-1]=')';
		cout&lt;&lt;str[StartLoop]&lt;&lt;endl;
	}
	else
	{
		if (startLoop&gt;0)
		{
			str[StartLoop][strlen(str[StartLoop])-1]=')';
		}
		if (startFinal&gt;0)
		{
			//must not have more '+'! so write \0 to end
			str[StartFinal][strlen(str[StartFinal])-1]='\0';
		}
		if (finalStart&gt;0)
		{
			str[FinalStart][strlen(str[FinalStart])-1]='\0';
		}
		if (finalLoop&gt;0)
		{
			str[FinalLoop][strlen(str[FinalLoop])-1]=')';
		}
		cout&lt;&lt;getFinalExpr(str)&lt;&lt;endl;
	}
}

void Reduce::beginReduce()
{
	int state=0;
	while (findStates(state))
	{
		if (findShortCut(state))
		{
			replace(state);
		}
		state++;
	}
	getExpr();
}



</pre>
<pre>
</pre>
<pre>	
	
	

</pre>
<pre><span lang="en-ca"><a name="result"></a><font size="3" color="#FF0000">The result is like following:</font></span></pre>
<pre><font size="3">star(star((b.star(b).a.b+a))).b.star(b).a.a.star(.star(star((b.star(b).a.b+a))).b.star(b).a.a.star((
a+b)))
Press any key to continue
</font>
</pre>
<p>กก</p>
<p><span lang="en-ca">**explanation**</span></p>
<p><span lang="en-ca">1. I used &quot;star&quot; to represent &quot;keleen star&quot; as I cannot 
print the exponent-like &quot;*&quot;'s.</span></p>
<p><span lang="en-ca">2. I used &quot;.&quot; to show it is a concatenation for better 
reading.</span></p>
<p><span lang="en-ca">3. &quot;+&quot; sign still means the &quot;union&quot;.</span></p>
<p><span lang="en-ca">4. Here is the input file which is the DFA for a language 
over {a,b} such that &quot;baa&quot; is its substring.</span></p>
<p><span lang="en-ca">5. The input file format is like following:</span></p>
<p><span lang="en-ca">&nbsp;&nbsp;&nbsp; Domain&nbsp;&nbsp; Expression&nbsp;&nbsp; 
Range&nbsp; isStart&nbsp; isFinal</span></p>
<p><span lang="en-ca">6. Domain and Range means that the transition functions is 
starting from Domain and ending at Range which is</span></p>
<p><span lang="en-ca">&nbsp;&nbsp;&nbsp; the index of states. The expression is 
the label. When Domain is the initial state, isState is true,</span></p>
<p><span lang="en-ca">&nbsp;&nbsp;&nbsp; indicated by &quot;1&quot;. Otherwise &quot;0&quot;. When 
Range is the final state, isFinal is &quot;1&quot;. Otherwise &quot;0&quot;.</span></p>
<p><span lang="en-ca">7. The input file is named &quot;rules.txt&quot; and stored in place 
of &quot;c:\&quot;.</span></p>
<pre>กก</pre>
<pre>	</pre>
<pre></pre>
<pre>			
</pre>

<pre></pre>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                                   
&nbsp;&nbsp;&nbsp; <a href="WhoAmI.htm">                  







                       <img src="picture/back.gif" style="border: medium none" alt="back.gif (341 bytes)" width="32" height="35"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<a href="index.htm"><img src="picture/up.gif" style="border: medium none" alt="up.gif (335 bytes)" width="35" height="32"></a>       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                         
<img src="picture/next.gif" style="border: medium none" alt="next.gif (337 bytes)" width="32" height="35">          


</p>

</body>

</html>