%{
// ////////////////////////////////////////////////////////
// Copyright (1994) Columbia University
// Department of Biochemistry and Molecular Biophysics
//
// Author: Weider Chang, Ph.D
// ///////////////////////////////////////////////////////

#include <stdio.h>
#include "linebuff.h"
#include "starasso.h"
#include "datablk.h"
#include "llistobj.h"
#include "listofiv.h"
#include "stack.h"
#include "starpasr.h"

extern id starParser;
static id currentGlobalBlock;

%}

%union {
  id object_ptr;
  char * char_ptr;
}

%token <char_ptr> STARFILENAME
%token <char_ptr> DATABLOCKNAME
%token <char_ptr> GLOBALNAME
%token <char_ptr> SAVENAME

%token <char_ptr> ITEMNAME
%token <char_ptr> LOOPMARK

%token <char_ptr> STRING
%token <char_ptr> LINESBEGIN
%token <char_ptr> LINE
%token <char_ptr> LINESEND

%token <char_ptr> LOOPITEMNAME
%token <char_ptr> INTERNALLOOP
%token <char_ptr> LOOPITEMVALUE
%token <char_ptr> LOOPEND
%token <char_ptr> SAVEEND

%type <object_ptr> StarFile
%type <object_ptr> GlobalDataBlock
%type <object_ptr> SaveFrame
%type <object_ptr> DataBlock
%type <object_ptr> ItemAssoc
%type <object_ptr> Strings
%type <object_ptr> LineBuffers
%type <object_ptr> Loop

%%

StarFile : STARFILENAME
{
  /* 
     This should be of type Dictionary rather than StarFile.
     If so, the second part of this rule should be changed.
     */
  [starParser addParsingFile:
   [starParser newBlocksWithName: $1 value: 0]];
}
| DataBlock 
{
  [starParser addParsingFile:
   [[starParser newBlocksWithName: 
     [starParser getCurrentFileName] value: $1]
    setGlobalBlock:currentGlobalBlock]];
}
| GlobalDataBlock
{
  currentGlobalBlock=[starParser newDataBlockWithName:
		      [starParser getCurrentFileName] value: $1];
  [starParser addGlobalBlock:currentGlobalBlock];
  [starParser addParsingFile: 
   [[starParser newBlocksWithName: 
     [starParser getCurrentFileName] value: 0]
    setGlobalBlock:currentGlobalBlock]];
}
| StarFile DataBlock
{
  if (!($$=[starParser getCurrentParsingFile]))
    {
      $$=[[starParser newBlocksWithName: 
	   [starParser getCurrentFileName] value: $2]
	  setGlobalBlock : currentGlobalBlock];
      [starParser addParsingFile: $$];
    }
  else
    [$$ addDataItem: $2];
}
| StarFile GlobalDataBlock
{
  if (!($$=[starParser getCurrentParsingGlobalBlock]))
    {
      $$=
	currentGlobalBlock=
	  [starParser 
	   newDataBlockWithName : [starParser getCurrentFileName]  value: $2];
      [starParser addGlobalBlock: $$];
    }
  else
    [$$ addDataItem: $2];
};


GlobalDataBlock : GLOBALNAME
{
  
  /* 
     Always is of type WDCStarDataBlock. 
     */
  $$=[starParser newDataBlockWithName: $1 value: 0];
}
| GlobalDataBlock ItemAssoc
{
  $$=[$1 addDataItem: $2];
};


DataBlock : DATABLOCKNAME
{
  
  /* 
     Always is of type WDCStarDataBlock. 
     */
  $$=[[starParser newDataBlockWithName: $1 value: 0]
      setGlobalBlock : currentGlobalBlock];
}
| ItemAssoc
{
  $$=[[[starParser newDataBlockWithName: "data_1" value: 0]
       setGlobalBlock : currentGlobalBlock] addDataItem: $1];
}
| DataBlock ItemAssoc
{
  $$=[$1 addDataItem: $2];
}
| DataBlock SaveFrame
{
  $$=[$1 addDataItem: $2];
};

SaveFrame : SAVENAME ItemAssoc SAVEEND
{
  /* 
     Always is of type WDCStarDataBlock. Save frame is a local reference
     data block within a data block. Need to determine the stop of a save
     frame.
     */
  $$=[starParser newDataBlockWithName: $1 value: $2];
}

ItemAssoc : ITEMNAME Strings
{
  /* Action for the following RHS rules are the same. However, Bison
     need to have one action associated with every rule.
     */
  /* 
     Alway is type of WDCStarItemAssocValue.
     */
  $$=[starParser newStarItemAssocWithName:$1 value:$2];
}
| ITEMNAME LineBuffers 
{
  /* 
     Alway is type of WDCStarItemAssocValue.
     */
  $$=[starParser newStarItemAssocWithName:$1 value:$2];
}
| LOOPMARK Loop
{
  /* 
     Alway is type of WDCStarItemAssocValue.
     */
  $$=[starParser newStarItemAssocWithName:$1 value:$2];
}
| ItemAssoc ItemAssoc
{
  $$=[$1 addStarAssocValue:$2];
};


Strings : STRING 
{
  
  /* 
     Singal string are of type WDCString.
     */
  
  $$=[starParser newStringInitFromCString:$1];
}
| Strings STRING
{

  /* 
     Strings are of type WDCLListOfObject of WDCString.
     */
  if (![$1 isMemberOfClassNamed: "WDCLListOfObject"])
    $1=[starParser newObjectListWithContent: $1];
  $$=[$1 addContent: [starParser newStringInitFromCString:$2]];
  
};


