<commit_before>/*
 * Copyright (C) 2006-2016  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation (FSF), 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 Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "vibrato.h"
#include "essentiamath.h"

using namespace std;
using namespace essentia;
using namespace standard;

const char* Vibrato::name = "Vibrato";
const char* Vibrato::category = "Pitch";
const char* Vibrato::description = DOC("This algorithm detects the presence of vibrato and estimates its parameters given a pitch contour [Hz]. The result is the vibrato frequency in Hz and the extend (peak to peak) in cents. If no vibrato is detected in a frame, the output of both values is zero.\n"
"\n"
"This algorithm should be given the outputs of a pitch estimator, i.e. PredominantMelody, PitchYinFFT or PitchMelodia and the corresponding sample rate with which it was computed.\n"
"\n"
"The algorithm is an extended version of the vocal vibrato detection in PerdominantMelody."
"\n"
"References:\n"
"  [1] J. Salamon and E. Gómez, \"Melody extraction from polyphonic music\n"
"  signals using pitch contour characteristics,\" IEEE Transactions on Audio,\n"
"  Speech, and Language Processing, vol. 20, no. 6, pp. 1759–1770, 2012.\n\n");

void Vibrato::configure() {

  _minFrequency = parameter("minFrequency").toReal();
  _maxFrequency = parameter("maxFrequency").toReal();
  _minExtend = parameter("minExtend").toReal();
  _maxExtend = parameter("maxExtend").toReal();
  _sampleRate = parameter("sampleRate").toReal();

  frameSize = int(0.350 * _sampleRate);
  fftSize = 4*frameSize;

  frameCutter->configure("frameSize", frameSize, "hopSize", 1, "startFromZero", true);
  window->configure("type", "hann", "zeroPadding", 3*frameSize);
  spectrum->configure("size", fftSize);
  spectralPeaks->configure("sampleRate", _sampleRate, "maxPeaks", 3, "orderBy", "magnitude");
}

void Vibrato::compute() {

  Real vibdBDropLobe = 15.;
  Real vibdBDropSecondPeak = 20.;

  const vector<Real>& pitch = _pitch.get();
  vector<Real>& vibratoFrequency =_vibratoFrequency.get();
  vector<Real>& vibratoExtend = _vibratoExtend.get();

  // if pitch vector is empty
  if (pitch.empty()) {
    vibratoFrequency.clear();
    vibratoExtend.clear();
    return;
  }

  vibratoFrequency.assign(pitch.size(), 0.);
  vibratoExtend.assign(pitch.size(), 0.);

  vector<Real> pitchP;

  // set negative pitch values to zero
  for (int i=0; i<(int)pitch.size(); i++) {
    if (pitch[i]<0) {
        pitchP.push_back(0.0);
    } else {
        pitchP.push_back(pitch[i]);
    }
  }

  // get contour start and end indices
  vector<Real> startC, endC;
  if (pitchP[0]>0){
    startC.push_back(0);
  }
  for (int i=0; i<(int)pitchP.size()-1; i++) {
    if (pitchP[i+1]>0 && pitchP[i]==0){
      startC.push_back(i+1);
    }
    if (pitchP[i+1]==0 && pitchP[i]>0) {
      endC.push_back(i);
    }
  }
  if (endC.size()<startC.size()) {
    endC.push_back(pitch.size()-1);
  }

  // iterate over contour segments
  for (int i=0; i<(int)startC.size(); i++) {
    // get a segment in cents
    vector<Real> contour;
    for (int ii=startC[i]; ii<=endC[i]; ii++) {
      contour.push_back(1200*log2(pitch[ii]/55.0));
    }

    // setup algorithm I/O
    vector<Real> frame;
    frameCutter->input("signal").set(contour);
    frameCutter->output("frame").set(frame);
    vector<Real> windowedFrame;
    window->input("frame").set(frame);
    window->output("frame").set(windowedFrame);
    vector<Real> vibSpectrum;
    spectrum->input("frame").set(windowedFrame);
    spectrum->output("spectrum").set(vibSpectrum);
    vector<Real> peakFrequencies, peakMagnitudes;
    spectralPeaks->input("spectrum").set(vibSpectrum);
    spectralPeaks->output("frequencies").set(peakFrequencies);
    spectralPeaks->output("magnitudes").set(peakMagnitudes);
    frameCutter->reset();

    int frameNumber=0;

    // frame-wise processing
    while (true) {

      //get a frame
      frameCutter->compute();
      frameNumber++;

      if(!frame.size()) {
        break;
      }

      // subtract mean pitch from frame
      Real m = mean(frame, 0, frame.size()-1);
      for (int ii=0; ii<(int)frame.size(); ii++) {
        frame[ii]-=m;
      }

      // spectral peaks
      window->compute();
      spectrum->compute();
      spectralPeaks->compute();

      int numberPeaks = peakFrequencies.size();
      if (!numberPeaks) {
        continue;
      }

      if (peakFrequencies[0] < _minFrequency || peakFrequencies[0] > _maxFrequency) {
        continue;
      }

      if (numberPeaks > 1) {  // there is at least one extra peak
        if (peakFrequencies[1] <= _maxFrequency) {
          continue;
        }
        if (20 * log10(peakMagnitudes[0]/peakMagnitudes[1]) < vibdBDropLobe) {
          continue;
        }
      }

      if (numberPeaks > 2) {  // there is a second extra peak
        if (peakFrequencies[2] <= _maxFrequency) {
          continue;
        }
        if (20 * log10(peakMagnitudes[0]/peakMagnitudes[2]) < vibdBDropSecondPeak) {
          continue;
        }
      }

      Real ext = frame[argmax(frame)] + abs(frame[argmin(frame)]);
      if (ext<_minExtend || ext>_maxExtend){
        continue;
      }

      for (int ii=startC[i]+frameNumber-1; ii<startC[i]+frameNumber+frameSize-1; ii++) {
        vibratoFrequency[ii]=peakFrequencies[0];
        vibratoExtend[ii]=ext;
      }
    }
  }
}

Vibrato::~Vibrato() {
  delete frameCutter;
  delete window;
  delete spectrum;
  delete spectralPeaks;
}

void Vibrato::reset() {
  Algorithm::reset();
  frameCutter->reset();
  spectralPeaks->reset();
  spectrum->reset();
  window->reset();
}
<commit_msg>Fix memory bug in Vibrato<commit_after>/*
 * Copyright (C) 2006-2016  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation (FSF), 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 Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "vibrato.h"
#include "essentiamath.h"

using namespace std;
using namespace essentia;
using namespace standard;

const char* Vibrato::name = "Vibrato";
const char* Vibrato::category = "Pitch";
const char* Vibrato::description = DOC("This algorithm detects the presence of vibrato and estimates its parameters given a pitch contour [Hz]. The result is the vibrato frequency in Hz and the extend (peak to peak) in cents. If no vibrato is detected in a frame, the output of both values is zero.\n"
"\n"
"This algorithm should be given the outputs of a pitch estimator, i.e. PredominantMelody, PitchYinFFT or PitchMelodia and the corresponding sample rate with which it was computed.\n"
"\n"
"The algorithm is an extended version of the vocal vibrato detection in PerdominantMelody."
"\n"
"References:\n"
"  [1] J. Salamon and E. Gómez, \"Melody extraction from polyphonic music\n"
"  signals using pitch contour characteristics,\" IEEE Transactions on Audio,\n"
"  Speech, and Language Processing, vol. 20, no. 6, pp. 1759–1770, 2012.\n\n");

void Vibrato::configure() {

  _minFrequency = parameter("minFrequency").toReal();
  _maxFrequency = parameter("maxFrequency").toReal();
  _minExtend = parameter("minExtend").toReal();
  _maxExtend = parameter("maxExtend").toReal();
  _sampleRate = parameter("sampleRate").toReal();

  frameSize = int(0.350 * _sampleRate);
  fftSize = 4*frameSize;

  frameCutter->configure("frameSize", frameSize, "hopSize", 1, "startFromZero", true);
  window->configure("type", "hann", "zeroPadding", 3*frameSize);
  spectrum->configure("size", fftSize);
  spectralPeaks->configure("sampleRate", _sampleRate, "maxPeaks", 3, "orderBy", "magnitude");
}

void Vibrato::compute() {

  Real vibdBDropLobe = 15.;
  Real vibdBDropSecondPeak = 20.;

  const vector<Real>& pitch = _pitch.get();
  vector<Real>& vibratoFrequency =_vibratoFrequency.get();
  vector<Real>& vibratoExtend = _vibratoExtend.get();

  // if pitch vector is empty
  if (pitch.empty()) {
    vibratoFrequency.clear();
    vibratoExtend.clear();
    return;
  }

  vibratoFrequency.assign(pitch.size(), 0.);
  vibratoExtend.assign(pitch.size(), 0.);

  vector<Real> pitchP;

  // set negative pitch values to zero
  for (int i=0; i<(int)pitch.size(); i++) {
    if (pitch[i]<0) {
        pitchP.push_back(0.0);
    } else {
        pitchP.push_back(pitch[i]);
    }
  }

  // get contour start and end indices
  vector<Real> startC, endC;
  if (pitchP[0]>0){
    startC.push_back(0);
  }
  for (int i=0; i<(int)pitchP.size()-1; i++) {
    if (pitchP[i+1]>0 && pitchP[i]==0) {
      startC.push_back(i+1);
    }
    if (pitchP[i+1]==0 && pitchP[i]>0) {
      endC.push_back(i);
    }
  }
  if (endC.size()<startC.size()) {
    endC.push_back(pitch.size()-1);
  }

  // iterate over contour segments
  for (int i=0; i<(int)startC.size(); i++) {
    // get a segment in cents
    vector<Real> contour;
    for (int ii=startC[i]; ii<=endC[i]; ii++) {
      contour.push_back(1200*log2(pitch[ii]/55.0));
    }

    // setup algorithm I/O
    vector<Real> frame;
    frameCutter->input("signal").set(contour);
    frameCutter->output("frame").set(frame);
    vector<Real> windowedFrame;
    window->input("frame").set(frame);
    window->output("frame").set(windowedFrame);
    vector<Real> vibSpectrum;
    spectrum->input("frame").set(windowedFrame);
    spectrum->output("spectrum").set(vibSpectrum);
    vector<Real> peakFrequencies, peakMagnitudes;
    spectralPeaks->input("spectrum").set(vibSpectrum);
    spectralPeaks->output("frequencies").set(peakFrequencies);
    spectralPeaks->output("magnitudes").set(peakMagnitudes);
    frameCutter->reset();

    int frameNumber=0;

    // frame-wise processing
    while (true) {

      //get a frame
      frameCutter->compute();
      frameNumber++;

      if(!frame.size()) {
        break;
      }

      // subtract mean pitch from frame
      Real m = mean(frame, 0, frame.size()-1);
      for (int ii=0; ii<(int)frame.size(); ii++) {
        frame[ii]-=m;
      }

      // spectral peaks
      window->compute();
      spectrum->compute();
      spectralPeaks->compute();

      int numberPeaks = peakFrequencies.size();
      if (!numberPeaks) {
        continue;
      }

      if (peakFrequencies[0] < _minFrequency || peakFrequencies[0] > _maxFrequency) {
        continue;
      }

      if (numberPeaks > 1) {  // there is at least one extra peak
        if (peakFrequencies[1] <= _maxFrequency) {
          continue;
        }
        if (20 * log10(peakMagnitudes[0]/peakMagnitudes[1]) < vibdBDropLobe) {
          continue;
        }
      }

      if (numberPeaks > 2) {  // there is a second extra peak
        if (peakFrequencies[2] <= _maxFrequency) {
          continue;
        }
        if (20 * log10(peakMagnitudes[0]/peakMagnitudes[2]) < vibdBDropSecondPeak) {
          continue;
        }
      }

      Real ext = frame[argmax(frame)] + abs(frame[argmin(frame)]);
      if (ext<_minExtend || ext>_maxExtend){
        continue;
      }

      int ii = startC[i]+frameNumber-1;
      vibratoFrequency[ii] = peakFrequencies[0];
      vibratoExtend[ii] = ext;
      // NOTE: no need to loop over the frame, as the hopSize is 1
      /*
      for (int ii=startC[i]+frameNumber-1; ii<startC[i]+frameNumber-1+frameSize; ii++) {
        vibratoFrequency[ii]=peakFrequencies[0];
        vibratoExtend[ii]=ext;
      }
      */
    }
  }
}

