#include "cps/CodeGen.h" #include "cps/ArrayHandler.h" #include "cps/Lexer.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Verifier.h" #include using namespace llvm; using namespace cps; CodeGen::~CodeGen() = default; CodeGen::CodeGen() { TheContext = std::make_unique(); TheModule = std::make_unique("cps_module", *TheContext); Builder = std::make_unique>(*TheContext); Types = std::make_unique(*TheContext); RuntimeChecker = std::make_unique(*TheModule, *TheContext, *Builder); Arrays = std::make_unique(*TheContext, *Builder, *TheModule, NamedValues, Symbols, *Types, *RuntimeChecker); FuncGen = std::make_unique(*TheContext, *TheModule, *Builder, *Types, NamedValues, Symbols); IntHandler = std::make_unique(*TheContext, *Builder, *TheModule, NamedValues); RealHelper = std::make_unique(*TheContext, *Builder, *TheModule, NamedValues); BoolHandler = std::make_unique(*TheContext, *Builder, *TheModule, NamedValues); ArithHandler = std::make_unique(*TheContext, *Builder); StrHandler = std::make_unique(*TheContext, *Builder, *TheModule, NamedValues); ChrHandler = std::make_unique(*TheContext, *Builder, *TheModule); StrConvHandler = std::make_unique(*TheContext, *Builder, *TheModule); SetupExternalFunctions(); } void CodeGen::SetupExternalFunctions() { std::vector PrintfArgs; PrintfArgs.push_back(PointerType::getUnqual(*TheContext)); FunctionType *PrintfType = FunctionType::get(Type::getInt32Ty(*TheContext), PrintfArgs, true); PrintfFunc = TheModule->getOrInsertFunction("printf", PrintfType); FunctionType *ScanfType = FunctionType::get(Type::getInt32Ty(*TheContext), PrintfArgs, true); ScanfFunc = TheModule->getOrInsertFunction("scanf", ScanfType); PrintfFormatStr = Builder->CreateGlobalStringPtr("%lld\n", "fmt_nl", 0, TheModule.get()); PrintfFloatFormatStr = Builder->CreateGlobalStringPtr("%f\n", "fmt_flt", 0, TheModule.get()); PrintfStringFormatStr = Builder->CreateGlobalStringPtr("%s\n", "fmt_str", 0, TheModule.get()); PrintfCharFormatStr = Builder->CreateGlobalStringPtr("%c\n", "fmt_chr", 0, TheModule.get()); ScanfFormatStr = Builder->CreateGlobalStringPtr("%lld", "fmt_in", 0, TheModule.get()); ScanfFloatFormatStr = Builder->CreateGlobalStringPtr("%lf", "fmt_in_flt", 0, TheModule.get()); ScanfStringFormatStr = Builder->CreateGlobalStringPtr("%s", "fmt_in_str", 0, TheModule.get()); TrueStr = Builder->CreateGlobalStringPtr("TRUE", "str_true", 0, TheModule.get()); FalseStr = Builder->CreateGlobalStringPtr("FALSE", "str_false", 0, TheModule.get()); EmptyStringStr = Builder->CreateGlobalStringPtr("", "str_empty", 0, TheModule.get()); Arrays->setupExternalFunctions(); } AllocaInst *CodeGen::CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { return CreateEntryBlockAlloca(TheFunction, Type::getInt64Ty(*TheContext), VarName); } AllocaInst *CodeGen::CreateEntryBlockAlloca(Function *TheFunction, Type *AllocType, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); return TmpB.CreateAlloca(AllocType, nullptr, VarName); } void CodeGen::registerSymbol(const std::string &Name, Value *Storage, const std::string &TypeName, bool IsArray) { NamedValues[Name] = Storage; Symbols[Name] = {Storage, TypeName, IsArray}; } const SymbolInfo *CodeGen::getSymbolInfo(const std::string &Name) const { auto It = Symbols.find(Name); if (It == Symbols.end()) { return nullptr; } return &It->second; } const TypeInfo *CodeGen::resolveType(const std::string &TypeName) const { return Types->resolve(TypeName); } Type *CodeGen::getLLVMType(const std::string &TypeName) const { return Types->getLLVMType(TypeName); } Value *CodeGen::getNamedValue(const std::string &Name) const { auto It = NamedValues.find(Name); return It == NamedValues.end() ? nullptr : It->second; } const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const { if (!Expr) return nullptr; if (dynamic_cast(Expr)) return resolveType("INTEGER"); if (dynamic_cast(Expr)) return resolveType("REAL"); if (dynamic_cast(Expr)) return resolveType("BOOLEAN"); if (dynamic_cast(Expr)) return resolveType("CHAR"); if (dynamic_cast(Expr)) return resolveType("STRING"); if (auto *Var = dynamic_cast(Expr)) { const SymbolInfo *Info = getSymbolInfo(Var->getName()); return Info ? resolveType(Info->TypeName) : nullptr; } if (auto *Arr = dynamic_cast(Expr)) { const SymbolInfo *Info = getSymbolInfo(Arr->getName()); return Info ? resolveType(Info->TypeName) : nullptr; } if (auto *Unary = dynamic_cast(Expr)) { if (Unary->getOp() == tok_not) { return resolveType("BOOLEAN"); } return getExprTypeInfo(Unary->getOperand()); } if (auto *Bin = dynamic_cast(Expr)) { switch (Bin->getOp()) { case tok_eq: case tok_ne: case '<': case '>': case tok_le: case tok_ge: case tok_and: case tok_or: return resolveType("BOOLEAN"); case '&': return resolveType("STRING"); default: break; } const TypeInfo *L = getExprTypeInfo(Bin->getLHS()); const TypeInfo *R = getExprTypeInfo(Bin->getRHS()); if ((L && L->Kind == TypeKind::Real) || (R && R->Kind == TypeKind::Real)) { return resolveType("REAL"); } return resolveType("INTEGER"); } if (auto *Call = dynamic_cast(Expr)) { const std::string &Name = Call->getCallee(); if (Name == "LENGTH" || Name == "ASC") return resolveType("INTEGER"); if (Name == "MID" || Name == "RIGHT" || Name == "LEFT" || Name == "LCASE" || Name == "UCASE" || Name == "CHR" || Name == "NUM_TO_STR") return resolveType("STRING"); if (Name == "IS_NUM") return resolveType("BOOLEAN"); if (Name == "STR_TO_NUM") return resolveType("REAL"); Function *CalleeF = TheModule->getFunction(Name); if (!CalleeF) return resolveType("INTEGER"); Type *RetTy = CalleeF->getReturnType(); if (RetTy->isVoidTy()) return resolveType("VOID"); if (RetTy->isDoubleTy()) return resolveType("REAL"); if (RetTy->isIntegerTy(1)) return resolveType("BOOLEAN"); if (RetTy->isIntegerTy(8)) return resolveType("CHAR"); if (RetTy->isPointerTy()) return resolveType("STRING"); return resolveType("INTEGER"); } return nullptr; } Value *CodeGen::coerceValueToType(Value *Val, const TypeInfo *TargetInfo) { if (!Val || !TargetInfo || !TargetInfo->LLVMType) return nullptr; if (Val->getType() == TargetInfo->LLVMType) { return Val; } switch (TargetInfo->Kind) { case TypeKind::Real: if (Val->getType()->isDoubleTy()) return Val; if (Val->getType()->isIntegerTy(1)) return Builder->CreateUIToFP(Val, Type::getDoubleTy(*TheContext), "bool_to_real"); if (Val->getType()->isIntegerTy(8)) return Builder->CreateUIToFP(Val, Type::getDoubleTy(*TheContext), "char_to_real"); if (Val->getType()->isIntegerTy()) return Builder->CreateSIToFP(Val, Type::getDoubleTy(*TheContext), "int_to_real"); break; case TypeKind::Integer: if (Val->getType()->isIntegerTy(64)) return Val; if (Val->getType()->isDoubleTy()) return Builder->CreateFPToSI(Val, Type::getInt64Ty(*TheContext), "real_to_int"); if (Val->getType()->isIntegerTy(1)) return Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext), "bool_to_int"); if (Val->getType()->isIntegerTy(8)) return Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext), "char_to_int"); if (Val->getType()->isIntegerTy()) return Builder->CreateSExtOrTrunc(Val, Type::getInt64Ty(*TheContext), "int_cast"); break; case TypeKind::Boolean: if (Val->getType()->isIntegerTy(1)) return Val; if (Val->getType()->isIntegerTy()) return Builder->CreateICmpNE(Val, Constant::getNullValue(Val->getType()), "to_bool"); if (Val->getType()->isDoubleTy()) return Builder->CreateFCmpONE(Val, ConstantFP::get(*TheContext, APFloat(0.0)), "to_bool"); if (Val->getType()->isPointerTy()) return Builder->CreateICmpNE(Val, ConstantPointerNull::get(cast(Val->getType())), "ptr_to_bool"); break; case TypeKind::Char: if (Val->getType()->isIntegerTy(8)) return Val; if (Val->getType()->isIntegerTy(1)) return Builder->CreateZExt(Val, Type::getInt8Ty(*TheContext), "bool_to_char"); if (Val->getType()->isDoubleTy()) return Builder->CreateFPToUI(Val, Type::getInt8Ty(*TheContext), "real_to_char"); if (Val->getType()->isIntegerTy()) return Builder->CreateTruncOrBitCast(Val, Type::getInt8Ty(*TheContext), "int_to_char"); break; case TypeKind::String: if (Val->getType()->isPointerTy()) return Val; if (Val->getType()->isIntegerTy(1)) { return Builder->CreateSelect(Val, TrueStr, FalseStr, "bool_to_str"); } if (Val->getType()->isDoubleTy()) { return StrConvHandler->emitNumToStr(Val, true); } if (Val->getType()->isIntegerTy(8)) { Function *MallocF = TheModule->getFunction("malloc"); if (!MallocF) { FunctionType *MallocTy = FunctionType::get(PointerType::getUnqual(*TheContext), {Type::getInt64Ty(*TheContext)}, false); MallocF = Function::Create(MallocTy, Function::ExternalLinkage, "malloc", TheModule.get()); } Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 2)), "char_str"); Builder->CreateStore(Val, Mem); Value *NullPtr = Builder->CreateInBoundsGEP(Type::getInt8Ty(*TheContext), Mem, ConstantInt::get(*TheContext, APInt(64, 1))); Builder->CreateStore(ConstantInt::get(Type::getInt8Ty(*TheContext), 0), NullPtr); return Mem; } if (Val->getType()->isIntegerTy()) { Value *AsInt = coerceValueToType(Val, resolveType("INTEGER")); return AsInt ? StrConvHandler->emitNumToStr(AsInt, false) : nullptr; } break; case TypeKind::Void: return nullptr; case TypeKind::Custom: if (Val->getType() == TargetInfo->LLVMType) return Val; if (Val->getType()->isPointerTy() && TargetInfo->LLVMType->isPointerTy()) { return Builder->CreateBitCast(Val, TargetInfo->LLVMType, "custom_ptr_cast"); } break; } fprintf(stderr, "Error: Cannot coerce value of LLVM type to target type %s\n", TargetInfo->Name.c_str()); return nullptr; } void CodeGen::emitDeclareStmt(DeclareStmtAST *Stmt) { const TypeInfo *Info = resolveType(Stmt->getType()); if (!Info || !Info->LLVMType || Info->isVoid()) { fprintf(stderr, "Error: Unknown type %s\n", Stmt->getType().c_str()); return; } Function *TheFunction = Builder->GetInsertBlock()->getParent(); AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Info->LLVMType, Stmt->getName()); Value *InitVal = nullptr; if (Info->isString()) { InitVal = EmptyStringStr; } else { InitVal = Types->getZeroValue(Info->Name); } if (InitVal) { Builder->CreateStore(InitVal, Alloca); } registerSymbol(Stmt->getName(), Alloca, Info->Name, false); } void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewline) { if (!Val || !Info) return; if (!Info->Printable && Info->Kind == TypeKind::Custom) { fprintf(stderr, "Error: OUTPUT for custom type %s is not implemented yet\n", Info->Name.c_str()); return; } std::vector Args; Value *Fmt = nullptr; if (Info->isReal()) { Fmt = AppendNewline ? PrintfFloatFormatStr : Builder->CreateGlobalStringPtr("%f", "fmt_flt_inline", 0, TheModule.get()); Args.push_back(Fmt); Args.push_back(Val); } else if (Info->isBoolean()) { Value *BoolVal = coerceValueToType(Val, resolveType("BOOLEAN")); Fmt = AppendNewline ? PrintfStringFormatStr : Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get()); Args.push_back(Fmt); Args.push_back(Builder->CreateSelect(BoolVal, TrueStr, FalseStr)); } else if (Info->isString()) { Value *StrVal = Val; if (StrVal->getType()->isPointerTy()) { Value *IsNull = Builder->CreateICmpEQ(StrVal, ConstantPointerNull::get(cast(StrVal->getType())), "str_is_null"); StrVal = Builder->CreateSelect(IsNull, EmptyStringStr, StrVal, "safe_str"); } Fmt = AppendNewline ? PrintfStringFormatStr : Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get()); Args.push_back(Fmt); Args.push_back(StrVal); } else if (Info->isChar()) { Value *CharVal = coerceValueToType(Val, resolveType("CHAR")); Value *Promoted = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "char_for_printf"); Fmt = AppendNewline ? PrintfCharFormatStr : Builder->CreateGlobalStringPtr("%c", "fmt_chr_inline", 0, TheModule.get()); Args.push_back(Fmt); Args.push_back(Promoted); } else { Value *IntVal = coerceValueToType(Val, resolveType("INTEGER")); Fmt = AppendNewline ? PrintfFormatStr : Builder->CreateGlobalStringPtr("%lld", "fmt_int_inline", 0, TheModule.get()); Args.push_back(Fmt); Args.push_back(IntVal); } Builder->CreateCall(PrintfFunc, Args); } void CodeGen::compile(const std::vector> &Statements) { FunctionType *FT = FunctionType::get(Type::getInt32Ty(*TheContext), false); Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get()); BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", F); Builder->SetInsertPoint(BB); for (const auto &Stmt : Statements) { emitStmt(Stmt.get()); } if (!Builder->GetInsertBlock()->getTerminator()) { Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0))); } verifyFunction(*F); } void CodeGen::print() { TheModule->print(errs(), nullptr); } Value *CodeGen::emitExpr(ExprAST *Expr) { if (!Expr) return nullptr; if (auto *Num = dynamic_cast(Expr)) { return IntHandler->createLiteral(Num->getVal()); } if (auto *Real = dynamic_cast(Expr)) { return RealHelper->createLiteral(Real->getVal()); } if (auto *Bool = dynamic_cast(Expr)) { return BoolHandler->createLiteral(Bool->getVal()); } if (auto *Chr = dynamic_cast(Expr)) { return ConstantInt::get(Type::getInt8Ty(*TheContext), static_cast(Chr->getVal())); } if (auto *Str = dynamic_cast(Expr)) { return StrHandler->createLiteral(Str->getVal()); } if (auto *Var = dynamic_cast(Expr)) { const SymbolInfo *Info = getSymbolInfo(Var->getName()); if (!Info) { fprintf(stderr, "Error: Unknown variable name %s\n", Var->getName().c_str()); return nullptr; } if (Info->IsArray) { return Info->Storage; } const TypeInfo *TypeInfo = resolveType(Info->TypeName); if (!TypeInfo || !TypeInfo->LLVMType) { fprintf(stderr, "Error: Unknown type for variable %s\n", Var->getName().c_str()); return nullptr; } Value *Loaded = Builder->CreateLoad(TypeInfo->LLVMType, Info->Storage, Var->getName().c_str()); if (TypeInfo->isString()) { Value *IsNull = Builder->CreateICmpEQ(Loaded, ConstantPointerNull::get(cast(Loaded->getType())), "str_is_null"); Loaded = Builder->CreateSelect(IsNull, EmptyStringStr, Loaded, "safe_var_str"); } return Loaded; } if (auto *ArrAcc = dynamic_cast(Expr)) { return Arrays->emitArrayAccess(ArrAcc, *this); } if (auto *Unary = dynamic_cast(Expr)) { Value *Operand = emitExpr(Unary->getOperand()); if (!Operand) return nullptr; if (Unary->getOp() == tok_not) { Operand = coerceValueToType(Operand, resolveType("BOOLEAN")); return Builder->CreateNot(Operand, "nottmp"); } } if (auto *Bin = dynamic_cast(Expr)) { Value *L = emitExpr(Bin->getLHS()); Value *R = emitExpr(Bin->getRHS()); if (!L || !R) return nullptr; return ArithHandler->emitBinaryOp(Bin->getOp(), L, R, Bin->getLine()); } if (auto *Call = dynamic_cast(Expr)) { std::string Name = Call->getCallee(); if (Name == "LENGTH") { if (Call->getArgs().size() != 1) { fprintf(stderr, "LENGTH expects 1 arg\n"); return nullptr; } return StrHandler->emitLength(emitExpr(Call->getArgs()[0].get())); } if (Name == "MID") { if (Call->getArgs().size() != 3) { fprintf(stderr, "MID expects 3 args\n"); return nullptr; } return StrHandler->emitMid(emitExpr(Call->getArgs()[0].get()), emitExpr(Call->getArgs()[1].get()), emitExpr(Call->getArgs()[2].get())); } if (Name == "RIGHT") { if (Call->getArgs().size() != 2) { fprintf(stderr, "RIGHT expects 2 args\n"); return nullptr; } return StrHandler->emitRight(emitExpr(Call->getArgs()[0].get()), emitExpr(Call->getArgs()[1].get())); } if (Name == "LEFT") { if (Call->getArgs().size() != 2) { fprintf(stderr, "LEFT expects 2 args\n"); return nullptr; } return StrHandler->emitLeft(emitExpr(Call->getArgs()[0].get()), emitExpr(Call->getArgs()[1].get())); } if (Name == "LCASE") { if (Call->getArgs().size() != 1) { fprintf(stderr, "LCASE expects 1 arg\n"); return nullptr; } return StrHandler->emitLCase(emitExpr(Call->getArgs()[0].get())); } if (Name == "UCASE") { if (Call->getArgs().size() != 1) { fprintf(stderr, "UCASE expects 1 arg\n"); return nullptr; } return StrHandler->emitUCase(emitExpr(Call->getArgs()[0].get())); } if (Name == "ASC") { if (Call->getArgs().size() != 1) return nullptr; Value *ArgVal = emitExpr(Call->getArgs()[0].get()); const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get()); Value *CharVal = nullptr; if (ArgType && ArgType->isChar()) { CharVal = coerceValueToType(ArgVal, resolveType("CHAR")); } else { CharVal = Builder->CreateLoad(Type::getInt8Ty(*TheContext), ArgVal, "char_load"); } Value *AscVal = ChrHandler->emitAsc(CharVal); return coerceValueToType(AscVal, resolveType("INTEGER")); } if (Name == "CHR") { if (Call->getArgs().size() != 1) return nullptr; Value *IntVal = coerceValueToType(emitExpr(Call->getArgs()[0].get()), resolveType("INTEGER")); Value *CharVal = ChrHandler->emitChr(IntVal); Function *MallocF = TheModule->getFunction("malloc"); Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 2))); Builder->CreateStore(CharVal, Mem); Value *NullPtr = Builder->CreateInBoundsGEP(Type::getInt8Ty(*TheContext), Mem, ConstantInt::get(*TheContext, APInt(64, 1))); Builder->CreateStore(ConstantInt::get(Type::getInt8Ty(*TheContext), 0), NullPtr); return Mem; } if (Name == "IS_NUM") { if (Call->getArgs().size() != 1) return nullptr; return StrConvHandler->emitIsNum(emitExpr(Call->getArgs()[0].get())); } if (Name == "NUM_TO_STR") { if (Call->getArgs().size() != 1) return nullptr; Value *NumV = emitExpr(Call->getArgs()[0].get()); bool IsReal = NumV->getType()->isDoubleTy(); if (NumV->getType()->isIntegerTy(8)) { NumV = coerceValueToType(NumV, resolveType("INTEGER")); } return StrConvHandler->emitNumToStr(NumV, IsReal); } if (Name == "STR_TO_NUM") { if (Call->getArgs().size() != 1) return nullptr; return StrConvHandler->emitStrToNum(emitExpr(Call->getArgs()[0].get()), true); } Function *CalleeF = TheModule->getFunction(Call->getCallee()); std::vector Args; for (unsigned i = 0; i < Call->getArgs().size(); ++i) { ExprAST *ArgExpr = Call->getArgs()[i].get(); bool IsByRef = false; if (CalleeF && i < CalleeF->arg_size()) { if (CalleeF->getArg(i)->getType()->isPointerTy()) { IsByRef = true; } } if (IsByRef) { if (auto *Var = dynamic_cast(ArgExpr)) { Value *Ptr = getNamedValue(Var->getName()); if (!Ptr) { fprintf(stderr, "Error: Unknown variable %s in BYREF call\n", Var->getName().c_str()); return nullptr; } Args.push_back(Ptr); } else { fprintf(stderr, "Error: BYREF argument must be a variable.\n"); return nullptr; } } else { Args.push_back(emitExpr(ArgExpr)); } } return FuncGen->emitCallExpr(Call, Args); } return nullptr; } void CodeGen::emitIfStmt(IfStmtAST *Stmt) { Value *CondV = emitExpr(Stmt->getCond()); if (!CondV) return; CondV = coerceValueToType(CondV, resolveType("BOOLEAN")); Function *TheFunction = Builder->GetInsertBlock()->getParent(); BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else", TheFunction); BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont", TheFunction); Builder->CreateCondBr(CondV, ThenBB, ElseBB); Builder->SetInsertPoint(ThenBB); for (const auto &S : Stmt->getThenStmts()) emitStmt(S.get()); if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(MergeBB); Builder->SetInsertPoint(ElseBB); for (const auto &S : Stmt->getElseStmts()) emitStmt(S.get()); if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(MergeBB); Builder->SetInsertPoint(MergeBB); } void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) { Function *TheFunction = Builder->GetInsertBlock()->getParent(); BasicBlock *CondBB = BasicBlock::Create(*TheContext, "whilecond", TheFunction); BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "whileloop", TheFunction); BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "whilecont", TheFunction); Builder->CreateBr(CondBB); Builder->SetInsertPoint(CondBB); Value *CondV = emitExpr(Stmt->getCond()); if (!CondV) return; CondV = coerceValueToType(CondV, resolveType("BOOLEAN")); Builder->CreateCondBr(CondV, LoopBB, AfterBB); Builder->SetInsertPoint(LoopBB); for (const auto &S : Stmt->getBody()) emitStmt(S.get()); if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(CondBB); Builder->SetInsertPoint(AfterBB); } void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) { Function *TheFunction = Builder->GetInsertBlock()->getParent(); BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "repeatloop", TheFunction); BasicBlock *CondBB = BasicBlock::Create(*TheContext, "repeatcond", TheFunction); BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "repeatcont", TheFunction); Builder->CreateBr(LoopBB); Builder->SetInsertPoint(LoopBB); for (const auto &S : Stmt->getBody()) emitStmt(S.get()); if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(CondBB); Builder->SetInsertPoint(CondBB); Value *CondV = emitExpr(Stmt->getCond()); if (!CondV) return; CondV = coerceValueToType(CondV, resolveType("BOOLEAN")); Builder->CreateCondBr(CondV, AfterBB, LoopBB); Builder->SetInsertPoint(AfterBB); } void CodeGen::emitForStmt(ForStmtAST *Stmt) { Function *TheFunction = Builder->GetInsertBlock()->getParent(); std::string VarName = Stmt->getVarName(); const SymbolInfo *Symbol = getSymbolInfo(VarName); if (!Symbol) { fprintf(stderr, "Error: Unknown variable in FOR loop %s\n", VarName.c_str()); return; } if (Symbol->TypeName != "INTEGER") { fprintf(stderr, "Error: FOR loop variable %s must be INTEGER\n", VarName.c_str()); return; } Value *StartVal = coerceValueToType(emitExpr(Stmt->getStart()), resolveType("INTEGER")); if (!StartVal) return; Value *Alloca = Symbol->Storage; Builder->CreateStore(StartVal, Alloca); BasicBlock *CondBB = BasicBlock::Create(*TheContext, "forcond", TheFunction); BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "forloop", TheFunction); BasicBlock *IncBB = BasicBlock::Create(*TheContext, "forinc", TheFunction); BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "forcont", TheFunction); Builder->CreateBr(CondBB); Builder->SetInsertPoint(CondBB); Value *CurVar = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str()); Value *EndVal = coerceValueToType(emitExpr(Stmt->getEnd()), resolveType("INTEGER")); if (!EndVal) return; bool IsNegativeStep = false; if (Stmt->getStep()) { if (auto *Num = dynamic_cast(Stmt->getStep())) { if (Num->getVal() < 0) IsNegativeStep = true; } } Value *CondV = IsNegativeStep ? Builder->CreateICmpSGE(CurVar, EndVal, "forcond_ge") : Builder->CreateICmpSLE(CurVar, EndVal, "forcond_le"); Builder->CreateCondBr(CondV, LoopBB, AfterBB); Builder->SetInsertPoint(LoopBB); for (const auto &S : Stmt->getBody()) emitStmt(S.get()); if (!Builder->GetInsertBlock()->getTerminator()) Builder->CreateBr(IncBB); Builder->SetInsertPoint(IncBB); Value *StepVal = nullptr; if (Stmt->getStep()) { StepVal = coerceValueToType(emitExpr(Stmt->getStep()), resolveType("INTEGER")); } else { StepVal = ConstantInt::get(*TheContext, APInt(64, 1)); } Value *CurValForInc = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str()); Value *NextVal = Builder->CreateAdd(CurValForInc, StepVal, "nextval"); Builder->CreateStore(NextVal, Alloca); Builder->CreateBr(CondBB); Builder->SetInsertPoint(AfterBB); } void CodeGen::emitStmt(StmtAST *Stmt) { if (!Stmt) return; if (auto *ArrDecl = dynamic_cast(Stmt)) { Arrays->emitArrayDeclare(ArrDecl, *this); return; } if (auto *ArrAssign = dynamic_cast(Stmt)) { Arrays->emitArrayAssign(ArrAssign, *this); return; } if (auto *FuncDef = dynamic_cast(Stmt)) { BasicBlock *SavedBlock = Builder->GetInsertBlock(); FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) { this->emitStmt(S); }); if (SavedBlock) Builder->SetInsertPoint(SavedBlock); return; } if (auto *Call = dynamic_cast(Stmt)) { Function *CalleeF = TheModule->getFunction(Call->getCallee()); std::vector Args; for (unsigned i = 0; i < Call->getArgs().size(); ++i) { ExprAST *ArgExpr = Call->getArgs()[i].get(); bool IsByRef = false; if (CalleeF && i < CalleeF->arg_size()) { if (CalleeF->getArg(i)->getType()->isPointerTy()) { IsByRef = true; } } if (IsByRef) { if (auto *Var = dynamic_cast(ArgExpr)) { Value *Ptr = getNamedValue(Var->getName()); if (!Ptr) { fprintf(stderr, "Error: Unknown variable %s in BYREF call\n", Var->getName().c_str()); return; } Args.push_back(Ptr); } else { fprintf(stderr, "Error: BYREF argument must be a variable.\n"); return; } } else { Args.push_back(emitExpr(ArgExpr)); } } FuncGen->emitCallStmt(Call, Args); return; } if (auto *Ret = dynamic_cast(Stmt)) { Value *RetVal = nullptr; if (Ret->getRetVal()) { RetVal = emitExpr(Ret->getRetVal()); } FuncGen->emitReturn(Ret, RetVal); return; } if (auto *Decl = dynamic_cast(Stmt)) { emitDeclareStmt(Decl); return; } if (auto *Assign = dynamic_cast(Stmt)) { const SymbolInfo *Info = getSymbolInfo(Assign->getName()); if (!Info) { fprintf(stderr, "Error: Unknown variable name %s\n", Assign->getName().c_str()); return; } if (Info->IsArray) { fprintf(stderr, "Error: Cannot assign array %s without indices\n", Assign->getName().c_str()); return; } Value *Val = emitExpr(Assign->getExpr()); const TypeInfo *TargetType = resolveType(Info->TypeName); Val = coerceValueToType(Val, TargetType); if (!Val) return; Builder->CreateStore(Val, Info->Storage); return; } if (auto *In = dynamic_cast(Stmt)) { const SymbolInfo *Info = getSymbolInfo(In->getName()); if (!Info) { fprintf(stderr, "Error: Unknown variable name %s\n", In->getName().c_str()); return; } if (Info->IsArray) { fprintf(stderr, "Error: INPUT for entire array %s is not supported\n", In->getName().c_str()); return; } const TypeInfo *TypeInfo = resolveType(Info->TypeName); if (!TypeInfo) { fprintf(stderr, "Error: Unknown type for INPUT %s\n", In->getName().c_str()); return; } std::vector Args; if (TypeInfo->isReal()) { Args.push_back(ScanfFloatFormatStr); Args.push_back(Info->Storage); Builder->CreateCall(ScanfFunc, Args); } else if (TypeInfo->isBoolean()) { AllocaInst *TempInt = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), "tmp_bool_input"); Args.push_back(ScanfFormatStr); Args.push_back(TempInt); Builder->CreateCall(ScanfFunc, Args); Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), TempInt); Value *BoolVal = Builder->CreateICmpNE(Val, ConstantInt::get(*TheContext, APInt(64, 0)), "bool_cast"); Builder->CreateStore(BoolVal, Info->Storage); } else if (TypeInfo->isString()) { Function *MallocF = TheModule->getFunction("malloc"); Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 1024)), "input_str"); Args.push_back(ScanfStringFormatStr); Args.push_back(Mem); Builder->CreateCall(ScanfFunc, Args); Builder->CreateStore(Mem, Info->Storage); } else if (TypeInfo->isChar()) { Value *CharFmt = Builder->CreateGlobalStringPtr(" %c", "fmt_in_char", 0, TheModule.get()); Args.push_back(CharFmt); Args.push_back(Info->Storage); Builder->CreateCall(ScanfFunc, Args); } else { Args.push_back(ScanfFormatStr); Args.push_back(Info->Storage); Builder->CreateCall(ScanfFunc, Args); } return; } if (auto *Out = dynamic_cast(Stmt)) { bool Handled = Arrays->tryEmitArrayOutput(Out->getExpr(), *this); if (Handled) return; Value *Val = emitExpr(Out->getExpr()); const TypeInfo *TypeInfo = getExprTypeInfo(Out->getExpr()); if (!TypeInfo) TypeInfo = resolveType("INTEGER"); emitOutputValue(Val, TypeInfo, true); return; } if (auto *IfStmt = dynamic_cast(Stmt)) { emitIfStmt(IfStmt); return; } if (auto *WhileStmt = dynamic_cast(Stmt)) { emitWhileStmt(WhileStmt); return; } if (auto *RepeatStmt = dynamic_cast(Stmt)) { emitRepeatStmt(RepeatStmt); return; } if (auto *ForStmt = dynamic_cast(Stmt)) { emitForStmt(ForStmt); return; } }