%{
/*****************************************************************************/
/*!
 * \file smtlib.y
 * 
 * Author: Clark Barrett
 * 
 * Created: Apr 30 2005
 *
 * 
 *
 * License to use, copy, modify, sell and/or distribute this software
 * and its documentation for any purpose is hereby granted without
 * royalty, subject to the terms and conditions defined in the \ref
 * LICENSE file provided with this distribution.
 * 
 * 
 * 
 */
/*****************************************************************************/
/* 
   This file contains the bison code for the parser that reads in CVC
   commands in SMT-LIB language.
*/
#include "SMTParser.h"
#include "klee/Expr.h"
#include "klee/ExprBuilder.h"
#include 
using namespace klee;
using namespace klee::expr;
// Define shortcuts for various things
#define PARSER SMTParser::parserTemp
#define BUILDER SMTParser::parserTemp->builder
#define DONE SMTParser::parserTemp->done
#define ASSUMPTIONS SMTParser::parserTemp->assumptions
#define QUERY SMTParser::parserTemp->satQuery
#define ARRAYSENABLED (SMTParser::parserTemp->arraysEnabled)
#define BVSIZE (SMTParser::parserTemp->bvSize)
#define QUERYPARSED SMTParser::parserTemp->queryParsed
// Suppress the bogus warning suppression in bison (it generates
// compile error)
#undef __GNUC_MINOR__
/* stuff that lives in smtlib.lex */
extern int smtliblex(void);
int smtliberror(const char *s)
{
  return SMTParser::parserTemp->Error(s);
}
#define YYLTYPE_IS_TRIVIAL 1
#define YYMAXDEPTH 10485760
%}
/*
%union {
  std::string *str;
  std::vector *strvec;
  CVC3::Expr *node;
  std::vector *vec;
  std::pair, std::vector > *pat_ann;
};
*/
%union {
  std::string *str;
  klee::expr::ExprHandle node;
  std::vector *vec;
};
%start cmd
/* strings are for better error messages.  
   "_TOK" is so macros don't conflict with kind names */
/*
%type  bench_attributes sort_symbs fun_symb_decls pred_symb_decls
%type  an_formulas quant_vars an_terms fun_symb patterns
%type  pattern 
%type  benchmark bench_name bench_attribute
%type  status fun_symb_decl fun_sig pred_symb_decl pred_sig
%type  an_formula quant_var an_atom prop_atom
%type  an_term basic_term sort_symb pred_symb
%type  var fvar
%type  logic_name quant_symb connective user_value attribute annotation
%type  annotations
%type  patterns_annotations
*/
%type  an_formula an_logical_formula an_atom prop_atom
%type  an_formulas
%type  an_term basic_term constant
%type  an_fun an_arithmetic_fun an_bitwise_fun
%type  an_pred
%type  logic_name status attribute user_value annotation annotations 
%type  var fvar symb
%token  NUMERAL_TOK
%token  SYM_TOK
%token  STRING_TOK
%token  AR_SYMB
%token  USER_VAL_TOK
%token  BV_TOK
%token  BVBIN_TOK
%token  BVHEX_TOK
%token BITVEC_TOK
%token TRUE_TOK
%token FALSE_TOK
%token ITE_TOK
%token NOT_TOK
%token IMPLIES_TOK
%token IF_THEN_ELSE_TOK
%token AND_TOK
%token OR_TOK
%token XOR_TOK
%token IFF_TOK
%token EXISTS_TOK
%token FORALL_TOK
%token LET_TOK
%token FLET_TOK
%token NOTES_TOK
%token CVC_COMMAND_TOK
%token SORTS_TOK
%token FUNS_TOK
%token PREDS_TOK
%token EXTENSIONS_TOK
%token DEFINITION_TOK
%token AXIOMS_TOK
%token LOGIC_TOK
%token COLON_TOK
%token LBRACKET_TOK
%token RBRACKET_TOK
%token LCURBRACK_TOK
%token RCURBRACK_TOK
%token LPAREN_TOK
%token RPAREN_TOK
%token SAT_TOK
%token UNSAT_TOK
%token UNKNOWN_TOK
%token ASSUMPTION_TOK
%token FORMULA_TOK
%token STATUS_TOK
%token BENCHMARK_TOK
%token EXTRASORTS_TOK
%token EXTRAFUNS_TOK
%token EXTRAPREDS_TOK
%token LANGUAGE_TOK
%token DOLLAR_TOK
%token QUESTION_TOK
%token DISTINCT_TOK
%token SEMICOLON_TOK
%token EOF_TOK
%token PAT_TOK
%token BIT0_TOK
%token BIT1_TOK
%token BVCONCAT_TOK
%token BVEXTRACT_TOK
%token BVNOT_TOK
%token BVAND_TOK
%token BVOR_TOK
%token BVNEG_TOK
%token BVNAND_TOK
%token BVNOR_TOK
%token BVXOR_TOK
%token BVXNOR_TOK
%token EQ_TOK
%token BVCOMP_TOK
%token BVULT_TOK
%token BVULE_TOK
%token BVUGT_TOK
%token BVUGE_TOK
%token BVSLT_TOK
%token BVSLE_TOK
%token BVSGT_TOK
%token BVSGE_TOK
%token BVADD_TOK
%token BVSUB_TOK
%token BVMUL_TOK
%token BVUDIV_TOK
%token BVUREM_TOK
%token BVSDIV_TOK
%token BVSREM_TOK
%token BVSMOD_TOK
%token BVSHL_TOK
%token BVLSHR_TOK
%token BVASHR_TOK
%token REPEAT_TOK
%token ZEXT_TOK
%token SEXT_TOK
%token ROL_TOK
%token ROR_TOK
%%
cmd:
    benchmark
    {
      YYACCEPT;
    }