Vibrato::~Vibrato() {
  delete frameCutter;
  delete window;
  delete spectrum;
  delete spectralPeaks;
}

void Vibrato::reset() {
  Algorithm::reset();
  frameCutter->reset();
  spectralPeaks->reset();
  spectrum->reset();
  window->reset();
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2013 Michael Krufky
 *
 * Author: Michael Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#define DBG 0

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

#include "functions.h"
#include "log.h"
#define CLASS_MODULE "desc"

#include "dvbpsi/dr_48.h" /* service descriptor */
#include "dvbpsi/dr_4d.h" /* short event descriptor */
#include "dvbpsi/dr_62.h" /* frequency list descriptor */
#include "dvbpsi/dr_83.h" /* LCN descriptor */

#include "desc.h"

#define dprintf(fmt, arg...) __dprintf(DBG_DESC, fmt, ##arg)

#define DT_Service                    0x48
#define DT_ShortEvent                 0x4d
#define DT_Teletext                   0x56
#define DT_FrequencyList              0x62
#define DT_LogicalChannelNumber       0x83

desc::desc()
//  : f_kill_thread(false)
{
	dprintf("()");
}

desc::~desc()
{
	dprintf("()");
}

bool desc::service(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_Service)
		return false;

	dvbpsi_service_dr_t* dr = dvbpsi_DecodeServiceDr(p_descriptor);
	if (!dr) return false;

	get_descriptor_text(dr->i_service_provider_name, dr->i_service_provider_name_length, provider_name);
	get_descriptor_text(dr->i_service_name,          dr->i_service_name_length,          service_name);

	dprintf("%s, %s", provider_name, service_name);

	return true;
}

bool desc::short_event(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_ShortEvent)
		return false;

	dvbpsi_short_event_dr_t* dr = dvbpsi_DecodeShortEventDr(p_descriptor);
	if (!dr) return false;

	memcpy(_4d.lang, dr->i_iso_639_code, 3);
	get_descriptor_text(dr->i_event_name, dr->i_event_name_length, _4d.name);
	get_descriptor_text(dr->i_text, dr->i_text_length, _4d.text);

	dprintf("%s, %s, %s", _4d.lang, _4d.name, _4d.text);

	return true;
}

bool desc::freq_list(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_FrequencyList)
		return false;

	dvbpsi_frequency_list_dr_t* dr = dvbpsi_DecodeFrequencyListDr(p_descriptor);
	if (!dr) return false;

	for (int i = 0; i < dr->i_number_of_frequencies; ++i) {
#if 0
		= dr->p_center_frequencies[i]
#else
		dprintf("%d", dr->p_center_frequencies[i]);
#endif
	}
	return true;
}

bool desc::_lcn(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_LogicalChannelNumber)
		return false;

	dvbpsi_lcn_dr_t* dr = dvbpsi_DecodeLCNDr(p_descriptor);
	if (!dr) return false;

	for (int i = 0; i < dr->i_number_of_entries; i ++) {
#if 0
		= lcn->p_entries[i].i_service_id;
		= lcn->p_entries[i].i_logical_channel_number;
#else
		lcn[dr->p_entries[i].i_service_id] = dr->p_entries[i].i_logical_channel_number;
		dprintf("%d, %d", dr->p_entries[i].i_service_id, lcn[dr->p_entries[i].i_service_id]);
#endif
	}

	return true;
}

void desc::decode(dvbpsi_descriptor_t* p_descriptor)
{
	while (p_descriptor) {
		switch (p_descriptor->i_tag) {
		case DT_Service:
			service(p_descriptor);
			break;
		case DT_ShortEvent:
			short_event(p_descriptor);
			break;
		case DT_FrequencyList:
			freq_list(p_descriptor);
			break;
		case DT_LogicalChannelNumber:
			_lcn(p_descriptor);
			break;
		default:
			dprintf("unknown descriptor tag: %02x", p_descriptor->i_tag);
			break;
		}
		p_descriptor = p_descriptor->p_next;
	}
}
<commit_msg>desc: display debug message if decoder failed<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2013 Michael Krufky
 *
 * Author: Michael Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#define DBG 0

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

#include "functions.h"
#include "log.h"
#define CLASS_MODULE "desc"

#include "dvbpsi/dr_48.h" /* service descriptor */
#include "dvbpsi/dr_4d.h" /* short event descriptor */
#include "dvbpsi/dr_62.h" /* frequency list descriptor */
#include "dvbpsi/dr_83.h" /* LCN descriptor */

#include "desc.h"

#define dprintf(fmt, arg...) __dprintf(DBG_DESC, fmt, ##arg)

#define DT_Service                    0x48
#define DT_ShortEvent                 0x4d
#define DT_Teletext                   0x56
#define DT_FrequencyList              0x62
#define DT_LogicalChannelNumber       0x83

#define desc_dr_failed(dr)			\
  ({						\
    bool __ret = !dr;				\
    if (__ret) dprintf("decoder failed!");	\
    __ret;					\
  })

desc::desc()
//  : f_kill_thread(false)
{
	dprintf("()");
}

desc::~desc()
{
	dprintf("()");
}

bool desc::service(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_Service)
		return false;

	dvbpsi_service_dr_t* dr = dvbpsi_DecodeServiceDr(p_descriptor);
	if (desc_dr_failed(dr)) return false;

	get_descriptor_text(dr->i_service_provider_name, dr->i_service_provider_name_length, provider_name);
	get_descriptor_text(dr->i_service_name,          dr->i_service_name_length,          service_name);

	dprintf("%s, %s", provider_name, service_name);

	return true;
}

bool desc::short_event(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_ShortEvent)
		return false;

	dvbpsi_short_event_dr_t* dr = dvbpsi_DecodeShortEventDr(p_descriptor);
	if (desc_dr_failed(dr)) return false;

	memcpy(_4d.lang, dr->i_iso_639_code, 3);
	get_descriptor_text(dr->i_event_name, dr->i_event_name_length, _4d.name);
	get_descriptor_text(dr->i_text, dr->i_text_length, _4d.text);

	dprintf("%s, %s, %s", _4d.lang, _4d.name, _4d.text);

	return true;
}

bool desc::freq_list(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_FrequencyList)
		return false;

	dvbpsi_frequency_list_dr_t* dr = dvbpsi_DecodeFrequencyListDr(p_descriptor);
	if (desc_dr_failed(dr)) return false;

	for (int i = 0; i < dr->i_number_of_frequencies; ++i) {
#if 0
		= dr->p_center_frequencies[i]
#else
		dprintf("%d", dr->p_center_frequencies[i]);
#endif
	}
	return true;
}

bool desc::_lcn(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_LogicalChannelNumber)
		return false;

	dvbpsi_lcn_dr_t* dr = dvbpsi_DecodeLCNDr(p_descriptor);
	if (desc_dr_failed(dr)) return false;

	for (int i = 0; i < dr->i_number_of_entries; i ++) {
#if 0
		= lcn->p_entries[i].i_service_id;
		= lcn->p_entries[i].i_logical_channel_number;
#else
		lcn[dr->p_entries[i].i_service_id] = dr->p_entries[i].i_logical_channel_number;
		dprintf("%d, %d", dr->p_entries[i].i_service_id, lcn[dr->p_entries[i].i_service_id]);
#endif
	}

	return true;
}

