Beispiel #1
0
/***************************************************************
* Function: RangeExpr::getSubExprs()
* Purpose : Access sub-expressions
* Initial : Maxime Chevalier-Boisvert on January 8, 2009
****************************************************************
Revisions and bug fixes:
*/
Expression::ExprVector RangeExpr::getSubExprs() const
{
	// Create a list to store the sub-expression pointers
	ExprVector list; 
	
	// Add the sub-expressions to the list
	list.push_back(m_pStartExpr); 
	list.push_back(m_pStepExpr);
	list.push_back(m_pEndExpr);
	
	// Return the list
	return list;	
}
Beispiel #2
0
// Return true if a comma (or closing brace) is necessary after the
// __if_exists/if_not_exists statement.
bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
                                                    bool &InitExprsOk) {
  bool trailingComma = false;
  IfExistsCondition Result;
  if (ParseMicrosoftIfExistsCondition(Result))
    return false;
  
  BalancedDelimiterTracker Braces(*this, tok::l_brace);
  if (Braces.consumeOpen()) {
    Diag(Tok, diag::err_expected) << tok::l_brace;
    return false;
  }

  switch (Result.Behavior) {
  case IEB_Parse:
    // Parse the declarations below.
    break;
        
  case IEB_Dependent:
    Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
      << Result.IsIfExists;
    // Fall through to skip.
      
  case IEB_Skip:
    Braces.skipToEnd();
    return false;
  }

  while (!isEofOrEom()) {
    trailingComma = false;
    // If we know that this cannot be a designation, just parse the nested
    // initializer directly.
    ExprResult SubElt;
    if (MayBeDesignationStart())
      SubElt = ParseInitializerWithPotentialDesignator();
    else
      SubElt = ParseInitializer();

    if (Tok.is(tok::ellipsis))
      SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());
    
    // If we couldn't parse the subelement, bail out.
    if (!SubElt.isInvalid())
      InitExprs.push_back(SubElt.release());
    else
      InitExprsOk = false;

    if (Tok.is(tok::comma)) {
      ConsumeToken();
      trailingComma = true;
    }

    if (Tok.is(tok::r_brace))
      break;
  }

  Braces.consumeClose();

  return !trailingComma;
}
Beispiel #3
0
// Flatten out all expressions with a given head.
void Expression::Flatten(const string head)
{
	ExprVector newLeaves;
	newLeaves.reserve(leaves.size());
	for(ExprVector::const_iterator leaf = leaves.begin(); leaf != leaves.end(); ++leaf)
		if((*leaf)->FunctionName() == head)
		{
			for(ExprVector::const_iterator subLeaf = (*leaf)->Leaves().begin(); subLeaf != (*leaf)->Leaves().end(); ++subLeaf)
				newLeaves.push_back(*subLeaf);
			(*leaf)->Leaves().clear();
			delete *leaf;
		}
		else
			newLeaves.push_back(*leaf);
	leaves = newLeaves;
}
Beispiel #4
0
void OpReplaceRepeated::Apply(Expression *expression, Calculator *calculator, int32 recursions)
{
	if(expression->LeafCount() != 2)
		throw ArgumentException("ReplaceRepeated expects 2 arguments.");
	if(expression->LeafCount() != 2)
		throw ArgumentException("ReplaceRepeated expects 2 arguments.");
	string leafFunction = expression->Leaf(1)->FunctionName();
	if(leafFunction != "Rule" && leafFunction != "RuleDelayed" && leafFunction != "List")
		throw ArgumentException("ReplaceRepeated expects its second argument to be a rule or a list of rules.");
	ExprVector rules;
	if(leafFunction == "List")
	{
		for(ExprVector::const_iterator item = expression->Leaf(1)->Leaves().begin(); item != expression->Leaf(1)->Leaves().end(); ++ item)
			if((*item)->FunctionName() != "Rule" && (*item)->FunctionName() != "RuleDelayed")
				throw ArgumentException("ReplaceRepeated expects its second argument to be a rule or a list of rules.");
		rules = expression->Leaf(1)->Leaves();
	}
	else
		rules.push_back(expression->Leaf(1));
	int32 iterations(0);
	Expression *result = expression->Leaf(0);
	while(true)
	{
		bool changed(false);
		if(!result->ReplaceAll(rules, calculator, &changed))
			break;
		if(!changed)
			break;
		++iterations;
		if(iterations >= Max_ReplaceRepeated_Iterations)
			throw LimitationException("Maximum number of iterations reached.");
	}
	expression->AssignLeaf(0);
	expression->Evaluate(calculator, recursions);
}
void TransformVector::MakeElementExprs(DeclVector &DeclVec, 
                                       ExprVector &ExprVec,
                                       ExtVectorElementExpr *E) {
  llvm::SmallVector<unsigned, 4> Indices;
  E->getEncodedElementAccess(Indices);
  Expr *BE = E->getBase();

  // If E is an arrow expression, the base pointer expression needs to be 
  // converted into a vector value expression.
  if (E->isArrow()) {
    QualType BaseTy = BE->getType();
    const PointerType *PTy = BaseTy->getAs<PointerType>();
    assert(PTy && "Not a pointer type");
    BE = new (ASTCtx) UnaryOperator(BE, UO_Deref, PTy->getPointeeType(),
                                    VK_RValue, OK_Ordinary, SourceLocation());
    BE = new (ASTCtx) ParenExpr(SourceLocation(), SourceLocation(), BE);
  }

  if (ExtVectorElementExpr *BP = dyn_cast<ExtVectorElementExpr>(BE)) {
    ExprVector BaseExprVec;
    MakeElementExprs(DeclVec, BaseExprVec, BP);
    for (unsigned i = 0, e = Indices.size(); i < e; i++) {
      ExprVec.push_back(BaseExprVec[Indices[i]]);
    }
  } else if (CompoundLiteralExpr *BP = dyn_cast<CompoundLiteralExpr>(BE)) {
    for (unsigned i = 0, e = Indices.size(); i < e; i++) {
      Expr *ElemE = GetSingleValueOfVecLiteral(DeclVec, BP, Indices[i]);
      ExprVec.push_back(ElemE);
    }
  } else {
    Expr *NewBE = ConvertVecLiteralInExpr(DeclVec, BE);
    const ExtVectorType *VecTy = NewBE->getType()->getAs<ExtVectorType>();
    assert(VecTy && "The type of BaseExpr is not a vector type.");

    QualType ElemTy = VecTy->getElementType();
    SourceLocation loc;

    for (unsigned i = 0, e = Indices.size(); i < e; i++) {
      unsigned Kind = CLExpressions::ZERO + Indices[i];
      ArraySubscriptExpr *ElemE = new (ASTCtx) ArraySubscriptExpr(
          NewBE,
          CLExprs.getExpr((CLExpressions::ExprKind)(Kind)), 
          ElemTy, VK_RValue, OK_Ordinary, loc);
      ExprVec.push_back(ElemE);
    }
  }
}
/**
* @brief Converts the given LLVM call instruction @a inst into an expression in BIR.
*/
ShPtr<CallExpr> LLVMInstructionConverter::convertCallInstToCallExpr(llvm::CallInst &inst) {
	ExprVector args;
	for (auto &arg: inst.arg_operands()) {
		args.push_back(getConverter()->convertValueToExpression(arg));
	}

	auto calledExpr = getConverter()->convertValueToExpression(inst.getCalledValue());
	return CallExpr::create(calledExpr, args);
}
Beispiel #7
0
/***************************************************************
* Function: ParamExpr::getSubExprs()
* Purpose : Access sub-expressions
* Initial : Maxime Chevalier-Boisvert on January 8, 2009
****************************************************************
Revisions and bug fixes:
*/
Expression::ExprVector ParamExpr::getSubExprs() const
{
	// Create a list to store the sub-expression pointers
	ExprVector list;

	// Add the symbol to the list
	list.push_back(m_pSymbolExpr);

	// For each argument
	for (size_t i = 0; i < m_arguments.size(); ++i)
	{
		// Add the sub-expression to the list
		list.push_back(m_arguments[i]);
	}

	// Return the list
	return list;
}
Beispiel #8
0
/***************************************************************
* Function: ParamExpr::copy()
* Purpose : Copy this IIR node recursively
* Initial : Maxime Chevalier-Boisvert on November 8, 2008
****************************************************************
Revisions and bug fixes:
*/
ParamExpr* ParamExpr::copy() const
{
	// Create an argument vector to store the argument copies
	ExprVector arguments;

	// Copy each argument
	for (ExprVector::const_iterator itr = m_arguments.begin(); itr != m_arguments.end(); ++itr)
		arguments.push_back((Expression*)(*itr)->copy());

	// Create and return a copy of this node
	return new ParamExpr(
		m_pSymbolExpr->copy(),
		arguments
	);
}
Beispiel #9
0
/***************************************************************
* Function: AssignStmt::copy()
* Purpose : Copy this IIR node recursively
* Initial : Maxime Chevalier-Boisvert on November 6, 2008
****************************************************************
Revisions and bug fixes:
*/
AssignStmt* AssignStmt::copy() const
{
	// Create a vector for the left expression copies
	ExprVector leftExprs;
	
	// Copy each left expression
	for (ExprVector::const_iterator itr = m_leftExprs.begin(); itr != m_leftExprs.end(); ++itr)
		leftExprs.push_back((*itr)->copy());
	
	// Create and return a copy of this node
	return new AssignStmt(
		leftExprs,
		m_pRightExpr->copy(),
		m_suppressOut
	);
}	
void RecursiveCFGBuilder::visit(ShPtr<IfStmt> stmt) {
	ShPtr<CFG::Node> beforeIfNode(currNode);

	// Create a node for the if statement.
	ShPtr<CFG::Node> ifNode(new CFG::Node());
	firstStmtNodeMapping[stmt] = ifNode;
	cfg->stmtNodeMapping[stmt] = ifNode;
	ifNode->stmts.push_back(stmt);
	cfg->addNode(ifNode);
	cfg->addEdge(beforeIfNode, ifNode);

	// Create a node for the bodies of the if statement.
	ExprVector conds;
	for (auto i = stmt->clause_begin(), e = stmt->clause_end(); i != e; ++i) {
		ShPtr<CFG::Node> clauseBody(addNode(i->second));
		cfg->addEdge(ifNode, clauseBody, generateIfCondEdgeLabel(conds, i->first));
		conds.push_back(i->first);
	}

	// Create a node for the else clause/statement's successor. If there is an
	// else clause, then we don't have to generate a node for the statement's
	// successor here. Indeed, if the else clause always ends with a return
	// statement, then the statement's successor is never entered. If the else
	// clause doesn't always ends with a return, the statement's successor will
	// be traversed when adding a node for the else clause.
	if (stmt->hasElseClause()) {
		ShPtr<CFG::Node> clauseBody(addNode(stmt->getElseClause()));
		cfg->addEdge(ifNode, clauseBody, generateIfCondEdgeLabel(conds));
		return;
	}
	ShPtr<Expression> edgeCond(generateIfCondEdgeLabel(conds));
	if (ShPtr<Statement> stmtSucc = stmt->getSuccessor()) {
		ShPtr<CFG::Node> afterIfNode(addNode(stmtSucc));
		cfg->addEdge(ifNode, afterIfNode, edgeCond);
		return;
	}
	currNode = ifNode;
	addForwardOrBackwardEdge(stmt, edgeCond);
}
Beispiel #11
0
void OpReplaceAll::Apply(Expression *expression, Calculator *calculator, int32 recursions)
{
	if(expression->LeafCount() != 2)
		throw ArgumentException("ReplaceAll expects 2 arguments.");
	string leafFunction = expression->Leaf(1)->FunctionName();
	if(leafFunction != "Rule" && leafFunction != "RuleDelayed" && leafFunction != "List")
		throw ArgumentException("ReplaceAll expects its second argument to be a rule or a list of rules.");
	if(leafFunction == "List")
	{
		for(ExprVector::const_iterator item = expression->Leaf(1)->Leaves().begin(); item != expression->Leaf(1)->Leaves().end(); ++ item)
			if((*item)->FunctionName() != "Rule" && (*item)->FunctionName() != "RuleDelayed")
				throw ArgumentException("ReplaceAll expects its second argument to be a rule or a list of rules.");
		expression->Leaf(0)->ReplaceAll(expression->Leaf(1)->Leaves(), calculator);
	}
	else
	{
		ExprVector rules;
		rules.push_back(expression->Leaf(1));
		expression->Leaf(0)->ReplaceAll(rules, calculator);
	}
	expression->AssignLeaf(0);
	expression->Evaluate(calculator, recursions);
}
Stmt *TransformVector::VisitInitListExpr(InitListExpr *Node) {
  // For conventional vector literals such as '{1, 2, 3, 4}'
  QualType ETy = Node->getType();
  if (ETy->isExtVectorType()) {
    CompoundLiteralExpr *CLE = new (ASTCtx) CompoundLiteralExpr(
        SourceLocation(), ASTCtx.getTrivialTypeSourceInfo(ETy),
        ETy, Node->getValueKind(), Node, false);
    return VisitCompoundLiteralExpr(CLE);
  }

  if (NeedFlattening) {
    ExprVector InitExprs;
    ExprVector *PrvInitExprs = CurInitExprs;
    CurInitExprs = &InitExprs;

    for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
      assert(Node->getInit(i) && "NULL InitExpr?");
      Expr *InitExpr = TransformExpr(Node->getInit(i));
      InitExprs.push_back(InitExpr);
    }

    for (unsigned i =0, e = InitExprs.size(); i < e; ++i) {
      Node->updateInit(ASTCtx, i, InitExprs[i]);
    }

    CurInitExprs = PrvInitExprs;

  } else {
    for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
      if (Node->getInit(i)) {
        Node->setInit(i, TransformExpr(Node->getInit(i)));
      }
    }
  }
  
  return Node;
}
Beispiel #13
0
/// ParseBraceInitializer - Called when parsing an initializer that has a
/// leading open brace.
///
///       initializer: [C99 6.7.8]
///         '{' initializer-list '}'
///         '{' initializer-list ',' '}'
/// [GNU]   '{' '}'
///
///       initializer-list:
///         designation[opt] initializer ...[opt]
///         initializer-list ',' designation[opt] initializer ...[opt]
///
ExprResult Parser::ParseBraceInitializer() {
  InMessageExpressionRAIIObject InMessage(*this, false);
  
  BalancedDelimiterTracker T(*this, tok::l_brace);
  T.consumeOpen();
  SourceLocation LBraceLoc = T.getOpenLocation();

  /// InitExprs - This is the actual list of expressions contained in the
  /// initializer.
  ExprVector InitExprs;

  if (Tok.is(tok::r_brace)) {
    // Empty initializers are a C++ feature and a GNU extension to C.
    if (!getLangOpts().CPlusPlus)
      Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
    // Match the '}'.
    return Actions.ActOnInitList(LBraceLoc, None, ConsumeBrace());
  }

  bool InitExprsOk = true;

  while (1) {
    // Handle Microsoft __if_exists/if_not_exists if necessary.
    if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
        Tok.is(tok::kw___if_not_exists))) {
      if (ParseMicrosoftIfExistsBraceInitializer(InitExprs, InitExprsOk)) {
        if (Tok.isNot(tok::comma)) break;
        ConsumeToken();
      }
      if (Tok.is(tok::r_brace)) break;
      continue;
    }

    // Parse: designation[opt] initializer

    // If we know that this cannot be a designation, just parse the nested
    // initializer directly.
    ExprResult SubElt;
    if (MayBeDesignationStart())
      SubElt = ParseInitializerWithPotentialDesignator();
    else
      SubElt = ParseInitializer();

    if (Tok.is(tok::ellipsis))
      SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());
    
    // If we couldn't parse the subelement, bail out.
    if (!SubElt.isInvalid()) {
      InitExprs.push_back(SubElt.release());
    } else {
      InitExprsOk = false;

      // We have two ways to try to recover from this error: if the code looks
      // grammatically ok (i.e. we have a comma coming up) try to continue
      // parsing the rest of the initializer.  This allows us to emit
      // diagnostics for later elements that we find.  If we don't see a comma,
      // assume there is a parse error, and just skip to recover.
      // FIXME: This comment doesn't sound right. If there is a r_brace
      // immediately, it can't be an error, since there is no other way of
      // leaving this loop except through this if.
      if (Tok.isNot(tok::comma)) {
        SkipUntil(tok::r_brace, StopBeforeMatch);
        break;
      }
    }

    // If we don't have a comma continued list, we're done.
    if (Tok.isNot(tok::comma)) break;

    // TODO: save comma locations if some client cares.
    ConsumeToken();

    // Handle trailing comma.
    if (Tok.is(tok::r_brace)) break;
  }

  bool closed = !T.consumeClose();

  if (InitExprsOk && closed)
    return Actions.ActOnInitList(LBraceLoc, InitExprs,
                                 T.getCloseLocation());

  return ExprError(); // an error occurred.
}
void RemoveUnusedStructField::getInitExprs(const Type *Ty, 
                                           const Expr *E,
                                           const IndexVector *IdxVec,
                                           ExprVector &InitExprs)
{
  const ArrayType *ArrayTy = dyn_cast<ArrayType>(Ty);
  if (ArrayTy) {
    const InitListExpr *ILE = dyn_cast<InitListExpr>(E);
    TransAssert(ILE && "Invalid array initializer!");
    unsigned int NumInits = ILE->getNumInits();
    Ty = ArrayTy->getElementType().getTypePtr();
    
    for (unsigned I = 0; I < NumInits; ++I) {
      const Expr *Init = ILE->getInit(I);
      getInitExprs(Ty, Init, IdxVec, InitExprs);
    }
    return;
  }
 
  const InitListExpr *ILE = dyn_cast<InitListExpr>(E);
  if (!ILE)
    return;

  const RecordType *RT = NULL;
  if (Ty->isUnionType()) {
    RT = Ty->getAsUnionType();
  }
  else if (Ty->isStructureType()) {
    RT = Ty->getAsStructureType();
  }
  else {
    TransAssert(0 && "Bad RecordType!");
  }

  const RecordDecl *RD = RT->getDecl();
  unsigned int VecSz = IdxVec->size();
  for (IndexVector::const_iterator FI = IdxVec->begin(),
       FE = IdxVec->end(); FI != FE; ++FI)
  {
    const FieldDecl *FD = getFieldDeclByIdx(RD, (*FI));
    TransAssert(FD && "NULL FieldDecl!");
    IndexVector *FieldIdxVec = FieldToIdxVector[FD];
    TransAssert(FieldIdxVec && "Cannot find FieldIdxVec!");

    Ty = FD->getType().getTypePtr();
    const Expr *Init;
    unsigned int InitListIdx;
    if (RD->isUnion())
      InitListIdx = 0;
    else
      InitListIdx = (*FI);

    if (InitListIdx >= ILE->getNumInits())
      return;

    Init = ILE->getInit(InitListIdx);

    if (FD == TheFieldDecl) {
      InitExprs.push_back(Init);
      TransAssert((VecSz == 1) && "Bad IndexVector size!"); (void)VecSz;
    }
    else {
      getInitExprs(Ty, Init, FieldIdxVec, InitExprs);
    }
  }
}
Beispiel #15
0
/// ParseAsmStatement - Parse a GNU extended asm statement.
///       asm-statement:
///         gnu-asm-statement
///         ms-asm-statement
///
/// [GNU] gnu-asm-statement:
///         'asm' type-qualifier[opt] '(' asm-argument ')' ';'
///
/// [GNU] asm-argument:
///         asm-string-literal
///         asm-string-literal ':' asm-operands[opt]
///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
///                 ':' asm-clobbers
///
/// [GNU] asm-clobbers:
///         asm-string-literal
///         asm-clobbers ',' asm-string-literal
///
StmtResult Parser::ParseAsmStatement(bool &msAsm) {
  assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
  SourceLocation AsmLoc = ConsumeToken();

  if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
      !isTypeQualifier()) {
    msAsm = true;
    return ParseMicrosoftAsmStatement(AsmLoc);
  }

  DeclSpec DS(AttrFactory);
  SourceLocation Loc = Tok.getLocation();
  ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed);

  // GNU asms accept, but warn, about type-qualifiers other than volatile.
  if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
    Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
  if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
    Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
  // FIXME: Once GCC supports _Atomic, check whether it permits it here.
  if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
    Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";

  // Remember if this was a volatile asm.
  bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
  if (Tok.isNot(tok::l_paren)) {
    Diag(Tok, diag::err_expected_lparen_after) << "asm";
    SkipUntil(tok::r_paren, StopAtSemi);
    return StmtError();
  }
  BalancedDelimiterTracker T(*this, tok::l_paren);
  T.consumeOpen();

  ExprResult AsmString(ParseAsmStringLiteral());

  // Check if GNU-style InlineAsm is disabled.
  // Error on anything other than empty string.
  if (!(getLangOpts().GNUAsm || AsmString.isInvalid())) {
    const auto *SL = cast<StringLiteral>(AsmString.get());
    if (!SL->getString().trim().empty())
      Diag(Loc, diag::err_gnu_inline_asm_disabled);
  }

  if (AsmString.isInvalid()) {
    // Consume up to and including the closing paren.
    T.skipToEnd();
    return StmtError();
  }

  SmallVector<IdentifierInfo *, 4> Names;
  ExprVector Constraints;
  ExprVector Exprs;
  ExprVector Clobbers;

  if (Tok.is(tok::r_paren)) {
    // We have a simple asm expression like 'asm("foo")'.
    T.consumeClose();
    return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
                                   /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,
                                   Constraints, Exprs, AsmString.get(),
                                   Clobbers, T.getCloseLocation());
  }

  // Parse Outputs, if present.
  bool AteExtraColon = false;
  if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
    // In C++ mode, parse "::" like ": :".
    AteExtraColon = Tok.is(tok::coloncolon);
    ConsumeToken();

    if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
      return StmtError();
  }

  unsigned NumOutputs = Names.size();

  // Parse Inputs, if present.
  if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
    // In C++ mode, parse "::" like ": :".
    if (AteExtraColon)
      AteExtraColon = false;
    else {
      AteExtraColon = Tok.is(tok::coloncolon);
      ConsumeToken();
    }

    if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
      return StmtError();
  }

  assert(Names.size() == Constraints.size() &&
         Constraints.size() == Exprs.size() && "Input operand size mismatch!");

  unsigned NumInputs = Names.size() - NumOutputs;

  // Parse the clobbers, if present.
  if (AteExtraColon || Tok.is(tok::colon)) {
    if (!AteExtraColon)
      ConsumeToken();

    // Parse the asm-string list for clobbers if present.
    if (Tok.isNot(tok::r_paren)) {
      while (1) {
        ExprResult Clobber(ParseAsmStringLiteral());

        if (Clobber.isInvalid())
          break;

        Clobbers.push_back(Clobber.get());

        if (!TryConsumeToken(tok::comma))
          break;
      }
    }
  }

  T.consumeClose();
  return Actions.ActOnGCCAsmStmt(
      AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(),
      Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation());
}
Beispiel #16
0
// Evaluates an expression. Considers all rules etc. In some cases there are simply
// no changes possible and the expression remains unchanged (e.g. a+b).
void Expression::Evaluate(Calculator *calculator, int32 recursions)
{
	// Since the expression is expected to be already structured, it must have a head.
	if(!head)
		throw DefinitionException("Expression::Evaluate: Expression has no head.");
	if(recursions > Max_Evaluate_Recursions)
		throw LimitationException("Maximum number of recursive definitions reached.");
	head->Evaluate(calculator, recursions);
	// If Expression is a symbol
	Definition *symbolDef = SymbolDefinition(calculator);
	if(symbolDef)
	{
		// Look if value is defined
		if(symbolDef->Value())
		{
			bool changed = !SameExpression(symbolDef->Value());
			AssignCloned(symbolDef->Value());
			if(changed)
				Evaluate(calculator, recursions + 1);
		}
	}
	// If head is a pure function
	if(head->FunctionName() == "Function" && head->LeafCount() == 1)
	{
		ExprPtr body(head->leaves.at(0));
		body->SubstituteSlots(leaves);
		body->Evaluate(calculator, recursions);
		head->leaves.clear();
		MoveNotCloned(body);
	}
	// If Expression is Function call
	Definition *def = FunctionDefinition(calculator);
	if(def)
	{
		AttributeSet attributes = def->Attributes();
		// Evaluate child leaves if no Hold attribute
		if(!attributes.Contains(atHoldAll) && !attributes.Contains(atHoldAllComplete))
		{
			if(!attributes.Contains(atHoldFirst))
				if(!leaves.empty())
					leaves.at(0)->Evaluate(calculator, recursions);
			if(!attributes.Contains(atHoldRest))
				if(leaves.size() > 1)
					for(ExprVector::const_iterator leaf = leaves.begin()+1; leaf != leaves.end(); ++leaf)
						(*leaf)->Evaluate(calculator, recursions);
		}
		// Flatten out sequences
		if(!attributes.Contains(atSequenceHold))
		{
			Flatten("Sequence");
		}
		// Apply down values
		for(ExprVector::const_iterator leaf = leaves.begin(); leaf != leaves.end(); ++leaf)
		{
			Definition *def(0);
			if((*leaf)->SymbolHead())
				def = (*leaf)->SymbolDefinition(calculator);
			else if((*leaf)->IsFunctionCall())
				def = (*leaf)->FrontFunctionDefinition(calculator);
			if(def)
			{
				bool changed(false);
				if(def->ApplyUpValues(this, calculator, &changed) && changed)
				{
					Evaluate(calculator, recursions + 1);
					return;
				}
			}
		}
		// Apply Flat attribute
		if(attributes.Contains(atFlat))
		{
			Flatten(FunctionName());
		}
		// Apply OneIdentity attribute
		if(attributes.Contains(atOneIdentity))
		{
			if(ApplyOneIdentity())
				return;
		}
		// Apply Listable attribute
		if(attributes.Contains(atListable))
		{
			// Determine resulting list length, check if there are lists with different lengths
			bool listFound(false);
			ExprVector::size_type listSize(0);
			for(ExprVector::const_iterator leaf = leaves.begin(); leaf != leaves.end(); ++leaf)
				if((*leaf)->FunctionName() == "List")
					if(!listFound)
					{
						listSize = (*leaf)->LeafCount();
						listFound = true;
					}
					else
						if(listSize != (*leaf)->LeafCount())
							throw EvaluateException("Listable operation requires lists of the same length.");
			// Construct resulting list
			if(listFound)
			{
				ExprVector items;
				// Number of resulting list items = items in operand list
				items.reserve(listSize);
				// Loop through list items
				for(ExprVector::size_type position = 0; position < listSize; ++position)
				{
					// List item = function call, number of operands = number of original operands
					Expression *item = new Expression(FunctionName(), leaves.size());
					for(ExprVector::iterator itemLeaf = leaves.begin(); itemLeaf != leaves.end(); ++itemLeaf)
					{
						if((*itemLeaf)->FunctionName() == "List")
						{
							// Add corresponding list item
							item->AppendLeaf(*((*itemLeaf)->leaves.begin() + position));
						}
						else
						{
							// Add "whole" item (clone if necessary)
							if(position == 0)
								item->AppendLeaf(*itemLeaf);
							else
								item->AppendLeaf((*itemLeaf)->Clone());
						}
					}
					items.push_back(item);
				}
				// Delete lists (elements are now in resulting list)
				for(ExprVector::iterator itemLeaf = leaves.begin(); itemLeaf != leaves.end(); ++itemLeaf)
					if((*itemLeaf)->FunctionName() == "List")
					{
						(*itemLeaf)->leaves.clear();
						delete *itemLeaf;
					}
				delete head;
				head = new Expression("List");
				leaves = items;
				// Evaluate the list for itself
				Evaluate(calculator, recursions);
				return;
			}
		}
		// Apply Orderless attribute
		if(attributes.Contains(atOrderless))
		{
			std::sort(leaves.begin(), leaves.end(), &Compare);
		}
		// Apply down value rules
		bool changed(false);
		if(def->ApplyDownValues(this, calculator, &changed))
		{
			if(changed)
				Evaluate(calculator, recursions + 1);
			return;
		}
		// Execute linked operator, if specified
		if(def->Predef())
			def->Predef()->Apply(this, calculator, recursions);
	}
	else
	{
		// Otherwise simply evaluate the leaves
		for(ExprVector::const_iterator leaf = leaves.begin(); leaf != leaves.end(); ++leaf)
			(*leaf)->Evaluate(calculator, recursions);
	}
}