/*---------------------------------------------------------------------------
File:         			GNFtoPDA..java
Package:                        JFLAP Version 3.0
Author:			        Eric Gramond 
                                
Description of Contents:	Contains class GNFtoPDA.
				
--------------------------------------------------------------------------*/

/* 
 * Susan H. Rodger, Magda Procopiuc, Octavian Procopiuc, Eric Gramond
 * Computer Science Department
 * Duke University
 * June 1998
 * Supported by National Science Foundation DUE-9596002 and DUE-9555084.
 *
 * Copyright (c) 1998
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the author.  The name of the author may not be used to
 * endorse or promote products derived from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

package flap;

import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.image.*;
import java.awt.event.*;


/**
 * converts a GNF grammar into a PDA 
 */
public class GNFtoPDA {

/**
 *  check for Z's, then check if it's GNF
 */
 public static void checkGrammar(Grammar g) throws BadInputException{

   Enumeration e, e2;
   Rule ru;
   boolean foundZ = false;
   GrammarRightHandToken gt;
   String error = "\nVariables cannot be called Z.\nZ is already used as empty stack symbol \n in the PDA.";
   
   for(e = g.getRules().elements(); e.hasMoreElements(); ) {
     ru = (Rule) e.nextElement();
     if( ru.getLeftHand().getContents().equals("Z")) 
       throw new BadInputException(error);
     
     for(e2 = ru.getRightHand().elements(); e2.hasMoreElements(); ) {
       gt = (GrammarRightHandToken) e2.nextElement();
       if(gt.getContents().equals("Z")) 
         throw new BadInputException(error);
     }
   }

   int i, j=1;
   for(e = g.getRules().elements(); e.hasMoreElements(); j++) {
     ru = (Rule) e.nextElement();
     
     if(ru.getRightHand().size() == 0)
       throw new BadInputException("\nOn line " + j + ": \nIn Greibach Normal Form, empty rules\n are not allowed.");

     i = 1;
     for(e2 = ru.getRightHand().elements(); e2.hasMoreElements(); i++) {
       gt = (GrammarRightHandToken) e2.nextElement();
       if(i==1 && !( gt instanceof Terminal)) 
         throw new BadInputException("\nOn line " + j + ": \nIn Greibach Normal Form, the right hand \nof a rule cannot begin with a variable.");
       if(i >1 && ! (gt instanceof Variable))
         throw new BadInputException("\nOn line " + j +":\n In Greibach Normal Form, terminals can \n only be the first token in the \nright hand of a rule.");
     }
   }
 }


/**
 * create the three starting states
 */
   public static void GNFtoStartPDA(Grammar cfg, Desktop d) {

	Dimension dim = d.getSize();
	State left, right, center;
	Transition trans;

	left = d.addState(dim.width/6, (5*dim.height)/6);
	center = d.addState(dim.width/2, (5*dim.height)/6);
	right = d.addState( (5*dim.width)/6, (5*dim.height)/6);
	right.isFinal =true; 

	trans = d.addTransition(left, center);
	trans.label = " , Z; " + cfg.getStart().getContents() + "Z";

	trans = d.addTransition(center, right);
	trans.label = " , Z; Z";

	d.initialState = left;
	d.modified = true;
	
	for(Enumeration e = d.theTransitions.elements(); e.hasMoreElements(); ) 
	    ((Transition) e.nextElement()).tokenizeLabel();
	
	
    }


    /**
     * build the entire machine from the grammar
     */

  public static void GNFtoPDA(Grammar cfg, Desktop d) {
    
    GNFtoStartPDA(cfg, d);
    State left, right, center;
    int i = 1;
    
    left = (State) d.theStates.elementAt(0);
    center = (State) d.theStates.elementAt(1);
    right = (State) d.theStates.elementAt(2);
    
    center.loopSize = Params._t_distance;
    
    int j;
    Rule ru;
    Enumeration e2;
    String leftS = "" , centerS = "" , rightS = "";
    Transition trans;

    for(Enumeration e = cfg.getRules().elements(); e.hasMoreElements(); ) {
      ru = (Rule) e.nextElement();

      j =1;      
      centerS = ru.getLeftHand().getContents().trim();
      leftS = "";
      rightS = "";
      for(e2 = ru.getRightHand().elements(); e2.hasMoreElements();j++ ) {
        if(j == 1)
          leftS = ((Terminal) e2.nextElement()).getContents().trim();
        else
          rightS += ((GrammarRightHandToken) e2.nextElement()).getContents();
      }
      trans = d.addTransition(center, center);
      trans.label = leftS + " ," + centerS + " ;" + rightS;
      if(rightS.length() == 0)
        trans.label += " ";
      center.loopSize += 2* Params._t_distance  / 3;
      trans.distance = i++;
    }
    
    
    for(Enumeration e = d.theTransitions.elements(); e.hasMoreElements(); ) {
      trans = (Transition) e.nextElement();
      trans.tokenizeLabel();
      if(trans.distance >= 1)
        trans.distance /= i-1;
    }
  }
  
}
