
%name-prefix="fp"
%pure-parser
%parse-param {const char*file_path}

%{
/*
 * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    This program 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 this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

# include  "fp_api.h"
# include  "pcb_priv.h"
# include  <cstdio>
# include  <cstdarg>


using namespace std;

/* Recent version of bison expect that the user supply a
   YYLLOC_DEFAULT macro that makes up a yylloc value from existing
   values. I need to supply an explicit version to account for the
   text field, that otherwise won't be copied. */
# define YYLLOC_DEFAULT(Current, Rhs, N)  do {       \
  (Current).first_line   = (Rhs)[1].first_line;      \
 } while (0)

static void yyerror(YYLTYPE*, const char*, const char*msg)
{
      fprintf(stderr, "%s\n", msg);
}

extern void init_fp_lexor(FILE*fd);
extern void destroy_fp_lexor();
extern int fplex(union YYSTYPE*yylvalp, YYLTYPE*yylloc);

static fp_pad_t cur_pad;
static fp_element_t cur_element;

%}

%union {
      long integer;
      char*text;
};

%token <text> STRING
%token <integer> INTEGER
%token K_ELEMENT
%token K_PAD

%type <integer> integer

%%

file_items : file_items file_item | file_item ;

file_item : element ;

element
  : K_ELEMENT element_header '(' element_items ')'
      { callback_fp_element(cur_element); }
  ;

element_header
  : '[' INTEGER STRING STRING STRING integer integer integer integer integer integer STRING ']'
      { cur_element.nflags = $2;
	cur_element.description = $3;  delete[]$3;
	cur_element.name = $4;         delete[]$4;
	cur_element.value = $5;        delete[]$5;
	cur_element.mx = $6;
	cur_element.my = $7;
	cur_element.tx = $8;
	cur_element.ty = $9;
	cur_element.tdir = $10;
	cur_element.tscale = $11;
	cur_element.tsflags = $12;     delete[]$12;
	cur_element.pads.clear();
      }
  | '[' error ']'
      { errormsg(@2, "Error in element header\n");
	yyerrok;
        cur_element.nflags = 0;
	cur_element.description = "";
	cur_element.name = "";
	cur_element.value = "";
	cur_element.mx = 0;
	cur_element.my = 0;
	cur_element.tx = 0;
	cur_element.ty = 0;
	cur_element.tdir = 0;
	cur_element.tscale = 0;
	cur_element.tsflags = "";
	cur_element.pads.clear();
      }
  ;

element_items
  : element_items element_item
  | element_item
  ;

element_item
  : pad  { cur_element.pads[cur_pad.name] = cur_pad; }
  ;

integer
  : INTEGER      { $$ = $1; }
  | '-' INTEGER  { $$ = -$2; }
  ;

pad
  : K_PAD '[' integer integer integer integer integer integer integer STRING STRING STRING ']'
      { cur_pad.rx1 = $3;
	cur_pad.ry1 = $4;
	cur_pad.rx2 = $5;
	cur_pad.ry2 = $6;
	cur_pad.thickness = $7;
	cur_pad.clearance = $8;
	cur_pad.mask = $9;
	cur_pad.name = $10;   delete[]$10;
	cur_pad.number = $11; delete[]$11;
	cur_pad.sflags = $12; delete[]$12;
      }

  | K_PAD '[' error ']'
      { errormsg(@3, "Error in pad header\n");
	yyerrok;
	cur_pad.rx1 = 0;
	cur_pad.ry1 = 0;
	cur_pad.rx2 = 0;
	cur_pad.ry2 = 0;
	cur_pad.thickness = 0;
	cur_pad.clearance = 0;
	cur_pad.mask = 0;
	cur_pad.name = "";
	cur_pad.number = "";
	cur_pad.sflags = "";
      }
  ;

%%

static string parse_file_path;
int parse_fp_errors = 0;
int parse_fp_sorrys = 0;

void errormsg(const YYLTYPE&loc, const char*fmt, ...)
{
      va_list ap;
      va_start(ap, fmt);

      fprintf(stderr, "%s:%d: error: ", parse_file_path.c_str(), loc.first_line);
      vfprintf(stderr, fmt, ap);
      va_end(ap);
      parse_fp_errors += 1;
}

void sorrymsg(const YYLTYPE&loc, const char*fmt, ...)
{
      va_list ap;
      va_start(ap, fmt);

      fprintf(stderr, "%s:%d: sorry: ", parse_file_path.c_str(), loc.first_line);
      vfprintf(stderr, fmt, ap);
      va_end(ap);
      parse_fp_sorrys += 1;
}

int parse_fp_file(const string&file_path)
{
      FILE*fd = fopen(file_path.c_str(), "r");
      if (fd == 0) {
	    perror(file_path.c_str());
	    return -1;
      }

      parse_file_path = file_path;
      parse_fp_errors = 0;
      parse_fp_sorrys = 0;
      init_fp_lexor(fd);
      int rc = yyparse(file_path.c_str());
      fclose(fd);
      destroy_fp_lexor();

      return rc;
}
