/* Bytecode definition file parser.
   Copyright (C) 1993 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */


%{

#include <stdio.h>
#include "hconfig.h"
#include "bi-defs.h"

extern char yytext[];
extern int yyleng;


/* Chain of all defs built by the parser. */
struct def *defs;
int ndefs;

static struct node *makenode ();
static struct variation *makevar ();
static struct def *makedef ();

void yyerror ();

%}

%union
{
  char *string;
  struct def *def;
  struct variation *variation;
  struct node *node;
}

%token <string> DEFOP STRING
%type <string> opt_string
%type <def> defs def
%type <variation> variations variation
%type <node> list items item

%%

top: 
  defs
    { defs = $1; }
  ;

defs:
  def
  | defs def
    { $2->next = $1; $$ = $2; }
  ;

def:
  DEFOP '(' STRING ',' opt_string ',' '(' variations ')' ')'
    { $$ = makedef ($3, $5, $8); }
  ;

variations:
  variation
  | variations ',' variation
    { $3->next = $1; $$ = $3; }
  ;

variation:
  '(' opt_string ')'
    { $$ = makevar ($2, (struct node *) NULL, (struct node *) NULL, (struct node *) NULL); }
  | '(' opt_string ',' list ')'
    { $$ = makevar ($2, $4, (struct node *) NULL, (struct node *) NULL); }
  | '(' opt_string ',' list ',' list ')'
    { $$ = makevar ($2, $4, $6, (struct node *) NULL); }
  | '(' opt_string ',' list ',' list ',' list ')'
    { $$ = makevar ($2, $4, $6, $8); }
  ;

opt_string:
  /* empty */ { $$ = ""; }
  | STRING { $$ = $1; }
  ;

list:
  '(' items ')'
    { $$ = $2; }
  | /* empty */
    { $$ = NULL; }
  ;

items:
  item
  /* Note right recursion. */
  | item ',' items
    { $1->next = $3; $$ = $1; }
  ;

item:
  STRING
    { $$ = makenode ($1); }
  ;

%%

static struct node *
makenode (s)
     char *s;
{
  struct node *n;

  n = (struct node *) malloc (sizeof (struct node));
  n->text = s;
  n->next = NULL;
  return n;
}

static struct variation *
makevar (name, inputs, outputs, literals)
     char *name;
     struct node *inputs, *outputs, *literals;
{
  struct variation *v;

  v = (struct variation *) malloc (sizeof (struct variation));
  v->name = name;
  v->code = ndefs++;
  v->inputs = inputs;
  v->outputs = outputs;
  v->literals = literals;
  v->next = NULL;
  return v;
}

static struct def *
makedef (name, template, vars)
     char *name, *template;
     struct variation *vars;
{
  struct def *d;

  d = (struct def *) malloc (sizeof (struct def));
  d->basename = name;
  d->template = template;
  d->variations = vars;
  d->next = NULL;
  return d;
}

void
yyerror (s)
     char *s;
{
  fprintf (stderr, "syntax error in input\n");
  exit (FATAL_EXIT_CODE);
}
