aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CodeGen.cc
diff options
context:
space:
mode:
author_ov4 <hausemasterstream@gmail.com>2026-03-27 01:50:32 +0000
committer_ov4 <hausemasterstream@gmail.com>2026-03-27 01:50:32 +0000
commitf2b051ae3e28135cc02589f3f698c43743cca48e (patch)
tree91582f514eda6665c8283875dd0b3ee491cc62ea /lib/CodeGen/CodeGen.cc
parent15f30a397a222e9256d41e8b8a7b6fff454b02da (diff)
feat: generalize typed array support
Diffstat (limited to 'lib/CodeGen/CodeGen.cc')
-rw-r--r--lib/CodeGen/CodeGen.cc690
1 files changed, 502 insertions, 188 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index c5b0ff3..c77f5d8 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -1,8 +1,9 @@
#include "cps/CodeGen.h"
#include "cps/ArrayHandler.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/IR/Instructions.h"
#include "cps/Lexer.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Verifier.h"
+#include <cstdio>
using namespace llvm;
using namespace cps;
@@ -13,12 +14,24 @@ CodeGen::CodeGen() {
TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("cps_module", *TheContext);
Builder = std::make_unique<IRBuilder<>>(*TheContext);
-
+
+ Types = std::make_unique<TypeSystem>(*TheContext);
RuntimeChecker = std::make_unique<RuntimeCheck>(*TheModule, *TheContext, *Builder);
-
- Arrays = std::make_unique<ArrayHandler>(*TheContext, *Builder, *TheModule, NamedValues, *RuntimeChecker);
-
- FuncGen = std::make_unique<FunctionGen>(*TheContext, *TheModule, *Builder, NamedValues);
+
+ Arrays = std::make_unique<ArrayHandler>(*TheContext,
+ *Builder,
+ *TheModule,
+ NamedValues,
+ Symbols,
+ *Types,
+ *RuntimeChecker);
+
+ FuncGen = std::make_unique<FunctionGen>(*TheContext,
+ *TheModule,
+ *Builder,
+ *Types,
+ NamedValues,
+ Symbols);
IntHandler = std::make_unique<IntegerHandler>(*TheContext, *Builder, *TheModule, NamedValues);
RealHelper = std::make_unique<RealHandler>(*TheContext, *Builder, *TheModule, NamedValues);
@@ -43,20 +56,316 @@ void CodeGen::SetupExternalFunctions() {
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()); // NEW
+ 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(Type::getInt64Ty(*TheContext), nullptr, VarName);
+ 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<IntegerExprAST*>(Expr)) return resolveType("INTEGER");
+ if (dynamic_cast<RealExprAST*>(Expr)) return resolveType("REAL");
+ if (dynamic_cast<BooleanExprAST*>(Expr)) return resolveType("BOOLEAN");
+ if (dynamic_cast<CharExprAST*>(Expr)) return resolveType("CHAR");
+ if (dynamic_cast<StringExprAST*>(Expr)) return resolveType("STRING");
+
+ if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
+ const SymbolInfo *Info = getSymbolInfo(Var->getName());
+ return Info ? resolveType(Info->TypeName) : nullptr;
+ }
+
+ if (auto *Arr = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
+ const SymbolInfo *Info = getSymbolInfo(Arr->getName());
+ return Info ? resolveType(Info->TypeName) : nullptr;
+ }
+
+ if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
+ if (Unary->getOp() == tok_not) {
+ return resolveType("BOOLEAN");
+ }
+ return getExprTypeInfo(Unary->getOperand());
+ }
+
+ if (auto *Bin = dynamic_cast<BinaryExprAST*>(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<CallExprAST*>(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<PointerType>(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<Value*> 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<PointerType>(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<std::unique_ptr<StmtAST>> &Statements) {
@@ -69,9 +378,10 @@ void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
emitStmt(Stmt.get());
}
- if (!Builder->GetInsertBlock()->getTerminator())
+ if (!Builder->GetInsertBlock()->getTerminator()) {
Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0)));
-
+ }
+
verifyFunction(*F);
}
@@ -94,19 +404,38 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return BoolHandler->createLiteral(Bool->getVal());
}
+ if (auto *Chr = dynamic_cast<CharExprAST*>(Expr)) {
+ return ConstantInt::get(Type::getInt8Ty(*TheContext), static_cast<unsigned char>(Chr->getVal()));
+ }
+
if (auto *Str = dynamic_cast<StringExprAST*>(Expr)) {
return StrHandler->createLiteral(Str->getVal());
}
-
+
if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
- Value *A = NamedValues[Var->getName()];
- if (!A) {
+ const SymbolInfo *Info = getSymbolInfo(Var->getName());
+ if (!Info) {
fprintf(stderr, "Error: Unknown variable name %s\n", Var->getName().c_str());
return nullptr;
}
-
- Type *AllocType = cast<AllocaInst>(A)->getAllocatedType();
- return Builder->CreateLoad(AllocType, A, Var->getName().c_str());
+ 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<PointerType>(Loaded->getType())),
+ "str_is_null");
+ Loaded = Builder->CreateSelect(IsNull, EmptyStringStr, Loaded, "safe_var_str");
+ }
+ return Loaded;
}
if (auto *ArrAcc = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
@@ -116,14 +445,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
Value *Operand = emitExpr(Unary->getOperand());
if (!Operand) return nullptr;
-
+
if (Unary->getOp() == tok_not) {
- if (Operand->getType()->isIntegerTy(64)) {
- Operand = Builder->CreateICmpNE(Operand, ConstantInt::get(*TheContext, APInt(64, 0)), "tobool");
- } else if (Operand->getType()->isDoubleTy()) {
- Operand = Builder->CreateFCmpONE(Operand, ConstantFP::get(*TheContext, APFloat(0.0)), "tobool");
- }
-
+ Operand = coerceValueToType(Operand, resolveType("BOOLEAN"));
return Builder->CreateNot(Operand, "nottmp");
}
}
@@ -132,7 +456,6 @@ Value *CodeGen::emitExpr(ExprAST *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());
}
@@ -144,18 +467,18 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
}
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()),
+ 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()),
+ 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()),
+ return StrHandler->emitLeft(emitExpr(Call->getArgs()[0].get()),
emitExpr(Call->getArgs()[1].get()));
}
if (Name == "LCASE") {
@@ -168,17 +491,27 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
}
if (Name == "ASC") {
if (Call->getArgs().size() != 1) return nullptr;
- Value *StrPtr = emitExpr(Call->getArgs()[0].get());
- Value *CharVal = Builder->CreateLoad(Type::getInt8Ty(*TheContext), StrPtr, "char_load");
- return ChrHandler->emitAsc(CharVal);
+ 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 *CharVal = ChrHandler->emitChr(emitExpr(Call->getArgs()[0].get()));
+ 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)));
+ 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;
}
@@ -189,8 +522,11 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
if (Name == "NUM_TO_STR") {
if (Call->getArgs().size() != 1) return nullptr;
Value *NumV = emitExpr(Call->getArgs()[0].get());
- bool isReal = NumV->getType()->isDoubleTy();
- return StrConvHandler->emitNumToStr(NumV, isReal);
+ 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;
@@ -199,28 +535,28 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
Function *CalleeF = TheModule->getFunction(Call->getCallee());
std::vector<Value*> Args;
-
+
for (unsigned i = 0; i < Call->getArgs().size(); ++i) {
ExprAST *ArgExpr = Call->getArgs()[i].get();
- bool isByRef = false;
+ bool IsByRef = false;
if (CalleeF && i < CalleeF->arg_size()) {
if (CalleeF->getArg(i)->getType()->isPointerTy()) {
- isByRef = true;
+ IsByRef = true;
}
}
- if (isByRef) {
+ if (IsByRef) {
if (auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr)) {
- Value *Ptr = NamedValues[Var->getName()];
+ 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;
+ fprintf(stderr, "Error: BYREF argument must be a variable.\n");
+ return nullptr;
}
} else {
Args.push_back(emitExpr(ArgExpr));
@@ -236,10 +572,7 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
Value *CondV = emitExpr(Stmt->getCond());
if (!CondV) return;
- 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");
+ CondV = coerceValueToType(CondV, resolveType("BOOLEAN"));
Function *TheFunction = Builder->GetInsertBlock()->getParent();
BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction);
@@ -261,7 +594,7 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
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);
@@ -271,16 +604,13 @@ void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CondV = emitExpr(Stmt->getCond());
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");
-
+ 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);
@@ -304,11 +634,7 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CondV = emitExpr(Stmt->getCond());
if (!CondV) return;
-
- 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");
+ CondV = coerceValueToType(CondV, resolveType("BOOLEAN"));
Builder->CreateCondBr(CondV, AfterBB, LoopBB);
@@ -318,15 +644,21 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Function *TheFunction = Builder->GetInsertBlock()->getParent();
std::string VarName = Stmt->getVarName();
-
- Value *StartVal = emitExpr(Stmt->getStart());
- if (!StartVal) return;
- Value *Alloca = NamedValues[VarName];
- if (!Alloca) {
+ 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);
@@ -338,22 +670,19 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CurVar = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str());
- Value *EndVal = emitExpr(Stmt->getEnd());
+ Value *EndVal = coerceValueToType(emitExpr(Stmt->getEnd()), resolveType("INTEGER"));
if (!EndVal) return;
- bool isNegativeStep = false;
+ bool IsNegativeStep = false;
if (Stmt->getStep()) {
if (auto *Num = dynamic_cast<IntegerExprAST*>(Stmt->getStep())) {
- if (Num->getVal() < 0) isNegativeStep = true;
+ if (Num->getVal() < 0) IsNegativeStep = true;
}
}
- Value *CondV;
- if (isNegativeStep) {
- CondV = Builder->CreateICmpSGE(CurVar, EndVal, "forcond_ge");
- } else {
- CondV = Builder->CreateICmpSLE(CurVar, EndVal, "forcond_le");
- }
+ Value *CondV = IsNegativeStep
+ ? Builder->CreateICmpSGE(CurVar, EndVal, "forcond_ge")
+ : Builder->CreateICmpSLE(CurVar, EndVal, "forcond_le");
Builder->CreateCondBr(CondV, LoopBB, AfterBB);
@@ -363,13 +692,13 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Builder->CreateBr(IncBB);
Builder->SetInsertPoint(IncBB);
- Value *StepVal;
+ Value *StepVal = nullptr;
if (Stmt->getStep()) {
- StepVal = emitExpr(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);
@@ -385,7 +714,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
Arrays->emitArrayDeclare(ArrDecl, *this);
return;
}
-
+
if (auto *ArrAssign = dynamic_cast<ArrayAssignStmtAST*>(Stmt)) {
Arrays->emitArrayAssign(ArrAssign, *this);
return;
@@ -394,40 +723,39 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
if (auto *FuncDef = dynamic_cast<FunctionDefAST*>(Stmt)) {
BasicBlock *SavedBlock = Builder->GetInsertBlock();
- FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) {
- this->emitStmt(S);
+ FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) {
+ this->emitStmt(S);
});
if (SavedBlock) Builder->SetInsertPoint(SavedBlock);
-
return;
}
- else if (auto *Call = dynamic_cast<CallStmtAST*>(Stmt)) {
+ if (auto *Call = dynamic_cast<CallStmtAST*>(Stmt)) {
Function *CalleeF = TheModule->getFunction(Call->getCallee());
std::vector<Value*> Args;
-
+
for (unsigned i = 0; i < Call->getArgs().size(); ++i) {
ExprAST *ArgExpr = Call->getArgs()[i].get();
- bool isByRef = false;
-
+ bool IsByRef = false;
+
if (CalleeF && i < CalleeF->arg_size()) {
if (CalleeF->getArg(i)->getType()->isPointerTy()) {
- isByRef = true;
+ IsByRef = true;
}
}
- if (isByRef) {
+ if (IsByRef) {
if (auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr)) {
- Value *Ptr = NamedValues[Var->getName()];
+ 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;
+ fprintf(stderr, "Error: BYREF argument must be a variable.\n");
+ return;
}
} else {
Args.push_back(emitExpr(ArgExpr));
@@ -437,7 +765,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
return;
}
- else if (auto *Ret = dynamic_cast<ReturnStmtAST*>(Stmt)) {
+ if (auto *Ret = dynamic_cast<ReturnStmtAST*>(Stmt)) {
Value *RetVal = nullptr;
if (Ret->getRetVal()) {
RetVal = emitExpr(Ret->getRetVal());
@@ -447,120 +775,106 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
}
if (auto *Decl = dynamic_cast<DeclareStmtAST*>(Stmt)) {
- 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 if (Decl->getType() == "STRING") StrHandler->emitDeclare(Decl->getName());
- else {
- fprintf(stderr, "Unknown type %s\n", Decl->getType().c_str());
- }
+ emitDeclareStmt(Decl);
+ return;
}
- else if (auto *Assign = dynamic_cast<AssignStmtAST*>(Stmt)) {
- Value *Val = emitExpr(Assign->getExpr());
- if (Val) {
- Value *Alloca = NamedValues[Assign->getName()];
- if (!Alloca) {
- 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));
- }
- if (AI->getAllocatedType() == Type::getInt64Ty(*TheContext) && Val->getType()->isDoubleTy()) {
- Val = Builder->CreateFPToSI(Val, Type::getInt64Ty(*TheContext), "double_to_int");
- }
-
- if (AI->getAllocatedType() == Type::getInt64Ty(*TheContext) && Val->getType()->isIntegerTy(1)) {
- Val = Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext));
- }
-
- Builder->CreateStore(Val, Alloca);
+ if (auto *Assign = dynamic_cast<AssignStmtAST*>(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;
}
- else if (auto *In = dynamic_cast<InputStmtAST*>(Stmt)) {
- Value *Alloca = NamedValues[In->getName()];
- if (Alloca) {
- AllocaInst *AI = cast<AllocaInst>(Alloca);
- std::vector<Value*> 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 if (AI->getAllocatedType()->isPointerTy()) {
- Value *BufSize = ConstantInt::get(*TheContext, APInt(64, 256));
+ if (auto *In = dynamic_cast<InputStmtAST*>(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;
+ }
- Args.push_back(ScanfStringFormatStr);
+ const TypeInfo *TypeInfo = resolveType(Info->TypeName);
+ if (!TypeInfo) {
+ fprintf(stderr, "Error: Unknown type for INPUT %s\n", In->getName().c_str());
+ return;
+ }
- AllocaInst *InputBuf = Builder->CreateAlloca(Type::getInt8Ty(*TheContext), ConstantInt::get(*TheContext, APInt(64, 1024)), "input_buf");
- Args.push_back(InputBuf);
- Builder->CreateCall(ScanfFunc, Args);
+ std::vector<Value*> 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);
- Function *MallocF = TheModule->getFunction("malloc");
- if (MallocF) {
- Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 1024)));
- Args[1] = Mem;
- Builder->CreateCall(ScanfFunc, Args);
- Builder->CreateStore(Mem, Alloca);
- }
- } else {
- Args.push_back(ScanfFormatStr);
- Args.push_back(Alloca);
- 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;
}
- else if (auto *Out = dynamic_cast<OutputStmtAST*>(Stmt)) {
- bool handled = Arrays->tryEmitArrayOutput(Out->getExpr(), *this, PrintfFunc, PrintfFormatStr);
-
- if (!handled) {
- Value *Val = emitExpr(Out->getExpr());
- if (Val) {
- std::vector<Value*> Args;
- 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 if (Val->getType()->isPointerTy()) {
- Args.push_back(PrintfStringFormatStr);
- Args.push_back(Val);
- } else {
- Args.push_back(PrintfFormatStr);
- Args.push_back(Val);
- }
-
- Builder->CreateCall(PrintfFunc, Args);
- }
- }
+
+ if (auto *Out = dynamic_cast<OutputStmtAST*>(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;
}
- else if (auto *IfStmt = dynamic_cast<IfStmtAST*>(Stmt)) {
+
+ if (auto *IfStmt = dynamic_cast<IfStmtAST*>(Stmt)) {
emitIfStmt(IfStmt);
+ return;
}
- else if (auto *WhileStmt = dynamic_cast<WhileStmtAST*>(Stmt)) {
+ if (auto *WhileStmt = dynamic_cast<WhileStmtAST*>(Stmt)) {
emitWhileStmt(WhileStmt);
+ return;
}
- else if (auto *RepeatStmt = dynamic_cast<RepeatStmtAST*>(Stmt)) {
+ if (auto *RepeatStmt = dynamic_cast<RepeatStmtAST*>(Stmt)) {
emitRepeatStmt(RepeatStmt);
+ return;
}
- else if (auto *ForStmt = dynamic_cast<ForStmtAST*>(Stmt)) {
+ if (auto *ForStmt = dynamic_cast<ForStmtAST*>(Stmt)) {
emitForStmt(ForStmt);
+ return;
}
}