;
benchmark:
    LPAREN_TOK BENCHMARK_TOK bench_name bench_attributes RPAREN_TOK { }
  | EOF_TOK
    { 
      DONE = true;
    }
;
bench_name:
    SYM_TOK { }
;
bench_attributes:
    bench_attribute { }
  | bench_attributes bench_attribute { }
;
bench_attribute:
    COLON_TOK ASSUMPTION_TOK an_formula
    {
      ASSUMPTIONS.push_back($3);
    }
  | COLON_TOK FORMULA_TOK an_formula 
    {
      QUERYPARSED = true;
      QUERY = $3;
    }
  | COLON_TOK STATUS_TOK status { }
  | COLON_TOK LOGIC_TOK logic_name 
    {
      if (*$3 != "QF_BV" && *$3 != "QF_AUFBV" && *$3 != "QF_UFBV") {
	llvm::errs() << "ERROR: Logic " << *$3 << " not supported.";
	exit(1);
      }
      if (*$3 == "QF_AUFBV")
        ARRAYSENABLED = true;
    }
/*
  | COLON_TOK EXTRASORTS_TOK LPAREN_TOK sort_symbs RPAREN_TOK
    { 
      // XXX?
    }
*/
  | COLON_TOK EXTRAFUNS_TOK LPAREN_TOK LPAREN_TOK SYM_TOK BITVEC_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK RPAREN_TOK RPAREN_TOK
    {
      PARSER->DeclareExpr(*$5, atoi($8->c_str()));
    }
/*
  | COLON_TOK EXTRAPREDS_TOK LPAREN_TOK pred_symb_decls RPAREN_TOK
    {
      //$$ = new CVC3::Expr(VC->listExpr("_SEQ", *$4));
      //delete $4;
    }
*/
  | COLON_TOK NOTES_TOK STRING_TOK
    {  }
  | COLON_TOK CVC_COMMAND_TOK STRING_TOK
    {  }
  | annotation
    {  }
;
logic_name  :
    SYM_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK
    {
      BVSIZE = atoi($3->c_str());
      delete $3;
      $$ = $1;
    }
  | SYM_TOK
    {
      $$ = $1;
    }
;
status:
    SAT_TOK { }
  | UNSAT_TOK { }
  | UNKNOWN_TOK { }
