/*
FILE DETAILS
description: header file needed for matrix operations in LCP solver, and some macros for the main
LCP function
project: MPT 3.0
filename: lcp_matrix.h
author: Colin N. Jones, Automatic Control Laboratory, ETH Zurich, 2006

LICENSE:
This program 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
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

REVISION HISTORY:
date: Nov, 2010
revised by: Martin Herceg, Automatic Control Laboratory, ETH Zurich, 2010
details: Included BLAS and LAPACK libraries which are standard in MATLAB. Replaced int
declarations with ptrdiff_t to be 32/64 compatible. Added declaration of LCP_options structure.
*/

#ifndef LCP_MATRIX__H
#define LCP_MATRIX__H

/**** MODULES ****/
/* Standard headers */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h> /* to have ptrdiff_t */
#include <math.h>
#include <time.h>

/* BLAS and LAPACK headers are in $MATLABROOT/extern/include
and are on the default search path when compiling with standard options */
#include <blas.h>
#include <lapack.h>

/**** MACROS ****/

/* Select an element from a column-major matrix */
#define C_SEL(mat,r,c) ((mat)->A[(r)+(c)*((mat)->rows_alloc)])

/* Select an element from a row-major matrix */
#define R_SEL(mat,r,c) ((mat)->A[(c)+(r)*((mat)->cols_alloc)])

/* Get a matrix */
#define MAT(mat) ((mat).A)

/* Get a matrix pointer */
#define pMAT(mat) ((mat)->A)

/* Get a pointer to a given column in a matrix */
#define COL(mat,n) &([C_SEL(mat,0,n)])

/* Get number of rows of a given matrix */
#define Matrix_Rows(pA) ((pA)->rows)

/* Get number of columns of a given matrix */
#define Matrix_Cols(pA) ((pA)->cols)

/* Dimension of an index set */
#define Index_Length(pI) ((pI)->len)

/* Assign value "x" to position "i" in the index set "I" */
#define Index_Set(pI,i,x) (((pI)->I[(i)]) = (x))

/* Obtain value of the index set "I" at the position "i" */
#define Index_Get(pI,i) ((pI)->I[(i)])

/**** TYPEDEFS AND STRUCTURES ****/

/* Matrices */
/* If a matrix is column-major, then the form is: */
/*      [M(0) M(rows_alloc)   M(2rows_alloc)   ... ] */
/*      [M(1) M(rows_alloc+1) M(2rows_alloc+1) ... ] */
/*      [...  ...             ....             ... ] */
typedef struct LCP_Matrix {
	double *A;
	ptrdiff_t rows,cols;
	ptrdiff_t rows_alloc, cols_alloc;
	char *name;
} T_Matrix, *PT_Matrix;

/* Index sets for basis defintion */
typedef struct LCP_IndexSet {
	/* C-based indexing used throughout. i.e. 0 is the first element */
	ptrdiff_t *I;
	ptrdiff_t len, len_alloc;
	char *name;
} T_Index, *PT_Index;

/* The basis */
typedef struct LCP_Basis {
	PT_Index pW;  /* Slacks in the basis */
	PT_Index pZ;  /* Variables in the basis */
	PT_Index pWc; /* Complement of W */

	PT_Index pP;  /* Work index (used to list positive variables) */

	/* B      = [I G;0 X]; */
	/* inv(B) = [I -G*iX; 0 iX] */
	/* G = M_W,Z */
	/* X = M_Wc,X */

	PT_Matrix pG, pX, pF, pLX, pUX, pUt;  /* F is used as factorization of X on exit from dgesv routine,
						                         Ut is full, column major upper triangular matrix */
	double *y,*z,*w, *v, *r;    /* work vectors */
	ptrdiff_t *p; /* work vector for dgesv, dgetrs */
	double *s; /* work vector for dgels */
} T_Basis, *PT_Basis;

/* options structure */
typedef struct LCP_options {
	double zerotol; /* zero tolerance*/
	double lextol; /* lexicographic tolerance - a small treshold to determine if values are equal */
	ptrdiff_t maxpiv; /* maximum number of pivots */
	ptrdiff_t nstepf; /* after n steps refactorize the basis */
	int clock;  /* print computation time */
	int verbose; /* verbose mode */
	int routine; /* routine from LAPACK library to solve linear equations in Basis_solve*/
	double timelimit; /* time limit for iterations in seconds */
	int normalize; /* normalize matrices M, q */
    double normalizethres; /* normalization threshold */
} T_Options;