void desc::decode(dvbpsi_descriptor_t* p_descriptor)
{
	while (p_descriptor) {
		switch (p_descriptor->i_tag) {
		case DT_Service:
			service(p_descriptor);
			break;
		case DT_ShortEvent:
			short_event(p_descriptor);
			break;
		case DT_FrequencyList:
			freq_list(p_descriptor);
			break;
		case DT_LogicalChannelNumber:
			_lcn(p_descriptor);
			break;
		default:
			dprintf("unknown descriptor tag: %02x", p_descriptor->i_tag);
			break;
		}
		p_descriptor = p_descriptor->p_next;
	}
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef _SYMBOL_LOADER_HXX
#define _SYMBOL_LOADER_HXX

#include <iostream>
#include <osl/module.h>
#include <rtl/ustring.hxx>

#define SYM_MAP(a) { #a, (SymbolFunc *)&a }

typedef void (*SymbolFunc) (void);

struct ApiMap
{
    const char *symName;
    SymbolFunc *refValue;
};

namespace
{
    const char *libNames[] = {
        "libvlc.so.5",
        "libvlccore.so.5",
        "libvlc.dll",
        "libvlc.dylib"
    };

    template<size_t N>
    bool tryLink( oslModule &aModule, const ApiMap ( &pMap )[N] )
    {
        for (uint i = 0; i < N; ++i)
        {
            SymbolFunc aMethod = ( SymbolFunc )osl_getFunctionSymbol
                ( aModule, OUString::createFromAscii( pMap[ i ].symName ).pData );
            if ( !aMethod )
                return false;

            *pMap[ i ].refValue = aMethod;
        }

        return true;
    }
}

template<size_t N>
bool InitApiMap( const ApiMap ( &pMap )[N]  )
{
    oslModule aModule;

    for (uint j = 0; j < sizeof(libNames) / sizeof(libNames[0]); ++j)
    {
        aModule = osl_loadModule( OUString::createFromAscii
                                  ( libNames[ j ] ).pData,
                                  SAL_LOADMODULE_DEFAULT );

        if( aModule == NULL)
            continue;

        tryLink( aModule, pMap );

        osl_unloadModule( aModule );
    }

    return false;
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Fixing symbol loader. Returns true if successful. false otherwise.<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef _SYMBOL_LOADER_HXX
#define _SYMBOL_LOADER_HXX

#include <iostream>
#include <osl/module.h>
#include <rtl/ustring.hxx>

#define SYM_MAP(a) { #a, (SymbolFunc *)&a }

typedef void (*SymbolFunc) (void);

struct ApiMap
{
    const char *symName;
    SymbolFunc *refValue;
};

namespace
{
    const char *libNames[] = {
        "libvlc.so.5",
        "libvlc.dll",
        "libvlc.dylib"
    };

    template<size_t N>
    bool tryLink( oslModule &aModule, const ApiMap ( &pMap )[N] )
    {
        for (uint i = 0; i < N; ++i)
        {
            SymbolFunc aMethod = ( SymbolFunc )osl_getFunctionSymbol
                ( aModule, OUString::createFromAscii( pMap[ i ].symName ).pData );
            if ( !aMethod )
            {
                std::cerr << "Cannot load method " << pMap[ i ].symName << std::endl;
                *pMap[ i ].refValue = NULL;
                return false;
            }

            *pMap[ i ].refValue = aMethod;
        }

        return true;
    }
}

template<size_t N>
bool InitApiMap( const ApiMap ( &pMap )[N]  )
{
    oslModule aModule;

    for (uint j = 0; j < sizeof(libNames) / sizeof(libNames[0]); ++j)
    {
        aModule = osl_loadModule( OUString::createFromAscii
                                  ( libNames[ j ] ).pData,
                                  SAL_LOADMODULE_DEFAULT );

        if( aModule == NULL)
            continue;

        if (tryLink( aModule, pMap ))
        {
            osl_unloadModule( aModule );
            return true;
        }

        osl_unloadModule( aModule );
    }

    std::cerr << "Cannot load libvlc" << std::endl;
    return false;
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#pragma ident "$Id: //depot/sgl/gpstk/dev/apps/MDPtools/NavProc.cpp#7 $"

/*
  Think, navdmp for mdp, with bonus output that you get data from all code/carrier
  combos.
*/

#include "Geodetic.hpp"
#include "NavProc.hpp"

#include "FormatConversionFunctions.hpp"

using namespace std;
using namespace gpstk;
using namespace gpstk::StringUtils;

//-----------------------------------------------------------------------------
MDPNavProcessor::MDPNavProcessor(gpstk::MDPStream& in, std::ofstream& out)
   : MDPProcessor(in, out),
     firstNav(true), almOut(false), ephOut(false),
     badNavSubframeCount(0), navSubframeCount(0)
{
   timeFormat = "%4Y/%03j/%02H:%02M:%02S";
}

//-----------------------------------------------------------------------------
MDPNavProcessor::~MDPNavProcessor()
{
   using gpstk::RangeCode;
   using gpstk::CarrierCode;
   using gpstk::StringUtils::asString;

   out << "Done processing data." << endl << endl;

   out << endl << "Navigation Subframe message summary:" << endl;
   if (firstNav)
      out << "  No Navigation Subframe messages processed." << endl;
   else
   {
      out << "  navSubframeCount: " << navSubframeCount << endl;
      out << "  badNavSubframeCount: " << badNavSubframeCount << endl;
   }

   out << endl;
}

//-----------------------------------------------------------------------------
void MDPNavProcessor::process(const gpstk::MDPNavSubframe& msg)
{
   if (firstNav)
   {
      firstNav = false;
      if (verboseLevel)
         out << msg.time.printf(timeFormat)
             << "  Received first Navigation Subframe message"
             << endl;
   }

   navSubframeCount++;
   short sfid = msg.getSFID();
   short svid = msg.getSVID();
   bool isAlm = sfid > 3;
   long sow = msg.getHOWTime();
   short page = ((sow-6) / 30) % 25 + 1;

   if (verboseLevel>2)
   {
      out << msg.time.printf(timeFormat)
          << "  prn:" << setw(2) << msg.prn
          << " " << asString(msg.carrier)
          << ":" << setw(6) << left << asString(msg.range)
          << " nav:" << static_cast<int>(msg.nav)
          << " SOW:" << setw(6) << sow
          << " SFID:" << sfid;
      if (isAlm)
         out << " SVID:" << svid
             << " Page:" << page;
      out << endl;
   }

   // Sanity check on the header time versus the HOW time
   short week = msg.time.GPSfullweek();
   if (sow <0 || sow>=604800)
   {
      badNavSubframeCount++;
      if (verboseLevel>1)
         out << msg.time.printf(timeFormat)
             << "  SOW bad: " << sow
             << endl;
      return;
   }

   DayTime howTime(week, msg.getHOWTime());
   if (howTime == msg.time)
   {
      // Move this back down to verboseLevel>0 when ITT fixes their code...
      if (verboseLevel>2)
         out << msg.time.printf(timeFormat) << "  header time is HOW time" << endl;
   }
   else if (howTime != msg.time+6)
   {
      badNavSubframeCount++;
      if (verboseLevel>1)
         out << msg.time.printf(timeFormat)
             << "  HOW/header time miscompare " << howTime.printf(timeFormat)
             << endl;
      return;
   }

   if ((isAlm && !almOut) || (!isAlm && !ephOut))
      return;

   NavIndex ni(RangeCarrierPair(msg.range, msg.carrier), msg.prn);
   prev[ni] = curr[ni];
   curr[ni] = msg;

   long sfa[10];
   msg.fillArray(sfa);
   long long_sfa[10];
   for( int j = 0; j < 10; j++ )
      long_sfa[j] = static_cast<long>( sfa[j] );

   if (gpstk::EngNav::subframeParity(long_sfa))
   {
      if (isAlm)
      {
         AlmanacPages& almPages = almPageStore[ni];
         EngAlmanac& engAlm = almStore[ni];
         SubframePage sp(sfid, page);
         almPages[sp] = msg;
         almPages.insert(make_pair(sp, msg));

         if (makeEngAlmanac(engAlm, almPages))
         {
            out << msg.time.printf(timeFormat)
                << "  Built complete alm from prn " << setw(2) << ni.second
                << " " << setw(2) << asString(ni.first.second)
                << " " << left << setw(6) <<  asString(ni.first.first)
                << endl;
            if (verboseLevel>1)
               engAlm.dump(out);
            almPages.clear();
            engAlm = EngAlmanac();
         }
      }
      else
      {
         EphemerisPages& ephPages = ephPageStore[ni];
         ephPages[sfid] = msg;
         EngEphemeris engEph;

         if (makeEngEphemeris(engEph, ephPages))
         {
            out << msg.time.printf(timeFormat)
                << "  Built complete eph from prn " << setw(2) << ni.second
                << " " << setw(2) << asString(ni.first.second)
                << " " << left << setw(6) << asString(ni.first.first)
                << " iocd:0x" << hex << setw(3) << engEph.getIODC() << dec
                << endl;
            if (verboseLevel>1)
               out << engEph;
            ephStore[ni] = engEph;
         }
      }
   }
   else
   {
      badNavSubframeCount++;
      out << msg.time.printf(timeFormat)
          << "  Parity error on prn:" << setw(2) << msg.prn
          << " " << asString(msg.carrier)
             << ":" << setw(6) << left << asString(msg.range)
          << " TOW:" << setw(6) << msg.getHOWTime()
          << " SFID:" << sfid
          << endl;
   }
}  // end of process()
<commit_msg>Made the parity check get executed for all subframes.<commit_after>#pragma ident "$Id: NavProc.cpp,v 1.1 2006/07/28 14:31:42 littlej Exp $"

/*
  Think, navdmp for mdp, with bonus output that you get data from all code/carrier
  combos.
*/

#include "Geodetic.hpp"
#include "NavProc.hpp"

#include "FormatConversionFunctions.hpp"

using namespace std;
using namespace gpstk;
using namespace gpstk::StringUtils;

//-----------------------------------------------------------------------------
MDPNavProcessor::MDPNavProcessor(gpstk::MDPStream& in, std::ofstream& out)
   : MDPProcessor(in, out),
     firstNav(true), almOut(false), ephOut(false),
     badNavSubframeCount(0), navSubframeCount(0)
{
   timeFormat = "%4Y/%03j/%02H:%02M:%02S";
}

//-----------------------------------------------------------------------------
MDPNavProcessor::~MDPNavProcessor()
{
   using gpstk::RangeCode;
   using gpstk::CarrierCode;
   using gpstk::StringUtils::asString;

   out << "Done processing data." << endl << endl;

   out << endl << "Navigation Subframe message summary:" << endl;
   if (firstNav)
      out << "  No Navigation Subframe messages processed." << endl;
   else
   {
      out << "  navSubframeCount: " << navSubframeCount << endl;
      out << "  badNavSubframeCount: " << badNavSubframeCount << endl;
   }

   out << endl;
}

//-----------------------------------------------------------------------------
void MDPNavProcessor::process(const gpstk::MDPNavSubframe& msg)
{
   if (firstNav)
   {
      firstNav = false;
      if (verboseLevel)
         out << msg.time.printf(timeFormat)
             << "  Received first Navigation Subframe message"
             << endl;
   }

   navSubframeCount++;
   short sfid = msg.getSFID();
   short svid = msg.getSVID();
   bool isAlm = sfid > 3;
   long sow = msg.getHOWTime();
   short page = ((sow-6) / 30) % 25 + 1;

   if (verboseLevel>2)
   {
      out << msg.time.printf(timeFormat)
          << "  prn:" << setw(2) << msg.prn
          << " " << asString(msg.carrier)
          << ":" << setw(6) << left << asString(msg.range)
          << " nav:" << static_cast<int>(msg.nav)
          << " SOW:" << setw(6) << sow
          << " SFID:" << sfid;
      if (isAlm)
         out << " SVID:" << svid
             << " Page:" << page;
      out << endl;
   }

   // Sanity check on the header time versus the HOW time
   short week = msg.time.GPSfullweek();
   if (sow <0 || sow>=604800)
   {
      badNavSubframeCount++;
      if (verboseLevel>1)
         out << msg.time.printf(timeFormat)
             << "  SOW bad: " << sow
             << endl;
      return;
   }

   DayTime howTime(week, msg.getHOWTime());
   if (howTime == msg.time)
   {
      // Move this back down to verboseLevel>0 when ITT fixes their code...
      if (verboseLevel>2)
         out << msg.time.printf(timeFormat) << "  header time is HOW time" << endl;
   }
   else if (howTime != msg.time+6)
   {
      badNavSubframeCount++;
      if (verboseLevel>1)
         out << msg.time.printf(timeFormat)
             << "  HOW/header time miscompare " << howTime.printf(timeFormat)
             << endl;
      return;
   }

//   if ((isAlm && !almOut) || (!isAlm && !ephOut))
//      return;

   NavIndex ni(RangeCarrierPair(msg.range, msg.carrier), msg.prn);
   prev[ni] = curr[ni];
   curr[ni] = msg;

   long sfa[10];
   msg.fillArray(sfa);
   long long_sfa[10];
   for( int j = 0; j < 10; j++ )
      long_sfa[j] = static_cast<long>( sfa[j] );

   if (gpstk::EngNav::subframeParity(long_sfa))
   {
      if (isAlm && almOut)
      {
         AlmanacPages& almPages = almPageStore[ni];
         EngAlmanac& engAlm = almStore[ni];
         SubframePage sp(sfid, page);
         almPages[sp] = msg;
         almPages.insert(make_pair(sp, msg));

         if (makeEngAlmanac(engAlm, almPages))
         {
            out << msg.time.printf(timeFormat)
                << "  Built complete alm from prn " << setw(2) << ni.second
                << " " << setw(2) << asString(ni.first.second)
                << " " << left << setw(6) <<  asString(ni.first.first)
                << endl;
            if (verboseLevel>1)
               engAlm.dump(out);
            almPages.clear();
            engAlm = EngAlmanac();
         }
      }
      if (!isAlm && ephOut)
      {
         EphemerisPages& ephPages = ephPageStore[ni];
         ephPages[sfid] = msg;
         EngEphemeris engEph;

         if (makeEngEphemeris(engEph, ephPages))
         {
            out << msg.time.printf(timeFormat)
                << "  Built complete eph from prn " << setw(2) << ni.second
                << " " << setw(2) << asString(ni.first.second)
                << " " << left << setw(6) << asString(ni.first.first)
                << " iocd:0x" << hex << setw(3) << engEph.getIODC() << dec
                << endl;
            if (verboseLevel>1)
               out << engEph;
            ephStore[ni] = engEph;
         }
      }
   }
   else
   {
      badNavSubframeCount++;
      out << msg.time.printf(timeFormat)
          << "  Parity error on prn:" << setw(2) << msg.prn
          << " " << asString(msg.carrier)
             << ":" << setw(6) << left << asString(msg.range)
          << " TOW:" << setw(6) << msg.getHOWTime()
          << " SFID:" << sfid
          << endl;
   }
}  // end of process()
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2019 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "../ImageOp.h"
#include "ToneMapper_ispc.h"

using namespace ospcommon;

namespace ospray {

  /*! \brief Generic tone mapping operator approximating ACES by default. */
  struct OSPRAY_SDK_INTERFACE ToneMapper : public TileOp
  {
    void commit() override;

    std::unique_ptr<LiveImageOp> attach(FrameBufferView &fbView) override;

    std::string toString() const override;

    // Params for the tone mapping curve
    float a, b, c, d;
    bool acesColor;
    float exposure;
  };

  struct OSPRAY_SDK_INTERFACE LiveToneMapper : public LiveTileOp
  {
    LiveToneMapper(FrameBufferView &fbView, void *ispcEquiv);

    ~LiveToneMapper() override;

    void process(Tile &t) override;

    void *ispcEquiv;
  };

  // Definitions //////////////////////////////////////////////////////////////

  void ToneMapper::commit()
  {
    ImageOp::commit();

    exposure = getParam1f("exposure", 1.f);
    // Default parameters fitted to the ACES 1.0 grayscale curve
    // (RRT.a1.0.3 + ODT.Academy.Rec709_100nits_dim.a1.0.3)
    // We included exposure adjustment to match 18% middle gray
    // (ODT(RRT(0.18)) = 0.18)
    const float aces_contrast = 1.6773f;
    const float aces_shoulder = 0.9714f;
    const float aces_midIn    = 0.18f;
    const float aces_midOut   = 0.18f;
    const float aces_hdrMax   = 11.0785f;

    a         = max(getParam1f("contrast", aces_contrast), 0.0001f);
    float d   = clamp(getParam1f("shoulder", aces_shoulder), 0.0001f, 1.f);
    float m   = clamp(getParam1f("midIn", aces_midIn), 0.0001f, 1.f);
    float n   = clamp(getParam1f("midOut", aces_midOut), 0.0001f, 1.f);
    float w   = max(getParam1f("hdrMax", aces_hdrMax), 1.f);
    acesColor = getParam1b("acesColor", true);

    // Solve b and c
    b = -((powf(m, -a * d) *
           (-powf(m, a) + (n * (powf(m, a * d) * n * powf(w, a) -
                                powf(m, a) * powf(w, a * d))) /
                              (powf(m, a * d) * n - n * powf(w, a * d)))) /
          n);

    // avoid discontinuous curve by clamping to 0
    c = max((powf(m, a * d) * n * powf(w, a) - powf(m, a) * powf(w, a * d)) /
                (powf(m, a * d) * n - n * powf(w, a * d)),
            0.f);
  }

  std::unique_ptr<LiveImageOp> ToneMapper::attach(FrameBufferView &fbView)
  {
    void *ispcEquiv = ispc::ToneMapper_create();
    ispc::ToneMapper_set(ispcEquiv, exposure, a, b, c, d, acesColor);
    return ospcommon::make_unique<LiveToneMapper>(fbView, ispcEquiv);
  }

  std::string ToneMapper::toString() const
  {
    return "ospray::ToneMapper";
  }

  LiveToneMapper::LiveToneMapper(FrameBufferView &_fbView, void *ispcEquiv)
      : LiveTileOp(_fbView), ispcEquiv(ispcEquiv)
  {
  }

  LiveToneMapper::~LiveToneMapper()
  {
    // TODO WILL: Release the ISPC equiv
  }

  void LiveToneMapper::process(Tile &tile)
  {
    ToneMapper_apply(ispcEquiv, (ispc::Tile &)tile);
  }

  OSP_REGISTER_IMAGE_OP(ToneMapper, tonemapper);

}  // namespace ospray
<commit_msg>fix bug where garbage value was used in ToneMapper (d)<commit_after>// ======================================================================== //
// Copyright 2009-2019 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "../ImageOp.h"
#include "ToneMapper_ispc.h"

using namespace ospcommon;

namespace ospray {

  /*! \brief Generic tone mapping operator approximating ACES by default. */
  struct OSPRAY_SDK_INTERFACE ToneMapper : public TileOp
  {
    void commit() override;

    std::unique_ptr<LiveImageOp> attach(FrameBufferView &fbView) override;

    std::string toString() const override;

    // Params for the tone mapping curve
    float a, b, c, d;
    bool acesColor;
    float exposure;
  };

  struct OSPRAY_SDK_INTERFACE LiveToneMapper : public LiveTileOp
  {
    LiveToneMapper(FrameBufferView &fbView, void *ispcEquiv);

    ~LiveToneMapper() override;

    void process(Tile &t) override;

    void *ispcEquiv;
  };

  // Definitions //////////////////////////////////////////////////////////////

  void ToneMapper::commit()
  {
    ImageOp::commit();

    exposure = getParam1f("exposure", 1.f);
    // Default parameters fitted to the ACES 1.0 grayscale curve
    // (RRT.a1.0.3 + ODT.Academy.Rec709_100nits_dim.a1.0.3)
    // We included exposure adjustment to match 18% middle gray
    // (ODT(RRT(0.18)) = 0.18)
    const float aces_contrast = 1.6773f;
    const float aces_shoulder = 0.9714f;
    const float aces_midIn    = 0.18f;
    const float aces_midOut   = 0.18f;
    const float aces_hdrMax   = 11.0785f;

    a = max(getParam1f("contrast", aces_contrast), 0.0001f);
    d = clamp(getParam1f("shoulder", aces_shoulder), 0.0001f, 1.f);

    float m = clamp(getParam1f("midIn", aces_midIn), 0.0001f, 1.f);
    float n = clamp(getParam1f("midOut", aces_midOut), 0.0001f, 1.f);

    float w   = max(getParam1f("hdrMax", aces_hdrMax), 1.f);
    acesColor = getParam1b("acesColor", true);

    // Solve b and c
    b = -((powf(m, -a * d) *
           (-powf(m, a) + (n * (powf(m, a * d) * n * powf(w, a) -
                                powf(m, a) * powf(w, a * d))) /
                              (powf(m, a * d) * n - n * powf(w, a * d)))) /
          n);

    // avoid discontinuous curve by clamping to 0
    c = max((powf(m, a * d) * n * powf(w, a) - powf(m, a) * powf(w, a * d)) /
                (powf(m, a * d) * n - n * powf(w, a * d)),
            0.f);
  }

  std::unique_ptr<LiveImageOp> ToneMapper::attach(FrameBufferView &fbView)
  {
    void *ispcEquiv = ispc::ToneMapper_create();
    ispc::ToneMapper_set(ispcEquiv, exposure, a, b, c, d, acesColor);
    return ospcommon::make_unique<LiveToneMapper>(fbView, ispcEquiv);
  }

  std::string ToneMapper::toString() const
  {
    return "ospray::ToneMapper";
  }

  LiveToneMapper::LiveToneMapper(FrameBufferView &_fbView, void *ispcEquiv)
      : LiveTileOp(_fbView), ispcEquiv(ispcEquiv)
  {
  }

  LiveToneMapper::~LiveToneMapper()
  {
    // TODO WILL: Release the ISPC equiv
  }

  void LiveToneMapper::process(Tile &tile)
  {
    ToneMapper_apply(ispcEquiv, (ispc::Tile &)tile);
  }

  OSP_REGISTER_IMAGE_OP(ToneMapper, tonemapper);

}  // namespace ospray
<|endoftext|>


<commit_before>#include <iostream>
#include <stdexcept>
#include <vector>
#include <unordered_map>

using namespace std;

std::unordered_map<std::string, double> constants =
        {
                {"Pi", 3.14},
                {"e",  2.7}
        };

enum class Token {
    Invalid,
    Minus,
    BinaryMinus,
    UnaryMinus,
    Plus,
    Mul,
    Div,
    Number,
    LeftBracket,
    RightBracket,
    End
};

/*
 * class for holding tokens and their values(in case of numbers/constants)
 * also has some useful methods
 */
struct Token_value {
    explicit Token_value(Token token, double value = 0.0) : token(token), value(value) {}

    /*
     * true if token is an operator
     */
    bool isOperator() {
        if ((token == Token::Plus) ||
            (token == Token::BinaryMinus) ||
            (token == Token::UnaryMinus) ||
            (token == Token::Mul) ||
            (token == Token::Div))
            return true;
        else
            return false;
    }

    /*
     * true if token is a binary + -
     */
    bool isPM() {
        if ((token == Token::Plus) ||
            (token == Token::BinaryMinus))
            return true;
        else
            return false;
    }

    Token token;
    double value;
};

/*
 * node for the calculation tree
 */
struct Node {
    /*
     * a leaf
     */
    Node(Token token, double value) :
            token(token), value(value) {}

    /*
     * a branch
     */
    Node(Token token, Node *left, Node *right) :
            token(token), left(left), right(right) {}

    Token token;
    double value = 0.0;
    Node *left = nullptr;
    Node *right = nullptr;
};

Token getToken(const char *&text) {

    while (const auto c = *text++) {

        switch (c) {
            case ' ':
                continue;
            case '-':
                return Token::Minus;
            case '+':
                return Token::Plus;
            case '*':
                return Token::Mul;
            case '/':
                return Token::Div;
            case '0':
                return Token::Number;
            case '(':
                return Token::LeftBracket;
            case ')':
                return Token::RightBracket;
        }

        if (c >= '1' && c <= '9') {
            for (auto c = *text; c >= '0' && c <= '9';) {
                text++;
                c = *text;
            }
            return Token::Number;
        }

        if (c == 'e')
            return Token::Number;
        if (c == 'P') {
            char d = *text;
            if (d == 'i') {
                text++;
                return Token::Number;
            } else
                return Token::Invalid;
        }
        return Token::Invalid;
    }
    return Token::End;

};

double getNumber(const char *start, const char *end) {

    double result = 0.0;

    if (*start == 'e')
        return constants["e"];
    else if (*start == 'P')
        return constants["Pi"];
    while (start <= end) {
        if (*start != ' ') {
            if (*start >= '0' && *start <= '9')
                result = result * 10 + *start - 48;
        }
        ++start;
    }

    return result;

}

/*
 * create a calculation tree from Token_values vector
 * by finding the operator with least priority and splitting
 */
Node *createTree(vector<Token_value> vector) {

    Node *nodeP;

    //variables for keeping count of brackets
    int min_priority = -1;
    int current_priority = 0;

    //variables describing current operator candidate to split on
    bool is_PM = false;
    bool is_unary_minus = false;

    //does current operator have less priority?
    bool changed = false;

    int opIndex = -1;
    int numberIndex = -1;
    int count = 0;
    for (auto token_v : vector) {

        if (token_v.token == Token::Number) {
            numberIndex = count;
            count++;
            continue;
        }

        if (token_v.isOperator()) {
            if ((min_priority == -1) || (current_priority < min_priority)) {
                changed = true;
            } else if (current_priority == min_priority) {
                if (token_v.isPM())
                    changed = true;
                else if (not is_PM) {
                    if (token_v.token == Token::UnaryMinus) {
                        if (opIndex == -1)
                            changed = true;
                    } else
                        changed = true;
                }
            }

            if (changed) {
                opIndex = count;
                min_priority = current_priority;
                is_unary_minus = (token_v.token == Token::UnaryMinus);
                is_PM = token_v.isPM();
                changed = false;
            }

        }
        if (token_v.token == Token::LeftBracket) {
            current_priority++;
        }
        if (token_v.token == Token::RightBracket) {
            current_priority--;
        }
        count++;
    }

    if (opIndex == -1) {
        nodeP = new Node(Token::Number, vector[numberIndex].value);
        return nodeP;
    }
    std::vector<Token_value> left_v;
    std::vector<Token_value> right_v;

    //min_priority = number of brackets we need to trim in the
    //beginning and end of the vector
    for (int count_2 = 0; count_2 < count; ++count_2) {
        if (count_2 + min_priority >= count)
            break;
        if (count_2 < min_priority) {
            continue;
        }
        if (count_2 < opIndex) {
            left_v.push_back(vector[count_2]);
        }
        if (count_2 > opIndex) {
            right_v.push_back(vector[count_2]);
        }
    }

    Node *leftNode;
    if (is_unary_minus) {
        leftNode = new Node(Token::Number, 0);
    } else
        leftNode = createTree(left_v);

    nodeP = new Node(vector[opIndex].token, leftNode, createTree(right_v));

    return nodeP;

}

/*
 * function for solving the calculation tree
 */
double solveTree(Node *node) {
    if (node->token == Token::Number) {
        double result = node->value;
        delete node;
        return result;
    }
    double lValue = solveTree(node->left);
    double rValue = solveTree(node->right);
    auto token = node->token;
    delete node;
    switch (token) {
        case Token::BinaryMinus:
            return lValue - rValue;
        case Token::UnaryMinus:
            return -rValue;
        case Token::Plus:
            return lValue + rValue;
        case Token::Mul:
            return lValue * rValue;
        case Token::Div: {
            if (rValue == 0)
                throw std::overflow_error("Exception: zero division");
            return lValue / rValue;
        }
        default:
            throw std::invalid_argument("Exception: could not solve tree");
    }
}

/*
 * main class that receives the expression,
 * checks its validity and has
 * a method for calculating it
 */
struct Calculator {
    explicit Calculator(char const *text) :
            ZeroDivision(false),
            n_tokens(0),
            result(0),
            text(text) {}

    bool isValid() {
        const char *end = text;
        bool invalid = false;
        bool is_operator = true;
        bool l_bracket = false;
        int openBrackets = 0;

        auto token = getToken(end);
        while (token != Token::End) {
            n_tokens++;
            switch (token) {
                case Token::Invalid: {
                    invalid = true;
                    break;
                }
                case Token::Number: {
                    if ((not is_operator) && (not l_bracket))
                        invalid = true;
                    l_bracket = false;
                    is_operator = false;
                    break;
                }
                case Token::Minus: {
                    is_operator = true;
                    l_bracket = false;
                    break;
                }
                case Token::LeftBracket: {
                    if ((not is_operator) && (not l_bracket))
                        invalid = true;
                    l_bracket = true;
                    is_operator = false;
                    openBrackets++;
                    break;
                }
                case Token::RightBracket: {
                    if (is_operator || l_bracket || (openBrackets < 1))
                        invalid = true;
                    l_bracket = false;
                    is_operator = false;
                    openBrackets--;
                    break;
                }
                default: {
                    if (is_operator || l_bracket)
                        invalid = true;
                    is_operator = true;
                }
            }
            if (invalid)
                break;
            token = getToken(end);
        }
        if (invalid || is_operator || openBrackets)
            return false;
        return true;
    }

    void tokenize() {
        const char *ptr1 = text;
        const char *ptr2 = text;
        bool prev_is_number_or_rbracket = false;

        for (int i = 0; i < n_tokens; ++i) {
            auto token = getToken(ptr2);

            if (token == Token::Number) {
                vector.emplace_back(token, getNumber(ptr1, ptr2));
                prev_is_number_or_rbracket = true;
            } else if (token == Token::Minus) {
                if (prev_is_number_or_rbracket)
                    vector.emplace_back(Token::BinaryMinus);
                else
                    vector.emplace_back(Token::UnaryMinus);
                prev_is_number_or_rbracket = false;
            } else {
                if (token == Token::RightBracket)
                    prev_is_number_or_rbracket = true;
                else
                    prev_is_number_or_rbracket = false;
                vector.emplace_back(token);
            }
            ptr1 = ptr2;
        }
    }

    double calculate() {
        this->tokenize();
        Node *tree;
        tree = createTree(vector);
        try {
            result = solveTree(tree);
        } catch (std::overflow_error &e) {
            ZeroDivision = true;
            return 0;
        }
        return result;
    }

    bool ZeroDivision;
    int n_tokens;
    double result;
    char const *text;
    std::vector<Token_value> vector;
};

int main(int argc, char const *argv[]) {
    if (argc == 1) {
        cout << "No expression provided";
        return 1;
    }

    char const *text = argv[1];
    bool isvalid;
    double result;

    Calculator calculator(text);
    isvalid = calculator.isValid();

    if (not isvalid) {
        cout << "Invalid expression";
        return 1;
    } else {
        result = calculator.calculate();
        if (calculator.ZeroDivision) {
            cout << "Exception: zero division";
            return 1;
        } else
            cout << result;
    }

    return 0;
}
<commit_msg>Koshman_hw03: fixed constants parsing<commit_after>#include <iostream>
#include <stdexcept>
#include <vector>
#include <unordered_map>

using namespace std;

std::unordered_map<std::string, double> constants =
        {
                {"Pi", 3.14},
                {"e",  2.7}
        };

enum class Token {
    Invalid,
    Minus,
    BinaryMinus,
    UnaryMinus,
    Plus,
    Mul,
    Div,
    Number,
    LeftBracket,
    RightBracket,
    End
};

/*
 * class for holding tokens and their values(in case of numbers/constants)
 * also has some useful methods
 */
struct Token_value {
    explicit Token_value(Token token, double value = 0.0) : token(token), value(value) {}

    /*
     * true if token is an operator
     */
    bool isOperator() {
        if ((token == Token::Plus) ||
            (token == Token::BinaryMinus) ||
            (token == Token::UnaryMinus) ||
            (token == Token::Mul) ||
            (token == Token::Div))
            return true;
        else
            return false;
    }

    /*
     * true if token is a binary + -
     */
    bool isPM() {
        if ((token == Token::Plus) ||
            (token == Token::BinaryMinus))
            return true;
        else
            return false;
    }

    Token token;
    double value;
};

/*
 * node for the calculation tree
 */
struct Node {
    /*
     * a leaf
     */
    Node(Token token, double value) :
            token(token), value(value) {}

    /*
     * a branch
     */
    Node(Token token, Node *left, Node *right) :
            token(token), left(left), right(right) {}

    Token token;
    double value = 0.0;
    Node *left = nullptr;
    Node *right = nullptr;
};

Token getToken(const char *&text) {

    while (const auto c = *text++) {

        switch (c) {
            case ' ':
                continue;
            case '-':
                return Token::Minus;
            case '+':
                return Token::Plus;
            case '*':
                return Token::Mul;
            case '/':
                return Token::Div;
            case '0':
                return Token::Number;
            case '(':
                return Token::LeftBracket;
            case ')':
                return Token::RightBracket;
        }

        if (c >= '1' && c <= '9') {
            for (auto c = *text; c >= '0' && c <= '9';) {
                text++;
                c = *text;
            }
            return Token::Number;
        }

        if (c == 'e')
            return Token::Number;
        if (c == 'P') {
            char d = *text;
            if (d == 'i') {
                text++;
                return Token::Number;
            } else
                return Token::Invalid;
        }
        return Token::Invalid;
    }
    return Token::End;

};

double getNumber(const char *start, const char *end) {

    double result = 0.0;
    while (*start == ' ')
        ++start;
    if (*start == 'e')
        return constants["e"];
    if (*start == 'P')
        return constants["Pi"];

    while (start < end) {
        result = result * 10 + *start - 48;
        ++start;
    }

    return result;

}

/*
 * create a calculation tree from Token_values vector
 * by finding the operator with least priority and splitting
 */
Node *createTree(vector<Token_value> vector) {

    Node *nodeP;

    //variables for keeping count of brackets
    int min_priority = -1;
    int current_priority = 0;

    //variables describing current operator candidate to split on
    bool is_PM = false;
    bool is_unary_minus = false;

    //does current operator have less priority?
    bool changed = false;

    int opIndex = -1;
    int numberIndex = -1;
    int count = 0;
    for (auto token_v : vector) {

        if (token_v.token == Token::Number) {
            numberIndex = count;
            count++;
            continue;
        }

        if (token_v.isOperator()) {
            if ((min_priority == -1) || (current_priority < min_priority)) {
                changed = true;
            } else if (current_priority == min_priority) {
                if (token_v.isPM())
                    changed = true;
                else if (not is_PM) {
                    if (token_v.token == Token::UnaryMinus) {
                        if (opIndex == -1)
                            changed = true;
                    } else
                        changed = true;
                }
            }

            if (changed) {
                opIndex = count;
                min_priority = current_priority;
                is_unary_minus = (token_v.token == Token::UnaryMinus);
                is_PM = token_v.isPM();
                changed = false;
            }

        }
        if (token_v.token == Token::LeftBracket) {
            current_priority++;
        }
        if (token_v.token == Token::RightBracket) {
            current_priority--;
        }
        count++;
    }

    if (opIndex == -1) {
        nodeP = new Node(Token::Number, vector[numberIndex].value);
        return nodeP;
    }
    std::vector<Token_value> left_v;
    std::vector<Token_value> right_v;

    //min_priority = number of brackets we need to trim in the
    //beginning and end of the vector
    for (int count_2 = 0; count_2 < count; ++count_2) {
        if (count_2 + min_priority >= count)
            break;
        if (count_2 < min_priority) {
            continue;
        }
        if (count_2 < opIndex) {
            left_v.push_back(vector[count_2]);
        }
        if (count_2 > opIndex) {
            right_v.push_back(vector[count_2]);
        }
    }

    Node *leftNode;
    if (is_unary_minus) {
        leftNode = new Node(Token::Number, 0);
    } else
        leftNode = createTree(left_v);

    nodeP = new Node(vector[opIndex].token, leftNode, createTree(right_v));

    return nodeP;

}

/*
 * function for solving the calculation tree
 */
double solveTree(Node *node) {
    if (node->token == Token::Number) {
        double result = node->value;
        delete node;
        return result;
    }
    double lValue = solveTree(node->left);
    double rValue = solveTree(node->right);
    auto token = node->token;
    delete node;
    switch (token) {
        case Token::BinaryMinus:
            return lValue - rValue;
        case Token::UnaryMinus:
            return -rValue;
        case Token::Plus:
            return lValue + rValue;
        case Token::Mul:
            return lValue * rValue;
        case Token::Div: {
            if (rValue == 0)
                throw std::overflow_error("Exception: zero division");
            return lValue / rValue;
        }
        default:
            throw std::invalid_argument("Exception: could not solve tree");
    }
}

/*
 * main class that receives the expression,
 * checks its validity and has
 * a method for calculating it
 */
struct Calculator {
    explicit Calculator(char const *text) :
            ZeroDivision(false),
            n_tokens(0),
            result(0),
            text(text) {}

    bool isValid() {
        const char *end = text;
        bool invalid = false;
        bool is_operator = true;
        bool l_bracket = false;
        int openBrackets = 0;

        auto token = getToken(end);
        while (token != Token::End) {
            n_tokens++;
            switch (token) {
                case Token::Invalid: {
                    invalid = true;
                    break;
                }
                case Token::Number: {
                    if ((not is_operator) && (not l_bracket))
                        invalid = true;
                    l_bracket = false;
                    is_operator = false;
                    break;
                }
                case Token::Minus: {
                    is_operator = true;
                    l_bracket = false;
                    break;
                }
                case Token::LeftBracket: {
                    if ((not is_operator) && (not l_bracket))
                        invalid = true;
                    l_bracket = true;
                    is_operator = false;
                    openBrackets++;
                    break;
                }
                case Token::RightBracket: {
                    if (is_operator || l_bracket || (openBrackets < 1))
                        invalid = true;
                    l_bracket = false;
                    is_operator = false;
                    openBrackets--;
                    break;
                }
                default: {
                    if (is_operator || l_bracket)
                        invalid = true;
                    is_operator = true;
                }
            }
            if (invalid)
                break;
            token = getToken(end);
        }
        if (invalid || is_operator || openBrackets)
            return false;
        return true;
    }

    void tokenize() {
        const char *ptr1 = text;
        const char *ptr2 = text;
        bool prev_is_number_or_rbracket = false;

        for (int i = 0; i < n_tokens; ++i) {
            auto token = getToken(ptr2);

            if (token == Token::Number) {
                vector.emplace_back(token, getNumber(ptr1, ptr2));
                prev_is_number_or_rbracket = true;
            } else if (token == Token::Minus) {
                if (prev_is_number_or_rbracket)
                    vector.emplace_back(Token::BinaryMinus);
                else
                    vector.emplace_back(Token::UnaryMinus);
                prev_is_number_or_rbracket = false;
            } else {
                if (token == Token::RightBracket)
                    prev_is_number_or_rbracket = true;
                else
                    prev_is_number_or_rbracket = false;
                vector.emplace_back(token);
            }
            ptr1 = ptr2;
        }
    }

    double calculate() {
        this->tokenize();
        Node *tree;
        tree = createTree(vector);
        try {
            result = solveTree(tree);
        } catch (std::overflow_error &e) {
            ZeroDivision = true;
            return 0;
        }
        return result;
    }

    bool ZeroDivision;
    int n_tokens;
    double result;
    char const *text;
    std::vector<Token_value> vector;
};

int main(int argc, char const *argv[]) {
    if (argc == 1) {
        cout << "No expression provided";
        return 1;
    }

    char const *text = argv[1];
    bool isvalid;
    double result;

    Calculator calculator(text);
    isvalid = calculator.isValid();

    if (not isvalid) {
        cout << "Invalid expression";
        return 1;
    } else {
        result = calculator.calculate();
        if (calculator.ZeroDivision) {
            cout << "Exception: zero division";
            return 1;
        } else
            cout << result;
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "compiler/grammar.hpp"
#include "compiler/conversions.hpp"

#include <boost/spirit/home/qi.hpp>
#include <boost/spirit/home/lex.hpp>

using namespace std::string_literals;

namespace perseus
{
  namespace detail
  {
    // rule definition; optional attributes are generated from the matched code
    template< typename attribute = boost::spirit::unused_type >
    using rule = boost::spirit::qi::rule< token_iterator, attribute(), skip_grammar >;

    //    terminals

    static rule< ast::string_literal > string{ string_literal_parser{}, "string literal"s };
    static rule< std::int32_t > decimal_integer{ decimal_integer_literal_parser{}, "decimal integer"s };
    static rule< std::int32_t > hexadecimal_integer{ hexadecimal_integer_literal_parser{}, "hexadecimal integer"s };
    static rule< std::int32_t > binary_integer{ binary_integer_literal_parser{}, "binary integer"s };
    static rule< std::int32_t > integer{ decimal_integer | hexadecimal_integer | binary_integer, "integer"s };

    static rule< ast::identifier > identifier{ boost::spirit::qi::token( token_id::identifier ), "identifier"s };
    static rule< ast::operator_identifier > operator_identifier{ boost::spirit::qi::token( token_id::operator_identifier ), "operator identifier"s };

    static rule<> if_{ boost::spirit::qi::token( token_id::if_ ), "if"s };
    static rule<> else_{ boost::spirit::qi::token( token_id::else_ ), "else"s };
    static rule<> while_{ boost::spirit::qi::token( token_id::while_ ), "while"s };
    static rule<> return_{ boost::spirit::qi::token( token_id::if_ ), "return"s };

    static rule<> colon{ boost::spirit::qi::token( token_id::colon ), "colon"s };
    static rule<> semicolon{ boost::spirit::qi::token( token_id::semicolon ), "semicolon"s };
    static rule<> dot{ boost::spirit::qi::token( token_id::dot ), "dot"s };
    static rule<> comma{ boost::spirit::qi::token( token_id::comma ), "comma"s };
    static rule<> equals{ boost::spirit::qi::token( token_id::equals ), "equals sign"s };
    static rule<> backtick{ boost::spirit::qi::token( token_id::backtick ), "backtick"s };

    static rule<> paren_open{ boost::spirit::qi::token( token_id::paren_open ), "opening paren"s };
    static rule<> paren_close{ boost::spirit::qi::token( token_id::paren_close ), "closing paren"s };
    static rule<> brace_open{ boost::spirit::qi::token( token_id::brace_open ), "opening brace"s };
    static rule<> brace_close{ boost::spirit::qi::token( token_id::brace_close ), "closing brace"s };
    static rule<> square_bracket_open{ boost::spirit::qi::token( token_id::square_bracket_open ), "opening square bracket"s };
    static rule<> square_bracket_close{ boost::spirit::qi::token( token_id::square_bracket_close ), "closing square bracket"s };

    //    non-terminals
    static grammar::start_type file;

    static rule< ast::expression > expression{ "expression"s };
    static rule< ast::operand > operand{ "operand"s };
    static rule< ast::operation > operation{ "operation"s };
    static rule< ast::binary_operation > binary_operation{ "binary operation"s };
    static rule< ast::unary_operation > unary_operation{ "unary operation"s };
    static rule< ast::if_expression > if_expression{ "if expression"s };
    static rule< ast::while_expression > while_expression{ "while expression"s };
    static rule< ast::call_expression > call_expression{ "call expression"s };
    static rule< ast::block_expression > block_expression{ "block expression"s };
    static rule< ast::parens_expression > parens_expression{ "parens expression"s };
    static rule< ast::index_expression > index_expression{ "index expression"s };

    grammar::grammar()
      : base_type( file, "perseus script"s )
    {
      // EOI = End of Input
      file %= expression > boost::spirit::qi::eoi;

      // what about operator_identifier? first class functions and all that?
      // this split is required to prevent left recursion, which in the parser turns into an infinite recursion.
      expression = operand >> *operation;
      operand = string | integer | identifier | unary_operation | if_expression | while_expression | block_expression | parens_expression;
      operation = binary_operation | call_expression | index_expression;
      {
        // x `op` y
        binary_operation = operator_identifier >> expression;

        // name( arg1, arg2 )
        // a % b means list of a separated by b; that has a minimum length of 1, thus the - (optional)
        call_expression = paren_open > -( expression % comma ) > paren_close;

        // object[index]
        index_expression = square_bracket_open > expression > square_bracket_close;

        // `op` x
        unary_operation = operator_identifier > expression;

        // if cond then_body else_body
        // Logically there's always an else, but it may be "nothing" (i.e. void).
        // > is an expectation concatenation: after an "if" terminal there *must* be an expression (allows for early abortion in case of errors and better errors)
        // this parsing is eager, i.e. `if c1 if c2 t else e` means `if c1 { if c2 t else e }`
        if_expression = if_ > expression > expression > ( ( else_ > expression ) | boost::spirit::qi::attr( ast::expression{ ast::void_expression{}, {} } ) );

        // while cond body
        while_expression = while_ > expression > expression;

        // { exp1; exp2 }
        block_expression = brace_open > ( expression % semicolon ) > brace_close;

        // ( expression )
        parens_expression = paren_open > expression > paren_close;
      }
    }
  }
  namespace detail
  {
    using skip_rule = boost::spirit::qi::rule< token_iterator >;

    // terminals
    static skip_rule whitespace{ boost::spirit::qi::token( token_id::whitespace ), "whitespace"s };
    static skip_rule comment{ boost::spirit::qi::token( token_id::whitespace ), "comment"s };
    // start symbol
    static skip_grammar::start_type skip{ whitespace | comment };

    skip_grammar::skip_grammar()
      : base_type( skip )
    {
    }
  }
}
<commit_msg>allow void expressions in blocks, e.g. {} and {foo;}<commit_after>#include "compiler/grammar.hpp"
#include "compiler/conversions.hpp"

#include <boost/spirit/home/qi.hpp>
#include <boost/spirit/home/lex.hpp>

using namespace std::string_literals;

namespace perseus
{
  namespace detail
  {
    // rule definition; optional attributes are generated from the matched code
    template< typename attribute = boost::spirit::unused_type >
    using rule = boost::spirit::qi::rule< token_iterator, attribute(), skip_grammar >;

    //    terminals

    static rule< ast::string_literal > string{ string_literal_parser{}, "string literal"s };
    static rule< std::int32_t > decimal_integer{ decimal_integer_literal_parser{}, "decimal integer"s };
    static rule< std::int32_t > hexadecimal_integer{ hexadecimal_integer_literal_parser{}, "hexadecimal integer"s };
    static rule< std::int32_t > binary_integer{ binary_integer_literal_parser{}, "binary integer"s };
    static rule< std::int32_t > integer{ decimal_integer | hexadecimal_integer | binary_integer, "integer"s };

    static rule< ast::identifier > identifier{ boost::spirit::qi::token( token_id::identifier ), "identifier"s };
    static rule< ast::operator_identifier > operator_identifier{ boost::spirit::qi::token( token_id::operator_identifier ), "operator identifier"s };

    static rule<> if_{ boost::spirit::qi::token( token_id::if_ ), "if"s };
    static rule<> else_{ boost::spirit::qi::token( token_id::else_ ), "else"s };
    static rule<> while_{ boost::spirit::qi::token( token_id::while_ ), "while"s };
    static rule<> return_{ boost::spirit::qi::token( token_id::if_ ), "return"s };

    static rule<> colon{ boost::spirit::qi::token( token_id::colon ), "colon"s };
    static rule<> semicolon{ boost::spirit::qi::token( token_id::semicolon ), "semicolon"s };
    static rule<> dot{ boost::spirit::qi::token( token_id::dot ), "dot"s };
    static rule<> comma{ boost::spirit::qi::token( token_id::comma ), "comma"s };
    static rule<> equals{ boost::spirit::qi::token( token_id::equals ), "equals sign"s };
    static rule<> backtick{ boost::spirit::qi::token( token_id::backtick ), "backtick"s };

    static rule<> paren_open{ boost::spirit::qi::token( token_id::paren_open ), "opening paren"s };
    static rule<> paren_close{ boost::spirit::qi::token( token_id::paren_close ), "closing paren"s };
    static rule<> brace_open{ boost::spirit::qi::token( token_id::brace_open ), "opening brace"s };
    static rule<> brace_close{ boost::spirit::qi::token( token_id::brace_close ), "closing brace"s };
    static rule<> square_bracket_open{ boost::spirit::qi::token( token_id::square_bracket_open ), "opening square bracket"s };
    static rule<> square_bracket_close{ boost::spirit::qi::token( token_id::square_bracket_close ), "closing square bracket"s };

    //    non-terminals
    static grammar::start_type file;

    static rule< ast::expression > expression{ "expression"s };
    static rule< ast::operand > operand{ "operand"s };
    static rule< ast::operation > operation{ "operation"s };
    static rule< ast::binary_operation > binary_operation{ "binary operation"s };
    static rule< ast::unary_operation > unary_operation{ "unary operation"s };
    static rule< ast::if_expression > if_expression{ "if expression"s };
    static rule< ast::while_expression > while_expression{ "while expression"s };
    static rule< ast::call_expression > call_expression{ "call expression"s };
    static rule< ast::block_expression > block_expression{ "block expression"s };
    static rule< ast::parens_expression > parens_expression{ "parens expression"s };
    static rule< ast::index_expression > index_expression{ "index expression"s };

    grammar::grammar()
      : base_type( file, "perseus script"s )
    {
      // EOI = End of Input
      file %= expression > boost::spirit::qi::eoi;

      // what about operator_identifier? first class functions and all that?
      // this split is required to prevent left recursion, which in the parser turns into an infinite recursion.
      expression = operand >> *operation;
      operand = string | integer | identifier | unary_operation | if_expression | while_expression | block_expression | parens_expression;
      operation = binary_operation | call_expression | index_expression;
      {
        // x `op` y
        binary_operation = operator_identifier >> expression;

        // name( arg1, arg2 )
        // a % b means list of a separated by b; that has a minimum length of 1, thus the - (optional)
        call_expression = paren_open > -( expression % comma ) > paren_close;

        // object[index]
        index_expression = square_bracket_open > expression > square_bracket_close;

        // `op` x
        unary_operation = operator_identifier > expression;

        // if cond then_body else_body
        // Logically there's always an else, but it may be "nothing" (i.e. void).
        // > is an expectation concatenation: after an "if" terminal there *must* be an expression (allows for early abortion in case of errors and better errors)
        // this parsing is eager, i.e. `if c1 if c2 t else e` means `if c1 { if c2 t else e }`
        auto default_to_void = boost::spirit::qi::attr( ast::expression{ ast::void_expression{},{} } );
        if_expression = if_ > expression > expression > ( ( else_ > expression ) | default_to_void );

        // while cond body
        while_expression = while_ > expression > expression;

        // { exp1; exp2 }
        block_expression = brace_open > ( ( expression | default_to_void ) % semicolon ) > brace_close;

        // ( expression )
        parens_expression = paren_open > expression > paren_close;
      }
    }
  }
  namespace detail
  {
    using skip_rule = boost::spirit::qi::rule< token_iterator >;

    // terminals
    static skip_rule whitespace{ boost::spirit::qi::token( token_id::whitespace ), "whitespace"s };
    static skip_rule comment{ boost::spirit::qi::token( token_id::whitespace ), "comment"s };
    // start symbol
    static skip_grammar::start_type skip{ whitespace | comment };

    skip_grammar::skip_grammar()
      : base_type( skip )
    {
    }
  }
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <mapnik/raster_colorizer.hpp>

using mapnik::raster_colorizer;
using mapnik::raster_colorizer_ptr;
using mapnik::color_band;
using mapnik::color_bands;
using mapnik::color;

namespace {
void append_band1(raster_colorizer_ptr & rc, color_band b)
{
    rc->append_band(b);
}
void append_band2(raster_colorizer_ptr & rc, color_band b, unsigned m)
{
    rc->append_band(b, m);
}
void append_band3(raster_colorizer_ptr & rc, float v, color c)
{
    rc->append_band(v, c);
}
void append_band4(raster_colorizer_ptr & rc, float v, color c, unsigned m)
{
    rc->append_band(v, c, m);
}
void append_band5(raster_colorizer_ptr & rc, float v, float vm, color c, unsigned m)
{
    rc->append_band(v, vm, c, m);
}
void append_band6(raster_colorizer_ptr & rc, float v, float vm, color c)
{
    rc->append_band(v, vm, c);
}
color_bands const& get_color_bands(raster_colorizer_ptr & rc)
{
    return rc->get_color_bands();
}
}

void export_raster_colorizer()
{
    using namespace boost::python;

    class_<raster_colorizer,raster_colorizer_ptr>("RasterColorizer", init<>("Default ctor."))

        .add_property("bands",make_function
                      (get_color_bands,
                       return_value_policy<reference_existing_object>()))
        .def("append_band", append_band1, "TODO: Write docs")
        .def("append_band", append_band2, "TODO: Write docs")
        .def("append_band", append_band3, "TODO: Write docs")
        .def("append_band", append_band4, "TODO: Write docs")
        .def("append_band", append_band5, "TODO: Write docs")
        .def("append_band", append_band6, "TODO: Write docs")
        .def("get_color", &raster_colorizer::get_color, "TODO: Write docs")
        ;

    class_<color_bands>("ColorBands",init<>("Default ctor."))
        .def(vector_indexing_suite<color_bands>())
        ;

    class_<color_band>("ColorBand",
                       init<float,color const&>("Deafult ctor."))
        .add_property("color", make_function
                      (&color_band::get_color,
                       return_value_policy<reference_existing_object>()))
        .add_property("value", &color_band::get_value)
        .add_property("max_value", &color_band::get_max_value)
        .def(self == self)
        .def("__str__",&color_band::to_string)
        ;
}
<commit_msg>619_raster_colorizer_documentation.patch from tmcw - closes #619<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <mapnik/raster_colorizer.hpp>

using mapnik::raster_colorizer;
using mapnik::raster_colorizer_ptr;
using mapnik::color_band;
using mapnik::color_bands;
using mapnik::color;

namespace {
void append_band1(raster_colorizer_ptr & rc, color_band b)
{
    rc->append_band(b);
}
void append_band2(raster_colorizer_ptr & rc, color_band b, unsigned m)
{
    rc->append_band(b, m);
}
void append_band3(raster_colorizer_ptr & rc, float v, color c)
{
    rc->append_band(v, c);
}
void append_band4(raster_colorizer_ptr & rc, float v, color c, unsigned m)
{
    rc->append_band(v, c, m);
}
void append_band5(raster_colorizer_ptr & rc, float v, float vm, color c, unsigned m)
{
    rc->append_band(v, vm, c, m);
}
void append_band6(raster_colorizer_ptr & rc, float v, float vm, color c)
{
    rc->append_band(v, vm, c);
}
color_bands const& get_color_bands(raster_colorizer_ptr & rc)
{
    return rc->get_color_bands();
}
}

void export_raster_colorizer()
{
    using namespace boost::python;

    class_<raster_colorizer,raster_colorizer_ptr>("RasterColorizer", init<>("Default ctor."))

        .add_property("bands",make_function
                      (get_color_bands,
                       return_value_policy<reference_existing_object>()))
        .def("append_band", append_band1,
            (arg("color_band")),
            "Append a color band to the raster colorizer.\n"
            "\n"
            "Usage:\n"
            ">>> colorizer = mapnik.ColorBand()\n"
            ">>> color = mapnik.Color(\"#0044cc\")\n"
            ">>> color_band = mapnik.ColorBand(3, color)\n"
            ">>> colorizer.append_band(color_band)\n"
            )
        .def("append_band", append_band2,
            (arg("color_band"), arg("midpoint")),
            "Append a color band with a midpoint to the raster colorizer.\n"
            "\n"
            "Usage:\n"
            ">>> colorizer = mapnik.ColorBand()\n"
            ">>> color = mapnik.Color(\"#0044cc\")\n"
            ">>> color_band = mapnik.ColorBand(3, color)\n"
            ">>> colorizer.append_band(color_band, 1)\n"
            )
        .def("append_band", append_band3,
            (arg("value"), arg("color")),
            "Append a color for a specific value to the raster colorizer\n"
            "\n"
            "Usage:\n"
            ">>> colorizer = mapnik.RasterColorizer()\n"
            ">>> color = mapnik.Color(\"#0044cc\")\n"
            ">>> colorizer.append_band(30, color)\n"
            )
        .def("append_band", append_band4,
            (arg("value"), arg("color"), arg("midpoints")),
            "Append a color for a certain value to the raster colorizer,\n"
            "with a specified midpoint.\n"
            "\n"
            "Usage:\n"
            ">>> colorizer = mapnik.RasterColorizer()\n"
            ">>> color = mapnik.Color(\"#0044cc\")\n"
            ">>> colorizer.append_band(30, color, 4)\n"
            )
        .def("append_band", append_band5,
            (arg("value"), arg("value_max"), arg("color"), arg("midpoints")),
            "Append a color for a value range from value to value_max\n"
            "to the raster colorizer, with a specified midpoint.\n"
            "\n"
            "Usage:\n"
            ">>> colorizer = mapnik.RasterColorizer()\n"
            ">>> color = mapnik.Color(\"#0044cc\")\n"
            ">>> colorizer.append_band(30, 40, color, 4)\n"
            )
        .def("append_band", append_band6,
            (arg("value"), arg("value_max"), arg("color")),
            "Append a color for a value range from value to value_max\n"
            "to the raster colorizer.\n"
            "\n"
            "Usage:\n"
            ">>> colorizer = mapnik.RasterColorizer()\n"
            ">>> color = mapnik.Color(\"#0044cc\")\n"
            ">>> colorizer.append_band(30, 40, color)\n"
            )
        .def("get_color", &raster_colorizer::get_color,
            "Get the color assigned to a certain value in raster data.\n"
            "By default, returns Color(\"transparent\")\n"
            "\n"
            "Usage:\n"
            ">>> colorizer = mapnik.RasterColorizer()\n"
            ">>> color = mapnik.Color(\"#0044cc\")\n"
            ">>> colorizer.append_band(30, 40, color)\n"
            ">>> colorizer.get_color(35)\n"
            "Color('#0044cc')\n"
            )
        ;

    class_<color_bands>("ColorBands",init<>("Default ctor."))
        .def(vector_indexing_suite<color_bands>())
        ;

    class_<color_band>("ColorBand",init<float,color const&>(
                       "A Color Band object.\n"
                       "Create with a value and color\n"
                       "\n"
                       "Usage:"
                       ">>> color = mapnik.Color(\"#fff000\")\n"
                       ">>> color_band = mapnik.ColorBand(4, color)\n"
          ))
        .add_property("color", make_function
                      (&color_band::get_color,
                       return_value_policy<reference_existing_object>()))
        .add_property("value", &color_band::get_value)
        .add_property("max_value", &color_band::get_max_value)
        .def(self == self)
        .def("__str__",&color_band::to_string)
        ;
}
<|endoftext|>