%{

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "cli_val.h"

extern int yy_cli_def_lineno;
static vtw_def *parse_defp;
static int parse_status; 
static boolean cli_def_type_only=0; /*{ if (cli_def_type_only) YYACCEPT;}*/
/* XXX: sigh, the -p flag to yacc should do this for us kkkk*/
#define yystacksize tpltstacksize
#define yysslim tpltsslim

/* forward prototypes */
extern int yy_cli_parse_parse();
extern int yy_cli_def_lex();
extern void yy_cli_parse_error(const char *);
static  void cli_deferror(const char *);
 extern FILE *yy_cli_def_in;
#define YYDEBUG 1
#define yy_cli_parse_lex yy_cli_def_lex
%}
%token EOL
%token MULTI
%token TAG
%token TYPE
%token HELP
%token DEFAULT
%token PATTERN
%token EXEC
%token SYNTAX
%token COMMIT
%token CHECK
%left SEMI
%token <val>VALUE
%token <type>TYPE_DEF
%token <strp>VAR
%token <strp> STRING
%token <strp> EX_STRING
%token SYNTAX_ERROR
%token <action>ACTION
%left ASSIGN
%left OR
%left AND
%right NOT
%left COMMA
%nonassoc <cond>COND
%token RP
%token LP
%type <nodep> val
%type <nodep> exp
%type <val>   val0
%type <nodep> action
%type <nodep> action0

%union {
  char *strp;
  valstruct val;
  vtw_type_e type;
  vtw_cond_e cond;
  vtw_node *nodep;
  vtw_act_type action;
}

%%

input:          tag 
                | EOL input
                | tag otherinput
		;

otherinput:     type EOL 
                | cause EOL
                | otherinput type EOL 
                | otherinput cause EOL
                | otherinput EOL
		| syntax_error 
		;

tag:            /* empty */
		| TAG EOL {parse_defp->tag = TRUE;}
		| MULTI EOL {parse_defp->multi = TRUE;}
		;

type:	      	TYPE TYPE_DEF SEMI STRING
		{ parse_defp->def_type = $2; 
                  parse_defp->def_type_help = $4; }
		;


type:	      	TYPE TYPE_DEF
		{ parse_defp->def_type = $2; 
                }
		;

cause:		help_cause
		| default_cause
		| syntax_cause
                | ACTION action { append(parse_defp->actions + $1, $2, 0);}
		;

help_cause:	HELP STRING 
                { parse_defp->def_type_help = $2; /* no semantics for now */ 
                }

default_cause:  DEFAULT VALUE 
		{
		   if ($2.val_type != parse_defp->def_type)
		     yy_cli_parse_error((const char *)"Bad default\n");
		   parse_defp->def_default = $2.val;
		}
default_cause:  DEFAULT STRING 
		{
		   if (TEXT_TYPE != parse_defp->def_type)
		     yy_cli_parse_error((const char *)"Bad default\n");
		   parse_defp->def_default = $2;
		}

syntax_cause:   SYNTAX exp {append(parse_defp->actions + syntax_act, $2, 0);}
		;

syntax_cause:   COMMIT exp {append(parse_defp->actions + syntax_act, $2, 1);}
		;

action0:        STRING { $$ = make_node(EXEC_OP, make_str_node($1),NULL);}
                ;
action:         action0
                | action0 SEMI STRING 
                   {$$ = make_node(HELP_OP, $1, make_str_node($3));}
                | exp 
                ;
exp:		  LP exp RP 
		   {$$=$2;}
		| exp AND exp {$$ = make_node(AND_OP,$1,$3);}
		| exp OR exp {$$ = make_node(OR_OP,$1,$3);}
		| val COND val 
		   {$$ = make_node(COND_OP,$1,$3);$$->vtw_node_aux = $2;}
		| PATTERN VAR STRING 
		   { $$ = make_node(PATTERN_OP,make_var_node($2),
				     make_str_node($3));}
		| EXEC STRING
		   { $$ = make_node(EXEC_OP,make_str_node($2),NULL);}
		| NOT exp {$$ = make_node(NOT_OP,$2,NULL);}
                | exp SEMI STRING 
                   {$$ = make_node(HELP_OP, $1, make_str_node($3));}
                | VAR ASSIGN val
                   {$$ = make_node(ASSIGN_OP, make_var_node($1), $3);}
		;

val:		  VAR {$$ = make_var_node($1);}
                | val0 {$$ = make_val_node(&($1));}
                | EX_STRING {$$=make_str_node0($1, B_QUOTE_OP);}
		;

val0:           VALUE 

                | val0 COMMA val0 { add_val(&($1), &($3)); $$=$1; }

		| STRING {$$ = str2val($1);}
                ;

syntax_error:	  SYNTAX_ERROR {
			cli_deferror("syntax error");
		}
		;


%%
char *parse_path;
int parse_def(vtw_def *defp, char *path, boolean type_only)
{
   int status;
   yy_cli_def_lineno = 1;
   parse_status = 0;
   parse_defp = defp;
   cli_def_type_only = type_only;
   yy_cli_def_in = fopen(path, "r");
#if 0
   yy_cli_parse_debug = 1;
#endif
   if (!yy_cli_def_in)
     return -5;
   parse_path = path;
   status = yy_cli_parse_parse(); /* 0 is OK */
   fclose(yy_cli_def_in);
   return status;
}
static void
cli_deferror(const char *s)
{
  printf("Error: %s in file %s, line %d\n",s, parse_path, 
	 yy_cli_def_lineno);
}

void yy_cli_parse_error(const char *s)
{
  cli_deferror(s);
}