/**** FUNCTIONS ****/

/* Basis functions */
PT_Basis Basis_Init(ptrdiff_t m);
void Basis_Free(PT_Basis pB);
void Basis_Print(PT_Basis pB);
ptrdiff_t  Basis_Pivot(PT_Basis pB, PT_Matrix pA, ptrdiff_t enter, ptrdiff_t leave);
ptrdiff_t Basis_Solve(PT_Basis pB, double *q, double *x, T_Options options);
void Reinitialize_Basis(ptrdiff_t m, PT_Basis pB);

void LU_Expand(PT_Matrix L, PT_Matrix U, double *y, double *z, double *w);
void LU_Replace_Col(PT_Matrix L, PT_Matrix U, ptrdiff_t kcol, double *y, double *z, double *w);
void LU_Replace_Row(PT_Matrix L, PT_Matrix U, ptrdiff_t krow, double *y, double *z, double *w);
void LU_Shrink(PT_Matrix L, PT_Matrix U, ptrdiff_t krow, ptrdiff_t kcol, double *y, double *z, double *w);
void LU_Solve0(PT_Matrix pL, PT_Matrix pU, double *vec, double *x);
void LU_Solve1(PT_Matrix pL, PT_Matrix pU, double *vec, double *x, ptrdiff_t *info);
void LU_Refactorize(PT_Basis pB);

/* Matrix functions */
PT_Matrix Matrix_Init(ptrdiff_t m, ptrdiff_t n, const char *name);
PT_Matrix Matrix_Init_NoAlloc(ptrdiff_t m, ptrdiff_t n, const char *name);
void Matrix_Free(PT_Matrix pMat);
void Matrix_Free_NoAlloc(PT_Matrix pMat);
void Matrix_Print_col(PT_Matrix pMat);
void Matrix_Print_row(PT_Matrix pMat);
void Matrix_Print_utril_row(PT_Matrix pMat);
void Matrix_Print_size(PT_Matrix pMat);
void Matrix_AddRow(PT_Matrix pA, double *row);
void Matrix_AddCol(PT_Matrix pA, double *col);
void Matrix_RemoveRow(PT_Matrix pA, ptrdiff_t row);
void Matrix_RemoveCol(PT_Matrix pA, ptrdiff_t col);
void Matrix_GetRow(PT_Matrix pA, double *row, ptrdiff_t row_index, PT_Index col_index);
void Matrix_GetCol(PT_Matrix pA, double *col, PT_Index row_index, ptrdiff_t col_index);
void Matrix_ReplaceCol(PT_Matrix pA, ptrdiff_t kcol, double *vec);
void Matrix_ReplaceRow(PT_Matrix pA, ptrdiff_t krow, double *vec);
void Matrix_Copy(PT_Matrix pA, PT_Matrix pB, double *w);
void Matrix_Triu(PT_Matrix pF, PT_Matrix pU, double *w);
void Matrix_Uzeros(PT_Matrix pF);
void Matrix_Full2RowTriangular(PT_Matrix pF, PT_Matrix  pU, double *w);
void Matrix_Transpose(PT_Matrix pA, PT_Matrix pB, double *w);
void Vector_Print_raw(double *vec, ptrdiff_t m);

/* Index set functions */
PT_Index Index_Init(ptrdiff_t len, const char *name);
void Index_Free(PT_Index pIndex);
void Index_Print(PT_Index pI);
void Index_Remove(PT_Index pI, ptrdiff_t leave);
void Index_Add(PT_Index pI, ptrdiff_t num);
void Index_Replace(PT_Index pI, ptrdiff_t index, ptrdiff_t newval);
ptrdiff_t Index_FindElement(PT_Index pI, ptrdiff_t element);

#endif


#ifndef SPECTRALSUBTRACTION_H
#define SPECTRALSUBTRACTION_H

#include <stdio.h>
#include <assert.h>
#include <float.h>
#include <gsl/gsl_block.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h>
#include <gsl/gsl_fft_complex.h>
#include <common/refcount.h>
#include "common/jexception.h"

