From 93175ba5edb0eacc182f573c4fd4556f089da305 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Fri, 30 Jan 2026 13:28:45 +0000 Subject: Added BYREF and BYVAL --- CMakeLists.txt | 2 +- include/cps/ArrayHandler.h | 6 +- include/cps/CodeGen.h | 2 +- include/cps/FunctionAST.h | 7 ++- include/cps/FunctionGen.h | 7 ++- include/cps/Lexer.h | 4 +- include/cps/Parser.h | 2 +- lib/CodeGen/ArrayHandler.cc | 8 +-- lib/CodeGen/CodeGen.cc | 66 +++++++++++++++++--- lib/CodeGen/FunctionGen.cc | 36 +++++++---- lib/Lexer/Lexer.cc | 3 + lib/Parser/ParserFunction.cc | 139 ++++++++++++++++++++++++++++++++++++++++++ lib/Parser/Parser_Function.cc | 129 --------------------------------------- 13 files changed, 244 insertions(+), 167 deletions(-) create mode 100644 lib/Parser/ParserFunction.cc delete mode 100644 lib/Parser/Parser_Function.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index f1eefd9..f43204b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include_directories(include) add_library(CPSLexer lib/Lexer/Lexer.cc) add_library(CPSParser lib/Parser/Parser.cc - lib/Parser/Parser_Function.cc + lib/Parser/ParserFunction.cc ) add_library(CPSCodeGen diff --git a/include/cps/ArrayHandler.h b/include/cps/ArrayHandler.h index 734f464..1ee91db 100644 --- a/include/cps/ArrayHandler.h +++ b/include/cps/ArrayHandler.h @@ -24,7 +24,7 @@ class ArrayHandler { llvm::LLVMContext *TheContext; llvm::IRBuilder<> *Builder; llvm::Module *TheModule; - std::map *NamedValues; + std::map *NamedValues; std::map ArrayTable; RuntimeCheck &RuntimeChecker; @@ -37,13 +37,13 @@ class ArrayHandler { void emitPrintLoop(const std::string &Name, int CurrentDim, std::vector CurrentIndices, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr); public: - ArrayHandler(llvm::LLVMContext &C, llvm::IRBuilder<> &B, llvm::Module &M, std::map &NV); + ArrayHandler(llvm::LLVMContext &C, llvm::IRBuilder<> &B, llvm::Module &M, std::map &NV); void setupExternalFunctions(); void emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG); void emitArrayAssign(ArrayAssignStmtAST *Stmt, CodeGen &CG); - ArrayHandler(llvm::LLVMContext &C, llvm::IRBuilder<> &B, llvm::Module &M, std::map &NV, RuntimeCheck &RC); + ArrayHandler(llvm::LLVMContext &C, llvm::IRBuilder<> &B, llvm::Module &M, std::map &NV, RuntimeCheck &RC); llvm::Value* emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG); diff --git a/include/cps/CodeGen.h b/include/cps/CodeGen.h index 832ba7a..85f605f 100644 --- a/include/cps/CodeGen.h +++ b/include/cps/CodeGen.h @@ -16,7 +16,7 @@ class CodeGen { std::unique_ptr TheContext; std::unique_ptr TheModule; std::unique_ptr> Builder; - std::map NamedValues; + std::map NamedValues; std::unique_ptr Arrays; std::unique_ptr RuntimeChecker; diff --git a/include/cps/FunctionAST.h b/include/cps/FunctionAST.h index 155bd8c..5b4da6c 100644 --- a/include/cps/FunctionAST.h +++ b/include/cps/FunctionAST.h @@ -3,24 +3,25 @@ #include #include #include +#include namespace cps { class PrototypeAST { std::string Name; - std::vector> Args; + std::vector> Args; std::string ReturnType; bool IsExternal; public: PrototypeAST(const std::string &Name, - std::vector> Args, + std::vector> Args, const std::string &ReturnType, bool IsExternal = false) : Name(Name), Args(std::move(Args)), ReturnType(ReturnType), IsExternal(IsExternal) {} const std::string &getName() const { return Name; } - const std::vector> &getArgs() const { return Args; } + const std::vector> &getArgs() const { return Args; } const std::string &getReturnType() const { return ReturnType; } bool isExternal() const { return IsExternal; } }; diff --git a/include/cps/FunctionGen.h b/include/cps/FunctionGen.h index c1a6ebd..84a2858 100644 --- a/include/cps/FunctionGen.h +++ b/include/cps/FunctionGen.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace cps { @@ -14,13 +15,13 @@ class FunctionGen { llvm::Module &Module; llvm::IRBuilder<> &Builder; - std::map &NamedValues; + std::map &NamedValues; - void createArgumentAllocas(llvm::Function *F, const std::vector> &Args); + void createArgumentAllocas(llvm::Function *F, const std::vector> &Args); public: FunctionGen(llvm::LLVMContext &C, llvm::Module &M, llvm::IRBuilder<> &B, - std::map &NV) + std::map &NV) : Context(C), Module(M), Builder(B), NamedValues(NV) {} llvm::Type *getLLVMType(const std::string &TypeName); diff --git a/include/cps/Lexer.h b/include/cps/Lexer.h index cd34435..4226cc3 100644 --- a/include/cps/Lexer.h +++ b/include/cps/Lexer.h @@ -49,7 +49,9 @@ enum Token { tok_returns = -403, tok_procedure = -404, tok_endprocedure = -405, - tok_call = -406 + tok_call = -406, + tok_byref = -407, + tok_byval = -408 }; class Lexer { diff --git a/include/cps/Parser.h b/include/cps/Parser.h index f328141..2a9c98a 100644 --- a/include/cps/Parser.h +++ b/include/cps/Parser.h @@ -36,7 +36,7 @@ class Parser { std::unique_ptr ParseProcedure(); std::unique_ptr ParseCallStmt(); std::unique_ptr ParseReturnStmt(); - std::vector> ParsePrototypeArgs(); + std::vector> ParsePrototypeArgs(); public: Parser(Lexer &L); diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc index 18b9253..5842f77 100644 --- a/lib/CodeGen/ArrayHandler.cc +++ b/lib/CodeGen/ArrayHandler.cc @@ -8,7 +8,7 @@ using namespace llvm; using namespace cps; -ArrayHandler::ArrayHandler(LLVMContext &C, IRBuilder<> &B, Module &M, std::map &NV, RuntimeCheck &RC) +ArrayHandler::ArrayHandler(LLVMContext &C, IRBuilder<> &B, Module &M, std::map &NV, RuntimeCheck &RC) : TheContext(&C), Builder(&B), TheModule(&M), NamedValues(&NV), RuntimeChecker(RC) { setupExternalFunctions(); } @@ -125,7 +125,7 @@ Value* ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) { Value *Offset = computeFlatIndex(Name, Indices); - AllocaInst *Alloca = (*NamedValues)[Name]; + Value *Alloca = (*NamedValues)[Name]; Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset); @@ -154,7 +154,7 @@ void ArrayHandler::emitArrayAssign(ArrayAssignStmtAST *Stmt, CodeGen &CG) { Value *Val = CG.emitExpr(Stmt->getExpr()); Value *Offset = computeFlatIndex(Name, Indices); - AllocaInst *Alloca = (*NamedValues)[Name]; + Value *Alloca = (*NamedValues)[Name]; Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset); @@ -197,7 +197,7 @@ void ArrayHandler::emitPrintLoop(const std::string &Name, int CurrentDim, std::v if (CurrentDim == Meta.Rank) { Value *Offset = computeFlatIndex(Name, CurrentIndices); - AllocaInst *Alloca = (*NamedValues)[Name]; + Value *Alloca = (*NamedValues)[Name]; Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca); Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext)); Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset); diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 6358699..bfbd8e0 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -70,7 +70,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { } if (auto *Var = dynamic_cast(Expr)) { - AllocaInst *A = NamedValues[Var->getName()]; + Value *A = NamedValues[Var->getName()]; if (!A) { fprintf(stderr, "Error: Unknown variable name %s\n", Var->getName().c_str()); return nullptr; @@ -109,9 +109,34 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { } if (auto *Call = dynamic_cast(Expr)) { + Function *CalleeF = TheModule->getFunction(Call->getCallee()); std::vector Args; - for (const auto &Arg : Call->getArgs()) { - Args.push_back(emitExpr(Arg.get())); + + 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 = NamedValues[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); } @@ -203,7 +228,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) { Value *StartVal = emitExpr(Stmt->getStart()); if (!StartVal) return; - AllocaInst *Alloca = NamedValues[VarName]; + Value *Alloca = NamedValues[VarName]; if (!Alloca) { fprintf(stderr, "Error: Unknown variable in FOR loop %s\n", VarName.c_str()); return; @@ -285,9 +310,34 @@ void CodeGen::emitStmt(StmtAST *Stmt) { } else if (auto *Call = dynamic_cast(Stmt)) { + Function *CalleeF = TheModule->getFunction(Call->getCallee()); std::vector Args; - for (const auto &ArgExpr : Call->getArgs()) { - Args.push_back(emitExpr(ArgExpr.get())); + + 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 = NamedValues[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; @@ -311,7 +361,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) { else if (auto *Assign = dynamic_cast(Stmt)) { Value *Val = emitExpr(Assign->getExpr()); if (Val) { - AllocaInst *Alloca = NamedValues[Assign->getName()]; + Value *Alloca = NamedValues[Assign->getName()]; if (!Alloca) { fprintf(stderr, "Error: Unknown variable name %s\n", Assign->getName().c_str()); return; @@ -320,7 +370,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) { } } else if (auto *In = dynamic_cast(Stmt)) { - AllocaInst *Alloca = NamedValues[In->getName()]; + Value *Alloca = NamedValues[In->getName()]; if (Alloca) { std::vector Args; Args.push_back(ScanfFormatStr); diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index b2adc08..a929943 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -13,27 +13,37 @@ Type *FunctionGen::getLLVMType(const std::string &TypeName) { return Type::getInt64Ty(Context); } -void FunctionGen::createArgumentAllocas(Function *F, const std::vector> &Args) { +void FunctionGen::createArgumentAllocas(Function *F, const std::vector> &Args) { Function::arg_iterator AI = F->arg_begin(); for (unsigned Idx = 0, E = Args.size(); Idx != E; ++Idx, ++AI) { - std::string ArgName = Args[Idx].first; - std::string ArgTypeStr = Args[Idx].second; - - Type *ArgType = getLLVMType(ArgTypeStr); - IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin()); - AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, ArgName); + std::string ArgName = std::get<0>(Args[Idx]); + std::string ArgTypeStr = std::get<1>(Args[Idx]); + bool IsRef = std::get<2>(Args[Idx]); Value *ArgVal = &(*AI); - Builder.CreateStore(ArgVal, Alloca); - - NamedValues[ArgName] = Alloca; + ArgVal->setName(ArgName); + + if (IsRef) { + NamedValues[ArgName] = ArgVal; + } else { + Type *ArgType = getLLVMType(ArgTypeStr); + IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin()); + AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, ArgName); + + Builder.CreateStore(ArgVal, Alloca); + NamedValues[ArgName] = Alloca; + } } } Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { std::vector ArgTypes; for (const auto &Arg : Proto->getArgs()) { - ArgTypes.push_back(getLLVMType(Arg.second)); + Type *T = getLLVMType(std::get<1>(Arg)); + if (std::get<2>(Arg)) { + T = T->getPointerTo(); + } + ArgTypes.push_back(T); } Type *RetType = getLLVMType(Proto->getReturnType()); @@ -43,7 +53,7 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { unsigned Idx = 0; for (auto &Arg : F->args()) { if (Idx < Proto->getArgs().size()) - Arg.setName(Proto->getArgs()[Idx++].first); + Arg.setName(std::get<0>(Proto->getArgs()[Idx++])); } return F; } @@ -65,7 +75,7 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST, BasicBlock *BB = BasicBlock::Create(Context, "entry", TheFunction); Builder.SetInsertPoint(BB); - std::map OldNamedValues = NamedValues; + std::map OldNamedValues = NamedValues; NamedValues.clear(); createArgumentAllocas(TheFunction, Proto->getArgs()); diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc index 6854cc9..da2e47f 100644 --- a/lib/Lexer/Lexer.cc +++ b/lib/Lexer/Lexer.cc @@ -54,6 +54,9 @@ int Lexer::gettok() { if (IdentifierStr == "RETURN") return tok_return; if (IdentifierStr == "RETURNS") return tok_returns; if (IdentifierStr == "CALL") return tok_call; + + if (IdentifierStr == "BYREF") return tok_byref; + if (IdentifierStr == "BYVAL") return tok_byval; return tok_identifier; } diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc new file mode 100644 index 0000000..d689aa6 --- /dev/null +++ b/lib/Parser/ParserFunction.cc @@ -0,0 +1,139 @@ +#include "cps/Parser.h" +#include "cps/FunctionAST.h" +#include + +using namespace cps; + +std::vector> Parser::ParsePrototypeArgs() { + std::vector> Args; + if (CurTok != '(') return Args; + getNextToken(); + + while (CurTok != ')') { + if (CurTok == -1000 || CurTok == -1001) getNextToken(); + + bool IsRef = false; + if (CurTok == tok_byref) { + IsRef = true; + getNextToken(); + } else if (CurTok == tok_byval) { + IsRef = false; + getNextToken(); + } + + if (CurTok != tok_identifier) { + fprintf(stderr, "Error: Expected argument name\n"); + return Args; + } + std::string Name = Lex.IdentifierStr; + getNextToken(); + + if (CurTok != tok_colon) { + fprintf(stderr, "Error: Expected ':' after argument name\n"); + return Args; + } + getNextToken(); + + std::string Type = "INTEGER"; + if (CurTok == tok_integer_kw) { + getNextToken(); + } else if (CurTok == tok_identifier) { + Type = Lex.IdentifierStr; + getNextToken(); + } else { + fprintf(stderr, "Error: Expected type (e.g. INTEGER) for argument '%s'\n", Name.c_str()); + return Args; + } + + Args.emplace_back(Name, Type, IsRef); + + if (CurTok == ')') break; + if (CurTok != ',') { + fprintf(stderr, "Error: Expected ',' or ')'\n"); + return Args; + } + getNextToken(); + } + getNextToken(); + return Args; +} + + +std::unique_ptr Parser::ParseFunction() { + getNextToken(); + std::string Name = Lex.IdentifierStr; + getNextToken(); + + auto Args = ParsePrototypeArgs(); + + std::string RetType = "INTEGER"; + if (CurTok == tok_returns) { + getNextToken(); + getNextToken(); + } + + auto Proto = std::make_unique(Name, std::move(Args), RetType); + + std::vector> Body; + while (CurTok != tok_endfunction && CurTok != tok_eof) { + auto Stmt = ParseStatement(); + if (Stmt) Body.push_back(std::move(Stmt)); + else if (CurTok != tok_eof && CurTok != tok_endfunction) getNextToken(); + } + getNextToken(); + + return std::make_unique(std::move(Proto), std::move(Body)); +} + +std::unique_ptr Parser::ParseProcedure() { + getNextToken(); + std::string Name = Lex.IdentifierStr; + getNextToken(); + + auto Args = ParsePrototypeArgs(); + auto Proto = std::make_unique(Name, std::move(Args), "VOID"); + + std::vector> Body; + while (CurTok != tok_endprocedure && CurTok != tok_eof) { + auto Stmt = ParseStatement(); + if (Stmt) Body.push_back(std::move(Stmt)); + else if (CurTok != tok_eof && CurTok != tok_endprocedure) getNextToken(); + } + getNextToken(); + + return std::make_unique(std::move(Proto), std::move(Body)); +} + +std::unique_ptr Parser::ParseCallStmt() { + getNextToken(); + std::string Callee = Lex.IdentifierStr; + getNextToken(); + + std::vector> Args; + if (CurTok == '(') { + getNextToken(); + while (CurTok != ')') { + auto Arg = ParseExpression(); + if (Arg) Args.push_back(std::move(Arg)); + + if (CurTok == ')') break; + if (CurTok != ',') { + fprintf(stderr, "Error: Expected ',' or ')' in call\n"); + return nullptr; + } + getNextToken(); + } + getNextToken(); + } + + return std::make_unique(Callee, std::move(Args)); +} + +std::unique_ptr Parser::ParseReturnStmt() { + getNextToken(); + std::unique_ptr Expr = nullptr; + if (CurTok != tok_endif && CurTok != tok_else && CurTok != tok_endfunction && CurTok != tok_endprocedure) { + Expr = ParseExpression(); + } + return std::make_unique(std::move(Expr)); +} diff --git a/lib/Parser/Parser_Function.cc b/lib/Parser/Parser_Function.cc deleted file mode 100644 index bdb4ee7..0000000 --- a/lib/Parser/Parser_Function.cc +++ /dev/null @@ -1,129 +0,0 @@ -#include "cps/Parser.h" -#include "cps/FunctionAST.h" - -using namespace cps; - -std::vector> Parser::ParsePrototypeArgs() { - std::vector> Args; - if (CurTok != '(') return Args; - getNextToken(); - - while (CurTok != ')') { - if (CurTok == -1000 || CurTok == -1001) getNextToken(); - - if (CurTok != tok_identifier) { - fprintf(stderr, "Error: Expected argument name\n"); - return Args; - } - std::string Name = Lex.IdentifierStr; - getNextToken(); - - if (CurTok != tok_colon) { - fprintf(stderr, "Error: Expected ':' after argument name\n"); - return Args; - } - getNextToken(); - - std::string Type = "INTEGER"; - if (CurTok == tok_integer_kw) { - getNextToken(); - } else if (CurTok == tok_identifier) { - Type = Lex.IdentifierStr; - getNextToken(); - } else { - fprintf(stderr, "Error: Expected type (e.g. INTEGER) for argument '%s'\n", Name.c_str()); - return Args; - } - - Args.push_back({Name, Type}); - - if (CurTok == ')') break; - if (CurTok != ',') { - fprintf(stderr, "Error: Expected ',' or ')'\n"); - return Args; - } - getNextToken(); - } - getNextToken(); - return Args; -} - - -std::unique_ptr Parser::ParseFunction() { - getNextToken(); - std::string Name = Lex.IdentifierStr; - getNextToken(); - - auto Args = ParsePrototypeArgs(); - - std::string RetType = "INTEGER"; - if (CurTok == tok_returns) { - getNextToken(); - getNextToken(); - } - - auto Proto = std::make_unique(Name, std::move(Args), RetType); - - std::vector> Body; - while (CurTok != tok_endfunction && CurTok != tok_eof) { - auto Stmt = ParseStatement(); - if (Stmt) Body.push_back(std::move(Stmt)); - else if (CurTok != tok_eof && CurTok != tok_endfunction) getNextToken(); - } - getNextToken(); - - return std::make_unique(std::move(Proto), std::move(Body)); -} - -std::unique_ptr Parser::ParseProcedure() { - getNextToken(); - std::string Name = Lex.IdentifierStr; - getNextToken(); - - auto Args = ParsePrototypeArgs(); - auto Proto = std::make_unique(Name, std::move(Args), "VOID"); - - std::vector> Body; - while (CurTok != tok_endprocedure && CurTok != tok_eof) { - auto Stmt = ParseStatement(); - if (Stmt) Body.push_back(std::move(Stmt)); - else if (CurTok != tok_eof && CurTok != tok_endprocedure) getNextToken(); - } - getNextToken(); - - return std::make_unique(std::move(Proto), std::move(Body)); -} - -std::unique_ptr Parser::ParseCallStmt() { - getNextToken(); - std::string Callee = Lex.IdentifierStr; - getNextToken(); - - std::vector> Args; - if (CurTok == '(') { - getNextToken(); - while (CurTok != ')') { - auto Arg = ParseExpression(); - if (Arg) Args.push_back(std::move(Arg)); - - if (CurTok == ')') break; - if (CurTok != ',') { - fprintf(stderr, "Error: Expected ',' or ')' in call\n"); - return nullptr; - } - getNextToken(); - } - getNextToken(); - } - - return std::make_unique(Callee, std::move(Args)); -} - -std::unique_ptr Parser::ParseReturnStmt() { - getNextToken(); - std::unique_ptr Expr = nullptr; - if (CurTok != tok_endif && CurTok != tok_else && CurTok != tok_endfunction && CurTok != tok_endprocedure) { - Expr = ParseExpression(); - } - return std::make_unique(std::move(Expr)); -} -- cgit v1.3.1-4-g156e