%{
static char VehicleConfig_yacc_id[] = "$Header$";

/*
$Log$
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "Micro.h"
#include "VehicleConfiguration.h"
#include "Stack.h"
  
#define dprintf if (debug) fprintf
#define MaxArgs 16
char *Args[MaxArgs];

int Nargs = 0;
int BraceLevel = 0;

class ParentComponent
{
  public:
  ParentComponent(VehicleComponent *component)
  {
    _component = component;
  }

  VehicleComponent *component()
  {
    return _component;
  }
  
  protected:
  VehicleComponent *_component;
  
};



// Function prototypes
int VC_error(char *errorBuf);
int VC_lex();
int VC_lineNo();
void setErrorBuf(char *msg);
int addArgument(char *ptr);
void resetArgs();
VehicleComponent *createComponent();
void unputToken();


extern "C" 
{
  void *alloca (unsigned size);
};


char ParseErrorBuf[512];
ParentComponent *Parent;
Stack<ParentComponent *> ParentStack(10);

const int eofReturn = -1;
const int errorReturn = 1;
const int okReturn = 0;

%}

%union 
{
  int integer;
  char *string;
}


%token MyEof
%token <string> WordToken StringToken 
%type <string> ArgList
%type <string> Argument

%%

Start: Siblings EndOfFile
{
  int debug = 1;
  dprintf(stderr, "Start found\n");

  if (BraceLevel != 0)
  {
    setErrorBuf("Missing }");
    return errorReturn;
  }
/* ***
  if (VC_char)
  {
    dprintf(stderr, "unput last token\n");
    unputToken();
  }  
*** */
}


SubTree: ParentComponent Siblings CloseBrace 
{
  int debug = 1;
  dprintf(stderr, "SubTree found\n");

  // Pop parent from stack
  delete Parent;
  Parent = ParentStack.pop();
};


Siblings: ChildlessComponent |
          Siblings ChildlessComponent |
          SubTree |
          Siblings SubTree
{
};


ParentComponent: ArgList OpenBrace
{
  int debug = 1;
  dprintf(stderr, "ParentComponent found\n");

  VehicleComponent *component;

  if (ParentStack.push(Parent) == -1)
  {
    setErrorBuf("Parent stack overflow");
    return errorReturn;
  }
  
  if ((component = createComponent()) == NULL)
    return errorReturn;

  Parent = new ParentComponent(component);
};

 
ChildlessComponent: ArgList ';'
{
  int debug = 1;
  dprintf(stderr, "ChildlessComponent found\n");

  if (createComponent() == NULL)
    return errorReturn;
};


ArgList: Argument |
         ArgList Argument
{
  int debug = 1;
  dprintf(stderr, "ArgList found\n");
  char *ptr = $1;
};


Argument: WordToken
{
  int debug = 1;
  dprintf(stderr, "Word Argument found\n");

  if (addArgument($1) == errorReturn)
    return errorReturn;
}

Argument: StringToken
{
  int debug = 1;
  dprintf(stderr, "String Argument found\n");

  if (addArgument($1) == errorReturn)
    return errorReturn;
}


OpenBrace:  '{'
{
  int debug = 1;
  dprintf(stderr, "OpenBrace found\n");

  BraceLevel++;
}

CloseBrace: '}'
{
  int debug = 1;
  dprintf(stderr, "CloseBrace found\n");

  if (--BraceLevel < 0)
  {
    setErrorBuf("Unbalanced }'s");
    return errorReturn;
  }
}



EndOfFile:           { fprintf(stderr, "Empty EndOfFile\n"); }
            |  MyEof { fprintf(stderr, "MyEof found\n"); }



%%

extern char *VC_text;

int VC_error(char *errorMsg)
{
  sprintf(ParseErrorBuf, 
	  "Line %d: %s\noffending text: \"%s\"", 
	  VC_lineNo(), errorMsg, VC_text);
  
  return 0;
}