#include "stream/stream.h"
#include "modulated/modulated.h"

class PSDEstimator {

 public:
  PSDEstimator(unsigned fftLen2);
  ~PSDEstimator();

  bool read_estimates( const String& fn );
  bool write_estimates( const String& fn );

  const gsl_vector* estimate() const {
    return estimates_;
  }

 protected:
  gsl_vector* estimates_; /* estimated noise PSD */
};

typedef refcount_ptr<PSDEstimator> PSDEstimatorPtr;

/**
   @class estimate the noise PSD for spectral subtraction (SS)
   1. construct an object
   2. add a noise sample
   3. get noise estimates
 */
class AveragePSDEstimator : public PSDEstimator {
 public:
  /**
      @brief A constructor for SS
      @param unsigned fftLen2[in] the half of the FFT point
      @param double alpha[in] the forgetting factor for recursive averaging.
                              If this is negative, the average is used
                              as the noise PSD estimate.
   */
  AveragePSDEstimator(unsigned fftLen2, float alpha = -1.0 );
  ~AveragePSDEstimator();

  void clear_samples();
  const gsl_vector* average();
  bool add_sample( const gsl_vector_complex *sample );
  void clear();

 protected:
  float alpha_;
  bool sample_added_;
  list<gsl_vector *> sampleL_;
};

typedef Inherit<AveragePSDEstimator, PSDEstimatorPtr> AveragePSDEstimatorPtr;

class SpectralSubtractor : public VectorComplexFeatureStream {
public:
  SpectralSubtractor(unsigned fftLen, bool halfBandShift = false, float ft=1.0, float flooringV=0.001, const String& nm = "SpectralSubtractor");
  ~SpectralSubtractor();

  virtual const gsl_vector_complex* next(int frameX = -5);
  virtual void reset();
  void clear(){
    for(NoisePSDIterator_ itr = noisePSDList_.begin(); itr != noisePSDList_.end(); itr++)
      (*itr)->clear();
  }

  void set_noise_over_estimation_factor(float ft){ ft_ = ft; }
  void set_channel(VectorComplexFeatureStreamPtr& chan, double alpha=-1 );
  void start_training(){ training_started_ = true; }
  void stop_training();
  void clear_noise_samples();
  void start_noise_subtraction(){ start_noise_subtraction_ = true; }
  void stop_noise_subtraction(){ start_noise_subtraction_ = false; }
  bool read_noise_file(const String& fn, unsigned idx=0);
  bool write_noise_file(const String& fn, unsigned idx=0){ return noisePSDList_.at(idx)->write_estimates(fn); }

#ifdef ENABLE_LEGACY_BTK_API
  void setNoiseOverEstimationFactor(float ft){ set_noise_over_estimation_factor(ft); }
  void setChannel(VectorComplexFeatureStreamPtr& chan, double alpha=-1){ set_channel(chan, alpha); }
  void startTraining(){ start_training(); }
  void stopTraining(){ stop_training(); }
  void clearNoiseSamples(){ clear_noise_samples(); }
  void startNoiseSubtraction(){ start_noise_subtraction(); }
  void stopNoiseSubtraction(){ stop_noise_subtraction(); }
  bool readNoiseFile( const String& fn, unsigned idx=0 ){ return read_noise_file(fn, idx); }
  bool writeNoiseFile( const String& fn, unsigned idx=0 ){ return write_noise_file(fn, idx); }
#endif

 protected:
  typedef list<VectorComplexFeatureStreamPtr>	ChannelList_;
  typedef ChannelList_::iterator		ChannelIterator_;
  typedef vector<AveragePSDEstimatorPtr>	NoisePSDList_;
  typedef NoisePSDList_::iterator		NoisePSDIterator_;

  ChannelList_		channelList_;
  NoisePSDList_         noisePSDList_;
  unsigned		fftLen_;
  unsigned		fftLen2_;
  bool			halfBandShift_;
  bool                  training_started_;
  unsigned              totalTrainingSampleN_;
  float			ft_;
  float			flooringV_;
  bool                  start_noise_subtraction_;
};

typedef Inherit<SpectralSubtractor, VectorComplexFeatureStreamPtr> SpectralSubtractorPtr;

