<commit_before>//=======================================================================
// Copyright (c) 2013-2014 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>

#include "report.hpp"
#include "expenses.hpp"
#include "earnings.hpp"
#include "budget_exception.hpp"
#include "accounts.hpp"

using namespace budget;

namespace {

typedef std::vector<std::vector<std::string>> graph_type;

void render(graph_type& graph){
    std::reverse(graph.begin(), graph.end());

    for(auto& line : graph){
        for(auto& col : line){
            std::cout << col;
        }
        std::cout << std::endl;
    }
}

void write(graph_type& graph, int row, int col, const std::string& value){
    for(std::size_t i = 0; i < value.size(); ++i){
        graph[row][col + i] = value[i];
    }
}

void monthly_report(budget::year year){
    auto today = budget::local_day();

    budget::money max_expenses;
    budget::money max_earnings;
    budget::money max_balance;
    budget::money min_expenses;
    budget::money min_earnings;
    budget::money min_balance;

    auto sm = start_month(year);

    std::vector<int> expenses(13);
    std::vector<int> earnings(13);
    std::vector<int> balances(13);

    for(unsigned short i = sm + 1; i < today.month() + 1; ++i){
        budget::month month = i;

        budget::money total_expenses;
        budget::money total_earnings;
        budget::money total_balance;

        for(auto& account : all_accounts(year, month)){
            auto expenses = accumulate_amount_if(all_expenses(),
                [year,month,account](budget::expense& e){return e.account == account.id && e.date.year() == year && e.date.month() == month;});
            auto earnings = accumulate_amount_if(all_earnings(),
                [year,month,account](budget::earning& e){return e.account == account.id && e.date.year() == year && e.date.month() == month;});

            total_expenses += expenses;
            total_earnings += earnings;

            auto balance = account.amount;
            balance -= expenses;
            balance += earnings;

            total_balance += balance;
        }

        expenses[month] = total_expenses.dollars();
        earnings[month] = total_earnings.dollars();
        balances[month] = total_balance.dollars();

        max_expenses = std::max(max_expenses, total_expenses);
        max_earnings = std::max(max_earnings, total_earnings);
        max_balance = std::max(max_balance, total_balance);
        min_expenses = std::min(min_expenses, total_expenses);
        min_earnings = std::min(min_earnings, total_earnings);
        min_balance = std::min(min_balance, total_balance);
    }

    auto height = terminal_height() - 9;
    //auto width = terminal_width() - 6;

    //TODO compute the scale based on the data
    unsigned int scale = 1000;
    unsigned int scale_width = 5;

    int min = 0;
    if(min_expenses.negative() || min_earnings.negative() || min_balance.negative()){
        min = std::min(min_expenses, std::min(min_earnings, min_balance)).dollars();
        min = -1 * ((std::abs(min) / scale) + 1) * scale;
    }

    unsigned int max = std::max(max_earnings, std::max(max_expenses, max_balance)).dollars();
    max = ((max / scale) + 1) * scale;

    unsigned int levels = max / scale + std::abs(min) / scale;

    unsigned int step_height = height / levels;
    unsigned int precision = scale / step_height;

    auto graph_height = 9 + step_height * levels;
    auto graph_width = 6 + (13 - sm) * 8 + (13 - sm - 1) * 2;

    graph_type graph(graph_height, std::vector<std::string>(graph_width, " "));

    //Display graph title

    write(graph, graph_height - 2, 8, "Monthly report of " + to_string(year));

    //Display scale

    for(size_t i = 0; i <= levels; ++i){
        int level = min + i * scale;

        write(graph, 4 + step_height * i, 1, to_string(level));
    }

    //Display bar

    unsigned int min_index = 3;
    unsigned int zero_index = min_index + 1 + (std::abs(min) / scale) * step_height;

    auto first_bar = scale_width + 2;

    //TODO Choose bar width based on the terminal width

    for(unsigned short i = sm + 1; i < today.month() + 1; ++i){
        budget::month month = i;

        auto col_start = first_bar + 10 * (i - sm - 1);

        //Display month legend
        auto month_str = month.as_short_string();
        write(graph, 1, col_start + 2, month_str);

        for(std::size_t j = 0; j < expenses[month] / precision; ++j){
           graph[zero_index + j][col_start] = "\033[1;41m \033[0m";
           graph[zero_index + j][col_start + 1] = "\033[1;41m \033[0m";
        }

        col_start += 3;

        for(std::size_t j = 0; j < earnings[month] / precision; ++j){
           graph[zero_index + j][col_start] = "\033[1;42m \033[0m";
           graph[zero_index + j][col_start + 1] = "\033[1;42m \033[0m";
        }

        col_start += 3;

        if(balances[month] >= 0){
            for(std::size_t j = 0; j < balances[month] / precision; ++j){
                graph[zero_index + j][col_start] = "\033[1;44m \033[0m";
                graph[zero_index + j][col_start + 1] = "\033[1;44m \033[0m";
            }
        } else {
            for(std::size_t j = 0; j < std::abs(balances[month]) / precision; ++j){
                graph[zero_index - 1 - j][col_start] = "\033[1;44m \033[0m";
                graph[zero_index - 1 - j][col_start + 1] = "\033[1;44m \033[0m";
            }
        }
    }

    //Display legend

    int start_legend = first_bar + 10 * (today.month() - sm) + 4;

    graph[4][start_legend - 2] = "|";
    graph[3][start_legend - 2] = "|";
    graph[2][start_legend - 2] = "|";

    graph[4][start_legend] = "\033[1;41m \033[0m";
    graph[3][start_legend] = "\033[1;42m \033[0m";
    graph[2][start_legend] = "\033[1;44m \033[0m";

    write(graph, 6, start_legend - 2, " ____________ ");
    write(graph, 5, start_legend - 2, "|            |");
    write(graph, 4, start_legend + 2, "Expenses |");
    write(graph, 3, start_legend + 2, "Earnings |");
    write(graph, 2, start_legend + 2, "Balance  |");
    write(graph, 1, start_legend - 2, "|____________|");

    //Render the graph

    render(graph);
}

} //end of anonymous namespace

void budget::report_module::load(){
    load_accounts();
    load_expenses();
    load_earnings();
}