VehicleComponent *createComponent()
{
  char buf[512];
  VehicleComponent *component = NULL;
  
  if (Nargs < 1)
  {
    setErrorBuf("Insufficient arguments");
    resetArgs(); 
    return NULL;
  }
  
  VehicleComponent::Type componentType = 
    VehicleComponent::mnemonicType(Args[0]);

  char *componentName = Args[1];
  
  switch (componentType)
  {
    case VehicleComponent::BusType:
    if (Nargs != 2)
    {
      sprintf(buf, "Syntax error - usage: %s name", Args[0]);
      setErrorBuf(buf);
      component = NULL;
    }
    else
      component = new Bus(componentName);

    break;

    case VehicleComponent::SwitchType:
    case VehicleComponent::VicorSwitchType:
    case VehicleComponent::IsoIoSwitchType:

    if (Nargs != 3)
    {
      sprintf(buf, "Syntax error - usage: %s name dmItem",
	      Args[0]);

      setErrorBuf(buf);
    }
    else
    {
      char *dmItem = Args[2];
      if (!strcmp(dmItem, "dummy"))
        // "dummy" item with no associated data manager item
	dmItem = NULL;
      
      if (componentType == VehicleComponent::SwitchType)
	component = new Switch(componentName, dmItem);

      if (componentType == VehicleComponent::VicorSwitchType)
	component = new VicorSwitch(componentName, dmItem);

      if (componentType == VehicleComponent::IsoIoSwitchType)
	component = new IsoIoSwitch(componentName, dmItem);

    }
    break;
    
    case VehicleComponent::MotorSwitchType:
    if (Nargs != 4)
    {
      sprintf(buf, "Syntax error - "
	      "usage: %s name dmItem enableDmItemPrefix",
	      Args[0]);

      setErrorBuf(buf);
    }
    else
      component = new MotorSwitch(componentName, Args[2], Args[3]);
    
    break;
      
    case VehicleComponent::IbcType:
    case VehicleComponent::DconType:
    case VehicleComponent::MotorMicroType:
      
    if (Nargs != 3)
    {
      sprintf(buf, "Syntax error - usage: %s name dmItemPrefix",
	      Args[0]);

      setErrorBuf(buf);
    }
    else
    {
      char *dmItem = Args[2];

      if (componentType == VehicleComponent::IbcType)
	component = new Ibc(componentName, dmItem);

      else if (componentType == VehicleComponent::DconType)
	component = new Dcon(componentName, dmItem);

      else if (componentType == VehicleComponent::MotorMicroType)
	component = new MotorMicro(componentName, dmItem);
      
    }
    
    break;
    

    case VehicleComponent::UnknownType:
    sprintf(buf, "Invalid VehicleComponent type \"%s\"\n",  Args[0]);
    setErrorBuf(buf);
    component = NULL;
    break;

    default:
    sprintf(buf, "Creation of component \"%s\" not yet implemented", Args[0]);
    setErrorBuf(buf);
    component = NULL;
  }

  resetArgs();

  if (component == NULL)
    return NULL;
  
  Parent->component()->addChild(component);
  return component;
}

int addArgument(char *ptr)
{
  if (Nargs >= MaxArgs)
  {
    char buf[100];
    sprintf(buf, "Exceeded %d tokens\n", MaxArgs);
    setErrorBuf(buf);
    return errorReturn;
  } 

  // If a string has been input, remove leading and trailing quotes
  if (*ptr == '"')
    ptr++;
  if (ptr[strlen(ptr)-1] == '"')
    ptr[strlen(ptr)-1] = '\0';

  Args[Nargs++] = strdup(ptr);
  return okReturn;
}


void resetArgs()
{
  for (int i = 0; i < Nargs; i++)
    free(Args[i]);
  
  Nargs = 0;
}

#ifdef ZILCH
int VehicleConfiguration::parseComponents(FILE *fp, 
					  BOOLEAN *error, 
					  char *errorMsg)
{
  int debug = 1;
  dprintf(stderr, "**** parseComponents() ****\n"); 
  static BOOLEAN firstParse = TRUE;

  if (firstParse)
  {
    Parent = new ParentComponent(vehicleBase);
  }
  
  int ret;
  extern FILE *VC_in;
  extern char ParseErrorBuf[];
  
  VC_in = fp;
  *error = FALSE;
  
  if ((ret = VC_parse()) != okReturn)
  {
    /* Error or end-of-file */
    if (ret == errorReturn)
    {
      *error = TRUE;
      strcpy(errorMsg, ParseErrorBuf);
    }
    return -1;
  }

  firstParse = FALSE;
  return 0;
}
#endif

void setErrorBuf(char *buf)
{
  sprintf(ParseErrorBuf, 
	  "Line %d: %s\n",
	  VC_lineNo(), buf);
}



main(int argc, char **argv)
{
  FILE *fp;

  if (argc != 2)
  {
    fprintf(stderr, "Usage: %s <inputfile>\n", argv[0]);
    exit(1);
  }
  char *inputFile = argv[1];  

  if ((fp = fopen(inputFile, "r")) == NULL)
  {
    fprintf(stderr, "Couldn't open file \"%s\"\n", inputFile);
    exit(1);
  }
  
  extern FILE *VC_in;
  VC_in = fp;

  VehicleBase *vehicleBase = new VehicleBase("Tiburon");
  Parent = new ParentComponent(vehicleBase);

  int ret;

  ret = VC_parse();
  
  if (ret == errorReturn)
  {
    fprintf(stderr, "Error from VC_parse():\n%s\n", ParseErrorBuf);
  }
  else
    printf("All done parsing file %s\n", inputFile);

  
  exit(0);
}