// ----- definition for class 'WienerFilter' -----
//
class WienerFilter : public VectorComplexFeatureStream {
 public:
  WienerFilter( VectorComplexFeatureStreamPtr &targetSignal, VectorComplexFeatureStreamPtr &noiseSignal, bool halfBandShift=false, float alpha=0.0, float flooringV=0.001, double beta=1.0, const String& nm = "WienerFilter");
  ~WienerFilter();
  virtual const gsl_vector_complex* next(int frameX = -5);
  virtual void reset();

  void    set_noise_amplification_factor(double beta){ beta_ = beta; }
  void    start_updating_noise_PSD(){ update_noise_PSD_ = true; }
  void    stop_updating_noise_PSD(){ update_noise_PSD_ = false; }

#ifdef ENABLE_LEGACY_BTK_API
  void    setNoiseAmplificationFactor(double beta){ set_noise_amplification_factor(beta); }
  void    startUpdatingNoisePSD(){ start_updating_noise_PSD(); }
  void    stopUpdatingNoisePSD(){ stop_updating_noise_PSD(); }
#endif

 private:
  gsl_vector *prev_PSDs_;
  gsl_vector *prev_PSDn_;
  VectorComplexFeatureStreamPtr target_signal_;
  VectorComplexFeatureStreamPtr noise_signal_;
  bool                          halfBandShift_;
  float			alpha_; // forgetting factor
  float			flooringV_;
  float                 beta_; // amplification coefficient for a noise signal
  bool                  update_noise_PSD_;
  unsigned		fftLen_;
  unsigned		fftLen2_;
};

typedef Inherit<WienerFilter, VectorComplexFeatureStreamPtr> WienerFilterPtr;

#endif


/* interpolation/gsl_interp2d.h
 *
 * Copyright 2012 David Zaslavsky
 *
 * This program 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_INTERP2D_H__
#define __GSL_INTERP2D_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <gsl/gsl_interp.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

typedef struct {
    const char* name;
    unsigned int min_size;
    void * (*alloc)(size_t xsize, size_t ysize);
    int    (*init)(void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize);
    int    (*eval)(const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z);
    int    (*eval_deriv_x) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_p);
    int    (*eval_deriv_y) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_p);
    int    (*eval_deriv_xx) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_pp);
    int    (*eval_deriv_xy) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_pp);
    int    (*eval_deriv_yy) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_pp);
    void   (*free)(void *);
} gsl_interp2d_type;

typedef struct {
    const gsl_interp2d_type * type; /* interpolation type */
    double xmin;                    /* minimum value of x for which data have been provided */
    double xmax;                    /* maximum value of x for which data have been provided */
    double ymin;                    /* minimum value of y for which data have been provided */
    double ymax;                    /* maximum value of y for which data have been provided */
    size_t xsize;                   /* number of x values provided */
    size_t ysize;                   /* number of y values provided */
    void * state;                   /* internal state object specific to the interpolation type */
} gsl_interp2d;

/* available types */
GSL_VAR const gsl_interp2d_type * gsl_interp2d_bilinear;
GSL_VAR const gsl_interp2d_type * gsl_interp2d_bicubic;

GSL_FUN gsl_interp2d * gsl_interp2d_alloc(const gsl_interp2d_type * T, const size_t xsize,
                                  const size_t ysize);

GSL_FUN const char * gsl_interp2d_name(const gsl_interp2d * interp);
GSL_FUN size_t gsl_interp2d_min_size(const gsl_interp2d * interp);
GSL_FUN size_t gsl_interp2d_type_min_size(const gsl_interp2d_type * T);
GSL_FUN int gsl_interp2d_set(const gsl_interp2d * interp, double zarr[],
                     const size_t i, const size_t j, const double z);
GSL_FUN double gsl_interp2d_get(const gsl_interp2d * interp, const double zarr[],
                        const size_t i, const size_t j);
GSL_FUN size_t gsl_interp2d_idx(const gsl_interp2d * interp,
                        const size_t i, const size_t j);
GSL_FUN int gsl_interp2d_init(gsl_interp2d * interp, const double xa[], const double ya[],
                      const double za[], const size_t xsize, const size_t ysize);
GSL_FUN void gsl_interp2d_free(gsl_interp2d * interp);

