示例#1
0
ASTForm* DistributiveAntiPrenexer::universalDistributiveAntiPrenex(ASTForm *form) {
    static_assert(std::is_base_of<ASTForm_q, ForallClass>::value, "ForallClass is not derived from 'ASTForm_q' class");

    // First call the anti-prenexing rule to push the quantifier as deep as possible
    //ASTForm* antiPrenexedForm = universalAntiPrenex<ForallClass>(form);

    // Push negations down as well
    NegationUnfolder negationUnfolding;
    ASTForm* antiPrenexedForm = reinterpret_cast<ASTForm*>(form->accept(negationUnfolding));

    if(antiPrenexedForm->kind == aAll1 || antiPrenexedForm->kind == aAll2) {
        // Not everything was pushed, we can try to call the distribution
        ForallClass* allForm = reinterpret_cast<ForallClass*>(antiPrenexedForm);
        switch(allForm->f->kind) {
            case aOr:
                return distributeConjunction<ForallClass>(allForm);
            case aAnd:
                return distributiveRule<ForallClass, ASTForm_And>(allForm);
            default:
                UniversalQuantifierRemover universalRemover;
                antiPrenexedForm = reinterpret_cast<ASTForm*>(antiPrenexedForm->accept(universalRemover));
                return reinterpret_cast<ASTForm*>(antiPrenexedForm->accept(negationUnfolding));
        }
    } else {
        // We are done
        return antiPrenexedForm;
    }
}
示例#2
0
ASTForm* DistributiveAntiPrenexer::existentialDistributiveAntiPrenex(ASTForm *form) {
    static_assert(std::is_base_of<ASTForm_q, ExistClass>::value, "ExistClass is not derived from 'ASTForm_q' class");

    // First call the anti-prenexing rule to push the quantifier as deep as possible
    //ASTForm* antiPrenexedForm = existentialAntiPrenex<ExistClass>(form);

    // Expand Universal Quantifier
    UniversalQuantifierRemover universalUnfolding;
    ASTForm* antiPrenexedForm = reinterpret_cast<ASTForm*>(form->accept(universalUnfolding));

    // Push negations down as well
    NegationUnfolder negationUnfolding;
    antiPrenexedForm = reinterpret_cast<ASTForm*>(antiPrenexedForm->accept(negationUnfolding));

    if(antiPrenexedForm->kind == aEx1 || antiPrenexedForm->kind == aEx2) {
        ExistClass* exForm = reinterpret_cast<ExistClass*>(antiPrenexedForm);
        switch(exForm->f->kind) {
            case aOr:
                return distributiveRule<ExistClass, ASTForm_Or>(exForm);
            case aAnd:
                return distributeDisjunction<ExistClass>(exForm);
            default:
                return antiPrenexedForm;
        }
    } else {
        // We are done
        return antiPrenexedForm;
    }
}
示例#3
0
void update_restriction(unsigned int oldVar, unsigned int newVar, IdentList* ffParams, ASTList* rrParams) {
	ASTForm *restriction = symbolTable.lookupRestriction(oldVar);
	if (restriction != nullptr) {
		restriction = restriction->clone()->unfoldMacro(ffParams, rrParams);
		symbolTable.updateRestriction(newVar, restriction);
	}
}
示例#4
0
/**
 * Unfolds the called macro by substituting its formal parameters with real
 * parameters
 *
 * @param called: called macro
 * @param realParams: real parameters
 * @return: unfolded formula
 */