;
/*
sort_symbs:
    sort_symb 
    {
      $$ = new std::vector;
      $$->push_back(*$1);
      delete $1;
    }
  | sort_symbs sort_symb
    { 
      $1->push_back(*$2);
      $$ = $1;
      delete $2;
    }
;
fun_symb_decls:
    fun_symb_decl
    {
      $$ = new std::vector;
      $$->push_back(*$1);
      delete $1;
    }
  |
    fun_symb_decls fun_symb_decl
    {
      $1->push_back(*$2);
      $$ = $1;
      delete $2;
    }
;
fun_symb_decl:
    LPAREN_TOK fun_sig annotations
    {
      $$ = $2;
      delete $3;
    }
  | LPAREN_TOK fun_sig RPAREN_TOK
    {
      $$ = $2;
    }
;
fun_sig:
    fun_symb sort_symbs
    {
      if ($2->size() == 1) {
        $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$1), (*$2)[0]));
      }
      else {
        CVC3::Expr tmp(VC->listExpr("_ARROW", *$2));
        $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$1), tmp));
      }
      delete $1;
      delete $2;
    }
;
pred_symb_decls:
    pred_symb_decl
    {
      $$ = new std::vector;
      $$->push_back(*$1);
      delete $1;
    }
  |
    pred_symb_decls pred_symb_decl
    {
      $1->push_back(*$2);
      $$ = $1;
      delete $2;
    }
;
pred_symb_decl:
    LPAREN_TOK pred_sig annotations
    {
      $$ = $2;
      delete $3;
    }
  | LPAREN_TOK pred_sig RPAREN_TOK
    {
      $$ = $2;
    }
;
pred_sig:
    pred_symb sort_symbs
    {
      std::vector tmp(*$2);
      tmp.push_back(VC->idExpr("_BOOLEAN"));
      CVC3::Expr tmp2(VC->listExpr("_ARROW", tmp));
      $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$1), tmp2));
      delete $1;
      delete $2;
    }
  | pred_symb
    {
      $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$1),
                                       VC->idExpr("_BOOLEAN")));
      delete $1;
    }
;
*/
an_formulas:
    an_formula
    {
      $$ = new std::vector;
      $$->push_back($1);
    }
  |
    an_formulas an_formula
    {
      $1->push_back($2);
      $$ = $1;
    }
;
an_logical_formula:
    LPAREN_TOK NOT_TOK an_formula annotations
    {
      $$ = BUILDER->Not($3);
    }
  | LPAREN_TOK IMPLIES_TOK an_formula an_formula annotations
    {
      $$ = Expr::createImplies($3, $4);  // XXX: move to builder?
    }
  | LPAREN_TOK IF_THEN_ELSE_TOK an_formula an_formula an_formula annotations
    {
      $$ = BUILDER->Select($3, $4, $5);
    }
  | LPAREN_TOK AND_TOK an_formulas annotations
    {
      $$ = PARSER->CreateAnd(*$3);
    }
  | LPAREN_TOK OR_TOK an_formulas annotations
    {
      $$ = PARSER->CreateOr(*$3);
    }
  | LPAREN_TOK XOR_TOK an_formulas annotations
    {
      $$ = PARSER->CreateXor(*$3);
    }
  | LPAREN_TOK IFF_TOK an_formula an_formula annotations
    {
      $$ = BUILDER->Eq($3, $4);
    }
;
an_formula:
    an_atom
    {
      $$ = $1;
    }
  | an_logical_formula
    {
      $$ = $1;
    }
  | LPAREN_TOK LET_TOK LPAREN_TOK var an_term RPAREN_TOK
        { 
	  PARSER->PushVarEnv();
	  PARSER->AddVar(*$4, $5); 
	} 
    an_formula annotations
    {
      $$ = $8;
      PARSER->PopVarEnv();
    }
  | LPAREN_TOK FLET_TOK LPAREN_TOK fvar an_formula RPAREN_TOK 
        { 
	  PARSER->PushFVarEnv();
	  PARSER->AddFVar(*$4, $5); 
	} 
    an_formula annotations
    {
      $$ = $8;
      PARSER->PopFVarEnv();
    }