GSL_FUN double gsl_interp2d_eval(const gsl_interp2d * interp, const double xarr[],
                         const double yarr[], const double zarr[], const double x,
                         const double y, gsl_interp_accel * xa, gsl_interp_accel * ya);

GSL_FUN double gsl_interp2d_eval_extrap(const gsl_interp2d * interp,
                                const double xarr[], const double yarr[],
                                const double zarr[], const double x,
                                const double y, gsl_interp_accel * xa,
                                gsl_interp_accel * ya);

GSL_FUN int gsl_interp2d_eval_e(const gsl_interp2d * interp, const double xarr[],
                        const double yarr[], const double zarr[],
                        const double x, const double y, gsl_interp_accel* xa,
                        gsl_interp_accel* ya, double * z);

#ifndef GSL_DISABLE_DEPRECATED

GSL_FUN int gsl_interp2d_eval_e_extrap(const gsl_interp2d * interp,
                               const double xarr[],
                               const double yarr[],
                               const double zarr[],
                               const double x,
                               const double y,
                               gsl_interp_accel * xa,
                               gsl_interp_accel * ya,
                               double * z);

#endif /* !GSL_DISABLE_DEPRECATED */

GSL_FUN int gsl_interp2d_eval_extrap_e(const gsl_interp2d * interp,
                               const double xarr[],
                               const double yarr[],
                               const double zarr[],
                               const double x,
                               const double y,
                               gsl_interp_accel * xa,
                               gsl_interp_accel * ya,
                               double * z);

GSL_FUN double gsl_interp2d_eval_deriv_x(const gsl_interp2d * interp, const double xarr[],
                                 const double yarr[], const double zarr[],
                                 const double x, const double y, gsl_interp_accel * xa,
                                 gsl_interp_accel * ya);

GSL_FUN int gsl_interp2d_eval_deriv_x_e(const gsl_interp2d * interp, const double xarr[],
                                const double yarr[], const double zarr[],
                                const double x, const double y,
                                gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);

GSL_FUN double gsl_interp2d_eval_deriv_y(const gsl_interp2d * interp, const double xarr[],
                                 const double yarr[], const double zarr[],
                                 const double x, const double y,
                                 gsl_interp_accel* xa, gsl_interp_accel* ya);

GSL_FUN int gsl_interp2d_eval_deriv_y_e(const gsl_interp2d * interp, const double xarr[],
                                const double yarr[], const double zarr[],
                                const double x, const double y,
                                gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);

GSL_FUN double gsl_interp2d_eval_deriv_xx(const gsl_interp2d * interp, const double xarr[],
                                  const double yarr[], const double zarr[],
                                  const double x, const double y,
                                  gsl_interp_accel * xa, gsl_interp_accel * ya);

GSL_FUN int gsl_interp2d_eval_deriv_xx_e(const gsl_interp2d * interp, const double xarr[],
                                 const double yarr[], const double zarr[],
                                 const double x, const double y,
                                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);

GSL_FUN double gsl_interp2d_eval_deriv_yy(const gsl_interp2d * interp, const double xarr[],
                                  const double yarr[], const double zarr[],
                                  const double x, const double y,
                                  gsl_interp_accel * xa, gsl_interp_accel * ya);

GSL_FUN int gsl_interp2d_eval_deriv_yy_e(const gsl_interp2d * interp, const double xarr[],
                                 const double yarr[], const double zarr[],
                                 const double x, const double y,
                                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);

GSL_FUN double gsl_interp2d_eval_deriv_xy(const gsl_interp2d * interp, const double xarr[],
                                  const double yarr[], const double zarr[],
                                  const double x, const double y,
                                  gsl_interp_accel * xa, gsl_interp_accel * ya);

GSL_FUN int gsl_interp2d_eval_deriv_xy_e(const gsl_interp2d * interp, const double xarr[],
                                 const double yarr[], const double zarr[],
                                 const double x, const double y,
                                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);

__END_DECLS

#endif /* __GSL_INTERP2D_H__ */