Loop : LOOPITEMNAME
{
  
  /*
     Looped items are of type WDCStarAssocValue. They can be linked 
     togather by using "addStarAssocValue:" method.
     */
  id temp=[starParser newStarItemAssocWithName:$1 value:0];
  [starParser initScopeStack];
  $$=[[WDCLListOfObject alloc] setContent : temp];
  
  /* Push the fist loop name scope level */
  
  [starParser pushScope: temp];
  
  /* Updat the current loop value scope */
  
  [starParser setCurrentScope : temp];
}
| Loop LOOPITEMNAME
{
  /* Adding new item. Same loop name scope level */
  
  $$=$1;
  [[starParser topScopeObject]
   addStarAssocValue : [starParser newStarItemAssocWithName: $2 value:0]];
}
| INTERNALLOOP LOOPITEMNAME
{
  /* Create the data item */
  
 // id currentObject=[starParser newStarItemAssocWithName : $2 value:0];
 // [starParser initScopeStack];
  
  /* Create the Loop_ item and assign the item to value of the Loop_ item */
  
 // $$=[starParser newStarItemAssocWithName : $1 value: currentObject];
  
  /* Push the 1st loop name scope and set the current loop value scope */
  
 // [[starParser pushScope: $$] setCurrentScope : $$];
  
  /* Push (raise to) the 2nd loop name scope level */ 
  
 // [starParser pushObject: currentObject]; 
}
| Loop INTERNALLOOP LOOPITEMNAME
{
  /* Create the data item */
  
  id temp=[starParser newStarItemAssocWithName : $3 value:0];

  $$=$1;
  
  /* Add the item to whoever is on the top of the nameScopeStack */
  
  [[starParser topScopeObject]
   addStarAssocValue : 
   [[[WDCLoopItemAssocValue alloc] setName:$2] addValue : temp]];
  
  [starParser pushScope : temp];
}
| Loop LOOPITEMVALUE
{
  id item, scopeStack, temp;
  $$=$1;
    
  /* Reduce to the current loop value scope */
  scopeStack=[starParser getStack];
  item=[scopeStack popToCurrentValueObjectAndReturnPreviousInputItem];
  
  /* find the current input item */

  item=[scopeStack getNextInputItem: item];

  if (!item) printf("problem here\n");
  if ([item getValue]) 
    {
      item=[item selectedDeepCopy];
      temp=[scopeStack popObject];
      // scopeStack should be empty or has an object of llistofobject
      if ([scopeStack isEmpty])
	{
	  if ([temp isKindOfClassNamed : "WDCLListOfObject"])
	    $$=temp;
	  else
	    $$=[[WDCLListOfObject alloc] setContent: temp];
	  [starParser pushScope: $$];
	}
      if ([[scopeStack topObject] isKindOfClassNamed : "WDCLListOfObject"])
	[[scopeStack topObject] addContent: item];
      else if ([scopeStack isLoopItem: [scopeStack topObject]])
	[[[scopeStack topObject] getValue] addContent: item];
      else
	printf("parser still have problem ....\n");
      [starParser pushScope: item];
      [scopeStack setCurrentValueScope: [scopeStack topObject]];
    }
  
  /* Set the value and push the current item to stack for next itemvalue */
  
  [starParser pushScope : [item addValue : 
			   [starParser newStringInitFromCString : $2]]];
}
| Loop LineBuffers
{
  id item, scopeStack, temp;
  $$=$1;
   
  /* Reduce to the current loop value scope */
  scopeStack=[starParser getStack];
  item=[scopeStack popToCurrentValueObjectAndReturnPreviousInputItem];
  
  /* find the current input item */

  item=[scopeStack getNextInputItem: item];
  
  if (!item) printf("problem in Looped linebuffers\n");
  
  if ([item getValue])
    {
      item=[item selectedDeepCopy];
      temp=[scopeStack popObject];
      if ([scopeStack isEmpty])
	{
	  if ([temp isKindOfClassNamed : "WDCLListOfObject"])
	    $$=temp;
	  else
	    $$=[[WDCLListOfObject alloc] setContent: temp];
	  [starParser pushScope: $$];
	}
      if ([[scopeStack topObject] 
	   isKindOfClassNamed : "WDCLListOfObject"])
	[[scopeStack topObject] addContent: item];
      else if ([scopeStack isLoopItem: [scopeStack topObject]])
	[[[scopeStack topObject] getValue] addContent: item];
      else
	printf("parser still have problem ....\n");
      [starParser pushScope: item];
      [scopeStack setCurrentValueScope: [scopeStack topObject]];
    }
  /* Set the value and push the current item to stack for next itemvalue */
  [starParser pushScope : [item addValue : $2]];
}
| Loop LOOPEND
{
  $$=$1;

  /* if the topObject is a loop_ item just pop one item, since this is a
     stop_ in item name input loop.
     */
  if ([[[starParser getStack] popObject] getValue])  /* not name input loop */
    {
      /* It is a stop_ in value input loop, then. */
      [[starParser getStack] reduceLoopItem];
    }
};

LineBuffers : LINESBEGIN 
{
  
  /* 
     LineBuffers are of type WDCLineBuffer.
     */

  $$=[starParser newLineBufferInitFromCString:$1]; 
}
| LineBuffers LINE
{
  $$=[$1 addCopyOfCString: $2];
};



%%

#include <stdio.h>

extern char * yytext;
extern FILE *yyin;
extern char ** fileList;
extern unsigned nFiles;
unsigned currentFile=0;


