diff options
| author | _ov4 <hausemasterstream@gmail.com> | 2026-02-02 08:45:01 +0000 |
|---|---|---|
| committer | _ov4 <hausemasterstream@gmail.com> | 2026-02-02 08:45:01 +0000 |
| commit | 419420770c4545ea4010047ef2153004d4700eed (patch) | |
| tree | bd19eed681dbb68ecb501b6cfc220c42a9803ef3 /lib | |
| parent | ecc0fc463ba54dd0cbe33bc14415f432eaa959de (diff) | |
Added REAL and BOOLEAN types, DIV and MOD operators
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/CodeGen/ArithmeticHandler.cc | 67 | ||||
| -rw-r--r-- | lib/CodeGen/BooleanHandler.cc | 16 | ||||
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 110 | ||||
| -rw-r--r-- | lib/CodeGen/IntegerHandler.cc | 16 | ||||
| -rw-r--r-- | lib/CodeGen/RealHandler.cc | 16 | ||||
| -rw-r--r-- | lib/Lexer/Lexer.cc | 27 | ||||
| -rw-r--r-- | lib/Parser/Parser.cc | 36 |
7 files changed, 247 insertions, 41 deletions
diff --git a/lib/CodeGen/ArithmeticHandler.cc b/lib/CodeGen/ArithmeticHandler.cc new file mode 100644 index 0000000..762f0a3 --- /dev/null +++ b/lib/CodeGen/ArithmeticHandler.cc @@ -0,0 +1,67 @@ +#include "cps/ArithmeticHandler.h" +#include <cstdio> + +using namespace llvm; +using namespace cps; + +Value *ArithmeticHandler::emitBinaryOp(int Op, Value *LHS, Value *RHS, int Line) { + bool LIsInt = LHS->getType()->isIntegerTy(64); + bool RIsInt = RHS->getType()->isIntegerTy(64); + bool LIsDouble = LHS->getType()->isDoubleTy(); + bool RIsDouble = RHS->getType()->isDoubleTy(); + + if (Op == '/') { + Value *LVal = LHS; + Value *RVal = RHS; + if (LIsInt) LVal = Builder.CreateSIToFP(LHS, Type::getDoubleTy(Context)); + if (RIsInt) RVal = Builder.CreateSIToFP(RHS, Type::getDoubleTy(Context)); + + // TODO: DIV divide by 0 runtime check + return Builder.CreateFDiv(LVal, RVal, "divtmp"); + } + + // DIV / MOD : Only Integer. + if (Op == tok_div || Op == tok_mod) { + if (!LIsInt || !RIsInt) { + fprintf(stderr, "Error: DIV and MOD operators require INTEGER operands.\n"); + return nullptr; + } + if (Op == tok_div) return Builder.CreateSDiv(LHS, RHS, "div_int_tmp"); + if (Op == tok_mod) return Builder.CreateSRem(LHS, RHS, "mod_tmp"); + } + + if (LIsDouble || RIsDouble) { + Value *LVal = LHS; + Value *RVal = RHS; + if (LIsInt) LVal = Builder.CreateSIToFP(LHS, Type::getDoubleTy(Context)); + if (RIsInt) RVal = Builder.CreateSIToFP(RHS, Type::getDoubleTy(Context)); + + switch (Op) { + case '+': return Builder.CreateFAdd(LVal, RVal, "addtmp"); + case '-': return Builder.CreateFSub(LVal, RVal, "subtmp"); + case '*': return Builder.CreateFMul(LVal, RVal, "multmp"); + + case tok_eq: return Builder.CreateFCmpOEQ(LVal, RVal, "eqtmp"); + case tok_ne: return Builder.CreateFCmpONE(LVal, RVal, "netmp"); + case '<': return Builder.CreateFCmpOLT(LVal, RVal, "slttmp"); + case '>': return Builder.CreateFCmpOGT(LVal, RVal, "sgttmp"); + case tok_le: return Builder.CreateFCmpOLE(LVal, RVal, "sletmp"); + case tok_ge: return Builder.CreateFCmpOGE(LVal, RVal, "sgetmp"); + } + } else { + switch (Op) { + case '+': return Builder.CreateAdd(LHS, RHS, "addtmp"); + case '-': return Builder.CreateSub(LHS, RHS, "subtmp"); + case '*': return Builder.CreateMul(LHS, RHS, "multmp"); + + case tok_eq: return Builder.CreateICmpEQ(LHS, RHS, "eqtmp"); + case tok_ne: return Builder.CreateICmpNE(LHS, RHS, "netmp"); + case '<': return Builder.CreateICmpSLT(LHS, RHS, "slttmp"); + case '>': return Builder.CreateICmpSGT(LHS, RHS, "sgttmp"); + case tok_le: return Builder.CreateICmpSLE(LHS, RHS, "sletmp"); + case tok_ge: return Builder.CreateICmpSGE(LHS, RHS, "sgetmp"); + } + } + + return nullptr; +} diff --git a/lib/CodeGen/BooleanHandler.cc b/lib/CodeGen/BooleanHandler.cc new file mode 100644 index 0000000..558ac95 --- /dev/null +++ b/lib/CodeGen/BooleanHandler.cc @@ -0,0 +1,16 @@ +#include "cps/BooleanHandler.h" + +using namespace llvm; +using namespace cps; + +void BooleanHandler::emitDeclare(const std::string &Name) { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); + AllocaInst *Alloca = TmpB.CreateAlloca(Type::getInt1Ty(Context), nullptr, Name); + Builder.CreateStore(ConstantInt::get(Context, APInt(1, 0)), Alloca); + NamedValues[Name] = Alloca; +} + +Value *BooleanHandler::createLiteral(bool Val) { + return ConstantInt::get(Context, APInt(1, Val ? 1 : 0)); +} diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index bfbd8e0..da6b005 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -1,6 +1,7 @@ #include "cps/CodeGen.h" #include "cps/ArrayHandler.h" #include "llvm/IR/Verifier.h" +#include "llvm/IR/Instructions.h" #include "cps/Lexer.h" using namespace llvm; @@ -19,6 +20,11 @@ CodeGen::CodeGen() { FuncGen = std::make_unique<FunctionGen>(*TheContext, *TheModule, *Builder, NamedValues); + IntHandler = std::make_unique<IntegerHandler>(*TheContext, *Builder, *TheModule, NamedValues); + RealHelper = std::make_unique<RealHandler>(*TheContext, *Builder, *TheModule, NamedValues); + BoolHandler = std::make_unique<BooleanHandler>(*TheContext, *Builder, *TheModule, NamedValues); + ArithHandler = std::make_unique<ArithmeticHandler>(*TheContext, *Builder); + SetupExternalFunctions(); } @@ -32,7 +38,14 @@ void CodeGen::SetupExternalFunctions() { 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()); + ScanfFormatStr = Builder->CreateGlobalStringPtr("%lld", "fmt_in", 0, TheModule.get()); + ScanfFloatFormatStr = Builder->CreateGlobalStringPtr("%lf", "fmt_in_flt", 0, TheModule.get()); + + TrueStr = Builder->CreateGlobalStringPtr("TRUE", "str_true", 0, TheModule.get()); + FalseStr = Builder->CreateGlobalStringPtr("FALSE", "str_false", 0, TheModule.get()); Arrays->setupExternalFunctions(); } @@ -65,8 +78,16 @@ void CodeGen::print() { Value *CodeGen::emitExpr(ExprAST *Expr) { if (!Expr) return nullptr; - if (auto *Num = dynamic_cast<NumberExprAST*>(Expr)) { - return ConstantInt::get(*TheContext, APInt(64, Num->getVal(), true)); + if (auto *Num = dynamic_cast<IntegerExprAST*>(Expr)) { + return IntHandler->createLiteral(Num->getVal()); + } + + if (auto *Real = dynamic_cast<RealExprAST*>(Expr)) { + return RealHelper->createLiteral(Real->getVal()); + } + + if (auto *Bool = dynamic_cast<BooleanExprAST*>(Expr)) { + return BoolHandler->createLiteral(Bool->getVal()); } if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) { @@ -76,9 +97,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { return nullptr; } - return Builder->CreateLoad(Type::getInt64Ty(*TheContext), A, Var->getName().c_str()); + Type *AllocType = cast<AllocaInst>(A)->getAllocatedType(); + return Builder->CreateLoad(AllocType, A, Var->getName().c_str()); } - if (auto *ArrAcc = dynamic_cast<ArrayAccessExprAST*>(Expr)) { return Arrays->emitArrayAccess(ArrAcc, *this); @@ -89,23 +110,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { Value *R = emitExpr(Bin->getRHS()); if (!L || !R) return nullptr; - switch (Bin->getOp()) { - case '+': return Builder->CreateAdd(L, R, "addtmp"); - case '-': return Builder->CreateSub(L, R, "subtmp"); - case '*': return Builder->CreateMul(L, R, "multmp"); - case '/': - RuntimeChecker->emitDivZeroCheck(R, Bin->getLine()); - return Builder->CreateSDiv(L, R, "divtmp"); - case tok_eq: return Builder->CreateICmpEQ(L, R, "eqtmp"); - case tok_ne: return Builder->CreateICmpNE(L, R, "netmp"); - case '<': return Builder->CreateICmpSLT(L, R, "slttmp"); - case '>': return Builder->CreateICmpSGT(L, R, "sgttmp"); - case tok_le: return Builder->CreateICmpSLE(L, R, "sletmp"); - case tok_ge: return Builder->CreateICmpSGE(L, R, "sgetmp"); - default: - fprintf(stderr, "Error: Invalid binary operator\n"); - return nullptr; - } + return ArithHandler->emitBinaryOp(Bin->getOp(), L, R, Bin->getLine()); } if (auto *Call = dynamic_cast<CallExprAST*>(Expr)) { @@ -150,6 +155,8 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) { if (CondV->getType()->isIntegerTy(64)) CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "ifcond"); + if (CondV->getType()->isIntegerTy(1)) + CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "ifcond"); Function *TheFunction = Builder->GetInsertBlock()->getParent(); BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction); @@ -183,6 +190,8 @@ void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) { if (!CondV) return; if (CondV->getType()->isIntegerTy(64)) CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "loopcond"); + if (CondV->getType()->isIntegerTy(1)) + CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "loopcond"); Builder->CreateCondBr(CondV, LoopBB, AfterBB); @@ -215,6 +224,8 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) { if (CondV->getType()->isIntegerTy(64)) CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "untilcond"); + if (CondV->getType()->isIntegerTy(1)) + CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "untilcond"); Builder->CreateCondBr(CondV, AfterBB, LoopBB); @@ -249,7 +260,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) { bool isNegativeStep = false; if (Stmt->getStep()) { - if (auto *Num = dynamic_cast<NumberExprAST*>(Stmt->getStep())) { + if (auto *Num = dynamic_cast<IntegerExprAST*>(Stmt->getStep())) { if (Num->getVal() < 0) isNegativeStep = true; } } @@ -353,10 +364,12 @@ void CodeGen::emitStmt(StmtAST *Stmt) { } if (auto *Decl = dynamic_cast<DeclareStmtAST*>(Stmt)) { - Function *TheFunction = Builder->GetInsertBlock()->getParent(); - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Decl->getName()); - NamedValues[Decl->getName()] = Alloca; - Builder->CreateStore(ConstantInt::get(*TheContext, APInt(64, 0)), Alloca); + if (Decl->getType() == "INTEGER") IntHandler->emitDeclare(Decl->getName()); + else if (Decl->getType() == "REAL") RealHelper->emitDeclare(Decl->getName()); + else if (Decl->getType() == "BOOLEAN") BoolHandler->emitDeclare(Decl->getName()); + else { + fprintf(stderr, "Unknown type %s\n", Decl->getType().c_str()); + } } else if (auto *Assign = dynamic_cast<AssignStmtAST*>(Stmt)) { Value *Val = emitExpr(Assign->getExpr()); @@ -366,16 +379,41 @@ void CodeGen::emitStmt(StmtAST *Stmt) { fprintf(stderr, "Error: Unknown variable name %s\n", Assign->getName().c_str()); return; } + + AllocaInst *AI = cast<AllocaInst>(Alloca); + + if (AI->getAllocatedType() == Type::getDoubleTy(*TheContext) && Val->getType()->isIntegerTy(64)) { + Val = Builder->CreateSIToFP(Val, Type::getDoubleTy(*TheContext)); + } Builder->CreateStore(Val, Alloca); } } else if (auto *In = dynamic_cast<InputStmtAST*>(Stmt)) { Value *Alloca = NamedValues[In->getName()]; if (Alloca) { + AllocaInst *AI = cast<AllocaInst>(Alloca); std::vector<Value*> Args; - Args.push_back(ScanfFormatStr); - Args.push_back(Alloca); - Builder->CreateCall(ScanfFunc, Args); + + if (AI->getAllocatedType()->isDoubleTy()) { + Args.push_back(ScanfFloatFormatStr); + Args.push_back(Alloca); + Builder->CreateCall(ScanfFunc, Args); + } else if (AI->getAllocatedType()->isIntegerTy(1)) { + 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, Alloca); + } else { + Args.push_back(ScanfFormatStr); + Args.push_back(Alloca); + Builder->CreateCall(ScanfFunc, Args); + } } } else if (auto *Out = dynamic_cast<OutputStmtAST*>(Stmt)) { @@ -385,8 +423,18 @@ void CodeGen::emitStmt(StmtAST *Stmt) { Value *Val = emitExpr(Out->getExpr()); if (Val) { std::vector<Value*> Args; - Args.push_back(PrintfFormatStr); - Args.push_back(Val); + if (Val->getType()->isDoubleTy()) { + Args.push_back(PrintfFloatFormatStr); + Args.push_back(Val); + } else if (Val->getType()->isIntegerTy(1)) { + Args.push_back(PrintfStringFormatStr); + Value *StrPtr = Builder->CreateSelect(Val, TrueStr, FalseStr); + Args.push_back(StrPtr); + } else { + Args.push_back(PrintfFormatStr); + Args.push_back(Val); + } + Builder->CreateCall(PrintfFunc, Args); } } diff --git a/lib/CodeGen/IntegerHandler.cc b/lib/CodeGen/IntegerHandler.cc new file mode 100644 index 0000000..8161593 --- /dev/null +++ b/lib/CodeGen/IntegerHandler.cc @@ -0,0 +1,16 @@ +#include "cps/IntegerHandler.h" + +using namespace llvm; +using namespace cps; + +void IntegerHandler::emitDeclare(const std::string &Name) { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); + AllocaInst *Alloca = TmpB.CreateAlloca(Type::getInt64Ty(Context), nullptr, Name); + Builder.CreateStore(ConstantInt::get(Context, APInt(64, 0)), Alloca); + NamedValues[Name] = Alloca; +} + +Value *IntegerHandler::createLiteral(int64_t Val) { + return ConstantInt::get(Context, APInt(64, Val, true)); +} diff --git a/lib/CodeGen/RealHandler.cc b/lib/CodeGen/RealHandler.cc new file mode 100644 index 0000000..a73dee2 --- /dev/null +++ b/lib/CodeGen/RealHandler.cc @@ -0,0 +1,16 @@ +#include "cps/RealHandler.h" + +using namespace llvm; +using namespace cps; + +void RealHandler::emitDeclare(const std::string &Name) { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); + AllocaInst *Alloca = TmpB.CreateAlloca(Type::getDoubleTy(Context), nullptr, Name); + Builder.CreateStore(ConstantFP::get(Context, APFloat(0.0)), Alloca); + NamedValues[Name] = Alloca; +} + +Value *RealHandler::createLiteral(double Val) { + return ConstantFP::get(Context, APFloat(Val)); +} diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc index da2e47f..ad7b4a1 100644 --- a/lib/Lexer/Lexer.cc +++ b/lib/Lexer/Lexer.cc @@ -3,6 +3,7 @@ #include <cstdio> #include <string> #include <algorithm> +#include <cstdlib> using namespace cps; @@ -21,9 +22,12 @@ int Lexer::gettok() { if (IdentifierStr == "DECLARE") return tok_declare; if (IdentifierStr == "INTEGER") return tok_integer_kw; - if (IdentifierStr == "BOOLEAN") return tok_integer_kw; // TODO: implement real BOOLEAN - if (IdentifierStr == "REAL") return tok_integer_kw; // TODO: implement real REAL + if (IdentifierStr == "BOOLEAN") return tok_boolean_kw; + if (IdentifierStr == "REAL") return tok_real_kw; + if (IdentifierStr == "TRUE") return tok_true; + if (IdentifierStr == "FALSE") return tok_false; + if (IdentifierStr == "INPUT") return tok_input; if (IdentifierStr == "OUTPUT") return tok_output; @@ -47,6 +51,9 @@ int Lexer::gettok() { if (IdentifierStr == "ARRAY") return tok_array; if (IdentifierStr == "OF") return tok_of; + if (IdentifierStr == "DIV") return tok_div; + if (IdentifierStr == "MOD") return tok_mod; + if (IdentifierStr == "FUNCTION") return tok_function; if (IdentifierStr == "ENDFUNCTION") return tok_endfunction; if (IdentifierStr == "PROCEDURE") return tok_procedure; @@ -63,12 +70,24 @@ int Lexer::gettok() { if (isdigit(LastChar)) { std::string NumStr; + bool isReal = false; do { NumStr += LastChar; LastChar = getchar(); + if (LastChar == '.' && !isReal) { + isReal = true; + NumStr += '.'; + LastChar = getchar(); + } } while (isdigit(LastChar)); - NumVal = strtoll(NumStr.c_str(), nullptr, 10); - return tok_number; + + if (isReal) { + RealVal = strtod(NumStr.c_str(), nullptr); + return tok_number_real; + } else { + NumVal = strtoll(NumStr.c_str(), nullptr, 10); + return tok_number_int; + } } if (LastChar == '<') { diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index 563dd9b..32a6db8 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -16,8 +16,11 @@ Parser::Parser(Lexer &L) : Lex(L) { BinopPrecedence['+'] = 20; BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; BinopPrecedence['/'] = 40; + BinopPrecedence[tok_div] = 40; + BinopPrecedence[tok_mod] = 40; } int Parser::GetTokPrecedence() { @@ -32,7 +35,13 @@ int Parser::getNextToken() { } std::unique_ptr<ExprAST> Parser::ParseNumberExpr() { - auto Result = std::make_unique<NumberExprAST>(Lex.NumVal); + if (CurTok == tok_number_real) { + auto Result = std::make_unique<RealExprAST>(Lex.RealVal); + getNextToken(); + return Result; + } + // Default to Int + auto Result = std::make_unique<IntegerExprAST>(Lex.NumVal); getNextToken(); return Result; } @@ -99,7 +108,16 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() { std::unique_ptr<ExprAST> Parser::ParsePrimary() { switch (CurTok) { case tok_identifier: return ParseIdentifierExpr(); - case tok_number: return ParseNumberExpr(); + case tok_number_int: return ParseNumberExpr(); + case tok_number_real: return ParseNumberExpr(); + case tok_true: { + getNextToken(); + return std::make_unique<BooleanExprAST>(true); + } + case tok_false: { + getNextToken(); + return std::make_unique<BooleanExprAST>(false); + } case '(': return ParseParenExpr(); default: fprintf(stderr, "Error: unknown token '%c' (%d) at line %d when expecting an expression\n", @@ -206,12 +224,18 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() { return std::make_unique<ArrayDeclareStmtAST>(Name, std::move(Bounds), "INTEGER"); } - else if (CurTok == tok_integer_kw) { + else { + std::string TypeStr; + if (CurTok == tok_integer_kw) TypeStr = "INTEGER"; + else if (CurTok == tok_real_kw) TypeStr = "REAL"; + else if (CurTok == tok_boolean_kw) TypeStr = "BOOLEAN"; + else { + fprintf(stderr, "Error: Unknown type in declaration\n"); + return nullptr; + } getNextToken(); - return std::make_unique<DeclareStmtAST>(Name); + return std::make_unique<DeclareStmtAST>(Name, TypeStr); } - - return nullptr; } std::unique_ptr<StmtAST> Parser::ParseIfStmt() { |