void budget::report_module::handle(const std::vector<std::string>& args){
    auto today = budget::local_day();

    if(args.size() == 1){
        monthly_report(today.year());
    } else {
        auto& subcommand = args[1];

        if(subcommand == "monthly"){
            monthly_report(today.year());
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}
<commit_msg>Prepare report account<commit_after>//=======================================================================
// Copyright (c) 2013-2014 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>

#include "report.hpp"
#include "expenses.hpp"
#include "earnings.hpp"
#include "budget_exception.hpp"
#include "accounts.hpp"

using namespace budget;

namespace {

typedef std::vector<std::vector<std::string>> graph_type;

void render(graph_type& graph){
    std::reverse(graph.begin(), graph.end());

    for(auto& line : graph){
        for(auto& col : line){
            std::cout << col;
        }
        std::cout << std::endl;
    }
}

void write(graph_type& graph, int row, int col, const std::string& value){
    for(std::size_t i = 0; i < value.size(); ++i){
        graph[row][col + i] = value[i];
    }
}

void monthly_report(budget::year year){
    auto today = budget::local_day();

    budget::money max_expenses;
    budget::money max_earnings;
    budget::money max_balance;
    budget::money min_expenses;
    budget::money min_earnings;
    budget::money min_balance;

    auto sm = start_month(year);

    std::vector<int> expenses(13);
    std::vector<int> earnings(13);
    std::vector<int> balances(13);

    for(unsigned short i = sm + 1; i < today.month() + 1; ++i){
        budget::month month = i;

        budget::money total_expenses;
        budget::money total_earnings;
        budget::money total_balance;

        for(auto& account : all_accounts(year, month)){
            auto expenses = accumulate_amount_if(all_expenses(),
                [year,month,account](budget::expense& e){return e.account == account.id && e.date.year() == year && e.date.month() == month;});
            auto earnings = accumulate_amount_if(all_earnings(),
                [year,month,account](budget::earning& e){return e.account == account.id && e.date.year() == year && e.date.month() == month;});

            total_expenses += expenses;
            total_earnings += earnings;

            auto balance = account.amount;
            balance -= expenses;
            balance += earnings;

            total_balance += balance;
        }

        expenses[month] = total_expenses.dollars();
        earnings[month] = total_earnings.dollars();
        balances[month] = total_balance.dollars();

        max_expenses = std::max(max_expenses, total_expenses);
        max_earnings = std::max(max_earnings, total_earnings);
        max_balance = std::max(max_balance, total_balance);
        min_expenses = std::min(min_expenses, total_expenses);
        min_earnings = std::min(min_earnings, total_earnings);
        min_balance = std::min(min_balance, total_balance);
    }

    auto height = terminal_height() - 9;
    //auto width = terminal_width() - 6;

    //TODO compute the scale based on the data
    unsigned int scale = 1000;
    unsigned int scale_width = 5;

    int min = 0;
    if(min_expenses.negative() || min_earnings.negative() || min_balance.negative()){
        min = std::min(min_expenses, std::min(min_earnings, min_balance)).dollars();
        min = -1 * ((std::abs(min) / scale) + 1) * scale;
    }

    unsigned int max = std::max(max_earnings, std::max(max_expenses, max_balance)).dollars();
    max = ((max / scale) + 1) * scale;

    unsigned int levels = max / scale + std::abs(min) / scale;

    unsigned int step_height = height / levels;
    unsigned int precision = scale / step_height;

    auto graph_height = 9 + step_height * levels;
    auto graph_width = 6 + (13 - sm) * 8 + (13 - sm - 1) * 2;

    graph_type graph(graph_height, std::vector<std::string>(graph_width, " "));

    //Display graph title

    write(graph, graph_height - 2, 8, "Monthly report of " + to_string(year));

    //Display scale

    for(size_t i = 0; i <= levels; ++i){
        int level = min + i * scale;

        write(graph, 4 + step_height * i, 1, to_string(level));
    }

    //Display bar

    unsigned int min_index = 3;
    unsigned int zero_index = min_index + 1 + (std::abs(min) / scale) * step_height;

    auto first_bar = scale_width + 2;

    //TODO Choose bar width based on the terminal width

    for(unsigned short i = sm + 1; i < today.month() + 1; ++i){
        budget::month month = i;

        auto col_start = first_bar + 10 * (i - sm - 1);

        //Display month legend
        auto month_str = month.as_short_string();
        write(graph, 1, col_start + 2, month_str);

        for(std::size_t j = 0; j < expenses[month] / precision; ++j){
           graph[zero_index + j][col_start] = "\033[1;41m \033[0m";
           graph[zero_index + j][col_start + 1] = "\033[1;41m \033[0m";
        }

        col_start += 3;

        for(std::size_t j = 0; j < earnings[month] / precision; ++j){
           graph[zero_index + j][col_start] = "\033[1;42m \033[0m";
           graph[zero_index + j][col_start + 1] = "\033[1;42m \033[0m";
        }

        col_start += 3;

        if(balances[month] >= 0){
            for(std::size_t j = 0; j < balances[month] / precision; ++j){
                graph[zero_index + j][col_start] = "\033[1;44m \033[0m";
                graph[zero_index + j][col_start + 1] = "\033[1;44m \033[0m";
            }
        } else {
            for(std::size_t j = 0; j < std::abs(balances[month]) / precision; ++j){
                graph[zero_index - 1 - j][col_start] = "\033[1;44m \033[0m";
                graph[zero_index - 1 - j][col_start + 1] = "\033[1;44m \033[0m";
            }
        }
    }

    //Display legend

    int start_legend = first_bar + 10 * (today.month() - sm) + 4;

    graph[4][start_legend - 2] = "|";
    graph[3][start_legend - 2] = "|";
    graph[2][start_legend - 2] = "|";

    graph[4][start_legend] = "\033[1;41m \033[0m";
    graph[3][start_legend] = "\033[1;42m \033[0m";
    graph[2][start_legend] = "\033[1;44m \033[0m";

    write(graph, 6, start_legend - 2, " ____________ ");
    write(graph, 5, start_legend - 2, "|            |");
    write(graph, 4, start_legend + 2, "Expenses |");
    write(graph, 3, start_legend + 2, "Earnings |");
    write(graph, 2, start_legend + 2, "Balance  |");
    write(graph, 1, start_legend - 2, "|____________|");

    //Render the graph

    render(graph);
}

void account_report(const std::string& account){
    //TODO
}

} //end of anonymous namespace

void budget::report_module::load(){
    load_accounts();
    load_expenses();
    load_earnings();
}

void budget::report_module::handle(const std::vector<std::string>& args){
    auto today = budget::local_day();

    if(args.size() == 1){
        monthly_report(today.year());
    } else {
        auto& subcommand = args[1];

        if(subcommand == "monthly"){
            monthly_report(today.year());
        } else if(subcommand == "account"){
            if(args.size() == 3){
                account_report(args[2]);
            } else {
                throw budget_exception("Invalid number of parameters");
            }
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}
<|endoftext|>


<commit_before>#pragma once

#include "cpputil.hh"
#include "ns.hh"
#include "gc.hh"
#include <atomic>
#include "refcache.hh"
#include "condvar.h"
#include "semaphore.h"
#include "seqlock.hh"
#include "mfs.hh"

class dirns;

u64 namehash(const strbuf<DIRSIZ>&);

struct file : public rcu_freed {
  virtual int stat(struct stat*) { return -1; }
  virtual ssize_t read(char *addr, size_t n) { return -1; }
  virtual ssize_t write(const char *addr, size_t n) { return -1; }
  virtual ssize_t pread(char *addr, size_t n, off_t offset) { return -1; }
  virtual ssize_t pwrite(const char *addr, size_t n, off_t offset) { return -1; }

  virtual void inc() = 0;
  virtual void dec() = 0;

protected:
  file() : rcu_freed("file") {}

  void do_gc(void) override { delete this; }
};

struct file_inode : public refcache::referenced, public file {
public:
  file_inode(sref<mnode> i, bool r, bool w, bool a)
    : ip(i), readable(r), writable(w), append(a), off(0) {}
  NEW_DELETE_OPS(file_inode);

  void inc() override { refcache::referenced::inc(); }
  void dec() override { refcache::referenced::dec(); }

  sref<mnode> ip;
  const bool readable;
  const bool writable;
  const bool append;
  u32 off;

  int stat(struct stat*) override;
  ssize_t read(char *addr, size_t n) override;
  ssize_t write(const char *addr, size_t n) override;
  ssize_t pread(char* addr, size_t n, off_t off) override;
  ssize_t pwrite(const char *addr, size_t n, off_t offset) override;
  void onzero() override;
};

struct file_socket : public referenced, public file {
public:
  file_socket() : socket(0), localsock(nullptr),
                  wsem("file::wsem", 1), rsem("file::rsem", 1) {}
  NEW_DELETE_OPS(file_socket);

  void inc() override { referenced::inc(); }
  void dec() override { referenced::dec(); }

  int socket;
  struct localsock *localsock;
  char socketpath[UNIX_PATH_MAX];

  ssize_t read(char *addr, size_t n) override;
  ssize_t write(const char *addr, size_t n) override;
  void onzero() override;

private:
  // XXX This locking should be handled in net, not here.
  semaphore wsem, rsem;
};

struct file_pipe_reader : public refcache::referenced, public file {
public:
  file_pipe_reader(pipe* p) : pipe(p) {}
  NEW_DELETE_OPS(file_pipe_reader);

  void inc() override { refcache::referenced::inc(); }
  void dec() override { refcache::referenced::dec(); }

  ssize_t read(char *addr, size_t n) override;
  void onzero() override;

private:
  struct pipe* const pipe;
};

struct file_pipe_writer : public referenced, public file {
public:
  file_pipe_writer(pipe* p) : pipe(p) {}
  NEW_DELETE_OPS(file_pipe_writer);

  void inc() override { referenced::inc(); }
  void dec() override { referenced::dec(); }

  ssize_t write(const char *addr, size_t n) override;
  void onzero() override;

private:
  struct pipe* const pipe;
};

// in-core file system types
struct inode : public referenced, public rcu_freed
{
  void  init();
  void  link();
  void  unlink();
  short nlink();

  inode& operator=(const inode&) = delete;
  inode(const inode& x) = delete;

  void do_gc() override { delete this; }

  // const for lifetime of object:
  const u32 dev;
  const u32 inum;

  // const unless inode is reused:
  u32 gen;
  std::atomic<short> type;
  short major;
  short minor;

  // locks for the rest of the inode
  seqcount<u64> seq;
  struct condvar cv;
  struct spinlock lock;
  char lockname[16];

  // initially null, set once:
  std::atomic<dirns*> dir;
  std::atomic<bool> valid;

  // protected by seq/lock:
  std::atomic<bool> busy;
  std::atomic<int> readbusy;

  u32 size;
  std::atomic<u32> addrs[NDIRECT+2];
  std::atomic<volatile u32*> iaddrs;
  short nlink_;

  // ??? what's the concurrency control plan?
  struct localsock *localsock;
  char socketpath[PATH_MAX];

private:
  inode(u32 dev, u32 inum);
  ~inode();
  NEW_DELETE_OPS(inode)

  static sref<inode> alloc(u32 dev, u32 inum);
  friend void initinode();
  friend sref<inode> iget(u32, u32);

protected:
  void onzero() override;
};

// device implementations

class mdev;

struct devsw {
  int (*read)(mdev*, char*, u32, u32);
  int (*write)(mdev*, const char*, u32, u32);
  void (*stat)(mdev*, struct stat*);
};

extern struct devsw devsw[];
<commit_msg>fix file subclass operator delete<commit_after>#pragma once

#include "cpputil.hh"
#include "ns.hh"
#include "gc.hh"
#include <atomic>
#include "refcache.hh"
#include "condvar.h"
#include "semaphore.h"
#include "seqlock.hh"
#include "mfs.hh"

class dirns;

u64 namehash(const strbuf<DIRSIZ>&);

struct file : public rcu_freed {
  virtual int stat(struct stat*) { return -1; }
  virtual ssize_t read(char *addr, size_t n) { return -1; }
  virtual ssize_t write(const char *addr, size_t n) { return -1; }
  virtual ssize_t pread(char *addr, size_t n, off_t offset) { return -1; }
  virtual ssize_t pwrite(const char *addr, size_t n, off_t offset) { return -1; }

  virtual void inc() = 0;
  virtual void dec() = 0;

protected:
  file() : rcu_freed("file") {}
};

struct file_inode : public refcache::referenced, public file {
public:
  file_inode(sref<mnode> i, bool r, bool w, bool a)
    : ip(i), readable(r), writable(w), append(a), off(0) {}
  NEW_DELETE_OPS(file_inode);

  void inc() override { refcache::referenced::inc(); }
  void dec() override { refcache::referenced::dec(); }

  sref<mnode> ip;
  const bool readable;
  const bool writable;
  const bool append;
  u32 off;

  int stat(struct stat*) override;
  ssize_t read(char *addr, size_t n) override;
  ssize_t write(const char *addr, size_t n) override;
  ssize_t pread(char* addr, size_t n, off_t off) override;
  ssize_t pwrite(const char *addr, size_t n, off_t offset) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }
};

struct file_socket : public referenced, public file {
public:
  file_socket() : socket(0), localsock(nullptr),
                  wsem("file::wsem", 1), rsem("file::rsem", 1) {}
  NEW_DELETE_OPS(file_socket);

  void inc() override { referenced::inc(); }
  void dec() override { referenced::dec(); }

  int socket;
  struct localsock *localsock;
  char socketpath[UNIX_PATH_MAX];

  ssize_t read(char *addr, size_t n) override;
  ssize_t write(const char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  // XXX This locking should be handled in net, not here.
  semaphore wsem, rsem;
};

struct file_pipe_reader : public refcache::referenced, public file {
public:
  file_pipe_reader(pipe* p) : pipe(p) {}
  NEW_DELETE_OPS(file_pipe_reader);

  void inc() override { refcache::referenced::inc(); }
  void dec() override { refcache::referenced::dec(); }

  ssize_t read(char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  struct pipe* const pipe;
};

struct file_pipe_writer : public referenced, public file {
public:
  file_pipe_writer(pipe* p) : pipe(p) {}
  NEW_DELETE_OPS(file_pipe_writer);

  void inc() override { referenced::inc(); }
  void dec() override { referenced::dec(); }

  ssize_t write(const char *addr, size_t n) override;
  void onzero() override;

protected:
  void do_gc(void) override { delete this; }

private:
  struct pipe* const pipe;
};

// in-core file system types
struct inode : public referenced, public rcu_freed
{
  void  init();
  void  link();
  void  unlink();
  short nlink();

  inode& operator=(const inode&) = delete;
  inode(const inode& x) = delete;

  void do_gc() override { delete this; }

  // const for lifetime of object:
  const u32 dev;
  const u32 inum;

  // const unless inode is reused:
  u32 gen;
  std::atomic<short> type;
  short major;
  short minor;

  // locks for the rest of the inode
  seqcount<u64> seq;
  struct condvar cv;
  struct spinlock lock;
  char lockname[16];

  // initially null, set once:
  std::atomic<dirns*> dir;
  std::atomic<bool> valid;

  // protected by seq/lock:
  std::atomic<bool> busy;
  std::atomic<int> readbusy;

  u32 size;
  std::atomic<u32> addrs[NDIRECT+2];
  std::atomic<volatile u32*> iaddrs;
  short nlink_;

  // ??? what's the concurrency control plan?
  struct localsock *localsock;
  char socketpath[PATH_MAX];

private:
  inode(u32 dev, u32 inum);
  ~inode();
  NEW_DELETE_OPS(inode)

  static sref<inode> alloc(u32 dev, u32 inum);
  friend void initinode();
  friend sref<inode> iget(u32, u32);

protected:
  void onzero() override;
};

// device implementations

class mdev;

struct devsw {
  int (*read)(mdev*, char*, u32, u32);
  int (*write)(mdev*, const char*, u32, u32);
  void (*stat)(mdev*, struct stat*);
};

extern struct devsw devsw[];
<|endoftext|>


<commit_before>/*
Copyright (c) 2015-2017 by the parties listed in the AUTHORS file.
All rights reserved.  Use of this source code is governed by
a BSD-style license that can be found in the LICENSE file.
*/

#include <toast_tod_internal.hpp>

#include <sstream>
#include <iostream>
#include <iomanip>

void toast::filter::polyfilter(
    const long order, double **signals, uint8_t *flags,
    const size_t n, const size_t nsignal,
    const long *starts, const long *stops, const size_t nscan ) {

    // Process the signals, one subscan at a time.  There is only one
    // flag vector, because the flags must be identical to apply the
    // same template matrix.

    char upper = 'U';
    char lower = 'L';
    char notrans = 'N';
    char trans = 'T';
    char diag = 'U';
    char nodiag = 'N';
    double fzero = 0.0;
    double fone = 1.0;
    int one = 1;
    int zero = 0;

    int norder = order + 1;

#pragma omp parallel for schedule(static)
    for ( int iscan=0; iscan<nscan; ++iscan ) {
        int start = starts[iscan];
        int stop = stops[iscan];
        if ( start < 0 ) start = 0;
        if ( stop > n-1 ) stop = n-1;
        if ( stop < start ) continue;
        int scanlen = stop - start + 1;

        // Build the template matrix

        double *templates = static_cast< double* >(
            toast::mem::aligned_alloc (
                scanlen*norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        double dx = 2. / scanlen;
        double xstart = 0.5*dx - 1;
        for ( int i=0; i<scanlen; ++i ) {
            if ( flags[start+i] ) continue;
            double x = xstart + i*dx;
            int offset = i*norder;
            if ( norder > 0 ) templates[offset++] = 1;
            if ( norder > 1 ) templates[offset++] = x;
            for ( int iorder=1; iorder<norder-1; ++iorder ) {
                templates[offset] =
                    ((2*iorder+1)*x*templates[offset-1]
                     - iorder*templates[offset-2]) / (iorder+1);
                ++offset;
            }
        }

        double *cov = static_cast< double* >(
            toast::mem::aligned_alloc (
                norder*norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        // invcov = templates x templates.T

        toast::lapack::syrk( &upper, &notrans, &norder, &scanlen, &fone,
                             templates, &norder, &fzero, cov,
                             &norder );

        // invert cov = invcov^-1 using LU decomposition

        int info = 0;
        toast::lapack::potrf( &upper, &norder, cov, &norder, &info );
        if ( info == 0 ) {
            toast::lapack::potri( &upper, &norder, cov, &norder, &info );
        }

        if ( info ) {
            // The matrix is singular.  Raise the appropriate quality
            // flags.
            for ( int i=0; i<scanlen; ++i ) {
                flags[start+i] = 255;
            }
            continue;
        }

        // Symmetrize for dgemv later on (workaround for dtrmv issue)

        for ( int row=0; row<norder; ++row ) {
          for ( int col=row+1; col<norder; ++col ) {
            cov[row*norder + col] = cov[col*norder + row];
          }
        }

        // Filter every signal

        double *proj = static_cast< double* >(
            toast::mem::aligned_alloc (
                norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        double *coeff = static_cast< double* >(
            toast::mem::aligned_alloc (
                norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        double *noise = static_cast< double* >(
            toast::mem::aligned_alloc (
                scanlen*sizeof(double), toast::mem::SIMD_ALIGN ) );

        for ( int isignal=0; isignal<nsignal; ++isignal ) {
            double *signal = signals[isignal] + start;

            // proj = templates x signal

            toast::lapack::gemv( &notrans, &norder, &scanlen, &fone, templates,
                                 &norder, signal, &one, &fzero, proj, &one );

            // coeff = cov x proj

            // For whatever reason, trmv refused to yield the right answer...
            // Use general matrix vector multiply instead

            //toast::lapack::trmv( &upper, &trans, &nodiag, &norder, cov,
            //                     &norder, coeff, &one );

            toast::lapack::gemv( &trans, &norder, &norder, &fone,
                                 cov, &norder, proj, &one,
                                 &fzero, coeff, &one );

            // noise = templates.T x coeff

            toast::lapack::gemv( &trans, &norder, &scanlen, &fone, templates,
                                 &norder, coeff, &one, &fzero, noise, &one );

            // Subtract noise

            for ( int i=0; i<scanlen; ++i ) signal[i] -= noise[i];
        }

        // Free workspace

        toast::mem::aligned_free( templates );
        toast::mem::aligned_free( cov );
        toast::mem::aligned_free( proj );
        toast::mem::aligned_free( coeff );
        toast::mem::aligned_free( noise );

    }

    return;
}
<commit_msg>Modify the polynomial filter to handle flagging more intuitively.<commit_after>/*
Copyright (c) 2015-2017 by the parties listed in the AUTHORS file.
All rights reserved.  Use of this source code is governed by
a BSD-style license that can be found in the LICENSE file.
*/

#include <toast_tod_internal.hpp>

#include <sstream>
#include <iostream>
#include <iomanip>

void toast::filter::polyfilter(
    const long order, double **signals, uint8_t *flags,
    const size_t n, const size_t nsignal,
    const long *starts, const long *stops, const size_t nscan ) {

    // Process the signals, one subscan at a time.  There is only one
    // flag vector, because the flags must be identical to apply the
    // same template matrix.

    char upper = 'U';
    char lower = 'L';
    char notrans = 'N';
    char trans = 'T';
    char diag = 'U';
    char nodiag = 'N';
    double fzero = 0.0;
    double fone = 1.0;
    int one = 1;
    int zero = 0;

    int norder = order + 1;

#pragma omp parallel for schedule(static)
    for ( int iscan=0; iscan<nscan; ++iscan ) {
        int start = starts[iscan];
        int stop = stops[iscan];
        if ( start < 0 ) start = 0;
        if ( stop > n-1 ) stop = n-1;
        if ( stop < start ) continue;
        int scanlen = stop - start + 1;

        // Build the full template matrix used to clean the signal.
        // We subtract the template value even from flagged samples to
        // support point source masking etc.

        double *full_templates = static_cast< double* >(
            toast::mem::aligned_alloc (
                scanlen*norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        double dx = 2. / scanlen;
        double xstart = 0.5*dx - 1;
        for ( int i=0; i<scanlen; ++i ) {
            double x = xstart + i*dx;
            int offset = i*norder;
            if ( norder > 0 ) full_templates[offset++] = 1;
            if ( norder > 1 ) full_templates[offset++] = x;
            for ( int iorder=1; iorder<norder-1; ++iorder ) {
                full_templates[offset] =
                    ((2*iorder+1)*x*full_templates[offset-1]
                     - iorder*full_templates[offset-2]) / (iorder+1);
                ++offset;
            }
        }

        // Assemble the flagged template matrix used in the linear regression

        double *templates = static_cast< double* >(
            toast::mem::aligned_alloc (
                scanlen*norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        for ( int i=0; i<scanlen; ++i ) {
            if ( flags[start+i] ) continue;
            for ( int offset=i*norder; offset<(i+1)*norder; ++offset )
                templates[offset] = full_templates[offset];
        }

        double *cov = static_cast< double* >(
            toast::mem::aligned_alloc (
                norder*norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        // invcov = templates x templates.T

        toast::lapack::syrk( &upper, &notrans, &norder, &scanlen, &fone,
                             templates, &norder, &fzero, cov,
                             &norder );

        // invert cov = invcov^-1 using LU decomposition

        int info = 0;
        toast::lapack::potrf( &upper, &norder, cov, &norder, &info );
        if ( info == 0 ) {
            toast::lapack::potri( &upper, &norder, cov, &norder, &info );
        }

        if ( info ) {
            // The matrix is singular.  Raise the appropriate quality
            // flags.
            for ( int i=0; i<scanlen; ++i ) {
                flags[start+i] = 255;
            }
            continue;
        }

        // Symmetrize for dgemv later on (workaround for dtrmv issue)

        for ( int row=0; row<norder; ++row ) {
          for ( int col=row+1; col<norder; ++col ) {
            cov[row*norder + col] = cov[col*norder + row];
          }
        }

        // Filter every signal

        double *proj = static_cast< double* >(
            toast::mem::aligned_alloc (
                norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        double *coeff = static_cast< double* >(
            toast::mem::aligned_alloc (
                norder*sizeof(double), toast::mem::SIMD_ALIGN ) );

        double *noise = static_cast< double* >(
            toast::mem::aligned_alloc (
                scanlen*sizeof(double), toast::mem::SIMD_ALIGN ) );

        for ( int isignal=0; isignal<nsignal; ++isignal ) {
            double *signal = signals[isignal] + start;

            // proj = templates x signal

            toast::lapack::gemv( &notrans, &norder, &scanlen, &fone, templates,
                                 &norder, signal, &one, &fzero, proj, &one );

            // coeff = cov x proj

            // For whatever reason, trmv refused to yield the right answer...
            // Use general matrix vector multiply instead

            //toast::lapack::trmv( &upper, &trans, &nodiag, &norder, cov,
            //                     &norder, coeff, &one );

            toast::lapack::gemv( &trans, &norder, &norder, &fone,
                                 cov, &norder, proj, &one,
                                 &fzero, coeff, &one );

            // noise = templates.T x coeff

            toast::lapack::gemv( &trans, &norder, &scanlen, &fone,
                                 full_templates, &norder, coeff, &one, &fzero,
                                 noise, &one );

            // Subtract noise

            for ( int i=0; i<scanlen; ++i ) signal[i] -= noise[i];
        }

        // Free workspace

        toast::mem::aligned_free( full_templates );
        toast::mem::aligned_free( templates );
        toast::mem::aligned_free( cov );
        toast::mem::aligned_free( proj );
        toast::mem::aligned_free( coeff );
        toast::mem::aligned_free( noise );

    }

    return;
}
<|endoftext|>


<commit_before>#pragma once

#include <pip/syntax.hpp>

#include <sexpr/translation.hpp>

namespace pip
{

  // Performs a first-pass translation of an s-expression program into a
  // StackVM program.
  class translator : public sexpr::translator<translator>
  {
    friend class sexpr::translator<translator>;
  public:
    translator(context& cxt);

    decl* operator()(const sexpr::expr* e) { return trans_program(e); }

		expr* translate_expr(const sexpr::expr* e);
		expr* translate_range_expr(const sexpr::expr* e);
		expr* translate_wild_expr(const sexpr::expr* e);
		expr* translate_miss_expr(const sexpr::expr* e);
		expr* translate_ref_expr(const sexpr::expr* e);
		expr* translate_field_expr(const sexpr::expr* e);
		expr* translate_int_expr(const sexpr::int_expr* e);

  private:
    decl* trans_program(const sexpr::expr* e);
    decl_seq trans_decls(const sexpr::expr* e);
    decl* trans_decl(const sexpr::expr* e);
    decl* trans_table(const sexpr::list_expr* e);

    match_seq trans_matches(const sexpr::expr* e);
    match_seq trans_matches(const sexpr::list_expr* e);

  private:
    // Matching extensions
    using sexpr::translator<translator>::match;

    void match(const sexpr::list_expr* list, int n, decl_seq* decls);
    void match(const sexpr::list_expr* list, int n, match_seq* matches);

  private:
    context& cxt;
  };

} // namespace pip
<commit_msg>changed expr headers to fit naming convention<commit_after>#pragma once

#include <pip/syntax.hpp>

#include <sexpr/translation.hpp>

namespace pip
{

  // Performs a first-pass translation of an s-expression program into a
  // StackVM program.
  class translator : public sexpr::translator<translator>
  {
    friend class sexpr::translator<translator>;
  public:
    translator(context& cxt);

    decl* operator()(const sexpr::expr* e) { return trans_program(e); }

		expr* trans_expr(const sexpr::expr* e);
		expr* trans_range_expr(const sexpr::expr* e);
		expr* trans_wild_expr(const sexpr::expr* e);
		expr* trans_miss_expr(const sexpr::expr* e);
		expr* trans_ref_expr(const sexpr::expr* e);
		expr* trans_field_expr(const sexpr::expr* e);
		expr* trans_int_expr(const sexpr::int_expr* e);

  private:
    decl* trans_program(const sexpr::expr* e);
    decl_seq trans_decls(const sexpr::expr* e);
    decl* trans_decl(const sexpr::expr* e);
    decl* trans_table(const sexpr::list_expr* e);

    match_seq trans_matches(const sexpr::expr* e);
    match_seq trans_matches(const sexpr::list_expr* e);

  private:
    // Matching extensions
    using sexpr::translator<translator>::match;

    void match(const sexpr::list_expr* list, int n, decl_seq* decls);
    void match(const sexpr::list_expr* list, int n, match_seq* matches);

  private:
    context& cxt;
  };

} // namespace pip
<|endoftext|>


<commit_before>/* Copyright (c) 2006, NIF File Format Library and Tools
All rights reserved.  Please see niflib.h for licence. */

#include "NiTriBasedGeomData.h"
#include "NiObject.h"
using namespace Niflib;

//Definition of TYPE constant
const Type NiTriBasedGeomData::TYPE("NiTriBasedGeomData", &NI_TRI_BASED_GEOM_DATA_PARENT::TypeConst() );

NiTriBasedGeomData::NiTriBasedGeomData() NI_TRI_BASED_GEOM_DATA_CONSTRUCT {}

NiTriBasedGeomData::~NiTriBasedGeomData() {}

void NiTriBasedGeomData::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
	NI_TRI_BASED_GEOM_DATA_READ
}

void NiTriBasedGeomData::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
	NI_TRI_BASED_GEOM_DATA_WRITE
}

string NiTriBasedGeomData::asString( bool verbose ) const {
	NI_TRI_BASED_GEOM_DATA_STRING
}

void NiTriBasedGeomData::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
	NI_TRI_BASED_GEOM_DATA_FIXLINKS
}

list<NiObjectRef> NiTriBasedGeomData::GetRefs() const {
	NI_TRI_BASED_GEOM_DATA_GETREFS
}

const Type & NiTriBasedGeomData::GetType() const {
	return TYPE;
};

void NiTriBasedGeomData::SetUVSetCount(int n) {
	uvSets.resize(n);
	hasUv = ( uvSets.size() != 0 );
}

//--Setters--//
void NiTriBasedGeomData::SetVertices( const vector<Vector3> & in ) {
	vertices = in;
	hasVertices = ( vertices.size() != 0 );

	//Clear out all other data as it is now based on old vertex information
	normals.clear();
	hasNormals = false;
	vertexColors.clear();
	this->hasVertexColors = false;
	for (uint i = 0; i < uvSets.size(); ++i ) {
		uvSets[i].clear();
	}

	//If any vertices were given, calculate the new center and radius
	//Check if there are no vertices
	if ( vertices.size() == 0 ) {
		center.Set(0.0f, 0.0f, 0.0f);
		radius = 0.0f;
		return;
	}

	//Set lows and highs to first vertex
	Vector3 lows = vertices[0];
	Vector3 highs = vertices[0];

	//Iterate through the rest of the vertices, adjusting the stored values
	//if a vertex with lower or higher values is found
	for (vector<Vector3>::const_iterator i = vertices.begin()+1; i != vertices.end(); ++i ) {
		if ( i->x > highs.x ) highs.x = i->x;
		else if ( i->x < lows.x ) lows.x = i->x;

		if ( i->y > highs.y ) highs.y = i->y;
		else if ( i->y < lows.y ) lows.y = i->y;

		if ( i->z > highs.z ) highs.z = i->z;
		else if ( i->z < lows.z ) lows.z = i->z;
	}

	//Now we know the extent of the shape, so the center will be the average of the lows and highs.
	center.x = (highs.x + lows.x) / 2.0f;
	center.y = (highs.y + lows.y) / 2.0f;
	center.z = (highs.z + lows.z) / 2.0f;

	//The radius will be the largest distance from the center
	Vector3 diff;
	float dist2(0.0f), maxdist2(0.0f);
	for (vector<Vector3>::const_iterator i = vertices.begin(); i != vertices.end(); ++i ) {
		diff = center;
		diff.x -= i->x;
		diff.y -= i->y;
		diff.z -= i->z;
		dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
		if ( dist2 > maxdist2 ) maxdist2 = dist2;
	};
	radius = sqrt(maxdist2);
}

void NiTriBasedGeomData::SetNormals( const vector<Vector3> & in ) {
	if (in.size() != vertices.size() && in.size() != 0 )
		throw runtime_error("Vector size must equal Vertex Count or zero.");
	normals = in;
	hasNormals = ( normals.size() != 0 );
}

void NiTriBasedGeomData::SetVertexColors( const vector<Color4> & in ) {
	if (in.size() != vertices.size() && in.size() != 0 )
		throw runtime_error("Vector size must equal Vertex Count or zero.");
	vertexColors = in;
	hasVertexColors = ( vertexColors.size() != 0 );
}

void NiTriBasedGeomData::SetUVSet( int index, const vector<TexCoord> & in ) {
	if (in.size() != vertices.size())
		throw runtime_error("Vector size must equal Vertex Count.");
	uvSets[index] = in;
}

/*! Returns the 3D center of the mesh.
 * \return The center of this mesh.
 */
Vector3 NiTriBasedGeomData::GetCenter() const {
	return center;
}

/*! Returns the radius of the mesh.  That is the distance from the center to
 * the farthest point from the center.
 * \return The radius of this mesh.
 */
float NiTriBasedGeomData::GetRadius() const {
	return radius;
}

void NiTriBasedGeomData::SetTriangles( const vector<Triangle> & in ) {
   throw runtime_error("SetTriangles is a must be implemented in the derived class.");
}<commit_msg>Altered exception message for NiTriBasedGeomData::SetTriangles Casting functions now check for NULL as of last commit.<commit_after>/* Copyright (c) 2006, NIF File Format Library and Tools
All rights reserved.  Please see niflib.h for licence. */

#include "NiTriBasedGeomData.h"
#include "NiObject.h"
using namespace Niflib;

//Definition of TYPE constant
const Type NiTriBasedGeomData::TYPE("NiTriBasedGeomData", &NI_TRI_BASED_GEOM_DATA_PARENT::TypeConst() );

NiTriBasedGeomData::NiTriBasedGeomData() NI_TRI_BASED_GEOM_DATA_CONSTRUCT {}

NiTriBasedGeomData::~NiTriBasedGeomData() {}

void NiTriBasedGeomData::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
	NI_TRI_BASED_GEOM_DATA_READ
}

void NiTriBasedGeomData::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
	NI_TRI_BASED_GEOM_DATA_WRITE
}

string NiTriBasedGeomData::asString( bool verbose ) const {
	NI_TRI_BASED_GEOM_DATA_STRING
}

void NiTriBasedGeomData::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
	NI_TRI_BASED_GEOM_DATA_FIXLINKS
}

list<NiObjectRef> NiTriBasedGeomData::GetRefs() const {
	NI_TRI_BASED_GEOM_DATA_GETREFS
}

const Type & NiTriBasedGeomData::GetType() const {
	return TYPE;
};

void NiTriBasedGeomData::SetUVSetCount(int n) {
	uvSets.resize(n);
	hasUv = ( uvSets.size() != 0 );
}

//--Setters--//
void NiTriBasedGeomData::SetVertices( const vector<Vector3> & in ) {
	vertices = in;
	hasVertices = ( vertices.size() != 0 );

	//Clear out all other data as it is now based on old vertex information
	normals.clear();
	hasNormals = false;
	vertexColors.clear();
	this->hasVertexColors = false;
	for (uint i = 0; i < uvSets.size(); ++i ) {
		uvSets[i].clear();
	}

	//If any vertices were given, calculate the new center and radius
	//Check if there are no vertices
	if ( vertices.size() == 0 ) {
		center.Set(0.0f, 0.0f, 0.0f);
		radius = 0.0f;
		return;
	}

	//Set lows and highs to first vertex
	Vector3 lows = vertices[0];
	Vector3 highs = vertices[0];

	//Iterate through the rest of the vertices, adjusting the stored values
	//if a vertex with lower or higher values is found
	for (vector<Vector3>::const_iterator i = vertices.begin()+1; i != vertices.end(); ++i ) {
		if ( i->x > highs.x ) highs.x = i->x;
		else if ( i->x < lows.x ) lows.x = i->x;

		if ( i->y > highs.y ) highs.y = i->y;
		else if ( i->y < lows.y ) lows.y = i->y;

		if ( i->z > highs.z ) highs.z = i->z;
		else if ( i->z < lows.z ) lows.z = i->z;
	}

	//Now we know the extent of the shape, so the center will be the average of the lows and highs.
	center.x = (highs.x + lows.x) / 2.0f;
	center.y = (highs.y + lows.y) / 2.0f;
	center.z = (highs.z + lows.z) / 2.0f;

	//The radius will be the largest distance from the center
	Vector3 diff;
	float dist2(0.0f), maxdist2(0.0f);
	for (vector<Vector3>::const_iterator i = vertices.begin(); i != vertices.end(); ++i ) {
		diff = center;
		diff.x -= i->x;
		diff.y -= i->y;
		diff.z -= i->z;
		dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
		if ( dist2 > maxdist2 ) maxdist2 = dist2;
	};
	radius = sqrt(maxdist2);
}

void NiTriBasedGeomData::SetNormals( const vector<Vector3> & in ) {
	if (in.size() != vertices.size() && in.size() != 0 )
		throw runtime_error("Vector size must equal Vertex Count or zero.");
	normals = in;
	hasNormals = ( normals.size() != 0 );
}

void NiTriBasedGeomData::SetVertexColors( const vector<Color4> & in ) {
	if (in.size() != vertices.size() && in.size() != 0 )
		throw runtime_error("Vector size must equal Vertex Count or zero.");
	vertexColors = in;
	hasVertexColors = ( vertexColors.size() != 0 );
}

void NiTriBasedGeomData::SetUVSet( int index, const vector<TexCoord> & in ) {
	if (in.size() != vertices.size())
		throw runtime_error("Vector size must equal Vertex Count.");
	uvSets[index] = in;
}

/*! Returns the 3D center of the mesh.
 * \return The center of this mesh.
 */
Vector3 NiTriBasedGeomData::GetCenter() const {
	return center;
}

/*! Returns the radius of the mesh.  That is the distance from the center to
 * the farthest point from the center.
 * \return The radius of this mesh.
 */
float NiTriBasedGeomData::GetRadius() const {
	return radius;
}

void NiTriBasedGeomData::SetTriangles( const vector<Triangle> & in ) {
   throw runtime_error("SetTriangles is not implemented for this object.");
}<|endoftext|>


<commit_before>#include "syntaxanalyzer.h"
#include "lexicalanalyzer.h"
#include <QMetaType>

SyntaxAnalyzer::SyntaxAnalyzer(QObject *parent) :
	QObject(parent),
	m_lexicalAnalyzer(new LexicalAnalyzer),
	m_exprCalculator(new ExprCalculator(this))
{
}

SyntaxAnalyzer::~SyntaxAnalyzer()
{
}

QString SyntaxAnalyzer::process(const QString &input)
{
	// there will be new Main function
	m_rpnCode.remove(RpnFunctionMain);

	// perform lexical analyzis
	m_lexicalAnalyzer->parse(input);
	if (m_lexicalAnalyzer->lexeme().type == LexemeEol) {
		throw Exception(tr("Input is empty"));
	}

	// Process the command: const declaration, const function or expression
	return command();
}

// Command = ConstDeclaration | Expression
QString SyntaxAnalyzer::command()
{
	QString result;

	// const declaration
	if (m_lexicalAnalyzer->lexeme().type == LexemeConst) {
		result = constDeclaration(); // result here is just a notification
		ensureNoMoreLexemes();
	}

	// func declaration
	else if (m_lexicalAnalyzer->lexeme().type == LexemeFunc) {
		result = functionDeclaration(); // result here is a notification too
		ensureNoMoreLexemes();
	}

	// expression
	else {
		RpnFunction mainFunction;
		mainFunction.argumentsCount = 0;
		mainFunction.codeThread << expression(); // convert expression to RPN
		m_rpnCode.insert(RpnFunctionMain, mainFunction);
		ensureNoMoreLexemes();
		result = QString::number(m_exprCalculator->calculate(m_rpnCode)); // calculate
	}

	return result;
}

// ConstDeclaration = 'const' Identifier '=' {Unary Op} Number
QString SyntaxAnalyzer::constDeclaration()
{
	// 'const'
	if (m_lexicalAnalyzer->lexeme().type != LexemeConst) {
		throw Exception(tr("Illegal constant declaration beginning"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Identifier
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier after ‘const’ expected"));
	}
	QString constName = m_lexicalAnalyzer->lexeme().value;
	m_lexicalAnalyzer->nextLexeme();

	// '='
	if (m_lexicalAnalyzer->lexeme().type != LexemeEqual) {
		throw Exception(tr("Sign ‘=’ expected after identifier"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// {UnaryOp}
	int signMultiplyer = 1;
	while (CheckLexeme::isUnaryOperation(m_lexicalAnalyzer->lexeme())) {
		if (m_lexicalAnalyzer->lexeme().type == LexemeMinus) {
			signMultiplyer *= -1;
		}
		m_lexicalAnalyzer->nextLexeme();
	}

	// Number
	if (m_lexicalAnalyzer->lexeme().type != LexemeNumber) {
		throw Exception(tr("Number after ‘=’ expected"));
	}
	Number constValue = number();
	m_lexicalAnalyzer->nextLexeme();

	// add constant to list
	m_consts[constName] = constValue;

	// return notification
	return tr("Constant ‘%1’ now means ‘%2’").arg(constName).arg(constValue);
}

// FunctionDeclaration = 'func' Indenifier '(' FormalArgument
//		{ ',' FormalArgument} ')' '=' Expression
QString SyntaxAnalyzer::functionDeclaration()
{
	/* Get function name */

	// 'func'
	if (m_lexicalAnalyzer->lexeme().type != LexemeFunc) {
		throw Exception(tr("Illegal function declaration beginning"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Identifier
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifyer after ‘func’ expected"));
	}
	QString functionName = m_lexicalAnalyzer->lexeme().value;
	m_lexicalAnalyzer->nextLexeme();

	/* Ensure there's no built in function with this name */
	if (m_exprCalculator->isBuiltInFunction(functionName)) {
		throw Exception(tr("There is built in function named ‘%1’").arg(functionName));
	}

	/* Get formal arguments and save them to list */

	if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
		throw Exception(tr("Opening bracket expected after function name"));
	}

	do {
		m_lexicalAnalyzer->nextLexeme();
		extractFormalArgument();
	} while (m_lexicalAnalyzer->lexeme().type == LexemeComma);

	if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
		throw Exception(tr("Closing bracket expected after formal arguments list"));
	}
	m_lexicalAnalyzer->nextLexeme();

	if (m_lexicalAnalyzer->lexeme().type != LexemeEqual) {
		throw Exception(tr("Equal sign expected after closing bracket"));
	}
	m_lexicalAnalyzer->nextLexeme();

	/* Parse the function body and save it */

	RpnFunction function;
	function.argumentsCount = m_workingParams.count();
	function.codeThread = expression();
	m_workingParams.clear();
	m_rpnCode.insert(functionName, function);

	/* Parse the function body and save it */
	return tr("Function ‘%1’ is declared").arg(functionName);
}

// Expression = Summand {SummOperator Summand}
RpnCodeThread SyntaxAnalyzer::expression()
{
	/* Note, that exception will be thrown in factor(), multOperation(), etc if something's wrong. */

	RpnCodeThread result;

	// first obligatory summand
	RpnCodeThread operand = summand();
	result << operand;

	// {SummOperator Summand} section
	while (CheckLexeme::isSummOperation(m_lexicalAnalyzer->lexeme())) {
		RpnElement operation = summOperation();
		operand = summand();

		result << operand << operation;
	}

	return result;
}

// Function = Identifier'(' ActualArgument{ ',' ActualArgument}')'
RpnCodeThread SyntaxAnalyzer::function()
{
	RpnCodeThread result;

	// Get function name and ensure it is built in or user defined

	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Function name expected"));
	}
	QString functionName = m_lexicalAnalyzer->lexeme().value;
	int formalArgumentsCount;
	if (m_exprCalculator->isBuiltInFunction(functionName)) {
		formalArgumentsCount = m_exprCalculator->builtInFunctionArgumentsCount(functionName);
	}
	else if (m_rpnCode.contains(functionName)) {
		formalArgumentsCount = m_rpnCode[functionName].argumentsCount;
	}
	else {
		throw Exception(tr("Undeclared function ‘%1’ call").arg(functionName));
	}
	m_lexicalAnalyzer->nextLexeme();

	if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
		throw Exception(tr("Opening bracket expected"));
	}

	// Parse actual arguments and add them to tread.
	// Ensure their count equals formal arguments count
	int actualArgumentsCount = 0;
	do {
		m_lexicalAnalyzer->nextLexeme();
		result << expression();
		actualArgumentsCount++;
		if (actualArgumentsCount > formalArgumentsCount) {
			throw Exception(tr("Too many arguments in ‘%1’ function call").arg(functionName));
		}
	} while (m_lexicalAnalyzer->lexeme().type == LexemeComma);

	if (actualArgumentsCount != formalArgumentsCount) {
		throw Exception(tr("Not enough arguments in ‘%1’ function call").arg(functionName));
	}

	if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
		throw Exception(tr("Closing bracket expected"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Add to thread a function call element
	RpnElement functionCall;
	functionCall.type = RpnElementFunction;
	functionCall.value = functionName;
	result << functionCall;

	return result;
}

// Factor = (UnaryOp Factor) | (PowerBase ['^' Factor])
RpnCodeThread SyntaxAnalyzer::factor()
{
	RpnCodeThread result;

	// UnaryOp Factor
	if (CheckLexeme::isUnaryOperation(m_lexicalAnalyzer->lexeme())) {

		if (m_lexicalAnalyzer->lexeme().type == LexemeMinus) {

			m_lexicalAnalyzer->nextLexeme();

			// -A = (-1) * A
			RpnElement minusOne = {RpnElementOperand, -1};
			RpnElement multiply = {RpnElementFunction, QVariant::fromValue(RpnFunctionMultiply)};
			RpnCodeThread rightOperand = factor();

			result << minusOne << rightOperand << multiply;
		}

		else if (m_lexicalAnalyzer->lexeme().type == LexemePlus) {
			m_lexicalAnalyzer->nextLexeme();
			result = factor();
		}

		else {
			throw Exception(tr("Unsupported unary operation"));
		}
	}

	else {
		RpnCodeThread base = powerBase();
		result << base;

		// ['^' Factor]
		if (m_lexicalAnalyzer->lexeme().type == LexemePower) {
			RpnElement power = {RpnElementFunction, QVariant::fromValue(RpnFunctionPower)};
			m_lexicalAnalyzer->nextLexeme();
			RpnCodeThread exponent = factor();

			result << exponent << power;
		}

	}

	return result;
}

// PowerBase = Number | Constant | Function | '('Expression')'
RpnCodeThread SyntaxAnalyzer::powerBase()
{
	RpnCodeThread result;

	// Number
	if (m_lexicalAnalyzer->lexeme().type == LexemeNumber) {
		Number value = number();
		RpnElement element = {RpnElementOperand, value};
		result << element;
	}

	// Constant | Function
	else if (m_lexicalAnalyzer->lexeme().type == LexemeIdentifier) {
		// Constant
		m_lexicalAnalyzer->nextLexeme();
		if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
			m_lexicalAnalyzer->previousLexeme();
			RpnElement element = constant();
			result << element;
		}
		// Function
		else {
			m_lexicalAnalyzer->previousLexeme();
			RpnCodeThread thread = function();
			result << thread;
		}
	}

	// '('Expression')'
	else if (m_lexicalAnalyzer->lexeme().type == LexemeOpeningBracket) {

		m_lexicalAnalyzer->nextLexeme();
		result = expression();

		if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
			throw Exception(tr("Closing bracket expected"));
		}

		m_lexicalAnalyzer->nextLexeme();
	}

	else {
		throw Exception(tr("Number or expression in brackets expected"));
	}

	return result;
}

// MultOperation = '*' | '/'
RpnElement SyntaxAnalyzer::multOperation()
{
	RpnElement result;
	result.type = RpnElementFunction;

	if (m_lexicalAnalyzer->lexeme().type == LexemeMultiply) {
		result.value.setValue(RpnFunctionMultiply);
	}
	else if(m_lexicalAnalyzer->lexeme().type == LexemeDivide) {
		result.value.setValue(RpnFunctionDivide);
	}
	else {
		throw Exception(tr("Multiplication operator expected"));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// Summand = Factor {MultOperator Factor}
RpnCodeThread SyntaxAnalyzer::summand()
{
	RpnCodeThread result;
	// first obligatory factor
	RpnCodeThread operand = factor();
	result << operand;

	// {MultOperation Factor} section
	while (CheckLexeme::isMultOperation(m_lexicalAnalyzer->lexeme())) {
		RpnElement operation = multOperation();
		operand = factor();

		result << operand << operation;
	}

	return result;
}

// SummOperation = '+' | '-'
RpnElement SyntaxAnalyzer::summOperation()
{
	RpnElement result;
	result.type = RpnElementFunction;

	if (m_lexicalAnalyzer->lexeme().type == LexemePlus) {
		result.value.setValue(RpnFunctionPlus);
	}
	else if(m_lexicalAnalyzer->lexeme().type == LexemeMinus) {
		result.value.setValue(RpnFunctionMinus);
	}
	else {
		throw Exception(tr("Summation operator expected"));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

Number SyntaxAnalyzer::number()
{
	bool ok = false;
	Number result = m_lexicalAnalyzer->lexeme().value.toDouble(&ok);
	if (!ok) {
		throw Exception(tr("Cannot convert ‘%1’ to a number").arg(m_lexicalAnalyzer->lexeme().value));
	}
	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// Constant = Identifier (formal arguments are processed here as well)
RpnElement SyntaxAnalyzer::constant()
{
	RpnElement result;
	QString constName = m_lexicalAnalyzer->lexeme().value;

	if (m_workingParams.contains(constName)) {
		// it is an argument
		result.type = RpnElementParam;
		result.value = m_workingParams.indexOf(constName, 1);
	}

	else if (m_consts.contains(constName)) {
		result.type = RpnElementOperand;
		result.value = m_consts.value(constName);
	}

	else {
		throw Exception(tr("Undeclared identifier ‘%1’").arg(constName));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// FormalArgument = Identifier
void SyntaxAnalyzer::extractFormalArgument()
{
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier expected if argument list"));
	}

	QString argumentName = m_lexicalAnalyzer->lexeme().value;
	if (m_workingParams.contains(argumentName)) {
		throw Exception(tr("Argument ‘%1’ is already in the list").arg(argumentName));
	}
	m_workingParams.append(argumentName);

	m_lexicalAnalyzer->nextLexeme();
}

void SyntaxAnalyzer::ensureNoMoreLexemes()
{
	if (m_lexicalAnalyzer->lexeme().type != LexemeEol) {
	   throw Exception(tr("End of file expected"));
   }
}

bool CheckLexeme::isMultOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemeMultiply) || (lexeme.type == LexemeDivide));
}

bool CheckLexeme::isSummOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemePlus) || (lexeme.type == LexemeMinus));
}

bool CheckLexeme::isUnaryOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemePlus) || (lexeme.type == LexemeMinus));
}

<commit_msg>Fixed user defined function processing. Argument link were set incorrectly.<commit_after>#include "syntaxanalyzer.h"
#include "lexicalanalyzer.h"
#include <QMetaType>

SyntaxAnalyzer::SyntaxAnalyzer(QObject *parent) :
	QObject(parent),
	m_lexicalAnalyzer(new LexicalAnalyzer),
	m_exprCalculator(new ExprCalculator(this))
{
}

SyntaxAnalyzer::~SyntaxAnalyzer()
{
}

QString SyntaxAnalyzer::process(const QString &input)
{
	// there will be new Main function
	m_rpnCode.remove(RpnFunctionMain);

	// perform lexical analyzis
	m_lexicalAnalyzer->parse(input);
	if (m_lexicalAnalyzer->lexeme().type == LexemeEol) {
		throw Exception(tr("Input is empty"));
	}

	// Process the command: const declaration, const function or expression
	return command();
}

// Command = ConstDeclaration | Expression
QString SyntaxAnalyzer::command()
{
	QString result;

	// const declaration
	if (m_lexicalAnalyzer->lexeme().type == LexemeConst) {
		result = constDeclaration(); // result here is just a notification
		ensureNoMoreLexemes();
	}

	// func declaration
	else if (m_lexicalAnalyzer->lexeme().type == LexemeFunc) {
		result = functionDeclaration(); // result here is a notification too
		ensureNoMoreLexemes();
	}

	// expression
	else {
		RpnFunction mainFunction;
		mainFunction.argumentsCount = 0;
		mainFunction.codeThread << expression(); // convert expression to RPN
		m_rpnCode.insert(RpnFunctionMain, mainFunction);
		ensureNoMoreLexemes();
		result = QString::number(m_exprCalculator->calculate(m_rpnCode)); // calculate
	}

	return result;
}

// ConstDeclaration = 'const' Identifier '=' {Unary Op} Number
QString SyntaxAnalyzer::constDeclaration()
{
	// 'const'
	if (m_lexicalAnalyzer->lexeme().type != LexemeConst) {
		throw Exception(tr("Illegal constant declaration beginning"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Identifier
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier after ‘const’ expected"));
	}
	QString constName = m_lexicalAnalyzer->lexeme().value;
	m_lexicalAnalyzer->nextLexeme();

	// '='
	if (m_lexicalAnalyzer->lexeme().type != LexemeEqual) {
		throw Exception(tr("Sign ‘=’ expected after identifier"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// {UnaryOp}
	int signMultiplyer = 1;
	while (CheckLexeme::isUnaryOperation(m_lexicalAnalyzer->lexeme())) {
		if (m_lexicalAnalyzer->lexeme().type == LexemeMinus) {
			signMultiplyer *= -1;
		}
		m_lexicalAnalyzer->nextLexeme();
	}

	// Number
	if (m_lexicalAnalyzer->lexeme().type != LexemeNumber) {
		throw Exception(tr("Number after ‘=’ expected"));
	}
	Number constValue = number();
	m_lexicalAnalyzer->nextLexeme();

	// add constant to list
	m_consts[constName] = constValue;

	// return notification
	return tr("Constant ‘%1’ now means ‘%2’").arg(constName).arg(constValue);
}

// FunctionDeclaration = 'func' Indenifier '(' FormalArgument
//		{ ',' FormalArgument} ')' '=' Expression
QString SyntaxAnalyzer::functionDeclaration()
{
	/* Get function name */

	// 'func'
	if (m_lexicalAnalyzer->lexeme().type != LexemeFunc) {
		throw Exception(tr("Illegal function declaration beginning"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Identifier
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifyer after ‘func’ expected"));
	}
	QString functionName = m_lexicalAnalyzer->lexeme().value;
	m_lexicalAnalyzer->nextLexeme();

	/* Ensure there's no built in function with this name */
	if (m_exprCalculator->isBuiltInFunction(functionName)) {
		throw Exception(tr("There is built in function named ‘%1’").arg(functionName));
	}

	/* Get formal arguments and save them to list */

	if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
		throw Exception(tr("Opening bracket expected after function name"));
	}

	do {
		m_lexicalAnalyzer->nextLexeme();
		extractFormalArgument();
	} while (m_lexicalAnalyzer->lexeme().type == LexemeComma);

	if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
		throw Exception(tr("Closing bracket expected after formal arguments list"));
	}
	m_lexicalAnalyzer->nextLexeme();

	if (m_lexicalAnalyzer->lexeme().type != LexemeEqual) {
		throw Exception(tr("Equal sign expected after closing bracket"));
	}
	m_lexicalAnalyzer->nextLexeme();

	/* Parse the function body and save it */

	RpnFunction function;
	function.argumentsCount = m_workingParams.count();
	function.codeThread = expression();
	m_workingParams.clear();
	m_rpnCode.insert(functionName, function);

	/* Parse the function body and save it */
	return tr("Function ‘%1’ is declared").arg(functionName);
}

// Expression = Summand {SummOperator Summand}
RpnCodeThread SyntaxAnalyzer::expression()
{
	/* Note, that exception will be thrown in factor(), multOperation(), etc if something's wrong. */

	RpnCodeThread result;

	// first obligatory summand
	RpnCodeThread operand = summand();
	result << operand;

	// {SummOperator Summand} section
	while (CheckLexeme::isSummOperation(m_lexicalAnalyzer->lexeme())) {
		RpnElement operation = summOperation();
		operand = summand();

		result << operand << operation;
	}

	return result;
}

// Function = Identifier'(' ActualArgument{ ',' ActualArgument}')'
RpnCodeThread SyntaxAnalyzer::function()
{
	RpnCodeThread result;

	// Get function name and ensure it is built in or user defined

	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Function name expected"));
	}
	QString functionName = m_lexicalAnalyzer->lexeme().value;
	int formalArgumentsCount;
	if (m_exprCalculator->isBuiltInFunction(functionName)) {
		formalArgumentsCount = m_exprCalculator->builtInFunctionArgumentsCount(functionName);
	}
	else if (m_rpnCode.contains(functionName)) {
		formalArgumentsCount = m_rpnCode[functionName].argumentsCount;
	}
	else {
		throw Exception(tr("Undeclared function ‘%1’ call").arg(functionName));
	}
	m_lexicalAnalyzer->nextLexeme();

	if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
		throw Exception(tr("Opening bracket expected"));
	}

	// Parse actual arguments and add them to tread.
	// Ensure their count equals formal arguments count
	int actualArgumentsCount = 0;
	do {
		m_lexicalAnalyzer->nextLexeme();
		result << expression();
		actualArgumentsCount++;
		if (actualArgumentsCount > formalArgumentsCount) {
			throw Exception(tr("Too many arguments in ‘%1’ function call").arg(functionName));
		}
	} while (m_lexicalAnalyzer->lexeme().type == LexemeComma);

	if (actualArgumentsCount != formalArgumentsCount) {
		throw Exception(tr("Not enough arguments in ‘%1’ function call").arg(functionName));
	}

	if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
		throw Exception(tr("Closing bracket expected"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Add to thread a function call element
	RpnElement functionCall;
	functionCall.type = RpnElementFunction;
	functionCall.value = functionName;
	result << functionCall;

	return result;
}

// Factor = (UnaryOp Factor) | (PowerBase ['^' Factor])
RpnCodeThread SyntaxAnalyzer::factor()
{
	RpnCodeThread result;

	// UnaryOp Factor
	if (CheckLexeme::isUnaryOperation(m_lexicalAnalyzer->lexeme())) {

		if (m_lexicalAnalyzer->lexeme().type == LexemeMinus) {

			m_lexicalAnalyzer->nextLexeme();

			// -A = (-1) * A
			RpnElement minusOne = {RpnElementOperand, -1};
			RpnElement multiply = {RpnElementFunction, QVariant::fromValue(RpnFunctionMultiply)};
			RpnCodeThread rightOperand = factor();

			result << minusOne << rightOperand << multiply;
		}

		else if (m_lexicalAnalyzer->lexeme().type == LexemePlus) {
			m_lexicalAnalyzer->nextLexeme();
			result = factor();
		}

		else {
			throw Exception(tr("Unsupported unary operation"));
		}
	}

	else {
		RpnCodeThread base = powerBase();
		result << base;

		// ['^' Factor]
		if (m_lexicalAnalyzer->lexeme().type == LexemePower) {
			RpnElement power = {RpnElementFunction, QVariant::fromValue(RpnFunctionPower)};
			m_lexicalAnalyzer->nextLexeme();
			RpnCodeThread exponent = factor();

			result << exponent << power;
		}

	}

	return result;
}

// PowerBase = Number | Constant | Function | '('Expression')'
RpnCodeThread SyntaxAnalyzer::powerBase()
{
	RpnCodeThread result;

	// Number
	if (m_lexicalAnalyzer->lexeme().type == LexemeNumber) {
		Number value = number();
		RpnElement element = {RpnElementOperand, value};
		result << element;
	}

	// Constant | Function
	else if (m_lexicalAnalyzer->lexeme().type == LexemeIdentifier) {
		// Constant
		m_lexicalAnalyzer->nextLexeme();
		if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
			m_lexicalAnalyzer->previousLexeme();
			RpnElement element = constant();
			result << element;
		}
		// Function
		else {
			m_lexicalAnalyzer->previousLexeme();
			RpnCodeThread thread = function();
			result << thread;
		}
	}

	// '('Expression')'
	else if (m_lexicalAnalyzer->lexeme().type == LexemeOpeningBracket) {

		m_lexicalAnalyzer->nextLexeme();
		result = expression();

		if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
			throw Exception(tr("Closing bracket expected"));
		}

		m_lexicalAnalyzer->nextLexeme();
	}

	else {
		throw Exception(tr("Number or expression in brackets expected"));
	}

	return result;
}

// MultOperation = '*' | '/'
RpnElement SyntaxAnalyzer::multOperation()
{
	RpnElement result;
	result.type = RpnElementFunction;

	if (m_lexicalAnalyzer->lexeme().type == LexemeMultiply) {
		result.value.setValue(RpnFunctionMultiply);
	}
	else if(m_lexicalAnalyzer->lexeme().type == LexemeDivide) {
		result.value.setValue(RpnFunctionDivide);
	}
	else {
		throw Exception(tr("Multiplication operator expected"));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// Summand = Factor {MultOperator Factor}
RpnCodeThread SyntaxAnalyzer::summand()
{
	RpnCodeThread result;
	// first obligatory factor
	RpnCodeThread operand = factor();
	result << operand;

	// {MultOperation Factor} section
	while (CheckLexeme::isMultOperation(m_lexicalAnalyzer->lexeme())) {
		RpnElement operation = multOperation();
		operand = factor();

		result << operand << operation;
	}

	return result;
}

// SummOperation = '+' | '-'
RpnElement SyntaxAnalyzer::summOperation()
{
	RpnElement result;
	result.type = RpnElementFunction;

	if (m_lexicalAnalyzer->lexeme().type == LexemePlus) {
		result.value.setValue(RpnFunctionPlus);
	}
	else if(m_lexicalAnalyzer->lexeme().type == LexemeMinus) {
		result.value.setValue(RpnFunctionMinus);
	}
	else {
		throw Exception(tr("Summation operator expected"));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

Number SyntaxAnalyzer::number()
{
	bool ok = false;
	Number result = m_lexicalAnalyzer->lexeme().value.toDouble(&ok);
	if (!ok) {
		throw Exception(tr("Cannot convert ‘%1’ to a number").arg(m_lexicalAnalyzer->lexeme().value));
	}
	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// Constant = Identifier (formal arguments are processed here as well)
RpnElement SyntaxAnalyzer::constant()
{
	RpnElement result;
	QString constName = m_lexicalAnalyzer->lexeme().value;

	if (m_workingParams.contains(constName)) {
		// it is an argument
		result.type = RpnElementParam;
		result.value = m_workingParams.indexOf(constName);
	}

	else if (m_consts.contains(constName)) {
		result.type = RpnElementOperand;
		result.value = m_consts.value(constName);
	}

	else {
		throw Exception(tr("Undeclared identifier ‘%1’").arg(constName));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// FormalArgument = Identifier
void SyntaxAnalyzer::extractFormalArgument()
{
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier expected if argument list"));
	}

	QString argumentName = m_lexicalAnalyzer->lexeme().value;
	if (m_workingParams.contains(argumentName)) {
		throw Exception(tr("Argument ‘%1’ is already in the list").arg(argumentName));
	}
	m_workingParams.append(argumentName);

	m_lexicalAnalyzer->nextLexeme();
}

void SyntaxAnalyzer::ensureNoMoreLexemes()
{
	if (m_lexicalAnalyzer->lexeme().type != LexemeEol) {
	   throw Exception(tr("End of file expected"));
   }
}

bool CheckLexeme::isMultOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemeMultiply) || (lexeme.type == LexemeDivide));
}

bool CheckLexeme::isSummOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemePlus) || (lexeme.type == LexemeMinus));
}

bool CheckLexeme::isUnaryOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemePlus) || (lexeme.type == LexemeMinus));
}

<|endoftext|>


<commit_before>#include "argparse.hpp"

int main(int argc, const char** argv) {

    struct Args {
        std::string architecture_file;
        std::string circuit;

        bool disp;
        bool auto_value;

        bool pack;
        bool place;
        bool route;

        bool timing_analysis;
        const char* slack_definition;
        bool echo_files;
        bool verify_file_digests;

        std::string blif_file;
        std::string net_file;
        std::string place_file;
        std::string route_file;
        std::string sdc_file;
        std::string outfile_prefix;

        bool absorb_buffer_luts;
        bool sweep_dangling_primary_ios;
        bool sweep_dangling_nets;
        bool sweep_dangling_blocks;
        bool sweep_constant_primary_outputs;

        bool connection_driven_clustering;
        bool allow_unrelated_clustering;
        float alpha_clustering;
        float beta_clustering;
        bool timing_driven_clustering;
        std::string cluster_seed_type;

        bool full_stats;
        bool gen_post_synthesis_netlist;
    };

    struct OnOff {
        bool from_str(std::string str) {
            if      (str == "on")  return true;
            else if (str == "off") return false;
            throw argparse::ArgParseConversionError("Invalid conversion");
        }

        std::string to_str(bool val) {
            if (val) return "on";
            return "off";
        }

        std::vector<std::string> default_choices() {
            return {"on", "off"};
        }
    };

    Args args;

    auto parser = argparse::ArgumentParser("Test parser for libargparse");
    parser.prog(argv[0]);
    parser.epilog("This is the epilog");

    auto& pos_grp = parser.add_argument_group("positional arguments:");

    pos_grp.add_argument(args.architecture_file, "architecture")
            .help("FPGA Architecture description file (XML)");
    pos_grp.add_argument(args.circuit, "circuit")
            .help("Circuit file (or circuit name if --blif_file specified)");

    auto& gfx_grp = parser.add_argument_group("graphics options:");
    gfx_grp.add_argument<bool,OnOff>(args.disp, "--disp")
            .help("Enable or disable interactive graphics")
            .default_value("off");
    gfx_grp.add_argument(args.auto_value, "--auto")
            .help("Controls how often VPR pauses for interactive"
                  " graphics (requiring Proceed to be clicked)."
                  " Higher values pause less frequently")
            .default_value("1")
            .choices({"0", "1", "2"});

    auto& stage_grp = parser.add_argument_group("stage options:");

    stage_grp.add_argument<bool,OnOff>(args.pack, "--pack")
            .help("Run packing")
            .action(argparse::Action::STORE_TRUE)
            .default_value("off");
    stage_grp.add_argument<bool,OnOff>(args.place, "--place")
            .help("Run placement")
            .action(argparse::Action::STORE_TRUE)
            .default_value("off");
    stage_grp.add_argument<bool,OnOff>(args.route, "--route")
            .help("Run routing")
            .action(argparse::Action::STORE_TRUE)
            .default_value("off");
    stage_grp.add_argument<bool,OnOff>(args.route, "--analysis")
            .help("Run analysis")
            .action(argparse::Action::STORE_TRUE)
            .default_value("off");

    stage_grp.epilog("If none of the stage options are specified, all stages are run.\n"
                     "Analysis is always run after routing.");

    auto& gen_grp = parser.add_argument_group("general options:");

    gen_grp.add_argument<bool,OnOff>(args.timing_analysis, "--timing_analysis")
            .help("Controls whether timing analysis (and timing driven optimizations) are enabled.")
            .default_value("on") ;
    gen_grp.add_argument(args.slack_definition, "--slack_definition")
            .help("Sets the slack definition used by the classic timing analyyzer")
            .default_value("R")
            .choices({"R", "I", "S", "G", "C", "N"});
    gen_grp.add_argument<bool,OnOff>(args.echo_files, "--echo_file")
            .help("Generate echo files of key internal data structures. Useful for debugging VPR, and typically end in .echo")
            .default_value("off");
    gen_grp.add_argument<bool,OnOff>(args.verify_file_digests, "--verify_file_digests")
            .help("Verify that intermediate files loaded by VPR (e.g. previous packing/placement/routing) are consistent")
            .default_value("on");

    auto& file_grp = parser.add_argument_group("filename options:");

    file_grp.add_argument(args.blif_file, "--blif_file")
            .help("Path to technology mapped circuit in BLIF format");
    file_grp.add_argument(args.net_file, "--net_file")
            .help("Path to packed netlist file");
    file_grp.add_argument(args.place_file, "--place_file")
            .help("Path to placement file");
    file_grp.add_argument(args.route_file, "--route_file")
            .help("Path to routing file");
    file_grp.add_argument(args.sdc_file, "--sdc_file")
            .help("Path to iming constraints file in SDC format");
    file_grp.add_argument(args.outfile_prefix, "--outfile_prefix")
            .help("Prefix for output files");

    auto& netlist_grp = parser.add_argument_group("netlist options:");
    netlist_grp.add_argument<bool,OnOff>(args.absorb_buffer_luts, "--absorb_buffer_luts")
            .help("Controls whether LUTS programmed as buffers are absorbed by downstream logic")
            .default_value("on");
    netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_primary_ios, "--sweep_dangling_primary_ios")
            .help("Controls whether dangling primary inputs and outputs are removed from the netlist")
            .default_value("on");
    netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_nets, "--sweep_dangling_nets")
            .help("Controls whether dangling nets are removed from the netlist")
            .default_value("on");
    netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_blocks, "--sweep_dangling_blocks")
            .help("Controls whether dangling blocks are removed from the netlist")
            .default_value("on");
    netlist_grp.add_argument<bool,OnOff>(args.sweep_constant_primary_outputs, "--sweep_constant_primary_outputs")
            .help("Controls whether primary outputs driven by constant values are removed from the netlist")
            .default_value("off");

    auto& pack_grp = parser.add_argument_group("packing options:");
    pack_grp.add_argument<bool,OnOff>(args.connection_driven_clustering, "--connection_driven_clustering")
            .help("Controls whether or not packing prioritizes the absorption of nets with fewer connections into a complex logic block over nets with more connections")
            .default_value("on");
    pack_grp.add_argument<bool,OnOff>(args.allow_unrelated_clustering, "--allow_unrelated_clustering")
            .help("Controls whether or not primitives with no attraction to the current cluster can be packed into it")
            .default_value("on");
    pack_grp.add_argument(args.alpha_clustering, "--alpha_clustering")
            .help("Parameter that weights the optimization of timing vs area. 0.0 focuses solely on area, 1.0 solely on timing.")
            .default_value("0.75");
    pack_grp.add_argument(args.beta_clustering, "--beta_clustering")
            .help("Parameter that weights the absorption of small nets vs signal sharing. 0.0 focuses solely on sharing, 1.0 solely on small net absoprtion. Only meaningful if --connection_driven_clustering=on")
            .default_value("0.9");
    pack_grp.add_argument<bool,OnOff>(args.timing_driven_clustering, "--timing_driven_clustering")
            .help("Controls whether custering optimizes for timing")
            .default_value("on");
    pack_grp.add_argument(args.cluster_seed_type, "--cluster_seed_type")
            .help("Controls how primitives are chosen as seeds.")
            .default_value("blend")
            .choices({"blend", "timing", "max_inputs"});

    //auto& pack_timing_grp = parser.add_argument_group("timing-driven packing options:");

    //auto& place_grp = parser.add_argument_group("placement options:");

    //auto& place_timing_grp = parser.add_argument_group("timing-driven placement options:");

    //auto& route_grp = parser.add_argument_group("routing options:");

    //auto& route_timing_grp = parser.add_argument_group("timing-driven routing options:");

    auto& analysis_grp = parser.add_argument_group("analysis options:");

    analysis_grp.add_argument<bool,OnOff>(args.full_stats, "--full_stats")
                .help("Print extra statistics about the circuit and it's routing (useful for wireability analysis)")
                .default_value("off");

    analysis_grp.add_argument<bool,OnOff>(args.gen_post_synthesis_netlist, "--gen_post_synthesis_netlist")
                .help("Generates the post-synthesis netlist (in BLIF and Verilog) along with delay information (in SDF)")
                .default_value("off");

#if 0
    parser.add_argument(args.long1, "--long")
              .help("Help for a long option")
              .default_value(9)
              .metavar("LONG_VALUE");

    parser.add_argument(args.long2, "--long2", "-l");

    //parser.add_argument(args.c, "-c")
                //.choices({"a", "b", "c", "d"});
                //;

    parser.add_argument(args.c, "pos1")
                .help("A positional argument");

    parser.add_argument(args.disp, "-disp")
                .action(argparse::Action::STORE_TRUE)
                .help("Enable display");
    parser.add_argument(args.disp, "-nodisp")
                .action(argparse::Action::STORE_FALSE)
                .help("Disable display");
#endif
    parser.print_help();

    parser.parse_args(argc, argv);

    std::cout << "args.disp: " << args.disp << "\n";

    //for(auto& arg : args) {
        //std::cout << arg.name() << ": " << arg.value() << "\n";
    //}

    return 0;
}
<commit_msg>Replicate the VPR command parser as an example<commit_after>#include "argparse.hpp"

int main(int argc, const char** argv) {

    struct Args {
        std::string architecture_file;
        std::string circuit;

        bool disp;
        bool auto_value;

        bool pack;
        bool place;
        bool route;

        bool timing_analysis;
        const char* slack_definition;
        bool echo_files;
        bool verify_file_digests;

        std::string blif_file;
        std::string net_file;
        std::string place_file;
        std::string route_file;
        std::string sdc_file;
        std::string outfile_prefix;

        bool absorb_buffer_luts;
        bool sweep_dangling_primary_ios;
        bool sweep_dangling_nets;
        bool sweep_dangling_blocks;
        bool sweep_constant_primary_outputs;

        bool connection_driven_clustering;
        bool allow_unrelated_clustering;
        float alpha_clustering;
        float beta_clustering;
        bool timing_driven_clustering;
        std::string cluster_seed_type;

        size_t seed;
        bool enable_timing_computations;
        float inner_num;
        float init_t;
        float exit_t;
        float alpha_t;
        std::string fix_pins;
        std::string place_algorithm;
        size_t place_chan_width;

        float timing_tradeoff;
        int recompute_crit_iter;
        int inner_loop_recompute_divider;
        float td_place_exp_first;
        float td_place_exp_last;

        int max_router_iterations;
        float first_iter_pres_fac;
        float initial_pres_fac;
        float pres_fac_mult;
        float acc_fac;
        int bb_factor;
        std::string base_cost_type;
        float bend_cost;
        std::string route_type;
        size_t route_chan_width;
        size_t min_route_chan_width_hint;
        bool verify_binary_search;
        std::string router_algorithm;
        int min_incremental_reroute_fanout;

        float astar_fac;
        float max_criticality;
        float criticality_exp;
        std::string routing_failure_predictor;

        bool power;
        std::string tech_properties_file;
        std::string activity_file;

        bool full_stats;
        bool gen_post_synthesis_netlist;
    };

    struct OnOff {
        bool from_str(std::string str) {
            if      (str == "on")  return true;
            else if (str == "off") return false;
            throw argparse::ArgParseConversionError("Invalid conversion");
        }

        std::string to_str(bool val) {
            if (val) return "on";
            return "off";
        }

        std::vector<std::string> default_choices() {
            return {"on", "off"};
        }
    };

    Args args;

    auto parser = argparse::ArgumentParser("Test parser for libargparse");
    parser.prog(argv[0]);
    parser.epilog("This is the epilog");

    auto& pos_grp = parser.add_argument_group("positional arguments:");

    pos_grp.add_argument(args.architecture_file, "architecture")
            .help("FPGA Architecture description file (XML)");
    pos_grp.add_argument(args.circuit, "circuit")
            .help("Circuit file (or circuit name if --blif_file specified)");

    auto& gfx_grp = parser.add_argument_group("graphics options:");
    gfx_grp.add_argument<bool,OnOff>(args.disp, "--disp")
            .help("Enable or disable interactive graphics")
            .default_value("off");
    gfx_grp.add_argument(args.auto_value, "--auto")
            .help("Controls how often VPR pauses for interactive"
                  " graphics (requiring Proceed to be clicked)."
                  " Higher values pause less frequently")
            .default_value("1")
            .choices({"0", "1", "2"});

    auto& stage_grp = parser.add_argument_group("stage options:");

    stage_grp.add_argument<bool,OnOff>(args.pack, "--pack")
            .help("Run packing")
            .action(argparse::Action::STORE_TRUE)
            .default_value("off");
    stage_grp.add_argument<bool,OnOff>(args.place, "--place")
            .help("Run placement")
            .action(argparse::Action::STORE_TRUE)
            .default_value("off");
    stage_grp.add_argument<bool,OnOff>(args.route, "--route")
            .help("Run routing")
            .action(argparse::Action::STORE_TRUE)
            .default_value("off");
    stage_grp.add_argument<bool,OnOff>(args.route, "--analysis")
            .help("Run analysis")
            .action(argparse::Action::STORE_TRUE)
            .default_value("off");

    stage_grp.epilog("If none of the stage options are specified, all stages are run.\n"
                     "Analysis is always run after routing.");

    auto& gen_grp = parser.add_argument_group("general options:");

    gen_grp.add_argument<bool,OnOff>(args.timing_analysis, "--timing_analysis")
            .help("Controls whether timing analysis (and timing driven optimizations) are enabled.")
            .default_value("on") ;
    gen_grp.add_argument(args.slack_definition, "--slack_definition")
            .help("Sets the slack definition used by the classic timing analyyzer")
            .default_value("R")
            .choices({"R", "I", "S", "G", "C", "N"});
    gen_grp.add_argument<bool,OnOff>(args.echo_files, "--echo_file")
            .help("Generate echo files of key internal data structures. Useful for debugging VPR, and typically end in .echo")
            .default_value("off");
    gen_grp.add_argument<bool,OnOff>(args.verify_file_digests, "--verify_file_digests")
            .help("Verify that intermediate files loaded by VPR (e.g. previous packing/placement/routing) are consistent")
            .default_value("on");

    auto& file_grp = parser.add_argument_group("filename options:");

    file_grp.add_argument(args.blif_file, "--blif_file")
            .help("Path to technology mapped circuit in BLIF format");
    file_grp.add_argument(args.net_file, "--net_file")
            .help("Path to packed netlist file");
    file_grp.add_argument(args.place_file, "--place_file")
            .help("Path to placement file");
    file_grp.add_argument(args.route_file, "--route_file")
            .help("Path to routing file");
    file_grp.add_argument(args.sdc_file, "--sdc_file")
            .help("Path to iming constraints file in SDC format");
    file_grp.add_argument(args.outfile_prefix, "--outfile_prefix")
            .help("Prefix for output files");

    auto& netlist_grp = parser.add_argument_group("netlist options:");
    netlist_grp.add_argument<bool,OnOff>(args.absorb_buffer_luts, "--absorb_buffer_luts")
            .help("Controls whether LUTS programmed as buffers are absorbed by downstream logic")
            .default_value("on");
    netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_primary_ios, "--sweep_dangling_primary_ios")
            .help("Controls whether dangling primary inputs and outputs are removed from the netlist")
            .default_value("on");
    netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_nets, "--sweep_dangling_nets")
            .help("Controls whether dangling nets are removed from the netlist")
            .default_value("on");
    netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_blocks, "--sweep_dangling_blocks")
            .help("Controls whether dangling blocks are removed from the netlist")
            .default_value("on");
    netlist_grp.add_argument<bool,OnOff>(args.sweep_constant_primary_outputs, "--sweep_constant_primary_outputs")
            .help("Controls whether primary outputs driven by constant values are removed from the netlist")
            .default_value("off");

    auto& pack_grp = parser.add_argument_group("packing options:");
    pack_grp.add_argument<bool,OnOff>(args.connection_driven_clustering, "--connection_driven_clustering")
            .help("Controls whether or not packing prioritizes the absorption of nets with fewer connections into a complex logic block over nets with more connections")
            .default_value("on");
    pack_grp.add_argument<bool,OnOff>(args.allow_unrelated_clustering, "--allow_unrelated_clustering")
            .help("Controls whether or not primitives with no attraction to the current cluster can be packed into it")
            .default_value("on");
    pack_grp.add_argument(args.alpha_clustering, "--alpha_clustering")
            .help("Parameter that weights the optimization of timing vs area. 0.0 focuses solely on area, 1.0 solely on timing.")
            .default_value("0.75");
    pack_grp.add_argument(args.beta_clustering, "--beta_clustering")
            .help("Parameter that weights the absorption of small nets vs signal sharing. 0.0 focuses solely on sharing, 1.0 solely on small net absoprtion. Only meaningful if --connection_driven_clustering=on")
            .default_value("0.9");
    pack_grp.add_argument<bool,OnOff>(args.timing_driven_clustering, "--timing_driven_clustering")
            .help("Controls whether custering optimizes for timing")
            .default_value("on");
    pack_grp.add_argument(args.cluster_seed_type, "--cluster_seed_type")
            .help("Controls how primitives are chosen as seeds. (Default: blend if timing driven, max_inputs otherwise)")
            .choices({"blend", "timing", "max_inputs"});

    auto& place_grp = parser.add_argument_group("placement options:");
    place_grp.add_argument(args.seed, "--seed")
            .help("Placement random number generator seed")
            .default_value("1");
    place_grp.add_argument<bool,OnOff>(args.enable_timing_computations, "--enable_timing_computations")
            .help("Displays delay statistics even if placement is not timing driven")
            .default_value("on");
    place_grp.add_argument(args.inner_num, "--inner_num")
            .help("Controls number of moves per temperature: inner_num * num_blocks ^ (4/3)")
            .default_value("10.0");
    place_grp.add_argument(args.init_t, "--init_t")
            .help("Initial temperature for manual annealing schedule")
            .default_value("100.0");
    place_grp.add_argument(args.exit_t, "--exit_t")
            .help("Temperature at which annealing which terminate for manual annealing schedule")
            .default_value("0.01");
    place_grp.add_argument(args.alpha_t, "--alpha_t")
            .help("Temperature scaling factor for manual annealing schedule. Old temperature is multiplied by alpha_t")
            .default_value("0.01");
    place_grp.add_argument(args.fix_pins, "--fix_pins")
            .help("Fixes I/O pad locations during placement."
                  " Can be 'random' for a random initial assignment,"
                  " 'off' to allow the place to optimize pad locations,"
                  " or a file specifying the pad locations.")
            .default_value("off");
    place_grp.add_argument(args.place_algorithm, "--place_algorithm")
            .help("Controls which placement algorithm is used")
            .default_value("path_timing_driven")
            .choices({"bounding_box", "path_timing_driven"});
    place_grp.add_argument(args.place_chan_width, "--place_chan_width")
            .help("Sets the assumed channel width during placement")
            .default_value("100");

    auto& place_timing_grp = parser.add_argument_group("timing-driven placement options:");
    place_timing_grp.add_argument(args.timing_tradeoff, "--timing_tradeoff")
            .help("Trade-off control between delay and wirelength during placement."
                  " 0.0 focuses completely on wirelength, 1.0 completely on timing")
            .default_value("0.5");
    place_timing_grp.add_argument(args.recompute_crit_iter, "--recompute_crit_iter")
            .help("Controls how many temperature updates occur between timing analysis during placement")
            .default_value("1");
    place_timing_grp.add_argument(args.inner_loop_recompute_divider, "--inner_loop_recompute_divider")
            .help("Controls how many timing analysies are perform in a single temperature during placement")
            .default_value("0");
    place_timing_grp.add_argument(args.td_place_exp_first, "--td_place_exp_first")
            .help("Controls how critical a connection is as a function of slack at the start of placement."
                  " A value of zero treats all connections as equally critical (regardless of slack)."
                  " Values larger than 1.0 cause low slack connections to be treated more critically."
                  " The value increases to --td_place_exp_last during placement.")
            .default_value("1.0");
    place_timing_grp.add_argument(args.td_place_exp_first, "--td_place_exp_first")
            .help("Controls how critical a connection is as a function of slack at the end of placement.")
            .default_value("8.0");

    auto& route_grp = parser.add_argument_group("routing options:");
    route_grp.add_argument(args.max_router_iterations, "--max_route_iterations")
            .help("Maximum number of Pathfinder-based routing iterations before the circuit is declared unroutable at a given channel width")
            .default_value("50");
    route_grp.add_argument(args.initial_pres_fac, "--first_iter_pres_fac")
            .help("Sets the present overuse factor for the first routing iteration")
            .default_value("0.0");
    route_grp.add_argument(args.initial_pres_fac, "--initial_pres_fac")
            .help("Sets the present overuse factor for the second routing iteration")
            .default_value("0.5");
    route_grp.add_argument(args.pres_fac_mult, "--pres_fac_mult")
            .help("Sets the growth factor by which the present overuse penalty factor is multiplied after each routing iteration")
            .default_value("1.3");
    route_grp.add_argument(args.acc_fac, "--acc_fac")
            .help("Specifies the accumulated overuse factor (historical congestion cost factor)")
            .default_value("1.0");
    route_grp.add_argument(args.bb_factor, "--bb_factor")
            .help("Sets the distance (in channels) outside a connection's bounding box which can be explored")
            .default_value("3");
    route_grp.add_argument(args.base_cost_type, "--base_cost_type")
            .help("Sets the basic cost of routing resource nodes:\n"
                  " * demand_only: based on expected demand of node type\n"
                  " * delay_normalized: like demand_only but normalized to magnitude of typical routing resource delay\n"
                  "(Default: demand_only for bread-first router, delay_normalized for timing-driven router)")
            .choices({"demand_only", "delay_normalized"});
    route_grp.add_argument(args.bend_cost, "--bend_cost")
            .help("The cost of a bend. (Default: 1.0 for global routing, 0.0 for detailed routing)");
    route_grp.add_argument(args.route_type, "--route_type")
            .help("Specifies whether global, or combined global and detailed routing is performed.")
            .choices({"global", "detailed"});
    route_grp.add_argument(args.route_chan_width, "--route_chan_width")
            .help("Specifies a fixed channel width to route at.");
    route_grp.add_argument(args.min_route_chan_width_hint, "--min_route_chan_width_hint")
            .help("Hint to the router what the minimum routable channel width is."
                  " Good hints can speed-up determining the minimum channel width.");
    route_grp.add_argument<bool,OnOff>(args.verify_binary_search, "--verify_binary_search")
            .help("Force the router to verify the minimum channel width by routing at"
                  " consecutively lower channel widths until two consecutive failures are observed.")
            .default_value("off");
    route_grp.add_argument(args.router_algorithm, "--router_algorithm")
            .help("Specifies the router algorithm to use.\n"
                  " * breadth_first: focuses solely on routability\n"
                  " * timing driven: focuses on routability and circuit speed\n")
            .default_value("timing_driven")
            .choices({"breadth_first", "timing_driven"});
    route_grp.add_argument(args.min_incremental_reroute_fanout, "--min_incremental_reroute_fanout")
            .help("The net fanout thershold above which nets will be re-routed incrementally.")
            .default_value("64");

    auto& route_timing_grp = parser.add_argument_group("timing-driven routing options:");
    route_timing_grp.add_argument(args.astar_fac, "--astar_fac")
            .help("How aggressive the directed search used by the timing-driven router is."
                  " Values between 1 and 2 are resonable; higher values trade some quality for reduced run-time")
            .default_value("1.2");
    route_timing_grp.add_argument(args.max_criticality, "--max_criticality")
            .help("Sets the maximum fraction of routing cost derived from delay (vs routability) for any net."
                  " 0.0 means no attention is paid to delay, 1.0 means nets on the critical path ignore congestion")
            .default_value("0.99");
    route_timing_grp.add_argument(args.criticality_exp, "--criticality_exp")
            .help("Controls the delay-routability trade-off for nets as a function of slack."
                  " 0.0 implies all nets treated equally regardless of slack."
                  " At large values (>> 1) only nets on the critical path will consider delay.")
            .default_value("1.0");
    route_timing_grp.add_argument(args.routing_failure_predictor, "--routing_failure_predictor")
            .help("Controls how aggressively the router will predict a routing as unsuccessful"
                  " and give up early. This can significantly reducing the run-time required"
                  " to find the minimum channel width).\n"
                  " * safe: Only abort when it is extremely unlikely a routing will succeed\n"
                  " * aggressive: Further reduce run-time by giving up earlier. This may increase the reported minimum channel width\n"
                  " * off: Only abort when the maximum number of iterations is reached\n")
            .default_value("safe")
            .choices({"safe", "aggressive", "off"});

    auto& analysis_grp = parser.add_argument_group("analysis options:");

    analysis_grp.add_argument<bool,OnOff>(args.full_stats, "--full_stats")
                .help("Print extra statistics about the circuit and it's routing (useful for wireability analysis)")
                .default_value("off");

    analysis_grp.add_argument<bool,OnOff>(args.gen_post_synthesis_netlist, "--gen_post_synthesis_netlist")
                .help("Generates the post-synthesis netlist (in BLIF and Verilog) along with delay information (in SDF)")
                .default_value("off");

    auto& power_grp = parser.add_argument_group("power analysis options:");
    power_grp.add_argument<bool,OnOff>(args.power, "--power")
        .help("Enable power estimation")
        .default_value("off");
    power_grp.add_argument(args.tech_properties_file, "--tech_properties_file")
        .help("XML file containing CMOS technology properties (see documentation).")
        .default_value("off");
    power_grp.add_argument(args.activity_file, "--activity_file")
        .help("Signal activities file for all nets (see documentation).")
        .default_value("off");

    parser.print_help();

    parser.parse_args(argc, argv);

    std::cout << "args.disp: " << args.disp << "\n";

    //for(auto& arg : args) {
        //std::cout << arg.name() << ": " << arg.value() << "\n";
    //}

    return 0;
}
<|endoftext|>