ASTForm* unfoldFormula(PredLibEntry* called, ASTList* realParams) {
    IdentList* formalParams = called->formals;

    ASTForm* clonnedFormula = (called->ast)->clone();
    ASTForm* unfoldedFormula = clonnedFormula->unfoldMacro(formalParams, realParams);

    Flattener f_visitor;
    return static_cast<ASTForm*>(unfoldedFormula->accept(f_visitor));
}
示例#5
0
ASTForm* FullAntiPrenexer::nonDistributiveRule(QuantifierClass *qForm) {
    static_assert(std::is_base_of<ASTForm_q, QuantifierClass>::value, "QuantifierClass is not derived from 'ASTForm_q' class");
    static_assert(std::is_base_of<ASTForm_ff, BinopClass>::value, "BinopClass is not derived from 'ASTForm_ff' class");

    // Ex . f1 op f2 -> (Ex X. f1) op f2
    // Ex . f2 op f2 -> f1 op (Ex X. f2)
    BinopClass *binopForm = static_cast<BinopClass*>(qForm->f);
    ASTForm *tempResult;

    IdentList *bound = qForm->vl;
    IdentList left, right, middle;
    IdentList free1, bound1;
    IdentList free2, bound2;
    binopForm->f1->freeVars(&free1, &bound1);
    binopForm->f2->freeVars(&free2, &bound2);

    for (auto var = bound->begin(); var != bound->end(); ++var) {
        bool varInLeft = free1.exists(*var);
        bool varInRight = free2.exists(*var);

        // Ex var. f1 op f2     | var in f1 && var in f2
        if (varInLeft && varInRight) {
            middle.push_back(*var);
        // (Ex var. f1) op f2   | var notin f2
        } else if(varInLeft) {
            left.push_back(*var);
        // f1 op (Ex var. f2)   | var notin f1
        } else if(varInRight) {
            right.push_back(*var);
        } // f1 op f2           | var notin f1 && var notin f2
    }

    qForm->f = nullptr;
    delete qForm;

    if(!left.empty()) {
        tempResult = new QuantifierClass(nullptr, new IdentList(left), binopForm->f1, binopForm->f1->pos);
        binopForm->f1 = static_cast<ASTForm*>(tempResult->accept(*this));
    }

    if(!right.empty()) {
        tempResult = new QuantifierClass(nullptr, new IdentList(right), binopForm->f2, binopForm->f2->pos);
        binopForm->f2 = static_cast<ASTForm*>(tempResult->accept(*this));
    }

    if(!middle.empty()) {
        tempResult = new QuantifierClass(nullptr, new IdentList(middle), binopForm, binopForm->pos);
        return tempResult;
    } else {
        return binopForm;
    }
}
示例#6
0
文件: mona.cpp 项目: ondrik/mona-vata
int 
main(int argc, char *argv[])
{
  std::set_new_handler(&mem_error);

  if (!ParseArguments(argc, argv)) {
    Usage();
    exit(-1);
  }

  // Disable core dump
  struct rlimit r_core;
  r_core.rlim_cur = 0;
  r_core.rlim_max = 0;
  setrlimit(RLIMIT_CORE, &r_core);

  // Set demo limits 
  if (options.demo) {
    struct rlimit r_cpu, r_as;
    memlimit = true;

    r_cpu.rlim_cur = 30; // max 30 secs.
    r_cpu.rlim_max = 30;
    setrlimit(RLIMIT_CPU, &r_cpu);

    r_as.rlim_cur = 20971520; // max 20MB
    r_as.rlim_max = 20971520;
    setrlimit(RLIMIT_DATA, &r_as);

    signal(SIGXCPU, &cpuLimit);
  }

  initTimer();
  Timer timer_total;
  timer_total.start();
  
  ///////// PARSING ////////////////////////////////////////////////////////

  if (options.printProgress)
    cout << "MONA v" << VERSION << "-" << RELEASE <<  " for WS1S/WS2S\n"
      "Copyright (C) 1997-2008 BRICS\n\n"
      "PARSING\n";

  Timer timer_parsing;
  timer_parsing.start();

  loadFile(inputFileName);
  yyparse();
  MonaAST *ast = untypedAST->typeCheck();
  lastPosVar = ast->lastPosVar;
  allPosVar = ast->allPosVar;

  timer_parsing.stop();

  if (options.printProgress) {
    cout << "Time: ";
    timer_parsing.print();
  }

  delete untypedAST;

  if (options.dump) {
    // Dump AST for main formula, verify formulas, and assertion
    cout << "Main formula:\n";
    (ast->formula)->dump();
    Deque<ASTForm *>::iterator vf;
    Deque<char *>::iterator vt;
    for (vf = ast->verifyformlist.begin(), vt = ast->verifytitlelist.begin();
	 vf != ast->verifyformlist.end(); vf++, vt++) {
      cout << "\n\nFormula " << *vt << ":\n";
      (*vf)->dump();
    }
    cout << "\n\nAssertions:\n";
    (ast->assertion)->dump();
    cout << "\n";

    if (lastPosVar != -1)
      cout << "\nLastPos variable: " 
	   << symbolTable.lookupSymbol(lastPosVar) << "\n";
    if (allPosVar != -1)
      cout << "\nAllPos variable: " 
	   << symbolTable.lookupSymbol(allPosVar) << "\n";
    
    // Dump ASTs for predicates and macros
    PredLibEntry *pred = predicateLib.first();
    while (pred != NULL) {
      if (pred->isMacro)
	cout << "\nMacro '";
      else
	cout << "\nPredicate '";
      cout << symbolTable.lookupSymbol(pred->name) 
	   << "':\n";
      (pred->ast)->dump();
      cout << "\n";
      pred = predicateLib.next();
    }

    // Dump restrictions
    if (symbolTable.defaultRestriction1) {
      cout << "\nDefault first-order restriction (" 
	   << symbolTable.lookupSymbol(symbolTable.defaultIdent1) << "):\n";
      symbolTable.defaultRestriction1->dump();
      cout << "\n";
    }
    if (symbolTable.defaultRestriction2) {
      cout << "\nDefault second-order restriction (" 
	   << symbolTable.lookupSymbol(symbolTable.defaultIdent2) << "):\n";
      symbolTable.defaultRestriction2->dump();
      cout << "\n";
    }

    Ident id;
    for (id = 0; id < (Ident) symbolTable.noIdents; id++) {
      Ident t;
      ASTForm *f = symbolTable.getRestriction(id, &t);
      if (f) {
	cout << "\nRestriction for #" << id << " (" 
	     << symbolTable.lookupSymbol(id) << "):";
	if (t != -1)
	  cout << " default\n";
	else {
	  cout << "\n";
	  f->dump();
	  cout << "\n";
	}
      }
    }
  }

  if (options.mode != TREE && 
      (options.graphvizSatisfyingEx || options.graphvizCounterEx ||
       options.inheritedAcceptance)) 
    cout << "Warning: options -gc, -gs, and -h are only used in tree mode\n";
  if (options.mode == TREE && options.graphvizDFA)
    cout << "Warning: option -gw is only used in linear mode\n";
  
  if (options.mode == TREE && (options.dump || options.whole) && 
      !options.externalWhole)
    printGuide();


  ///////// CODE GENERATION ////////////////////////////////////////////////
  
  if (options.printProgress)
    cout << "\nCODE GENERATION\n";
  Timer timer_gencode;
  timer_gencode.start();
  
  // Generate code
  codeTable = new CodeTable;
  VarCode formulaCode = ast->formula->makeCode();
  VarCode assertionCode = ast->assertion->makeCode();
  Deque<VarCode> verifyCode;
  /* #warning NEW: 'VERIFY' */
  for (Deque<ASTForm *>::iterator i = ast->verifyformlist.begin(); 
       i != ast->verifyformlist.end(); i++)
    verifyCode.push_back((*i)->makeCode());

  // Implicitly assert restrictions for all global variables
  for (IdentList::iterator i = ast->globals.begin(); 
       i != ast->globals.end(); i++)
    assertionCode = andList(assertionCode, getRestriction(*i, NULL));

  // Restrict assertion if not trivial
  if (assertionCode.code->kind != cTrue)
    assertionCode = codeTable->insert
      (new Code_Restrict(assertionCode, assertionCode.code->pos));

  // Add assertion to main formula and to all verify formulas
  for (Deque<VarCode>::iterator i = verifyCode.begin(); 
       i != verifyCode.end(); i++) {
    assertionCode.code->refs++;
    *i = andList(*i, VarCode(copy(assertionCode.vars), assertionCode.code));
  }
  formulaCode = andList(formulaCode, assertionCode);

  timer_gencode.stop();
  if (options.printProgress) {
    codeTable->print_statistics();
    /* if (options.dump && options.statistics)
      codeTable->print_sizes(); */
    cout << "Time: ";
    timer_gencode.print();
  }
  
  ///////// REORDER BDD OFFSETS ////////////////////////////////////////////

  if (options.reorder >= 1) {
    Timer timer_reorder;
    timer_reorder.start();
    if (options.printProgress)
      cout << "\nREORDERING\n";

    // reorder using heuristics
    offsets.reorder();
    
    // regenerate DAG in new codetable
    CodeTable *oldCodeTable = codeTable, *newCodeTable = new CodeTable;
    IdentList emptylist;
    codeTable = newCodeTable;
    regenerate = true; // force making new nodes
    VarCode newcode = formulaCode.substCopy(&emptylist, &emptylist);
    Deque<VarCode> newverifycode;
    for (Deque<VarCode>::iterator i = verifyCode.begin(); 
	 i != verifyCode.end(); i++)
      newverifycode.push_back((*i).substCopy(&emptylist, &emptylist));
    codeTable->clearSCTable();
    regenerate = false;
    codeTable = oldCodeTable;
    formulaCode.remove();
    for (Deque<VarCode>::iterator i = verifyCode.begin(); 
	 i != verifyCode.end(); i++)
      (*i).remove();
    formulaCode = newcode;
    verifyCode.reset();
    for (Deque<VarCode>::iterator i = newverifycode.begin(); 
	 i != newverifycode.end(); i++)
      verifyCode.push_back(*i);
    delete oldCodeTable;
    codeTable = newCodeTable;

    if (options.printProgress) {
      codeTable->print_statistics2();
      cout << "Time: ";
      timer_reorder.print();
    }
  }

  ///////// REDUCTION AND CODE DUMPING /////////////////////////////////////

  if (options.optimize >= 1) {
    if (options.printProgress)
      cout << "\nREDUCTION\n";
    Timer timer_reduction;
    timer_reduction.start();
    
    // Reduce
    formulaCode.reduceAll(&verifyCode);

    timer_reduction.stop();
    if (options.printProgress) {
      codeTable->print_reduction_statistics();
      /* if (options.dump && options.statistics)
	 codeTable->print_sizes(); */
      cout << "Time: ";
      timer_reduction.print();
    }
  }
  
  if (options.dump) {
    // Dump symboltable
    symbolTable.dump();
    
    // Dump code
    cout << "\nMain formula:\n";
    formulaCode.dump();
    cout << "\n\n";
    Deque<VarCode>::iterator i;
    Deque<char *>::iterator j;
    for (i = verifyCode.begin(), j = ast->verifytitlelist.begin(); 
	 i != verifyCode.end(); i++, j++) {
      cout << "Formula " << *j << ":\n";
      (*i).dump();
      cout << "\n\n";
    }
  }
  
  if (options.graphvizDAG) {
    printf("digraph MONA_CODE_DAG {\n"
	   " size = \"7.5,10.5\";\n"
	   " main [shape = plaintext];\n"
	   " main -> L%lx;\n", 
	   (unsigned long) formulaCode.code);
    formulaCode.code->viz();
    Deque<VarCode>::iterator i;
    Deque<char *>::iterator j;
    for (i = verifyCode.begin(), j = ast->verifytitlelist.begin(); 
	 i != verifyCode.end(); i++, j++) {
      printf(" \"%s\" [shape = plaintext];\n"
	     " \"%s\" -> L%lx;\n", 
	     *j, *j, (unsigned long) (*i).code);
      (*i).code->viz();
    }
    formulaCode.unmark();
    for (Deque<VarCode>::iterator i = verifyCode.begin(); 
	 i != verifyCode.end(); i++)
      (*i).unmark();
    cout << "}\n";
  }

  ///////// AUTOMATON CONSTRUCTION /////////////////////////////////////////

  // Make variable lists
  Deque<char *> *verifytitlelist = ast->verifytitlelist.copy();
  if (lastPosVar != -1)
    ast->globals.remove(lastPosVar); 
  if (allPosVar != -1)
    ast->globals.remove(allPosVar); 
  ast->globals.sort(); // sort by id (= index)
  int numVars = ast->globals.size();
  int ix = 0;
  char **vnames = new char*[numVars];
  unsigned *offs = new unsigned[numVars];
  char *types = new char[numVars];
  int **univs = new int*[numVars];
  int *trees = new int[numVars];
  SSSet *statespaces = new SSSet[numVars];
  IdentList sign, freeVars;
  IdentList::iterator id;
  for (id = ast->globals.begin(); id != ast->globals.end(); id++, ix++) {
    statespaces[ix] = stateSpaces(*id);
    vnames[ix] = symbolTable.lookupSymbol(*id);
    offs[ix] = offsets.off(*id);
    sign.push_back(ix);
    freeVars.push_back(*id);
    switch (symbolTable.lookupType(*id)) {
    case VarnameTree:
      trees[ix] = 1;
      break;
    default:
      trees[ix] = 0;
    }
    IdentList *uu = symbolTable.lookupUnivs(*id);
    if (uu) {
      unsigned j;
      univs[ix] = new int[uu->size()+1];
      for (j = 0; j < uu->size(); j++)
	univs[ix][j] = symbolTable.lookupUnivNumber(uu->get(j));
      univs[ix][j] = -1;
    }
    else
      univs[ix] = 0;
    switch (symbolTable.lookupType(*id)) 
      {
      case Varname0: 
	types[ix] = 0;
	break;
      case Varname1: 
	types[ix] = 1;
	break;
      default:
	types[ix] = 2;
	break;
      }
  }
  
  if (options.printProgress)
    cout << "\nAUTOMATON CONSTRUCTION\n";

  Timer timer_automaton;
  timer_automaton.start();
  
  DFA *dfa = 0;
  Deque<DFA *> dfalist;
  GTA *gta = 0;
  Deque<GTA *> gtalist;
  
  // Initialize
  bdd_init();
  codeTable->init_print_progress();

  if (options.mode != TREE) { 
    // Generate DFAs
    dfa = formulaCode.DFATranslate();
    if (lastPosVar != -1)
      dfa = st_dfa_lastpos(dfa, lastPosVar);
    if (allPosVar != -1)
      dfa = st_dfa_allpos(dfa, allPosVar);
    for (Deque<VarCode>::iterator i = verifyCode.begin(); 
	 i != verifyCode.end(); i++) {
      DFA *d = (*i).DFATranslate();
      if (lastPosVar != -1)
	d = st_dfa_lastpos(d, lastPosVar);
      if (allPosVar != -1)
	d = st_dfa_allpos(d, allPosVar);
      dfalist.push_back(d);
    }
  }
  else { 
    // Generate GTAs
    gta = formulaCode.GTATranslate();
    if (allPosVar != -1)
      gta = st_gta_allpos(gta, allPosVar);
    for (Deque<VarCode>::iterator i = verifyCode.begin(); 
	 i != verifyCode.end(); i++) {
      GTA *g = (*i).GTATranslate();
      if (allPosVar != -1)
	g = st_gta_allpos(g, allPosVar);
      gtalist.push_back(g);
    }
  }
  formulaCode.remove();
  for (Deque<VarCode>::iterator i = verifyCode.begin(); 
       i != verifyCode.end(); i++)
    (*i).remove();
  
  timer_automaton.stop();
  if (options.printProgress) {
    if (options.statistics)
      cout << "Total automaton construction time: ";
    else
      cout << "Time: ";
    timer_automaton.print();
  }

  delete ast;
  delete codeTable;

  ///////// PRINT AUTOMATON ////////////////////////////////////////////////

  DFA *dfa2 = dfa;
  GTA *gta2 = gta;
  Deque<DFA *> *dfalist2 = &dfalist;
  Deque<GTA *> *gtalist2 = &gtalist;

  if (options.whole &&
      !options.externalWhole)
    cout << "\n";
  if (options.unrestrict) {
    // Unrestrict automata
    if (options.mode != TREE) {
      DFA *t = dfaCopy(dfa2);
      dfaUnrestrict(t);
      dfa2 = dfaMinimize(t);
      dfaFree(t);
      dfalist2 = new Deque<DFA *>;
      for (Deque<DFA *>::iterator i = dfalist.begin(); i != dfalist.end(); i++) {
	t = dfaCopy(*i);
	dfaUnrestrict(t);
	dfalist2->push_back(dfaMinimize(t));
	dfaFree(t);
      }
    }
    else {
      GTA *t = gtaCopy(gta2);
      gtaUnrestrict(t);
      gta2 = gtaMinimize(t);
      gtaFree(t);
      gtalist2 = new Deque<GTA *>;
      for (Deque<GTA *>::iterator i = gtalist.begin(); i != gtalist.end(); i++) {
	t = gtaCopy(*i);
	gtaUnrestrict(t);
	gtalist2->push_back(gtaMinimize(t));
	gtaFree(t);	
      }
    }
  }

  if (options.whole)
    // Print whole automaton
    if (options.mode != TREE) {
      if (options.externalWhole) {
	if (!dfalist.empty())
	  cout << "Main formula:\n";
	DFA *t = dfaCopy(dfa2);
	st_dfa_replace_indices(t, &sign, &freeVars, false, true);
	dfaExport(t, 0, numVars, vnames, types);
	dfaFree(t);
	Deque<DFA *>::iterator i;
	Deque<char *>::iterator j;
	for (i = dfalist2->begin(), j = verifytitlelist->begin();
	     i != dfalist2->end(); i++, j++) {
	  cout << "\nFormula " << *j << ":\n";
	  t = dfaCopy(*i);
	  st_dfa_replace_indices(t, &sign, &freeVars, false, true);
	  dfaExport(t, 0, numVars, vnames, types);
	  dfaFree(t);
	}
      }
      else if (options.graphvizDFA) {
	dfaPrintGraphviz(dfa2, numVars, offs);
	for (Deque<DFA *>::iterator i = dfalist2->begin(); i != dfalist2->end(); i++)
	  dfaPrintGraphviz(*i, numVars, offs);
      }
      else {
	if (!dfalist.empty())
	  cout << "Main formula:\n";
	dfaPrint(dfa2, numVars, vnames, offs);
	Deque<DFA *>::iterator i;
	Deque<char *>::iterator j;
	for (i = dfalist2->begin(), j = verifytitlelist->begin(); 
	     i != dfalist2->end(); i++, j++) {
	  cout << "\nFormula " << *j << ":\n";
	  dfaPrint(*i, numVars, vnames, offs);
	}
      }
    }
    else {
      if (options.externalWhole) {
	if (!gtalist.empty())
	  cout << "Main formula:\n";
	GTA *t = gtaCopy(gta2);
	st_gta_replace_indices(t, &sign, &freeVars, false, true);
	gtaExport(t, 0, numVars, vnames, types, statespaces, 
		  options.inheritedAcceptance);
	gtaFree(t);
	Deque<GTA *>::iterator i;
	Deque<char *>::iterator j;
	for (i = gtalist2->begin(), j = verifytitlelist->begin();
	     i != gtalist2->end(); i++, j++) {
	  cout << "\nFormula " << *j << ":\n";
	  t = gtaCopy(*i);
	  st_gta_replace_indices(t, &sign, &freeVars, false, true);
	  gtaExport(t, 0, numVars, vnames, types, statespaces, 
		    options.inheritedAcceptance);
	  gtaFree(t);
	}
      }
      else {
	if (!gtalist.empty())
	  cout << "Main formula:\n";
	gtaPrint(gta2, offs, numVars, vnames, 
		 options.inheritedAcceptance);
	Deque<GTA *>::iterator i;
	Deque<char *>::iterator j;
	for (i = gtalist2->begin(), j = verifytitlelist->begin();
	     i != gtalist2->end(); i++, j++) {
	  cout << "\nFormula " << *j << ":\n";
	  gtaPrint(*i, offs, numVars, vnames, 
		   options.inheritedAcceptance);
	}
      }
    }
  else if (options.analysis &&
	   !options.graphvizSatisfyingEx &&
	   !options.graphvizCounterEx &&
	   options.printProgress) {
    // Print summary only
    if (options.mode != TREE) {
      if (!dfalist.empty())
	cout << "Main formula:";
      dfaPrintVitals(dfa2);
      Deque<DFA *>::iterator i;
      Deque<char *>::iterator j;
      for (i = dfalist2->begin(), j = verifytitlelist->begin(); 
	   i != dfalist2->end(); i++, j++) {
	cout << "\nFormula " << *j << ":";
	dfaPrintVitals(*i);
      }
    }
    else {
      if (!gtalist.empty())
	cout << "Main formula:";
      gtaPrintTotalSize(gta2);
      Deque<GTA *>::iterator i;
      Deque<char *>::iterator j;
      for (i = gtalist2->begin(), j = verifytitlelist->begin(); 
	   i != gtalist2->end(); i++, j++) {
	cout << "\nFormula " << *j << ":";
	gtaPrintTotalSize(*i);
      }
    }
  }
  if (dfa2 != dfa) {
    dfaFree(dfa2);
    for (Deque<DFA *>::iterator i = dfalist2->begin(); i != dfalist2->end(); i++) 
      dfaFree(*i);
    delete dfalist2;
  }
  if (gta2 != gta) {
    gtaFree(gta2);
    for (Deque<GTA *>::iterator i = gtalist2->begin(); i != gtalist2->end(); i++) 
      gtaFree(*i);
    delete gtalist2;
  }

  ///////// AUTOMATON ANALYSIS /////////////////////////////////////////////

  if (options.analysis) {
    if (options.printProgress)
      cout << "\nANALYSIS\n";
    
    if (options.mode != TREE) {
      if (!dfalist.empty())
	cout << "Main formula:\n";
      dfaAnalyze(dfa, numVars, vnames, offs, types, 
		 options.treemodeOutput);
      Deque<DFA *>::iterator i;
      Deque<char *>::iterator j;
      for (i = dfalist.begin(), j = verifytitlelist->begin(); 
	   i != dfalist.end(); i++, j++) {
	cout << "\nFormula " << *j << ":\n";
	dfaAnalyze(*i, numVars, vnames, offs, types, 
		   options.treemodeOutput);
      }
    }
    else {
      if (numTypes == 0 || options.treemodeOutput) {
	if (!gtalist.empty())
	  cout << "Main formula:\n";
	gtaAnalyze(gta, numVars, vnames, offs,
		   options.graphvizSatisfyingEx,
		   options.graphvizCounterEx);
	Deque<GTA *>::iterator i;
	Deque<char *>::iterator j;
	for (i = gtalist.begin(), j = verifytitlelist->begin(); 
	     i != gtalist.end(); i++, j++) {
	  cout << "\nFormula " << *j << ":\n";
	  gtaAnalyze(*i, numVars, vnames, offs,
		     options.graphvizSatisfyingEx,
		     options.graphvizCounterEx);
	}
      }
      else {
	if (options.graphvizSatisfyingEx ||
	    options.graphvizCounterEx)
	  cout << "Graphviz output of typed trees not implemented.\n";
	if (!gtalist.empty())
	  cout << "Main formula:\n";
	gtaTypeAnalyze(gta, numVars, vnames, types, offs, univs, trees);
	Deque<GTA *>::iterator i;
	Deque<char *>::iterator j;
	for (i = gtalist.begin(), j = verifytitlelist->begin(); 
	     i != gtalist.end(); i++, j++) {
	  cout << "\nFormula " << *j << ":\n";
	  gtaTypeAnalyze(*i, numVars, vnames, types, offs, univs, trees);
	}
      }
    }
  }

  ///////// CLEAN UP ///////////////////////////////////////////////////////

  if (options.mode != TREE) {
    dfaFree(dfa);
    for (Deque<DFA *>::iterator i = dfalist.begin(); i != dfalist.end(); i++)
      dfaFree(*i);
  }
  else {
    gtaFree(gta);
    for (Deque<GTA *>::iterator i = gtalist.begin(); i != gtalist.end(); i++)
      gtaFree(*i);
    freeGuide();
  }
  delete verifytitlelist;

  Deque<FileSource *>::iterator i;
  for (i = source.begin(); i != source.end(); i++)
    delete *i;
  
  for (ix = 0; ix < numVars; ix++) {
    delete[] univs[ix];
    mem_free(statespaces[ix]);
  }
  delete[] statespaces;
  delete[] vnames;
  delete[] offs;
  delete[] types;
  delete[] univs;
  delete[] trees;
  freeTreetypes();
    
  if (options.statistics)
    print_statistics();

  if (options.time) {
    timer_total.stop();
    cout << "\nTotal time:     ";
    timer_total.print();
    print_timing();
  }
  else if (options.printProgress) { 
    timer_total.stop();
    cout << "\nTotal time: ";
    timer_total.print();
  }
#ifdef MAXALLOCATED
  cout << "Maximum space allocated: " << (maxallocated+524288)/1048576 << " MB\n";
#endif
}