;
an_atom:
    prop_atom 
    {
      $$ = $1;
    }
  | LPAREN_TOK prop_atom annotations 
    {
      $$ = $2;
    }
  
  | an_pred
    {
      $$ = $1;
    }
/*
  | LPAREN_TOK DISTINCT_TOK an_terms annotations
    {
      $$ = new CVC3::Expr(VC->listExpr("_DISTINCT", *$3));
//       std::vector tmp;
//       tmp.push_back(*$2);
//       tmp.insert(tmp.end(), $3->begin(), $3->end());
//       $$ = new CVC3::Expr(VC->listExpr(tmp));
//       for (unsigned i = 0; i < (*$3).size(); ++i) {
//         tmp.push_back(($3)[i])
// 	for (unsigned j = i+1; j < (*$3).size(); ++j) {
// 	  tmp.push_back(VC->listExpr("_NEQ", (*$3)[i], (*$3)[j]));
// 	}
//       }
//       $$ = new CVC3::Expr(VC->listExpr("_AND", tmp));
      delete $3;
      delete $4;
    }
  | LPAREN_TOK DISTINCT_TOK an_terms RPAREN_TOK
    {
      $$ = new CVC3::Expr(VC->listExpr("_DISTINCT", *$3));
//       std::vector tmp;
//       for (unsigned i = 0; i < (*$3).size(); ++i) {
// 	for (unsigned j = i+1; j < (*$3).size(); ++j) {
// 	  tmp.push_back(VC->listExpr("_NEQ", (*$3)[i], (*$3)[j]));
// 	}
//       }
//       $$ = new CVC3::Expr(VC->listExpr("_AND", tmp));
      delete $3;
    }
*/
;
prop_atom:
    TRUE_TOK
    {
      $$ = BUILDER->Constant(1, 1);
    }
  | FALSE_TOK
    { 
      $$ = BUILDER->Constant(0, 1);;
    }
  | fvar
    {
      $$ = PARSER->GetFVar(*$1);
    }
;  
an_pred:
    LPAREN_TOK EQ_TOK an_term an_term annotations
    {
      $$ = BUILDER->Eq($3, $4);
    }
  | LPAREN_TOK BVULT_TOK an_term an_term annotations
    {
      $$ = BUILDER->Ult($3, $4);
    }
  | LPAREN_TOK BVULE_TOK an_term an_term annotations
    {
      $$ = BUILDER->Ule($3, $4);
    }
  | LPAREN_TOK BVUGT_TOK an_term an_term annotations
    {
      $$ = BUILDER->Ugt($3, $4);
    }
  | LPAREN_TOK BVUGE_TOK an_term an_term annotations
    {
      $$ = BUILDER->Uge($3, $4);
    }
  | LPAREN_TOK BVSLT_TOK an_term an_term annotations
    {
      $$ = BUILDER->Slt($3, $4);
    }
  | LPAREN_TOK BVSLE_TOK an_term an_term annotations
    {
      $$ = BUILDER->Sle($3, $4);
    }
  | LPAREN_TOK BVSGT_TOK an_term an_term annotations
    {
      $$ = BUILDER->Sgt($3, $4);
    }
  | LPAREN_TOK BVSGE_TOK an_term an_term annotations
    {
      $$ = BUILDER->Sge($3, $4);
    }
