// Filename: stitchParser.y
// Created by:  drose (08Nov99)
// 
////////////////////////////////////////////////////////////////////

%{

#include "stitchParserDefs.h"
#include "stitchLexerDefs.h"
#include "stitchCommand.h"

////////////////////////////////////////////////////////////////////
// Defining the interface to the parser.
////////////////////////////////////////////////////////////////////

#define YYERROR_VERBOSE

typedef vector<StitchCommand *> CommandStack;
static CommandStack cstack;
static StitchCommand *parent; 

void
stitch_init_parser(istream &in, const string &filename,
                   StitchCommand *tos) {
  stitch_init_lexer(in, filename);
  parent = tos;
  cstack.push_back(parent);
}

%}

%token <number> NUMBER NUMBER_FEET NUMBER_INCHES
%token <str> IDENTIFIER
%token <str> STRING

%token KW_DEFINE
%token KW_LENS
%token KW_INPUT_IMAGE
%token KW_OUTPUT_IMAGE
%token KW_EYEPOINT
%token KW_PERSPECTIVE
%token KW_FISHEYE
%token KW_CYLINDRICAL
%token KW_PSPHERE
%token KW_FOCAL_LENGTH
%token KW_FOV
%token KW_SINGULARITY_TOLERANCE
%token KW_RESOLUTION
%token KW_FILENAME
%token KW_FADE
%token KW_POINT
%token KW_SHOW_POINTS
%token KW_IMAGE_SIZE
%token KW_FILM_SIZE
%token KW_FILM_OFFSET
%token KW_GRID
%token KW_UNTEXTURED_COLOR
%token KW_HPR
%token KW_POS
%token KW_RADIUS
%token KW_ANGLE
%token KW_HEIGHT
%token KW_LAYERS
%token KW_STITCH
%token KW_SCREEN
%token KW_POINTS
%token KW_USING
%token KW_IN
%token KW_MM
%token KW_FT
%token KW_CM
%token KW_P

%type <command> command
%type <command> group_command
%type <command> simple_command
%type <number> length
%type <number> length_units
%type <number> resolution
%type <number> resolution_units
%type <vec> point
%type <vec> vec2
%type <vec> vec3
%type <vec> length_pair
%type <vec> length_triple
%type <vec> color
%type <str> name
%type <str> optional_name

%%

stitch_file:
        commands

commands:
        empty
        | commands command
{
  //  parent->add_nested($2);
}
        | commands KW_POINTS '{' points_list '}'
        ;

command:
        group_command
{
  parent = $1;
  cstack.push_back(parent);
}
        nested_commands
{
  cstack.pop_back();
  parent = cstack.back();
}
        | simple_command ';'
{
  $$ = $1;
}
        ;

nested_commands:
        '{' commands '}'
        | ';'
        ;

group_command:
        KW_DEFINE name
{
  $$ = new StitchCommand(parent, StitchCommand::C_define);
  $$->set_name($2);
}
        | KW_LENS optional_name
{
  $$ = new StitchCommand(parent, StitchCommand::C_lens);
  $$->set_name($2);
}
        | KW_INPUT_IMAGE optional_name
{
  $$ = new StitchCommand(parent, StitchCommand::C_input_image);
  $$->set_name($2);
}
        | KW_OUTPUT_IMAGE optional_name
{
  $$ = new StitchCommand(parent, StitchCommand::C_output_image);
  $$->set_name($2);
}
        | KW_EYEPOINT optional_name
{
  $$ = new StitchCommand(parent, StitchCommand::C_eyepoint);
  $$->set_name($2);
}
        | KW_STITCH optional_name
{
  $$ = new StitchCommand(parent, StitchCommand::C_stitch);
  $$->set_name($2);
}
        | KW_SCREEN optional_name
{
  $$ = new StitchCommand(parent, StitchCommand::C_screen);
  $$->set_name($2);
}
        | KW_USING
{
  cstack.push_back(new StitchCommand(parent, StitchCommand::C_using));
}
        using_list
{
  $$ = cstack.back();
  cstack.pop_back();
}
        ;

