Пример #1
0
AstNode* Parser::parseStatement() {
    if (isKeyword(currentTokenValue())) {
      if (currentTokenValue() == "function") {
          return parseFunction();
      } else if (currentTokenValue() == "for") {
          return parseFor();
      } else if (currentTokenValue() == "if") {
          return parseIf();
      } else if (currentTokenValue() == "while") {
          return parseWhile();
      } else if (currentTokenValue() == "print") {
          return parsePrint();
      } else if (currentTokenValue() == "int") {
          return parseDeclaration(VT_INT);
      } else if (currentTokenValue() == "double") {
          return parseDeclaration(VT_DOUBLE);
      } else if (currentTokenValue() == "string") {
          return parseDeclaration(VT_STRING);
      } else if (currentTokenValue() == "return") {
          return parseReturn();
      } else {
          cout << "unhandled keyword " << currentTokenValue() << endl;
          assert(false);
          return 0;
      }
    }
    if (currentToken() == tLBRACE) {
       return parseBlock(true);
    }
    if ((currentToken() == tIDENT) && isAssignment(lookaheadToken(1))) {
        return parseAssignment();
    }
    return parseExpression();
}
Пример #2
0
QString CharacterClassSettings::toOperator(QString op) const
{
	if(!isOperator(op))return QString();
	if(!isAssignment(op))return op;
	if(d->assignmentChars.first!=0)op=op.mid(1);
	if(d->assignmentChars.second!=0)op=op.left(op.size()-1);
	return op;
}
Пример #3
0
void
SimdStringType::generateCode
    (const SyntaxNodePtr &node,
     LContext &lcontext) const
{
    SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext);

    if (isAssignment (node))
    {
	slcontext.addInst
	    (new SimdAssignInst (alignedObjectSize(), node->lineNumber));
	return;
    }

    if (UnaryOpNodePtr unOp = node.cast<UnaryOpNode>())
    {
	switch (unOp->op)
	{
	  default:

	    MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber,
		"Cannot apply " << tokenAsString (unOp->op) << " "
		"operator to value of type " << 
		unOp->operand->type->asString() << ".");
	}

	return;
    }

    if (BinaryOpNodePtr binOp = node.cast<BinaryOpNode>())
    {
	switch (binOp->op)
	{
	  default:

	    MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber,
		"Invalid operand types "
		"for " << tokenAsString (binOp->op) << " operator "
		"(" << binOp->leftOperand->type->asString() << " " <<
		tokenAsString (binOp->op) << " " <<
		binOp->rightOperand->type->asString() << ").");
	}

	return;
    }

    if (node.cast<CallNode>())
    {
	//
	// Push a placeholder for the return value for a call to
	// a function that returns an int.
	//

	slcontext.addInst (new SimdPushPlaceholderInst (alignedObjectSize(),
	                                                node->lineNumber));
	return;
    }
}
Пример #4
0
static bool isTrivialAssignment(FnSymbol* fn, FnSet& visited)
{
  if (! isAssignment(fn))
    return false;
  if (isTrivial(fn, visited))
    return true;

  return false;
}
Пример #5
0
void
SimdArrayType::generateCode
    (const SyntaxNodePtr &node,
     LContext &lcontext) const
{
    SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext);

    VariableNodePtr var = node.cast<VariableNode>();
    if( var && var->initialValue.cast<ValueNode>())
    {
	SizeVector sizes;
	SizeVector offsets;
	coreSizes(0, sizes, offsets);
 	slcontext.addInst (new SimdInitializeInst(sizes, 
						  offsets,
						  node->lineNumber));
	return;
    }
    else if (isAssignment(node))  // return or assignment
    {
	slcontext.addInst (new SimdAssignArrayInst
			     (size(), elementSize(), node->lineNumber));
	return;
    }
    else if ( node.cast<ArrayIndexNode>() )
    {
	if(unknownSize() || unknownElementSize())
	{
	    
	    slcontext.addInst (new SimdIndexVSArrayInst(elementSize(),
							unknownElementSize(), 
							size(),
							unknownSize(),
							node->lineNumber));
	}
	else
	{
	    slcontext.addInst (new SimdIndexArrayInst(elementSize(), 
						      node->lineNumber,
						      size()));
	}
	return;
    }
    else if (node.cast<SizeNode>())
    {
	assert(size() == 0);
	slcontext.addInst (new SimdPushRefInst (unknownSize(), 
						node->lineNumber));
    }
    else if (node.cast<CallNode>())
    {
	slcontext.addInst (new SimdPushPlaceholderInst(objectSize(), 
						       node->lineNumber));
	return;
    }
}
Пример #6
0
 void SetNonzerosSlice<Add>::simplifyMe(MX& ex) {
   // Simplify if addition
   if (isAssignment()) {
     MX t = this->dep(1);
     if (Add) {
       ex += t;
     } else {
       ex = t;
     }
   }
 }