;
an_arithmetic_fun:
    LPAREN_TOK BVNEG_TOK an_term annotations
    {
      smtliberror("bvneg not supported yet");
      $$ = NULL; // TODO
    }
  | LPAREN_TOK BVADD_TOK an_term an_term annotations
    {
      $$ = BUILDER->Add($3, $4);
    }
  | LPAREN_TOK BVSUB_TOK an_term an_term annotations
    {
      $$ = BUILDER->Sub($3, $4);
    }
  | LPAREN_TOK BVMUL_TOK an_term an_term annotations
    {
      $$ = BUILDER->Mul($3, $4);
    }
  | LPAREN_TOK BVUDIV_TOK an_term an_term annotations
    {
      $$ = BUILDER->UDiv($3, $4);
    }
  | LPAREN_TOK BVUREM_TOK an_term an_term annotations
    {
      $$ = BUILDER->URem($3, $4);
    }
  | LPAREN_TOK BVSDIV_TOK an_term an_term annotations
    {
      $$ = BUILDER->SDiv($3, $4);
    }
  | LPAREN_TOK BVSREM_TOK an_term an_term annotations
    {
      $$ = BUILDER->SRem($3, $4);
    }
  | LPAREN_TOK BVSMOD_TOK an_term an_term annotations
    {
      smtliberror("bvsmod not supported yet");
      $$ = NULL; // TODO
    }
;
an_bitwise_fun:
    LPAREN_TOK BVNOT_TOK an_term annotations
    {
      $$ = BUILDER->Not($3);
    }
  | LPAREN_TOK BVAND_TOK an_term an_term annotations
    {
      $$ = BUILDER->And($3, $4);
    }
  | LPAREN_TOK BVOR_TOK an_term an_term annotations
    {
      $$ = BUILDER->Or($3, $4);
    }
  | LPAREN_TOK BVXOR_TOK an_term an_term annotations
    {
      $$ = BUILDER->Xor($3, $4);
    }
  | LPAREN_TOK BVXNOR_TOK an_term an_term annotations
    {      
      smtliberror("bvxnor not supported yet");
      $$ = NULL;  // TODO
    }
  | LPAREN_TOK BVSHL_TOK an_term an_term annotations
    {
      $$ = BUILDER->Shl($3, $4);
    }
  | LPAREN_TOK BVLSHR_TOK an_term an_term annotations
    {
      $$ = BUILDER->LShr($3, $4);
    }
  | LPAREN_TOK BVASHR_TOK an_term an_term annotations
    {
      $$ = BUILDER->AShr($3, $4);
    }
  | LPAREN_TOK ROL_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK an_term annotations
    {
      smtliberror("rotate_left not supported yet");
      $$ = NULL; // TODO
    }
  | LPAREN_TOK ROR_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK an_term annotations
    {
      smtliberror("rotate_right not supported yet");
      $$ = NULL; // TODO
    }
 
  | LPAREN_TOK ZEXT_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK an_term annotations
    {
      $$ = BUILDER->ZExt($6, $6->getWidth() + PARSER->StringToInt(*$4));
    }
  | LPAREN_TOK SEXT_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK an_term annotations
    {
      $$ = BUILDER->SExt($6, $6->getWidth() + PARSER->StringToInt(*$4));
    }
  | LPAREN_TOK BVCONCAT_TOK an_term an_term annotations
    {
      $$ = BUILDER->Concat($3, $4);
    }
  | LPAREN_TOK REPEAT_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK an_term annotations
    {
      smtliberror("repeat not supported yet");
      $$ = NULL; // TODO
    }
  | LPAREN_TOK BVEXTRACT_TOK LBRACKET_TOK NUMERAL_TOK COLON_TOK NUMERAL_TOK RBRACKET_TOK an_term annotations
    {
      int off = PARSER->StringToInt(*$6);
      $$ = BUILDER->Extract($8, off, PARSER->StringToInt(*$4) - off + 1);
    }
;
an_fun:
    an_logical_formula
    {
      $$ = $1;
    }
  | an_pred
    {
      $$ = $1;
    }
  | LPAREN_TOK BVCOMP_TOK an_term an_term annotations
    {
      $$ = BUILDER->Eq($3, $4);
    }
 
  | an_arithmetic_fun
    {
      $$ = $1;
    }
  | an_bitwise_fun
    {
      $$ = $1;
    }