simple_command:
        KW_PERSPECTIVE
{
  $$ = new StitchCommand(parent, StitchCommand::C_perspective);
}
        | KW_FISHEYE
{
  $$ = new StitchCommand(parent, StitchCommand::C_fisheye);
}
        | KW_CYLINDRICAL
{
  $$ = new StitchCommand(parent, StitchCommand::C_cylindrical);
}
        | KW_PSPHERE
{
  $$ = new StitchCommand(parent, StitchCommand::C_psphere);
}
        | KW_FOCAL_LENGTH length
{
  $$ = new StitchCommand(parent, StitchCommand::C_focal_length);
  $$->set_length($2);
}
        | KW_FOV NUMBER
{
  $$ = new StitchCommand(parent, StitchCommand::C_fov);
  $$->set_number($2);
}
        | KW_SINGULARITY_TOLERANCE NUMBER
{
  $$ = new StitchCommand(parent, StitchCommand::C_singularity_tolerance);
  $$->set_number($2);
}
        | KW_RESOLUTION resolution
{
  $$ = new StitchCommand(parent, StitchCommand::C_resolution);
  $$->set_resolution($2);
}
        | KW_FILENAME STRING
{
  $$ = new StitchCommand(parent, StitchCommand::C_filename);
  $$->set_str($2);
}
        | KW_FADE STRING
{
  $$ = new StitchCommand(parent, StitchCommand::C_fade);
  $$->set_str($2);
}
        | KW_POINT name point
{
  if ($<num_components>3 == 2) {
    $$ = new StitchCommand(parent, StitchCommand::C_point2d);
    $$->set_point2d((const LPoint2d &)$3);
  } else {
    $$ = new StitchCommand(parent, StitchCommand::C_point3d);
    $$->set_point3d((const LPoint3d &)$3);
  }
  $$->set_name($2);
}
        | KW_SHOW_POINTS NUMBER color
{
  $$ = new StitchCommand(parent, StitchCommand::C_show_points);
  $$->set_number($2);
  $$->set_color($3);
}
        | KW_IMAGE_SIZE vec2
{
  $$ = new StitchCommand(parent, StitchCommand::C_image_size);
  $$->set_point2d((const LPoint2d &)$2);
}
        | KW_FILM_SIZE length_pair
{
  $$ = new StitchCommand(parent, StitchCommand::C_film_size);
  $$->set_length_pair((const LPoint2d &)$2);
}
        | KW_FILM_OFFSET length_pair
{
  $$ = new StitchCommand(parent, StitchCommand::C_film_offset);
  $$->set_length_pair((const LPoint2d &)$2);
}
        | KW_GRID vec2
{
  $$ = new StitchCommand(parent, StitchCommand::C_grid);
  $$->set_point2d((const LPoint2d &)$2);
}
        | KW_UNTEXTURED_COLOR color
{
  $$ = new StitchCommand(parent, StitchCommand::C_untextured_color);
  $$->set_color((const Colord &)$2);
}
        | KW_HPR vec3
{
  $$ = new StitchCommand(parent, StitchCommand::C_hpr);
  $$->set_point3d((const LPoint3d &)$2);
}
        | KW_POS length_triple
{
  $$ = new StitchCommand(parent, StitchCommand::C_pos);
  $$->set_point3d((const LPoint3d &)$2);
}
        | KW_RADIUS length
{
  $$ = new StitchCommand(parent, StitchCommand::C_radius);
  $$->set_number($2);
}
        | KW_ANGLE vec2
{
  $$ = new StitchCommand(parent, StitchCommand::C_angle);
  $$->set_point2d((const LPoint2d &)$2);
}
        | KW_HEIGHT length_pair
{
  $$ = new StitchCommand(parent, StitchCommand::C_height);
  $$->set_point2d((const LPoint2d &)$2);
}
        | KW_LAYERS
{
  $$ = new StitchCommand(parent, StitchCommand::C_layers);
}
        | IDENTIFIER
{
  $$ = new StitchCommand(parent, StitchCommand::C_user_command);
  if (!$$->add_using($1)) {
    yyerror("Undefined identifier " + $1);
  }
}
        ;

using_list:
        IDENTIFIER
{
  if (!cstack.back()->add_using($1)) {
    yyerror("Undefined identifier " + $1);
  }
}
        | using_list ',' IDENTIFIER
{
  if (!cstack.back()->add_using($3)) {
    yyerror("Undefined identifier " + $3);
  }
}
        ;