Пример #7
0
void
SimdStructType::generateCode
    (const SyntaxNodePtr &node,
     LContext &lcontext) const
{
    SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext);

    VariableNodePtr var = node.cast<VariableNode>();
    if( var && var->initialValue.cast<ValueNode>())
    {
	SizeVector sizes;
	SizeVector offsets;
	coreSizes(0, sizes, offsets);
 	slcontext.addInst (new SimdInitializeInst(sizes, 
						  offsets, 
						  node->lineNumber));
	return;
    }

    if( MemberNodePtr mem = node.cast<MemberNode>() )
    {
 	slcontext.addInst (new SimdAccessMemberInst(mem->offset,
 						       (node->lineNumber)));
	return;
    }

    if (isAssignment (node))
    {
	slcontext.addInst (new SimdAssignInst
			     (alignedObjectSize(), node->lineNumber));
	return;
    }

    if (node.cast<CallNode>())
    {
	// Push a placeholder for the return value for a call to
	// a function that returns a struct
	slcontext.addInst (new SimdPushPlaceholderInst (alignedObjectSize(),
						        node->lineNumber));
	return;
    }
}
Пример #8
0
bool BinaryOpNode::ContainLvalueRecourse(VarSymbol *id) const {
	return isAssignment(token->value) && (
		left->isIdent() && dynamic_cast<IdentifierNode*>(left)->token->str == id->name || 
		left->ContainLvalueRecourse(id) || 
		right->ContainLvalueRecourse(id));
}
Пример #9
0
void
MibParser::doTrapTypes(ifstream* ifile)
{
  skipImports(ifile);
  // now lets do trap types
  while (!ifile->eof())
  {
    try 
    {

      // read each line of file
      char lineBuffer[4096];
      char* lineBuf = lineBuffer;
      memset(lineBuffer, 0, 4096);

      ifile->getline(lineBuffer, 4096);
      int count = ifile->gcount();

      if (isComment(lineBuf))
	continue;

      if (strstr(lineBuf, "DESCRIPTION"))
	skipDescription(lineBuf, ifile);

      if (isTrapType(lineBuf))
      {
	node* n = new node;
	n->trap = true;
	while (*lineBuf == ' ' || *lineBuf == '\t') 
	  lineBuf++;
	char* spec = strstr(lineBuf, "TRAP-TYPE");
	if (spec != NULL)
	{
	  spec--;
	  while (*spec == ' ' || *spec == '\t')
	    spec--;
	}
	*++spec = 0;
	strncpy(n->name, lineBuf, 256);
	  
	while (1)
	{
	  memset(lineBuffer, 0, 4096);
	  lineBuf = lineBuffer;	

	  ifile->getline(lineBuffer, 4096);
	  count = ifile->gcount();
	  
	  if (isEnterprise(lineBuf))
	  {
	    char* ent = strstr(lineBuf, "ENTERPRISE");
	    ent += 10;
	    //	    while (*ent == ' ' || *ent == '\t')
	    while (*ent == ' ' || *ent == '\t' || *ent == '{')
	      ent++;
	    //	    int len = strlen(lineBuf);
	    int len = strlen(ent);
	    char* entEnd = ent + (len - 1);
	    //	    while (*entEnd == ' ' || *entEnd == '\r' || *entEnd == '\t')
	    while (*entEnd == ' ' || *entEnd == '\r' || *entEnd == '\t' || *entEnd == '}')
	      entEnd--;
	    *++entEnd = 0;
	    strncpy(n->oid, ent, 256);

	  }

	  if (isAssignment(lineBuf))
	  {
	    char* assign = strstr(lineBuf, "::=");
	    assign += 3;

	    while (*assign == ' ' || *assign == '\t')
		assign++;

	    //////////////////////
	    char* commentSpec = strstr(assign, "--");
	    if (commentSpec != NULL)
	      *commentSpec = 0;
	    //////////////////////
	    
	    char* assignEnd = assign + (strlen(assign) - 1);
	    while (*assignEnd == ' ' || *assignEnd == '\r' || *assignEnd == '\t')
	      assignEnd--;
	    *++assignEnd = 0;

	    strcat(n->oid, ".");	    
	    strcat(n->oid, assign);

	    n->insert(n);
	    break;
	  }

	  if (isVariableClause(lineBuf))
	  {
	    BOOL done = FALSE;
	    char* firstPosition;
	    char* lastPosition;
	    int currentCount;
	    int state = OPENCURLY;
	    int nextState;

	    while (!done)
	    {
	      switch (state)
	      {
	       case GETLINE:
		 {
		   memset(lineBuffer, 0, 4096);
		   lineBuf = lineBuffer;	
		   ifile->getline(lineBuffer, 4096);
		   count = ifile->gcount();
		   currentCount = 1;
		   state = nextState;
		   firstPosition = lineBuf;
		   break;
		 }
	     
	       case OPENCURLY:
		 {
		   firstPosition = lineBuf;
		   // find the opening curly brace
		   for (currentCount = 1; currentCount < count; currentCount++)
		   {
		     if (*firstPosition != '{')
		       firstPosition++;
		     else
		       break;
		   }
		   if (currentCount == count)
		   {
		     // look on next line
		     nextState = state;
		     state = GETLINE;
		   }
		   else
		   {
		     firstPosition++; 
		     currentCount++;
		     state = FINDVARBIND;
		   }
		   break;
		 }
	     
	       case FINDVARBIND:
		 {
		   // now skip white space to first varbind
		   for (; currentCount < count; currentCount++)
		   {
		     if (*firstPosition == ' ' || *firstPosition == '\t')
		       firstPosition++;
		     else
		       break;
		   }
		   if (currentCount == count)
		   {
		     nextState = state;
		     state = GETLINE;
		   }
		   else
		   {
		     // now find end of first varbind
		     lastPosition = firstPosition;
		     for (; currentCount < count; currentCount++)
		     {
		       if (*lastPosition != ' ' && *lastPosition != '\t' 
			   && *lastPosition != ',' && *lastPosition != '}')
			 lastPosition++;
		       else
			 break;
		     }
		     if (currentCount == count) // error
		     {
		       state = DONE;
		       break;
		     }
		   
		     char saveChar = *lastPosition;
		     *lastPosition = 0;
		     markInUse(firstPosition);
		     *lastPosition = saveChar;
		     if (saveChar == ',')
		     {
		       lastPosition++; 
		       currentCount++;
		     }
		     else
		       if (strchr(lastPosition, '}'))
			 state = DONE;
		     firstPosition = lastPosition;
		   }
		   break;
		 }
	     
	       case DONE:
		 done = TRUE;
		 break;
	      } // switch (state)
	    } // while (!done)
	  } // if (isVariableClause(lineBuf))	  
	} // while (1)
      } // if (isTrapType(lineBuf))
    }
    catch(...)
    {
      
    }
  }
  ifile->clear();
  ifile->seekg(0);
}
Пример #10
0
void
SimdHalfType::generateCode
    (const SyntaxNodePtr &node,
     LContext &lcontext) const
{
    SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext);

    if (isAssignment (node))
    {
	slcontext.addInst
	    (new SimdAssignInst (alignedObjectSize(), node->lineNumber));
	return;
    }

    if (UnaryOpNodePtr unOp = node.cast<UnaryOpNode>())
    {
	switch (unOp->op)
	{
	  case TK_MINUS:
	    slcontext.addInst
		(new SimdUnaryOpInst <half, half, UnaryMinusOp>
		 (node->lineNumber));
	    break;

	  default:

	    MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber,
		"Cannot apply " << tokenAsString (unOp->op) << " "
		"operator to value of type " << 
		unOp->operand->type->asString() << ".");
	}

	return;
    }

    if (BinaryOpNodePtr binOp = node.cast<BinaryOpNode>())
    {
	switch (binOp->op)
	{
	  case TK_DIV:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, half, DivOp>
		 (node->lineNumber));
	    break;

	  case TK_EQUAL:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, bool, EqualOp>
		 (node->lineNumber));
	    break;

	  case TK_GREATER:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, bool, GreaterOp>
		 (node->lineNumber));
	    break;

	  case TK_GREATEREQUAL:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, bool, GreaterEqualOp>
		 (node->lineNumber));
	    break;

	  case TK_LESS:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, bool, LessOp>
		 (node->lineNumber));
	    break;

	  case TK_LESSEQUAL:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, bool, LessEqualOp>
		 (node->lineNumber));
	    break;

	  case TK_MINUS:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, half, BinaryMinusOp>
		 (node->lineNumber));
	    break;

	  case TK_NOTEQUAL:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, bool, NotEqualOp>
		 (node->lineNumber));
	    break;

	  case TK_PLUS:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, half, PlusOp>
		 (node->lineNumber));
	    break;

	  case TK_TIMES:
	    slcontext.addInst
		(new SimdBinaryOpInst <half, half, half, TimesOp>
		 (node->lineNumber));
	    break;

	  default:

	    MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber,
		"Invalid operand types "
		"for " << tokenAsString (binOp->op) << " operator "
		"(" << binOp->leftOperand->type->asString() << " " <<
		tokenAsString (binOp->op) << " " <<
		binOp->rightOperand->type->asString() << ").");
	}

	return;
    }

    if (node.cast<CallNode>())
    {
	//
	// Push a placeholder for the return value for a call to
	// a function that returns an int.
	//

	slcontext.addInst
	    (new SimdPushPlaceholderInst (alignedObjectSize(),
					  node->lineNumber));
	return;
    }
}
Пример #11
0
void
SimdBoolType::generateCode
    (const SyntaxNodePtr &node,
     LContext &lcontext) const
{
    SimdLContext &slcontext = static_cast <SimdLContext &> (lcontext);

    if (isAssignment (node))
    {
	slcontext.addInst
	    (new SimdAssignInst (alignedObjectSize(), node->lineNumber));
	return;
    }

    if (UnaryOpNodePtr unOp = node.cast<UnaryOpNode>())
    {
	switch (unOp->op)
	{
	  case TK_BITNOT:

	    //
	    // We use the C++ ! operation to evaluate the CTL expression ~x,
	    // where x is of type bool.  This ensures that ~true == false
	    // and ~false == true.
	    //

	    slcontext.addInst
		(new SimdUnaryOpInst <bool, bool, NotOp>(node->lineNumber));
	    break;

	  case TK_NOT:
	    slcontext.addInst
		(new SimdUnaryOpInst <bool, bool, NotOp>(node->lineNumber));
	    break;

	  default:

	    MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber,
		"Cannot apply " << tokenAsString (unOp->op) << " "
		"operator to value of type " << 
		unOp->operand->type->asString() << ".");
	}

	return;
    }

    if (BinaryOpNodePtr binOp = node.cast<BinaryOpNode>())
    {
	switch (binOp->op)
	{
	  case TK_BITAND:

	    //
	    // For the bit-wise &, | and ^ operators, we normalize bool
	    // operands before applying the operators.  This avoids
	    // surprises, for example, true^true == true.
	    // 

	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, BoolBitAndOp>
		 (node->lineNumber));
	    break;

	  case TK_BITOR:
	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, BoolBitOrOp>
		 (node->lineNumber));
	    break;

	  case TK_BITXOR:
	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, BoolBitXorOp>
		 (node->lineNumber));
	    break;

	  case TK_EQUAL:
	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, EqualOp>
		 (node->lineNumber));
	    break;

	  case TK_GREATER:
	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, GreaterOp>
		 (node->lineNumber));
	    break;

	  case TK_GREATEREQUAL:
	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, GreaterEqualOp>
		 (node->lineNumber));
	    break;

	  case TK_LESS:
	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, LessOp>
		 (node->lineNumber));
	    break;

	  case TK_LESSEQUAL:
	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, LessEqualOp>
		 (node->lineNumber));
	    break;

	  case TK_NOTEQUAL:
	    slcontext.addInst
		(new SimdBinaryOpInst <bool, bool, bool, NotEqualOp>
		 (node->lineNumber));
	    break;

	  default:

	    MESSAGE_LE (lcontext, ERR_OP_TYPE, node->lineNumber,
		"Invalid operand types "
		"for " << tokenAsString (binOp->op) << " operator "
		"(" << binOp->leftOperand->type->asString() << " " <<
		tokenAsString (binOp->op) << " " <<
		binOp->rightOperand->type->asString() << ").");
	}

	return;
    }

    if (node.cast<CallNode>())
    {
	//
	// Push a placeholder for the return value for a call to
	// a function that returns an int.
	//
	slcontext.addInst (new SimdPushPlaceholderInst(alignedObjectSize(),
						       node->lineNumber));
	return;
    }
}
Пример #12
0
// The argument is assumed to be an assignment function.
// It is deemed to be simple if it contains only 'move', 'addr of', '=',
// 'return' primitives and calls only simple assignments (recursively).
// We also require that it return void (for now).
// The FLAG_TRIVIAL_ASSIGNMENT is used to ensure that we visit each such
// function only once.
static bool isTrivial(FnSymbol* fn, FnSet& visited)
{
  // Visit each function only once.
  if (visited.find(fn) != visited.end())
  {
    // Found it.
    if (fn->hasFlag(FLAG_TRIVIAL_ASSIGNMENT))
      return true;
    else
      return false;
  }
  visited.insert(fn);

  // We assume that compiler-generated assignments are field-by-field copies.
  // Note that this overloads the meaning of this flag with:
  // "Assignment operations flagged as 'compiler generated' shall contain only
  // field assignments and assignment primitives."
  // We can then assume that all nested calls are field extractions or
  // assignments, and we only have to check the latter.
  if (! fn->hasFlag(FLAG_COMPILER_GENERATED))
    return false;

  // After all compiler-supplied assignments use the new signature, this can
  // become an assert.
  if (fn->retType != dtVoid)
    return false;

  // The base argument types must match.
  ArgSymbol* lhs = fn->getFormal(1);
  ArgSymbol* rhs = fn->getFormal(2);
  if (lhs->type->getValType() != rhs->type->getValType())
    return false;

  // Assume this is a field-by-field copy.
  // If none of the fields of this record (or tuple) has a user-defined
  // assignment (recursively), then it can be replaced by a bulk copy.
  // Traverse the call expressions in the body of the function.
  // These should all be one of the allowed primitives or calls to simple
  // assignments.  If anything else, the assignment is "interesting", and
  // cannot be replaced.
  std::vector<BaseAST*> asts;
  collect_asts_STL(fn->body, asts);
  for_vector(BaseAST, ast, asts)
  {
    if (CallExpr* call = toCallExpr(ast))
    {
      if (FnSymbol* fieldAsgn = call->isResolved())
      {
        if (isAssignment(fieldAsgn))
          if (! isTrivial(fieldAsgn, visited))
            return false;
      }
      else
      {
        // This is a primitive.
        switch(call->primitive->tag)
        {
         default:
          return false;

          // These are the allowable primitives.
         case PRIM_MOVE:
         case PRIM_ASSIGN:
         case PRIM_ADDR_OF:
         case PRIM_DEREF:
         case PRIM_GET_MEMBER:
         case PRIM_GET_MEMBER_VALUE:
         case PRIM_SET_MEMBER:
         case PRIM_RETURN: // We expect return _void.
          break;
        }
      }
    }
  }

  fn->addFlag(FLAG_TRIVIAL_ASSIGNMENT);
  return true;
}
Пример #13
0
sExpression *eval(sExpression *exp, sEnvironment *env){
  /* ------------------atom-----------------------*/
  /* 1, 10, false, null, "abc" */
  if(isSelfEval(exp))
  {
    return exp;
  }
  /* a symbol */
  else if(isVariable(exp, env))
  {
    return lookupVariable(toSymb(exp), env);
  }
  /* ------------------list-----------------------*/
  /* (quote blur blur) */
  else if(isQuoted(exp))
  {
    return textOfQuoted(exp);
  }
  /* (set! name value) */
  else if(isAssignment(exp))
  {
    return evalAssignment(exp, env);
  }
  /* (define name value) */
  else if(isDefinition(exp))
  {
    return evalDefine(exp, env);
  }
  /* (define-syntax name ...) */
  else if(isDefinitionSyntax(exp))
  {
    return evalDefineSyntax(exp, env);
  }
  /* (if blur blur blur) */
  else if(isIf(exp))
  {
    return evalIf(toList(exp), env);
  }
  /* (lambda (args) (body)) */
  else if(isLambdaConst(exp))
  {
    sList *body;
    sList *param = toList( cadr(toList(exp)));
    sExpression *temp = cdr(toList( cdr(toList(exp))));
    if(isList(temp)){
      body = toList(temp);
    }else{
      body = toList(cons(temp, &sNull));
    }
    return newLambda(param, body, env);
  }
  /* (syntax blur blur) syntax rule */
  else if(isSymbol(car(toList(exp))) && isSyntaxRule(eval(car(toList(exp)), env)))
  {
    sExpression *exp2 = evalSyntaxRule(toSyntax(eval(car(toList(exp)), env)), exp);
    return eval(exp2, env);
  }
  /* the other list (x . y) */
  else if(isApplication(exp))
  {
    if(LAZY_EVAL){
      sExpression *proexp = actualValue(operator(toList(exp)), env);
      if(isLambdaType(proexp) || isPrimitiveProc(proexp)){
        sExpression *operand = operands(toList(exp));
        return applyLazly(proexp, operand, env);
      }
    }else{
      sExpression *proexp = eval(operator(toList(exp)), env);
      if(isLambdaType(proexp) || isPrimitiveProc(proexp)){
        sExpression *operand = operands(toList(exp));
        sExpression *arguments = listOfValues(operand, env);
        return apply(proexp, arguments, env);
      }
    }
  }
  return &sError;
}
Пример #14
0
//
// Establishes the type of the resultant operation, as well as
// makes the operator the correct one for the operands.
//
// Returns false if operator can't work on operands.
//
bool TIntermBinary::promote(TInfoSink &infoSink)
{
    // This function only handles scalars, vectors, and matrices.
    if (mLeft->isArray() || mRight->isArray())
    {
        infoSink.info.message(EPrefixInternalError, getLine(),
                              "Invalid operation for arrays");
        return false;
    }

    // GLSL ES 2.0 does not support implicit type casting.
    // So the basic type should usually match.
    bool basicTypesMustMatch = true;

    // Check ops which require integer / ivec parameters
    switch (mOp)
    {
      case EOpBitShiftLeft:
      case EOpBitShiftRight:
      case EOpBitShiftLeftAssign:
      case EOpBitShiftRightAssign:
        // Unsigned can be bit-shifted by signed and vice versa, but we need to
        // check that the basic type is an integer type.
        basicTypesMustMatch = false;
        if (!IsInteger(mLeft->getBasicType()) || !IsInteger(mRight->getBasicType()))
        {
            return false;
        }
        break;
      case EOpBitwiseAnd:
      case EOpBitwiseXor:
      case EOpBitwiseOr:
      case EOpBitwiseAndAssign:
      case EOpBitwiseXorAssign:
      case EOpBitwiseOrAssign:
        // It is enough to check the type of only one operand, since later it
        // is checked that the operand types match.
        if (!IsInteger(mLeft->getBasicType()))
        {
            return false;
        }
        break;
      default:
        break;
    }

    if (basicTypesMustMatch && mLeft->getBasicType() != mRight->getBasicType())
    {
        return false;
    }

    //
    // Base assumption:  just make the type the same as the left
    // operand.  Then only deviations from this need be coded.
    //
    setType(mLeft->getType());

    // The result gets promoted to the highest precision.
    TPrecision higherPrecision = GetHigherPrecision(
        mLeft->getPrecision(), mRight->getPrecision());
    getTypePointer()->setPrecision(higherPrecision);

    // Binary operations results in temporary variables unless both
    // operands are const.
    if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
    {
        getTypePointer()->setQualifier(EvqTemporary);
    }

    const int nominalSize =
        std::max(mLeft->getNominalSize(), mRight->getNominalSize());

    //
    // All scalars or structs. Code after this test assumes this case is removed!
    //
    if (nominalSize == 1)
    {
        switch (mOp)
        {
          //
          // Promote to conditional
          //
          case EOpEqual:
          case EOpNotEqual:
          case EOpLessThan:
          case EOpGreaterThan:
          case EOpLessThanEqual:
          case EOpGreaterThanEqual:
            setType(TType(EbtBool, EbpUndefined));
            break;

          //
          // And and Or operate on conditionals
          //
          case EOpLogicalAnd:
          case EOpLogicalOr:
            // Both operands must be of type bool.
            if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool)
            {
                return false;
            }
            setType(TType(EbtBool, EbpUndefined));
            break;

          default:
            break;
        }
        return true;
    }

    // If we reach here, at least one of the operands is vector or matrix.
    // The other operand could be a scalar, vector, or matrix.
    // Can these two operands be combined?
    //
    TBasicType basicType = mLeft->getBasicType();
    switch (mOp)
    {
      case EOpMul:
        if (!mLeft->isMatrix() && mRight->isMatrix())
        {
            if (mLeft->isVector())
            {
                mOp = EOpVectorTimesMatrix;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              mRight->getCols(), 1));
            }
            else
            {
                mOp = EOpMatrixTimesScalar;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              mRight->getCols(), mRight->getRows()));
            }
        }
        else if (mLeft->isMatrix() && !mRight->isMatrix())
        {
            if (mRight->isVector())
            {
                mOp = EOpMatrixTimesVector;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              mLeft->getRows(), 1));
            }
            else
            {
                mOp = EOpMatrixTimesScalar;
            }
        }
        else if (mLeft->isMatrix() && mRight->isMatrix())
        {
            mOp = EOpMatrixTimesMatrix;
            setType(TType(basicType, higherPrecision, EvqTemporary,
                          mRight->getCols(), mLeft->getRows()));
        }
        else if (!mLeft->isMatrix() && !mRight->isMatrix())
        {
            if (mLeft->isVector() && mRight->isVector())
            {
                // leave as component product
            }
            else if (mLeft->isVector() || mRight->isVector())
            {
                mOp = EOpVectorTimesScalar;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              nominalSize, 1));
            }
        }
        else
        {
            infoSink.info.message(EPrefixInternalError, getLine(),
                                  "Missing elses");
            return false;
        }

        if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
        {
            return false;
        }
        break;

      case EOpMulAssign:
        if (!mLeft->isMatrix() && mRight->isMatrix())
        {
            if (mLeft->isVector())
            {
                mOp = EOpVectorTimesMatrixAssign;
            }
            else
            {
                return false;
            }
        }
        else if (mLeft->isMatrix() && !mRight->isMatrix())
        {
            if (mRight->isVector())
            {
                return false;
            }
            else
            {
                mOp = EOpMatrixTimesScalarAssign;
            }
        }
        else if (mLeft->isMatrix() && mRight->isMatrix())
        {
            mOp = EOpMatrixTimesMatrixAssign;
            setType(TType(basicType, higherPrecision, EvqTemporary,
                          mRight->getCols(), mLeft->getRows()));
        }
        else if (!mLeft->isMatrix() && !mRight->isMatrix())
        {
            if (mLeft->isVector() && mRight->isVector())
            {
                // leave as component product
            }
            else if (mLeft->isVector() || mRight->isVector())
            {
                if (!mLeft->isVector())
                    return false;
                mOp = EOpVectorTimesScalarAssign;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              mLeft->getNominalSize(), 1));
            }
        }
        else
        {
            infoSink.info.message(EPrefixInternalError, getLine(),
                                  "Missing elses");
            return false;
        }

        if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
        {
            return false;
        }
        break;

      case EOpAssign:
      case EOpInitialize:
      case EOpAdd:
      case EOpSub:
      case EOpDiv:
      case EOpIMod:
      case EOpBitShiftLeft:
      case EOpBitShiftRight:
      case EOpBitwiseAnd:
      case EOpBitwiseXor:
      case EOpBitwiseOr:
      case EOpAddAssign:
      case EOpSubAssign:
      case EOpDivAssign:
      case EOpIModAssign:
      case EOpBitShiftLeftAssign:
      case EOpBitShiftRightAssign:
      case EOpBitwiseAndAssign:
      case EOpBitwiseXorAssign:
      case EOpBitwiseOrAssign:
        if ((mLeft->isMatrix() && mRight->isVector()) ||
            (mLeft->isVector() && mRight->isMatrix()))
        {
            return false;
        }

        // Are the sizes compatible?
        if (mLeft->getNominalSize() != mRight->getNominalSize() ||
            mLeft->getSecondarySize() != mRight->getSecondarySize())
        {
            // If the nominal sizes of operands do not match:
            // One of them must be a scalar.
            if (!mLeft->isScalar() && !mRight->isScalar())
                return false;

            // In the case of compound assignment other than multiply-assign,
            // the right side needs to be a scalar. Otherwise a vector/matrix
            // would be assigned to a scalar. A scalar can't be shifted by a
            // vector either.
            if (!mRight->isScalar() &&
                (isAssignment() ||
                mOp == EOpBitShiftLeft ||
                mOp == EOpBitShiftRight))
                return false;

            // Operator cannot be of type pure assignment.
            if (mOp == EOpAssign || mOp == EOpInitialize)
                return false;
        }

        {
            const int secondarySize = std::max(
                mLeft->getSecondarySize(), mRight->getSecondarySize());
            setType(TType(basicType, higherPrecision, EvqTemporary,
                          nominalSize, secondarySize));
        }
        break;

      case EOpEqual:
      case EOpNotEqual:
      case EOpLessThan:
      case EOpGreaterThan:
      case EOpLessThanEqual:
      case EOpGreaterThanEqual:
        if ((mLeft->getNominalSize() != mRight->getNominalSize()) ||
            (mLeft->getSecondarySize() != mRight->getSecondarySize()))
        {
            return false;
        }
        setType(TType(EbtBool, EbpUndefined));
        break;

      default:
        return false;
    }
    return true;
}
Пример #15
0
//
// Establishes the type of the resultant operation, as well as
// makes the operator the correct one for the operands.
//
// For lots of operations it should already be established that the operand
// combination is valid, but returns false if operator can't work on operands.
//
bool TIntermBinary::promote(TInfoSink &infoSink)
{
    ASSERT(mLeft->isArray() == mRight->isArray());

    //
    // Base assumption:  just make the type the same as the left
    // operand.  Then only deviations from this need be coded.
    //
    setType(mLeft->getType());

    // The result gets promoted to the highest precision.
    TPrecision higherPrecision = GetHigherPrecision(
        mLeft->getPrecision(), mRight->getPrecision());
    getTypePointer()->setPrecision(higherPrecision);

    // Binary operations results in temporary variables unless both
    // operands are const.
    if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
    {
        getTypePointer()->setQualifier(EvqTemporary);
    }

    const int nominalSize =
        std::max(mLeft->getNominalSize(), mRight->getNominalSize());

    //
    // All scalars or structs. Code after this test assumes this case is removed!
    //
    if (nominalSize == 1)
    {
        switch (mOp)
        {
          //
          // Promote to conditional
          //
          case EOpEqual:
          case EOpNotEqual:
          case EOpLessThan:
          case EOpGreaterThan:
          case EOpLessThanEqual:
          case EOpGreaterThanEqual:
            setType(TType(EbtBool, EbpUndefined));
            break;

          //
          // And and Or operate on conditionals
          //
          case EOpLogicalAnd:
          case EOpLogicalXor:
          case EOpLogicalOr:
            ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
            setType(TType(EbtBool, EbpUndefined));
            break;

          default:
            break;
        }
        return true;
    }

    // If we reach here, at least one of the operands is vector or matrix.
    // The other operand could be a scalar, vector, or matrix.
    // Can these two operands be combined?
    //
    TBasicType basicType = mLeft->getBasicType();
    switch (mOp)
    {
      case EOpMul:
        if (!mLeft->isMatrix() && mRight->isMatrix())
        {
            if (mLeft->isVector())
            {
                mOp = EOpVectorTimesMatrix;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              mRight->getCols(), 1));
            }
            else
            {
                mOp = EOpMatrixTimesScalar;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              mRight->getCols(), mRight->getRows()));
            }
        }
        else if (mLeft->isMatrix() && !mRight->isMatrix())
        {
            if (mRight->isVector())
            {
                mOp = EOpMatrixTimesVector;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              mLeft->getRows(), 1));
            }
            else
            {
                mOp = EOpMatrixTimesScalar;
            }
        }
        else if (mLeft->isMatrix() && mRight->isMatrix())
        {
            mOp = EOpMatrixTimesMatrix;
            setType(TType(basicType, higherPrecision, EvqTemporary,
                          mRight->getCols(), mLeft->getRows()));
        }
        else if (!mLeft->isMatrix() && !mRight->isMatrix())
        {
            if (mLeft->isVector() && mRight->isVector())
            {
                // leave as component product
            }
            else if (mLeft->isVector() || mRight->isVector())
            {
                mOp = EOpVectorTimesScalar;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              nominalSize, 1));
            }
        }
        else
        {
            infoSink.info.message(EPrefixInternalError, getLine(),
                                  "Missing elses");
            return false;
        }

        if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
        {
            return false;
        }
        break;

      case EOpMulAssign:
        if (!mLeft->isMatrix() && mRight->isMatrix())
        {
            if (mLeft->isVector())
            {
                mOp = EOpVectorTimesMatrixAssign;
            }
            else
            {
                return false;
            }
        }
        else if (mLeft->isMatrix() && !mRight->isMatrix())
        {
            if (mRight->isVector())
            {
                return false;
            }
            else
            {
                mOp = EOpMatrixTimesScalarAssign;
            }
        }
        else if (mLeft->isMatrix() && mRight->isMatrix())
        {
            mOp = EOpMatrixTimesMatrixAssign;
            setType(TType(basicType, higherPrecision, EvqTemporary,
                          mRight->getCols(), mLeft->getRows()));
        }
        else if (!mLeft->isMatrix() && !mRight->isMatrix())
        {
            if (mLeft->isVector() && mRight->isVector())
            {
                // leave as component product
            }
            else if (mLeft->isVector() || mRight->isVector())
            {
                if (!mLeft->isVector())
                    return false;
                mOp = EOpVectorTimesScalarAssign;
                setType(TType(basicType, higherPrecision, EvqTemporary,
                              mLeft->getNominalSize(), 1));
            }
        }
        else
        {
            infoSink.info.message(EPrefixInternalError, getLine(),
                                  "Missing elses");
            return false;
        }

        if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
        {
            return false;
        }
        break;

      case EOpAssign:
      case EOpInitialize:
        // No more additional checks are needed.
        ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
            (mLeft->getSecondarySize() == mRight->getSecondarySize()));
        break;
      case EOpAdd:
      case EOpSub:
      case EOpDiv:
      case EOpIMod:
      case EOpBitShiftLeft:
      case EOpBitShiftRight:
      case EOpBitwiseAnd:
      case EOpBitwiseXor:
      case EOpBitwiseOr:
      case EOpAddAssign:
      case EOpSubAssign:
      case EOpDivAssign:
      case EOpIModAssign:
      case EOpBitShiftLeftAssign:
      case EOpBitShiftRightAssign:
      case EOpBitwiseAndAssign:
      case EOpBitwiseXorAssign:
      case EOpBitwiseOrAssign:
        if ((mLeft->isMatrix() && mRight->isVector()) ||
            (mLeft->isVector() && mRight->isMatrix()))
        {
            return false;
        }

        // Are the sizes compatible?
        if (mLeft->getNominalSize() != mRight->getNominalSize() ||
            mLeft->getSecondarySize() != mRight->getSecondarySize())
        {
            // If the nominal sizes of operands do not match:
            // One of them must be a scalar.
            if (!mLeft->isScalar() && !mRight->isScalar())
                return false;

            // In the case of compound assignment other than multiply-assign,
            // the right side needs to be a scalar. Otherwise a vector/matrix
            // would be assigned to a scalar. A scalar can't be shifted by a
            // vector either.
            if (!mRight->isScalar() &&
                (isAssignment() ||
                mOp == EOpBitShiftLeft ||
                mOp == EOpBitShiftRight))
                return false;
        }

        {
            const int secondarySize = std::max(
                mLeft->getSecondarySize(), mRight->getSecondarySize());
            setType(TType(basicType, higherPrecision, EvqTemporary,
                          nominalSize, secondarySize));
            if (mLeft->isArray())
            {
                ASSERT(mLeft->getArraySize() == mRight->getArraySize());
                mType.setArraySize(mLeft->getArraySize());
            }
        }
        break;

      case EOpEqual:
      case EOpNotEqual:
      case EOpLessThan:
      case EOpGreaterThan:
      case EOpLessThanEqual:
      case EOpGreaterThanEqual:
        ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
            (mLeft->getSecondarySize() == mRight->getSecondarySize()));
        setType(TType(EbtBool, EbpUndefined));
        break;

      default:
        return false;
    }
    return true;
}