/*
 Copyright (C) 2002 M. Marques, A. Castro, A. Rubio, G. Bertsch

 This program 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.

 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., 51 Franklin Street, Fifth Floor, Boston, MA
 02110-1301, USA.

 $Id: parse_exp.c 13079 2015-02-18 16:06:42Z dstrubbe $
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h>

#include "liboct_parser.h"
#include "symbols.h"

static char *par_string;
static int par_pos;
parse_result par_res;

static int oct_parser_lex(void);
static int oct_parser_error (char *s)  /* Called by oct_parser_parse on error */
{
  /* Do nothing */
  /* printf("%s\n", s); */
  return 0;
}

/* include the parser */
#include "grammar.c"

int parse_exp(char *exp, parse_result *r)
{
  int o;

  par_string = exp;
  par_pos = 0;

  o = oct_parser_parse();
  if(o == 0){
    r->type = par_res.type;
    if(r->type == PR_CMPLX)
      r->value.c = par_res.value.c;
    else
      r->value.s = par_res.value.s;
  }
  return o;
}

int get_real(char *s, double *d)
{
  int n=0;
  sscanf(s, "%lg", d);
  while(*s && (isdigit(*s) || *s=='.' || *s=='e' || *s=='E')){
    if((*s=='e' || *s=='E') && (*(s+1)=='+' || *(s+1)=='-')) {s++; n++;}
    s++; n++;
  }
  return n;
}

static int oct_parser_lex (){
  int c;
  char *symbuf = 0, *symbuf2 = 0;
  int length = 0;

  /* Ignore whitespace, get first nonwhite character.  */
  while ((c = par_string[par_pos++]) == ' ' || c == '\t');

  if (c == '\0')
    return '\n';

  /* Char starts a number => parse the number.         */
  if (c == '.' || isdigit (c)){
    par_pos--;
    par_pos += get_real(&par_string[par_pos], &GSL_REAL(yylval.val));
    return NUM;
  }

  /* get the logical operators */
  if (c == '<' && par_string[par_pos] == '='){
    par_pos++;
    return LE;
  }

  if (c == '>' && par_string[par_pos] == '='){
    par_pos++;
    return GE;
  }

  if (c == '=' && par_string[par_pos] == '='){
    par_pos++;
    return EQUAL;
  }

  /*
  if (c == ':' && par_string[par_pos] == '='){
    par_pos++;
    return SET;
  }
  */

  if (c == '&' && par_string[par_pos] == '&'){
    par_pos++;
    return LAND;
  }

  if (c == '|' && par_string[par_pos] == '|'){
    par_pos++;
    return LOR;
  }

  /* Char starts an identifier => read the name.       */
  if (isalpha (c) || c == '\'' || c == '\"'){
    symrec *s;
    char startc = (char)c;
    int i;

    /* Initially make the buffer long enough
       for a 40-character symbol name.  */
    if (length == 0)
      length = 40, symbuf = (char *)malloc (length + 1);

    if(startc == '\'' || startc == '\"')
      c = par_string[par_pos++];
    else
      startc = 0; /* false */

    i = 0;
    do{
      /* If buffer is full, make it larger.        */
      if (i == length){
	length *= 2;
	symbuf2 = (char *)realloc (symbuf, length + 1);
	if (symbuf2 == NULL) {
	  fprintf(stderr, "Parser error: failed to reallocate buffer to size %i.\n", length);
	  exit(1);
	} else {
	  symbuf = symbuf2;
	}
      }
      /* Add this character to the buffer.         */
      symbuf[i++] = (char)c;
      /* Get another character.                    */
      c = par_string[par_pos++];
    }while (c != '\0' &&
	    ((startc && c!=startc) || (!startc && (isalnum(c) || c == '_' ))));

    if(!startc) par_pos--;
    symbuf[i] = '\0';

    if(!startc){
      s = getsym (symbuf);
      if (s == 0){
	int jj;
	for (jj = 0; reserved_symbols[jj] != 0; jj++){
	  if(strcmp(symbuf, reserved_symbols[jj]) == 0){
	    fprintf(stderr, "Parser error: trying to redefine reserved symbol '%s'.\n", symbuf);
	    exit(1);
	  }
	}

	s = putsym (symbuf, S_CMPLX);
      }
      yylval.tptr = s;

      free(symbuf);
      if(s->type == S_CMPLX)
	return VAR;
      else
	return FNCT;
    }else{
      yylval.str = strdup(symbuf);

      free(symbuf);
      return STR;
    }
  }

  /* Any other character is a token by itself.        */
  return c;
}