points_list:
        empty
        | points_list name point ';'
{
  StitchCommand *cmd;
  if ($<num_components>3 == 2) {
    cmd = new StitchCommand(parent, StitchCommand::C_point2d);
    cmd->set_point2d((const LPoint2d &)$3);
  } else {
    cmd = new StitchCommand(parent, StitchCommand::C_point3d);
    cmd->set_point3d((const LPoint3d &)$3);
  }
  cmd->set_name($2);
  //  parent->add_nested(cmd);
}
        ;
  

length:
        NUMBER length_units
{
  $$ = $1 * $2
}
        | NUMBER_FEET
{
  $$ = $1 * 304.8;  // ft to mm
}
        | NUMBER_INCHES
{
  $$ = $1 * 25.4;  // in to mm
}
        | NUMBER_FEET NUMBER_INCHES
{
  if ($1 < 0.0) {
    $$ = $1 * 304.8 - $2 * 25.4;
  } else {
    $$ = $1 * 304.8 + $2 * 25.4;
  }
}
        | NUMBER
{
  $$ = $1;   // implicitly mm
}
        ;


length_units:
        KW_IN
{
  $$ = 25.4;   // in to mm
}
        | KW_CM
{
  $$ = 10.0;   // cm to mm
}
        | KW_MM
{
  $$ = 1.0;
}
        | KW_FT
{
  $$ = 304.8;  // ft to mm
}
        ;


resolution:
        NUMBER resolution_units
{
  $$ = $1 * $2;    // convert to pixels per mm
}
        ;

resolution_units:
        KW_P '/' length_units
{
  $$ = 1.0 / $3;
}
        ;

point:
        '(' NUMBER NUMBER ')'
{
  $$.set($2, $3, 0.0, 0.0);
  $<num_components>$ = 2;
}
        | '(' NUMBER ',' NUMBER ')'
{
  $$.set($2, $4, 0.0, 0.0);
  $<num_components>$ = 2;
}
        | '(' NUMBER NUMBER NUMBER ')'
{
  $$.set($2, $3, $4, 0.0);
  $<num_components>$ = 3;
}
        | '(' NUMBER ',' NUMBER ',' NUMBER ')'
{
  $$.set($2, $4, $6, 0.0);
  $<num_components>$ = 3;
}
        ;

vec2:
        '(' NUMBER NUMBER ')'
{
  $$.set($2, $3, 0.0, 0.0);
  $<num_components>$ = 2;
}
        | '(' NUMBER ',' NUMBER ')'
{
  $$.set($2, $4, 0.0, 0.0);
  $<num_components>$ = 2;
}
        ;

vec3:   '(' NUMBER NUMBER NUMBER ')'
{
  $$.set($2, $3, $4, 0.0);
  $<num_components>$ = 3;
}
        | '(' NUMBER ',' NUMBER ',' NUMBER ')'
{
  $$.set($2, $4, $6, 0.0);
  $<num_components>$ = 3;
}
        ;

length_pair:
	'(' length ',' length ')'
{
  $$.set($2, $4, 0.0, 0.0);
  $<num_components>$ = 2;
}
        ;

length_triple:
        '(' length ',' length ',' length ')'
{
  $$.set($2, $4, $6, 0.0);
  $<num_components>$ = 3;
}
        ;

color:
        '(' NUMBER NUMBER NUMBER ')'
{
  $$.set($2, $3, $4, 1.0);
  $<num_components>$ = 3;
}
        | '(' NUMBER ',' NUMBER ',' NUMBER ')'
{
  $$.set($2, $4, $6, 1.0);
  $<num_components>$ = 3;
}
        | '(' NUMBER NUMBER NUMBER NUMBER ')'
{
  $$.set($2, $3, $4, $5);
  $<num_components>$ = 4;
}
        | '(' NUMBER ',' NUMBER ',' NUMBER ',' NUMBER ')'
{
  $$.set($2, $4, $6, $8);
  $<num_components>$ = 4;
}
        ;

name:
        IDENTIFIER
        ;

optional_name:
        IDENTIFIER
        | empty
{
  $$ = "";
}
        ;

empty:
        ;
