static AIExpType_t *makeExpression( AIOp_t *op, AIExpType_t *exp1, AIExpType_t *exp2 ) { if ( isUnaryOp( op->opType ) ) { AIUnaryOp_t *u = ( AIUnaryOp_t * ) op; u->exp = exp1; } else if ( isBinaryOp( op->opType ) ) { AIBinaryOp_t *b = ( AIBinaryOp_t * ) op; b->exp1 = exp1; b->exp2 = exp2; } return ( AIExpType_t * ) op; }
static AIExpType_t *Primary( pc_token_list **list ) { pc_token_list *current = *list; AIExpType_t *tree = nullptr; if ( isUnaryOp( opTypeFromToken( ¤t->token ) ) ) { AIExpType_t *t; AIOp_t *op = newOp( current ); *list = current->next; t = ReadConditionExpression( list, op->opType ); if ( !t ) { Log::Warn( "Missing right operand for %s on line %d", opTypeToString( op->opType ), current->token.line ); FreeOp( op ); return nullptr; } tree = makeExpression( op, t, nullptr ); } else if ( current->token.string[0] == '(' ) { *list = current->next; tree = ReadConditionExpression( list, OP_NONE ); if ( !expectToken( ")", list, true ) ) { return nullptr; } } else if ( current->token.type == tokenType_t::TT_NUMBER ) { tree = ( AIExpType_t * ) newValueLiteral( list ); } else if ( current->token.type == tokenType_t::TT_NAME ) { tree = ( AIExpType_t * ) newValueFunc( list ); } else { Log::Warn( "token %s on line %d is not valid", current->token.string, current->token.line ); } return tree; }
AstNode* Parser::parseUnary() { if (isUnaryOp(currentToken())) { TokenKind op = currentToken(); consumeToken(); return new UnaryOpNode(_currentTokenIndex, op, parseUnary()); } else if (currentToken() == tIDENT && lookaheadToken(1) == tLPAREN) { AstNode* expr = parseCall(); return expr; } else if (currentToken() == tIDENT) { AstVar* var = _currentScope->lookupVariable(currentTokenValue()); if (var == 0) { error("undeclared variable: %s", currentTokenValue().c_str()); } LoadNode* result = new LoadNode(_currentTokenIndex, var); consumeToken(); return result; } else if (currentToken() == tDOUBLE) { DoubleLiteralNode* result = new DoubleLiteralNode(_currentTokenIndex, parseDouble(currentTokenValue())); consumeToken(); return result; } else if (currentToken() == tINT) { IntLiteralNode* result = new IntLiteralNode(_currentTokenIndex, parseInt(currentTokenValue())); consumeToken(); return result; } else if (currentToken() == tSTRING) { StringLiteralNode* result = new StringLiteralNode(_currentTokenIndex, currentTokenValue()); consumeToken(); return result; } else if (currentToken() == tLPAREN) { consumeToken(); AstNode* expr = parseExpression(); ensureToken(tRPAREN); return expr; } else { error("Unexpected token: %s", tokenStr(currentToken())); return 0; } }
void FreeOp( AIOp_t *op ) { if ( !op ) { return; } if ( isBinaryOp( op->opType ) ) { AIBinaryOp_t *b = ( AIBinaryOp_t * ) op; FreeExpression( b->exp1 ); FreeExpression( b->exp2 ); } else if ( isUnaryOp( op->opType ) ) { AIUnaryOp_t *u = ( AIUnaryOp_t * ) op; FreeExpression( u->exp ); } BG_Free( op ); }
static AIOp_t *newOp( pc_token_list *list ) { pc_token_list *current = list; AIOp_t *ret = nullptr; AIOpType_t op = opTypeFromToken( ¤t->token ); if ( isBinaryOp( op ) ) { AIBinaryOp_t *b = ( AIBinaryOp_t * ) BG_Alloc( sizeof( *b ) ); b->opType = op; ret = ( AIOp_t * ) b; } else if ( isUnaryOp( op ) ) { AIUnaryOp_t *u = ( AIUnaryOp_t * ) BG_Alloc( sizeof( *u ) ); u->opType = op; ret = ( AIOp_t * ) u; } return ret; }
llvm::Value* genFloatPrimitiveMethodCall(Function& function, const SEM::Type* type, const String& methodName, const SEM::FunctionType functionType, llvm::ArrayRef<SEM::Value> templateArgs, PendingResultArray args, llvm::Value* const hintResultValue) { auto& module = function.module(); auto& builder = function.getBuilder(); const auto& typeName = type->getObjectType()->name().first(); const auto methodID = module.context().getMethodID(CanonicalizeMethodName(methodName)); const auto methodOwner = methodID.isConstructor() ? nullptr : args[0].resolveWithoutBind(function); if (methodName == "__move_to") { const auto moveToPtr = args[1].resolve(function); const auto moveToPosition = args[2].resolve(function); const auto destPtr = builder.CreateInBoundsGEP(moveToPtr, moveToPosition); const auto castedDestPtr = builder.CreatePointerCast(destPtr, genPointerType(module, type)); genMoveStore(function, methodOwner, castedDestPtr, type); return ConstantGenerator(module).getVoidUndef(); } else if (methodName == "create") { return ConstantGenerator(module).getPrimitiveFloat(typeName, 0.0); } else if (methodName == "__setdead" || methodName == "__set_dead") { // Do nothing. return ConstantGenerator(module).getVoidUndef(); } else if (methodName == "__islive" || methodName == "__is_live") { return ConstantGenerator(module).getI1(true); } else if (methodName.starts_with("implicit_cast_") || methodName.starts_with("cast_")) { const auto argType = functionType.parameterTypes().front(); const auto operand = args[0].resolve(function); const auto selfType = genType(module, type); if (isFloatType(module, argType)) { if (methodName.starts_with("implicit_cast_")) { return builder.CreateFPExt(operand, selfType); } else { return builder.CreateFPTrunc(operand, selfType); } } else if (isUnsignedIntegerType(module, argType)) { return builder.CreateUIToFP(operand, selfType); } else if (isSignedIntegerType(module, argType)) { return builder.CreateSIToFP(operand, selfType); } else { llvm_unreachable("Unknown float cast source type."); } } else if (isUnaryOp(methodName)) { const auto zero = ConstantGenerator(module).getPrimitiveFloat(typeName, 0.0); if (methodName == "implicit_cast" || methodName == "cast") { return callCastMethod(function, methodOwner, type, methodName, templateArgs.front().typeRefType(), hintResultValue); } else if (methodName == "implicit_copy" || methodName == "copy" || methodName == "plus") { return methodOwner; } else if (methodName == "minus") { return builder.CreateFNeg(methodOwner); } else if (methodName == "isZero") { return builder.CreateFCmpOEQ(methodOwner, zero); } else if (methodName == "isPositive") { return builder.CreateFCmpOGT(methodOwner, zero); } else if (methodName == "isNegative") { return builder.CreateFCmpOLT(methodOwner, zero); } else if (methodName == "abs") { // Generates: (value < 0) ? -value : value. const auto lessThanZero = builder.CreateFCmpOLT(methodOwner, zero); return builder.CreateSelect(lessThanZero, builder.CreateFNeg(methodOwner), methodOwner); } else if (methodName == "sqrt") { llvm::Type* const intrinsicTypes[] = { methodOwner->getType() }; const auto sqrtIntrinsic = llvm::Intrinsic::getDeclaration(module.getLLVMModulePtr(), llvm::Intrinsic::sqrt, intrinsicTypes); llvm::Value* const sqrtArgs[] = { methodOwner }; return builder.CreateCall(sqrtIntrinsic, sqrtArgs); } else { llvm_unreachable("Unknown primitive unary op."); } } else if (isBinaryOp(methodName)) { const auto operand = args[1].resolveWithoutBind(function); if (methodName == "add") { return builder.CreateFAdd(methodOwner, operand); } else if (methodName == "subtract") { return builder.CreateFSub(methodOwner, operand); } else if (methodName == "multiply") { return builder.CreateFMul(methodOwner, operand); } else if (methodName == "divide") { return builder.CreateFDiv(methodOwner, operand); } else if (methodName == "modulo") { return builder.CreateFRem(methodOwner, operand); } else if (methodName == "equal") { return builder.CreateFCmpOEQ(methodOwner, operand); } else if (methodName == "not_equal") { return builder.CreateFCmpONE(methodOwner, operand); } else if (methodName == "less_than") { return builder.CreateFCmpOLT(methodOwner, operand); } else if (methodName == "less_than_or_equal") { return builder.CreateFCmpOLE(methodOwner, operand); } else if (methodName == "greater_than") { return builder.CreateFCmpOGT(methodOwner, operand); } else if (methodName == "greater_than_or_equal") { return builder.CreateFCmpOGE(methodOwner, operand); } else if (methodName == "compare") { const auto isLessThan = builder.CreateFCmpOLT(methodOwner, operand); const auto isGreaterThan = builder.CreateFCmpOGT(methodOwner, operand); const auto minusOne = ConstantGenerator(module).getI8(-1); const auto zero = ConstantGenerator(module).getI8(0); const auto plusOne = ConstantGenerator(module).getI8(1); return builder.CreateSelect(isLessThan, minusOne, builder.CreateSelect(isGreaterThan, plusOne, zero)); } else { llvm_unreachable("Unknown primitive binary op."); } } else { printf("%s\n", methodName.c_str()); llvm_unreachable("Unknown primitive method."); } }
void Expression::traverseTree( BTreeNode *root, bool conditionalRoot ) { Traverser t(root); t.start(); // special case: if we are starting at the root node then // we are dealing with something of the form variable = 6 // or variable = portb ///TODO reimplement assignments as two branched trees? if ( t.current() == root && !root->hasChildren() && t.current()->childOp() != pin && t.current()->childOp() != notpin && t.current()->childOp() != function && t.current()->childOp() != read_keypad ) { switch(root->type()) { case number: m_pic->assignNum(root->value()); break; case variable: m_pic->assignVar(root->value()); break; default: break; // Should never get here } // no need to traverse the tree as there is none. return; } t.setCurrent(root); if(t.current()->hasChildren()) { // Here we work out what needs evaulating, and in which order. // To minimize register usage, if only one branch needs traversing, // then that branch should be done first. bool evaluateLeft = t.current()->left()->needsEvaluating(); BTreeNode *evaluateFirst; BTreeNode *evaluateSecond; // If both need doing, then it really doesn't matter which we do // first (unless we are looking to do really complex optimizations... // Cases: // - Both need evaluating, // - or left needs doing first, // in both cases we evaluate left, then right. if( evaluateLeft ) { evaluateFirst = t.current()->left(); evaluateSecond = t.current()->right(); } // Otherwise it is best to evaluate right first for reasons given above. else { evaluateFirst = t.current()->right(); evaluateSecond = t.current()->left(); } QString dest1 = mb->dest(); mb->incDest(); QString dest2 = mb->dest(); mb->decDest(); bool evaluated = false; if( evaluateFirst->hasChildren() ) { traverseTree(evaluateFirst); evaluated = true; } else if( isUnaryOp(evaluateFirst->childOp()) ) { doUnaryOp( evaluateFirst->childOp(), evaluateFirst ); evaluated = true; } if ( evaluated ) { // We need to save the result if we are going tro traverse the other // branch, or if we are performing a subtraction in which case the // value wanted in working is not the current value. // But as the optimizer will deal with unnecessary variables anyway, // always save to a register evaluateFirst->setReg( dest1 ); evaluateFirst->setType( variable ); m_pic->saveToReg( dest1 ); } evaluated = false; if( evaluateSecond->hasChildren() ) { mb->incDest(); mb->incDest(); traverseTree(evaluateSecond); evaluated = true; mb->decDest(); mb->decDest(); } else if( isUnaryOp(evaluateSecond->childOp()) ) { doUnaryOp( evaluateSecond->childOp(), evaluateSecond ); evaluated = true; } if ( evaluated ) { evaluateSecond->setReg( dest2 ); evaluateSecond->setType( variable ); m_pic->saveToReg( dest2 ); } } if(t.current()->childOp()==divbyzero) { mistake( Microbe::DivisionByZero ); } // If we are at the top level of something like 'if a == 3 then', then we are ready to put // in the if code, else the expression just evaluates to 0 or 1 if(conditionalRoot && t.current() == root) m_pic->setConditionalCode(m_ifCode, m_elseCode); // Handle operations // (functions are not actually supported) if(isUnaryOp(t.current()->childOp())) doUnaryOp( t.current()->childOp(), t.current() ); else doOp( t.current()->childOp(), t.current()->left(), t.current()->right() ); }
bool IsPostfix(AST* expr) { assert(isUnaryOp(Type(expr))); return (expr->first != NULL); }
bool IsPrefix(AST* expr) { assert(isUnaryOp(Type(expr))); return (expr->second != NULL); }