/*
      else if (ARRAYSENABLED && *$1 == "select") {
        $$->push_back(VC->idExpr("_READ"));
      }
      else if (ARRAYSENABLED && *$1 == "store") {
        $$->push_back(VC->idExpr("_WRITE"));
      }
*/
;
constant:
    BIT0_TOK
    {
      $$ = PARSER->GetConstExpr("0", 2, 1);
    }
  | BIT1_TOK
    {
      $$ = PARSER->GetConstExpr("1", 2, 1);
    }
  | BVBIN_TOK
    {
      $$ = PARSER->GetConstExpr($1->substr(5), 2, $1->length()-5);
    }
  | BVHEX_TOK
    {
      $$ = PARSER->GetConstExpr($1->substr(5), 16, ($1->length()-5)*4);
    }
  | BV_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK
    {
      $$ = PARSER->GetConstExpr($1->substr(2), 10, PARSER->StringToInt(*$3));
    }
;
an_term:
    basic_term 
    {
      $$ = $1;
    }
  | LPAREN_TOK basic_term annotations 
    {
      $$ = $2;
      delete $3;
    }
  | an_fun
    {
      $$ = $1;
    }
  | LPAREN_TOK ITE_TOK an_formula an_term an_term annotations
    {
      $$ = BUILDER->Select($3, $4, $5);
    }
;
basic_term:
    constant 
    {
      $$ = $1;
    }
  | var
    {
      $$ = PARSER->GetVar(*$1);
    }
  | symb
    {
      $$ = PARSER->GetVar(*$1);
    }
;
annotations:
    RPAREN_TOK { }
  | annotation annotations { }
;
annotation:
    attribute { }
  | attribute user_value {  }
;
user_value:
    USER_VAL_TOK  
    {
      delete $1;
    }
;
/*
sort_symb:
    SYM_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK
    {
      if (BVENABLED && *$1 == "BitVec") {
        $$ = new CVC3::Expr(VC->listExpr("_BITVECTOR", VC->ratExpr(*$3)));
      }
      else {
        $$ = new CVC3::Expr(VC->listExpr(*$1, VC->ratExpr(*$3)));
      }
      delete $1;
      delete $3;
    }
  | SYM_TOK LBRACKET_TOK NUMERAL_TOK COLON_TOK NUMERAL_TOK RBRACKET_TOK
    {
      if (BVENABLED && ARRAYSENABLED && *$1 == "Array") {
        $$ = new CVC3::Expr(VC->listExpr("_ARRAY",
                                         VC->listExpr("_BITVECTOR", VC->ratExpr(*$3)),
                                         VC->listExpr("_BITVECTOR", VC->ratExpr(*$5))));
      }
      else {
        $$ = new CVC3::Expr(VC->listExpr(*$1, VC->ratExpr(*$3), VC->ratExpr(*$5)));
      }
      delete $1;
      delete $3;
      delete $5;
    }
  | SYM_TOK 
    { 
      if (*$1 == "Real") {
	$$ = new CVC3::Expr(VC->idExpr("_REAL"));
      } else if (*$1 == "Int") {
	$$ = new CVC3::Expr(VC->idExpr("_INT"));
      } else {
	$$ = new CVC3::Expr(VC->idExpr(*$1));
      }
      delete $1;
    }
;
*/
/*
fun_symb:
    SYM_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK
    {
      else if (BVENABLED &&
               $1->size() > 2 &&
               (*$1)[0] == 'b' &&
               (*$1)[1] == 'v') {
        int i = 2;
        while ((*$1)[i] >= '0' && (*$1)[i] <= '9') ++i;
        if ((*$1)[i] == '\0') {
          $$->push_back(VC->idExpr("_BVCONST"));
          $$->push_back(VC->ratExpr($1->substr(2), 10));
        }
        else $$->push_back(VC->idExpr(*$1));
      }
      else $$->push_back(VC->idExpr(*$1));
      $$->push_back(VC->ratExpr(*$3));
      delete $1;
      delete $3;
    }
;
*/
attribute:
    COLON_TOK SYM_TOK
    {
      $$ = $2;
    }
;
var:
    QUESTION_TOK SYM_TOK
    {
      $$ = $2;
    }
;
fvar:
    DOLLAR_TOK SYM_TOK
    {
      $$ = $2;
    }
;
symb:
    SYM_TOK
    {
      $$ = $1;
    }
%%