aboutsummaryrefslogtreecommitdiff
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
parent15f30a397a222e9256d41e8b8a7b6fff454b02da (diff)
feat: generalize typed array support
-rw-r--r--CMakeLists.txt1
-rw-r--r--include/cps/AST.h7
-rw-r--r--include/cps/ArrayHandler.h41
-rw-r--r--include/cps/CodeGen.h18
-rw-r--r--include/cps/FunctionGen.h13
-rw-r--r--include/cps/Lexer.h3
-rw-r--r--include/cps/Parser.h2
-rw-r--r--include/cps/TypeSystem.h71
-rw-r--r--lib/CodeGen/ArrayHandler.cc326
-rw-r--r--lib/CodeGen/CodeGen.cc690
-rw-r--r--lib/CodeGen/FunctionGen.cc62
-rw-r--r--lib/CodeGen/TypeSystem.cc156
-rw-r--r--lib/Lexer/Lexer.cc84
-rw-r--r--lib/Parser/Parser.cc72
-rw-r--r--lib/Parser/ParserFunction.cc49
15 files changed, 1182 insertions, 413 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index acc96a6..b82c9d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,6 +30,7 @@ add_library(CPSCodeGen
lib/CodeGen/StringHandler.cc
lib/CodeGen/CharHandler.cc
lib/CodeGen/StringConversionHandler.cc
+ lib/CodeGen/TypeSystem.cc
)
llvm_map_components_to_libnames(llvm_libs core support native irreader)
diff --git a/include/cps/AST.h b/include/cps/AST.h
index f07e937..f24d987 100644
--- a/include/cps/AST.h
+++ b/include/cps/AST.h
@@ -32,6 +32,13 @@ public:
bool getVal() const { return Val; }
};
+class CharExprAST : public ExprAST {
+ char Val;
+public:
+ CharExprAST(char Val) : Val(Val) {}
+ char getVal() const { return Val; }
+};
+
class StringExprAST : public ExprAST {
std::string Val;
public:
diff --git a/include/cps/ArrayHandler.h b/include/cps/ArrayHandler.h
index 1ee91db..f15004f 100644
--- a/include/cps/ArrayHandler.h
+++ b/include/cps/ArrayHandler.h
@@ -4,6 +4,8 @@
#include "llvm/IR/Module.h"
#include "cps/AST.h"
#include "cps/RuntimeCheck.h"
+#include "cps/TypeSystem.h"
+#include <cstdint>
#include <map>
#include <string>
#include <vector>
@@ -11,11 +13,13 @@
namespace cps {
struct ArrayMetadata {
- int Rank;
- llvm::Type* ElementType;
+ int Rank = 0;
+ std::string ElementTypeName;
+ llvm::Type *ElementType = nullptr;
+ uint64_t ElementSize = 0;
std::vector<llvm::Value*> LowerBounds;
std::vector<llvm::Value*> UpperBounds;
- std::vector<llvm::Value*> Multipliers;
+ std::vector<llvm::Value*> Multipliers;
};
class CodeGen;
@@ -25,6 +29,8 @@ class ArrayHandler {
llvm::IRBuilder<> *Builder;
llvm::Module *TheModule;
std::map<std::string, llvm::Value*> *NamedValues;
+ std::map<std::string, SymbolInfo> *Symbols;
+ TypeSystem &Types;
std::map<std::string, ArrayMetadata> ArrayTable;
RuntimeCheck &RuntimeChecker;
@@ -32,22 +38,31 @@ class ArrayHandler {
llvm::FunctionCallee MallocFunc;
llvm::FunctionCallee FreeFunc;
- llvm::Value* computeFlatIndex(const std::string &Name, const std::vector<llvm::Value*> &Indices);
-
- void emitPrintLoop(const std::string &Name, int CurrentDim, std::vector<llvm::Value*> CurrentIndices, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr);
+ llvm::Value *computeFlatIndex(const std::string &Name, const std::vector<llvm::Value*> &Indices);
+ llvm::Value *getArrayBasePointer(const std::string &Name);
+ llvm::Value *getElementPointer(const std::string &Name, llvm::Value *Offset);
+ const ArrayMetadata *getMetadata(const std::string &Name) const;
+ void emitPrintLoop(const std::string &Name,
+ int CurrentDim,
+ std::vector<llvm::Value*> CurrentIndices,
+ CodeGen &CG);
public:
- ArrayHandler(llvm::LLVMContext &C, llvm::IRBuilder<> &B, llvm::Module &M, std::map<std::string, llvm::Value*> &NV);
+ ArrayHandler(llvm::LLVMContext &C,
+ llvm::IRBuilder<> &B,
+ llvm::Module &M,
+ std::map<std::string, llvm::Value*> &NV,
+ std::map<std::string, SymbolInfo> &Sym,
+ TypeSystem &TS,
+ RuntimeCheck &RC);
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<std::string, llvm::Value*> &NV, RuntimeCheck &RC);
-
- llvm::Value* emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG);
+ llvm::Value *emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG);
- bool tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr);
+ bool tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG);
};
-}
+} // namespace cps
diff --git a/include/cps/CodeGen.h b/include/cps/CodeGen.h
index 121f30d..07ff3e8 100644
--- a/include/cps/CodeGen.h
+++ b/include/cps/CodeGen.h
@@ -5,6 +5,7 @@
#include "cps/AST.h"
#include "cps/RuntimeCheck.h"
#include "cps/FunctionGen.h"
+#include "cps/TypeSystem.h"
#include "cps/IntegerHandler.h"
#include "cps/RealHandler.h"
@@ -16,6 +17,7 @@
#include <map>
#include <memory>
+#include <string>
namespace cps {
@@ -26,6 +28,8 @@ class CodeGen {
std::unique_ptr<llvm::Module> TheModule;
std::unique_ptr<llvm::IRBuilder<>> Builder;
std::map<std::string, llvm::Value*> NamedValues;
+ std::map<std::string, SymbolInfo> Symbols;
+ std::unique_ptr<TypeSystem> Types;
std::unique_ptr<ArrayHandler> Arrays;
std::unique_ptr<RuntimeCheck> RuntimeChecker;
@@ -45,6 +49,7 @@ class CodeGen {
llvm::Value *PrintfFormatStr; // %lld\n
llvm::Value *PrintfFloatFormatStr; // %f\n
llvm::Value *PrintfStringFormatStr; // %s\n
+ llvm::Value *PrintfCharFormatStr; // %c\n
llvm::Value *ScanfFormatStr; // %lld
llvm::Value *ScanfFloatFormatStr; // %lf
@@ -52,9 +57,18 @@ class CodeGen {
llvm::Value *TrueStr; // "TRUE"
llvm::Value *FalseStr; // "FALSE"
+ llvm::Value *EmptyStringStr; // ""
void SetupExternalFunctions();
llvm::AllocaInst *CreateEntryBlockAlloca(llvm::Function *TheFunction, const std::string &VarName);
+ llvm::AllocaInst *CreateEntryBlockAlloca(llvm::Function *TheFunction, llvm::Type *AllocType, const std::string &VarName);
+
+ void registerSymbol(const std::string &Name, llvm::Value *Storage, const std::string &TypeName, bool IsArray = false);
+ const SymbolInfo *getSymbolInfo(const std::string &Name) const;
+ const TypeInfo *getExprTypeInfo(ExprAST *Expr) const;
+ llvm::Value *coerceValueToType(llvm::Value *Val, const TypeInfo *TargetInfo);
+ void emitDeclareStmt(DeclareStmtAST *Stmt);
+ void emitOutputValue(llvm::Value *Val, const TypeInfo *TypeInfo, bool AppendNewline = true);
void emitIfStmt(IfStmtAST *Stmt);
void emitWhileStmt(WhileStmtAST *Stmt);
@@ -69,6 +83,10 @@ public:
llvm::Value *emitExpr(ExprAST *Expr);
void emitStmt(StmtAST *Stmt);
+
+ const TypeInfo *resolveType(const std::string &TypeName) const;
+ llvm::Type *getLLVMType(const std::string &TypeName) const;
+ llvm::Value *getNamedValue(const std::string &Name) const;
friend class ArrayHandler;
};
diff --git a/include/cps/FunctionGen.h b/include/cps/FunctionGen.h
index 84a2858..7ebb7f4 100644
--- a/include/cps/FunctionGen.h
+++ b/include/cps/FunctionGen.h
@@ -2,6 +2,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "cps/FunctionAST.h"
+#include "cps/TypeSystem.h"
#include <map>
#include <vector>
#include <functional>
@@ -14,15 +15,21 @@ class FunctionGen {
llvm::LLVMContext &Context;
llvm::Module &Module;
llvm::IRBuilder<> &Builder;
+ TypeSystem &Types;
std::map<std::string, llvm::Value*> &NamedValues;
+ std::map<std::string, SymbolInfo> &Symbols;
void createArgumentAllocas(llvm::Function *F, const std::vector<std::tuple<std::string, std::string, bool>> &Args);
public:
- FunctionGen(llvm::LLVMContext &C, llvm::Module &M, llvm::IRBuilder<> &B,
- std::map<std::string, llvm::Value*> &NV)
- : Context(C), Module(M), Builder(B), NamedValues(NV) {}
+ FunctionGen(llvm::LLVMContext &C,
+ llvm::Module &M,
+ llvm::IRBuilder<> &B,
+ TypeSystem &TS,
+ std::map<std::string, llvm::Value*> &NV,
+ std::map<std::string, SymbolInfo> &Sym)
+ : Context(C), Module(M), Builder(B), Types(TS), NamedValues(NV), Symbols(Sym) {}
llvm::Type *getLLVMType(const std::string &TypeName);
diff --git a/include/cps/Lexer.h b/include/cps/Lexer.h
index df84d0b..e8d2609 100644
--- a/include/cps/Lexer.h
+++ b/include/cps/Lexer.h
@@ -49,6 +49,8 @@ enum Token {
tok_ucase = -35,
tok_string_literal = -36,
tok_left = -37,
+ tok_char_kw = -38,
+ tok_char_literal = -39,
tok_identifier = -100,
tok_number_int = -101,
@@ -83,6 +85,7 @@ public:
std::string StringVal;
int64_t NumVal;
double RealVal;
+ char CharVal = '\0';
int gettok();
int getLine() const { return CurrentLine; }
diff --git a/include/cps/Parser.h b/include/cps/Parser.h
index 877c684..19f49be 100644
--- a/include/cps/Parser.h
+++ b/include/cps/Parser.h
@@ -5,6 +5,7 @@
#include <memory>
#include <map>
#include <tuple>
+#include <string>
namespace cps {
@@ -25,6 +26,7 @@ class Parser {
std::unique_ptr<ExprAST> ParseNumberExpr();
std::unique_ptr<ExprAST> ParseIdentifierExpr();
std::unique_ptr<ExprAST> ParseParenExpr();
+ std::string ParseTypeName(bool AllowVoid = false);
std::unique_ptr<ExprAST> ParseStringBuiltin(const std::string &FuncName);
diff --git a/include/cps/TypeSystem.h b/include/cps/TypeSystem.h
new file mode 100644
index 0000000..32c348f
--- /dev/null
+++ b/include/cps/TypeSystem.h
@@ -0,0 +1,71 @@
+#pragma once
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Type.h"
+#include <cstdint>
+#include <map>
+#include <string>
+
+namespace cps {
+
+enum class TypeKind {
+ Integer,
+ Real,
+ Boolean,
+ String,
+ Char,
+ Void,
+ Custom
+};
+
+struct TypeInfo {
+ std::string Name;
+ llvm::Type *LLVMType = nullptr;
+ uint64_t ElementSize = 0;
+ TypeKind Kind = TypeKind::Custom;
+ bool Printable = false;
+ bool Builtin = false;
+ bool ReferenceLike = false;
+
+ bool isNumeric() const;
+ bool isIntegral() const;
+ bool isReal() const;
+ bool isBoolean() const;
+ bool isString() const;
+ bool isChar() const;
+ bool isVoid() const;
+};
+
+struct SymbolInfo {
+ llvm::Value *Storage = nullptr;
+ std::string TypeName;
+ bool IsArray = false;
+};
+
+class TypeSystem {
+ llvm::LLVMContext &Context;
+ std::map<std::string, TypeInfo> Types;
+
+ void registerBuiltins();
+
+public:
+ explicit TypeSystem(llvm::LLVMContext &Ctx);
+
+ const TypeInfo *resolve(const std::string &TypeName) const;
+ bool hasType(const std::string &TypeName) const;
+
+ const TypeInfo *registerType(const std::string &TypeName,
+ llvm::Type *LLVMType,
+ uint64_t ElementSize,
+ TypeKind Kind = TypeKind::Custom,
+ bool Printable = false,
+ bool ReferenceLike = false,
+ bool Builtin = false);
+
+ llvm::Type *getLLVMType(const std::string &TypeName) const;
+ uint64_t getElementSize(const std::string &TypeName) const;
+ llvm::Constant *getZeroValue(const std::string &TypeName) const;
+};
+
+} // namespace cps
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc
index 5842f77..fd55009 100644
--- a/lib/CodeGen/ArrayHandler.cc
+++ b/lib/CodeGen/ArrayHandler.cc
@@ -1,22 +1,35 @@
#include "cps/ArrayHandler.h"
#include "cps/CodeGen.h"
-#include "llvm/IR/Type.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Type.h"
+#include <cstdio>
using namespace llvm;
using namespace cps;
-ArrayHandler::ArrayHandler(LLVMContext &C, IRBuilder<> &B, Module &M, std::map<std::string, Value*> &NV, RuntimeCheck &RC)
- : TheContext(&C), Builder(&B), TheModule(&M), NamedValues(&NV), RuntimeChecker(RC) {
+ArrayHandler::ArrayHandler(LLVMContext &C,
+ IRBuilder<> &B,
+ Module &M,
+ std::map<std::string, Value*> &NV,
+ std::map<std::string, SymbolInfo> &Sym,
+ TypeSystem &TS,
+ RuntimeCheck &RC)
+ : TheContext(&C),
+ Builder(&B),
+ TheModule(&M),
+ NamedValues(&NV),
+ Symbols(&Sym),
+ Types(TS),
+ RuntimeChecker(RC) {
setupExternalFunctions();
}
void ArrayHandler::setupExternalFunctions() {
std::vector<Type*> MallocArgs;
MallocArgs.push_back(Type::getInt64Ty(*TheContext));
-
+
FunctionType *MallocType = FunctionType::get(PointerType::getUnqual(*TheContext), MallocArgs, false);
MallocFunc = TheModule->getOrInsertFunction("malloc", MallocType);
@@ -26,89 +39,124 @@ void ArrayHandler::setupExternalFunctions() {
FreeFunc = TheModule->getOrInsertFunction("free", FreeType);
}
+const ArrayMetadata *ArrayHandler::getMetadata(const std::string &Name) const {
+ auto It = ArrayTable.find(Name);
+ if (It == ArrayTable.end()) {
+ return nullptr;
+ }
+ return &It->second;
+}
+
+Value *ArrayHandler::computeFlatIndex(const std::string &Name, const std::vector<Value*> &Indices) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) return nullptr;
+
+ Value *Offset = ConstantInt::get(*TheContext, APInt(64, 0));
+ for (size_t i = 0; i < Indices.size(); ++i) {
+ Value *Idx = Indices[i];
+ Value *Lower = Meta->LowerBounds[i];
+ Value *Diff = Builder->CreateSub(Idx, Lower);
+ Value *Term = Builder->CreateMul(Diff, Meta->Multipliers[i]);
+ Offset = Builder->CreateAdd(Offset, Term);
+ }
+ return Offset;
+}
+
+Value *ArrayHandler::getArrayBasePointer(const std::string &Name) {
+ auto It = NamedValues->find(Name);
+ if (It == NamedValues->end() || !It->second) {
+ return nullptr;
+ }
+ return Builder->CreateLoad(PointerType::getUnqual(*TheContext), It->second, (Name + "_raw").c_str());
+}
+
+Value *ArrayHandler::getElementPointer(const std::string &Name, Value *Offset) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta || !Offset) return nullptr;
+
+ Value *RawPtr = getArrayBasePointer(Name);
+ if (!RawPtr) return nullptr;
+
+ PointerType *TypedPtrTy = PointerType::getUnqual(Meta->ElementType);
+ Value *TypedPtr = Builder->CreateBitCast(RawPtr, TypedPtrTy, Name + "_typed_ptr");
+ return Builder->CreateGEP(Meta->ElementType, TypedPtr, Offset, Name + "_elem_ptr");
+}
+
void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) {
std::string Name = Stmt->getName();
- int Rank = Stmt->getBounds().size();
-
- std::vector<Value*> Lows, Highs, Dims;
+ int Rank = static_cast<int>(Stmt->getBounds().size());
+
+ const TypeInfo *ElemInfo = Types.resolve(Stmt->getType());
+ if (!ElemInfo || !ElemInfo->LLVMType || ElemInfo->isVoid()) {
+ fprintf(stderr, "Error: Unknown array element type %s\n", Stmt->getType().c_str());
+ return;
+ }
+
+ std::vector<Value*> Lows;
+ std::vector<Value*> Highs;
+ std::vector<Value*> Dims;
Value *TotalElements = ConstantInt::get(*TheContext, APInt(64, 1));
-
+
for (const auto &Pair : Stmt->getBounds()) {
Value *L = CG.emitExpr(Pair.first.get());
Value *R = CG.emitExpr(Pair.second.get());
-
+ L = CG.coerceValueToType(L, CG.resolveType("INTEGER"));
+ R = CG.coerceValueToType(R, CG.resolveType("INTEGER"));
+
if (!L || !R) return;
-
- Value *L64 = Builder->CreateSExt(L, Type::getInt64Ty(*TheContext));
- Value *R64 = Builder->CreateSExt(R, Type::getInt64Ty(*TheContext));
-
+
Lows.push_back(L);
Highs.push_back(R);
-
- Value *Diff = Builder->CreateSub(R64, L64);
- Value *DimSize = Builder->CreateAdd(Diff, ConstantInt::get(*TheContext, APInt(64, 1)));
+
+ Value *Diff = Builder->CreateSub(R, L, Name + "_dim_diff");
+ Value *DimSize = Builder->CreateAdd(Diff, ConstantInt::get(*TheContext, APInt(64, 1)), Name + "_dim_size");
Dims.push_back(DimSize);
-
- TotalElements = Builder->CreateMul(TotalElements, DimSize);
+ TotalElements = Builder->CreateMul(TotalElements, DimSize, Name + "_total_elems");
}
-
+
std::vector<Value*> Multipliers(Rank);
Multipliers[Rank - 1] = ConstantInt::get(*TheContext, APInt(64, 1));
-
for (int i = Rank - 2; i >= 0; --i) {
- Value *NextMult = Multipliers[i+1];
- Value *NextDimSize = Dims[i+1];
- Multipliers[i] = Builder->CreateMul(NextMult, NextDimSize);
+ Multipliers[i] = Builder->CreateMul(Multipliers[i + 1], Dims[i + 1], Name + "_mult");
}
ArrayMetadata Meta;
Meta.Rank = Rank;
- Meta.ElementType = Type::getInt64Ty(*TheContext);
- Meta.LowerBounds = Lows;
- Meta.UpperBounds = Highs;
- Meta.Multipliers = Multipliers;
+ Meta.ElementTypeName = ElemInfo->Name;
+ Meta.ElementType = ElemInfo->LLVMType;
+ Meta.ElementSize = ElemInfo->ElementSize;
+ Meta.LowerBounds = std::move(Lows);
+ Meta.UpperBounds = std::move(Highs);
+ Meta.Multipliers = std::move(Multipliers);
ArrayTable[Name] = Meta;
-
- Value *ElemSize = ConstantInt::get(*TheContext, APInt(64, 8));
- Value *TotalBytes = Builder->CreateMul(TotalElements, ElemSize);
-
- CallInst *Ptr = Builder->CreateCall(MallocFunc, TotalBytes);
-
+ Value *ElemSize = ConstantInt::get(*TheContext, APInt(64, ElemInfo->ElementSize));
+ Value *TotalBytes = Builder->CreateMul(TotalElements, ElemSize, Name + "_total_bytes");
+ CallInst *Ptr = Builder->CreateCall(MallocFunc, TotalBytes, Name + "_malloc");
+
+ FunctionType *MemsetType = FunctionType::get(PointerType::getUnqual(*TheContext),
+ {PointerType::getUnqual(*TheContext), Type::getInt32Ty(*TheContext), Type::getInt64Ty(*TheContext)},
+ false);
+ FunctionCallee MemsetFunc = TheModule->getOrInsertFunction("memset", MemsetType);
+ Builder->CreateCall(MemsetFunc,
+ {Ptr, ConstantInt::get(Type::getInt32Ty(*TheContext), 0), TotalBytes});
+
Function *TheFunction = Builder->GetInsertBlock()->getParent();
- IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
-
- AllocaInst *Alloca = TmpB.CreateAlloca(PointerType::getUnqual(*TheContext), nullptr, Name);
-
+ AllocaInst *Alloca = CG.CreateEntryBlockAlloca(TheFunction, PointerType::getUnqual(*TheContext), Name);
Builder->CreateStore(Ptr, Alloca);
- (*NamedValues)[Name] = Alloca;
-}
-Value* ArrayHandler::computeFlatIndex(const std::string &Name, const std::vector<Value*> &Indices) {
- if (ArrayTable.find(Name) == ArrayTable.end()) return nullptr;
- const auto &Meta = ArrayTable[Name];
-
- Value *Offset = ConstantInt::get(*TheContext, APInt(64, 0));
-
- for (size_t i = 0; i < Indices.size(); ++i) {
- Value *Idx = Indices[i];
- Value *Lower = Meta.LowerBounds[i];
- Value *Diff = Builder->CreateSub(Idx, Lower);
- Value *Term = Builder->CreateMul(Diff, Meta.Multipliers[i]);
- Offset = Builder->CreateAdd(Offset, Term);
- }
- return Offset;
+ CG.registerSymbol(Name, Alloca, ElemInfo->Name, true);
}
-Value* ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) {
+Value *ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) {
std::string Name = Expr->getName();
- if (ArrayTable.find(Name) == ArrayTable.end()) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) {
fprintf(stderr, "Error: Undeclared array %s\n", Name.c_str());
return nullptr;
}
-
- const auto &Meta = ArrayTable[Name];
- if (Expr->getIndices().size() != Meta.Rank) {
+
+ if (Expr->getIndices().size() != static_cast<size_t>(Meta->Rank)) {
fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str());
return nullptr;
}
@@ -116,125 +164,147 @@ Value* ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) {
std::vector<Value*> Indices;
for (size_t i = 0; i < Expr->getIndices().size(); ++i) {
Value *Idx = CG.emitExpr(Expr->getIndices()[i].get());
- Indices.push_back(Idx);
+ Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER"));
+ if (!Idx) return nullptr;
- Value *Lower = Meta.LowerBounds[i];
- Value *Upper = Meta.UpperBounds[i];
- RuntimeChecker.emitIndexCheck(Idx, Lower, Upper, Expr->getLine());
+ Indices.push_back(Idx);
+ RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Expr->getLine());
}
-
+
Value *Offset = computeFlatIndex(Name, Indices);
-
- 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);
-
- return Builder->CreateLoad(Type::getInt64Ty(*TheContext), ElemPtr);
+ Value *ElemPtr = getElementPointer(Name, Offset);
+ if (!ElemPtr) return nullptr;
+
+ Value *Val = Builder->CreateLoad(Meta->ElementType, ElemPtr, Name + "_elem");
+ if (Meta->ElementTypeName == "STRING") {
+ Value *IsNull = Builder->CreateICmpEQ(Val,
+ ConstantPointerNull::get(cast<PointerType>(Meta->ElementType)),
+ Name + "_str_is_null");
+ Val = Builder->CreateSelect(IsNull, CG.EmptyStringStr, Val, Name + "_safe_str");
+ }
+ return Val;
}
void ArrayHandler::emitArrayAssign(ArrayAssignStmtAST *Stmt, CodeGen &CG) {
std::string Name = Stmt->getName();
- if (ArrayTable.find(Name) == ArrayTable.end()) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) {
fprintf(stderr, "Error: Undeclared array %s\n", Name.c_str());
return;
}
-
+
+ if (Stmt->getIndices().size() != static_cast<size_t>(Meta->Rank)) {
+ fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str());
+ return;
+ }
+
std::vector<Value*> Indices;
for (size_t i = 0; i < Stmt->getIndices().size(); ++i) {
Value *Idx = CG.emitExpr(Stmt->getIndices()[i].get());
- Indices.push_back(Idx);
+ Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER"));
+ if (!Idx) return;
- const auto &Meta = ArrayTable[Name];
- Value *Lower = Meta.LowerBounds[i];
- Value *Upper = Meta.UpperBounds[i];
- RuntimeChecker.emitIndexCheck(Idx, Lower, Upper, Stmt->getLine());
+ Indices.push_back(Idx);
+ RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Stmt->getLine());
}
-
+
+ const TypeInfo *ElemInfo = Types.resolve(Meta->ElementTypeName);
Value *Val = CG.emitExpr(Stmt->getExpr());
+ Val = CG.coerceValueToType(Val, ElemInfo);
+ if (!Val) return;
+
Value *Offset = computeFlatIndex(Name, Indices);
-
- 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);
-
+ Value *ElemPtr = getElementPointer(Name, Offset);
+ if (!ElemPtr) return;
+
Builder->CreateStore(Val, ElemPtr);
}
-bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr) {
+bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG) {
std::string Name;
std::vector<Value*> Indices;
-
+
if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
Name = Var->getName();
- if (ArrayTable.find(Name) == ArrayTable.end()) return false;
- }
- else if (auto *Acc = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
+ if (!getMetadata(Name)) return false;
+ } else if (auto *Acc = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
Name = Acc->getName();
- if (ArrayTable.find(Name) == ArrayTable.end()) return false;
-
- for (const auto &Idx : Acc->getIndices()) {
- Indices.push_back(CG.emitExpr(Idx.get()));
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) return false;
+
+ for (size_t i = 0; i < Acc->getIndices().size(); ++i) {
+ Value *Idx = CG.emitExpr(Acc->getIndices()[i].get());
+ Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER"));
+ if (!Idx) return false;
+ Indices.push_back(Idx);
+ RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Acc->getLine());
+ }
+
+ if (Indices.size() > static_cast<size_t>(Meta->Rank)) {
+ fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str());
+ return true;
}
} else {
return false;
}
-
- const auto &Meta = ArrayTable[Name];
-
- if (Indices.size() == Meta.Rank) {
+
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) return false;
+ if (Indices.size() == static_cast<size_t>(Meta->Rank)) {
return false;
}
-
- emitPrintLoop(Name, Indices.size(), Indices, PrintfFunc, FmtStr);
+
+ emitPrintLoop(Name, static_cast<int>(Indices.size()), Indices, CG);
return true;
}
-void ArrayHandler::emitPrintLoop(const std::string &Name, int CurrentDim, std::vector<Value*> CurrentIndices, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr) {
- const auto &Meta = ArrayTable[Name];
-
- if (CurrentDim == Meta.Rank) {
+void ArrayHandler::emitPrintLoop(const std::string &Name,
+ int CurrentDim,
+ std::vector<Value*> CurrentIndices,
+ CodeGen &CG) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) return;
+
+ if (CurrentDim == Meta->Rank) {
Value *Offset = computeFlatIndex(Name, CurrentIndices);
-
- 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);
- Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), ElemPtr);
-
- std::vector<Value*> Args;
- Args.push_back(FmtStr);
- Args.push_back(Val);
- Builder->CreateCall(PrintfFunc, Args);
+ Value *ElemPtr = getElementPointer(Name, Offset);
+ if (!ElemPtr) return;
+
+ Value *Val = Builder->CreateLoad(Meta->ElementType, ElemPtr, Name + "_print_val");
+ if (Meta->ElementTypeName == "STRING") {
+ Value *IsNull = Builder->CreateICmpEQ(Val,
+ ConstantPointerNull::get(cast<PointerType>(Meta->ElementType)),
+ Name + "_print_str_is_null");
+ Val = Builder->CreateSelect(IsNull, CG.EmptyStringStr, Val, Name + "_print_safe_str");
+ }
+
+ CG.emitOutputValue(Val, Types.resolve(Meta->ElementTypeName), true);
return;
}
-
+
Function *TheFunction = Builder->GetInsertBlock()->getParent();
BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "arr_loop", TheFunction);
BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "arr_after", TheFunction);
-
- IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
- AllocaInst *LoopVar = TmpB.CreateAlloca(Type::getInt64Ty(*TheContext), nullptr, "idx");
-
- Value *Start = Meta.LowerBounds[CurrentDim];
- Value *End = Meta.UpperBounds[CurrentDim];
-
+
+ AllocaInst *LoopVar = CG.CreateEntryBlockAlloca(TheFunction, Type::getInt64Ty(*TheContext), "idx");
+ Value *Start = Meta->LowerBounds[CurrentDim];
+ Value *End = Meta->UpperBounds[CurrentDim];
+
Builder->CreateStore(Start, LoopVar);
Builder->CreateBr(LoopBB);
-
+
Builder->SetInsertPoint(LoopBB);
Value *CurVal = Builder->CreateLoad(Type::getInt64Ty(*TheContext), LoopVar);
-
+
std::vector<Value*> NextIndices = CurrentIndices;
NextIndices.push_back(CurVal);
- emitPrintLoop(Name, CurrentDim + 1, NextIndices, PrintfFunc, FmtStr);
-
+ emitPrintLoop(Name, CurrentDim + 1, NextIndices, CG);
+
Value *NextVal = Builder->CreateAdd(CurVal, ConstantInt::get(*TheContext, APInt(64, 1)));
Builder->CreateStore(NextVal, LoopVar);
-
+
Value *Cond = Builder->CreateICmpSLE(NextVal, End);
Builder->CreateCondBr(Cond, LoopBB, AfterBB);
-
+
Builder->SetInsertPoint(AfterBB);
}
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;
}
}
diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc
index a929943..89aa3d8 100644
--- a/lib/CodeGen/FunctionGen.cc
+++ b/lib/CodeGen/FunctionGen.cc
@@ -1,16 +1,17 @@
#include "cps/FunctionGen.h"
#include "llvm/IR/Verifier.h"
-#include <iostream>
+#include <cstdio>
using namespace llvm;
using namespace cps;
Type *FunctionGen::getLLVMType(const std::string &TypeName) {
- if (TypeName == "INTEGER") return Type::getInt64Ty(Context);
- if (TypeName == "BOOLEAN") return Type::getInt1Ty(Context);
- if (TypeName == "REAL") return Type::getDoubleTy(Context);
- if (TypeName == "VOID") return Type::getVoidTy(Context);
- return Type::getInt64Ty(Context);
+ Type *Resolved = Types.getLLVMType(TypeName);
+ if (!Resolved) {
+ fprintf(stderr, "Error: Unknown type %s\n", TypeName.c_str());
+ return Type::getInt64Ty(Context);
+ }
+ return Resolved;
}
void FunctionGen::createArgumentAllocas(Function *F, const std::vector<std::tuple<std::string, std::string, bool>> &Args) {
@@ -19,20 +20,23 @@ void FunctionGen::createArgumentAllocas(Function *F, const std::vector<std::tupl
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);
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;
+ Symbols[ArgName] = {ArgVal, ArgTypeStr, false};
+ continue;
}
+
+ 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;
+ Symbols[ArgName] = {Alloca, ArgTypeStr, false};
}
}
@@ -48,23 +52,28 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) {
Type *RetType = getLLVMType(Proto->getReturnType());
FunctionType *FT = FunctionType::get(RetType, ArgTypes, false);
- Function *F = Function::Create(FT, Function::ExternalLinkage, Proto->getName(), &Module);
+ Function *F = Module.getFunction(Proto->getName());
+ if (!F) {
+ F = Function::Create(FT, Function::ExternalLinkage, Proto->getName(), &Module);
+ }
unsigned Idx = 0;
for (auto &Arg : F->args()) {
- if (Idx < Proto->getArgs().size())
+ if (Idx < Proto->getArgs().size()) {
Arg.setName(std::get<0>(Proto->getArgs()[Idx++]));
+ }
}
return F;
}
-Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
+Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
const std::function<void(StmtAST*)> &StmtEmitter) {
PrototypeAST *Proto = FuncAST->getProto();
Function *TheFunction = Module.getFunction(Proto->getName());
- if (!TheFunction)
+ if (!TheFunction) {
TheFunction = emitPrototype(Proto);
+ }
if (!TheFunction) return nullptr;
if (!TheFunction->empty()) {
@@ -76,8 +85,10 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
Builder.SetInsertPoint(BB);
std::map<std::string, llvm::Value*> OldNamedValues = NamedValues;
+ std::map<std::string, SymbolInfo> OldSymbols = Symbols;
NamedValues.clear();
-
+ Symbols.clear();
+
createArgumentAllocas(TheFunction, Proto->getArgs());
for (const auto &Stmt : FuncAST->getBody()) {
@@ -85,19 +96,24 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
}
if (!Builder.GetInsertBlock()->getTerminator()) {
- if (Proto->getReturnType() == "VOID")
+ if (Proto->getReturnType() == "VOID") {
Builder.CreateRetVoid();
- else
+ } else {
Builder.CreateRet(Constant::getNullValue(TheFunction->getReturnType()));
+ }
}
verifyFunction(*TheFunction);
NamedValues = OldNamedValues;
+ Symbols = OldSymbols;
return TheFunction;
}
-static Value *GenerateCall(llvm::Module &Module, llvm::IRBuilder<> &Builder, llvm::LLVMContext &Context,
- const std::string &CalleeName, const std::vector<llvm::Value*> &Args) {
+static Value *GenerateCall(llvm::Module &Module,
+ llvm::IRBuilder<> &Builder,
+ llvm::LLVMContext &Context,
+ const std::string &CalleeName,
+ const std::vector<llvm::Value*> &Args) {
Function *CalleeF = Module.getFunction(CalleeName);
if (!CalleeF) {
std::vector<Type*> ArgTypes;
diff --git a/lib/CodeGen/TypeSystem.cc b/lib/CodeGen/TypeSystem.cc
new file mode 100644
index 0000000..59dcc18
--- /dev/null
+++ b/lib/CodeGen/TypeSystem.cc
@@ -0,0 +1,156 @@
+#include "cps/TypeSystem.h"
+#include "llvm/IR/Constants.h"
+#include <utility>
+
+using namespace llvm;
+using namespace cps;
+
+bool TypeInfo::isNumeric() const {
+ return Kind == TypeKind::Integer || Kind == TypeKind::Real;
+}
+
+bool TypeInfo::isIntegral() const {
+ return Kind == TypeKind::Integer || Kind == TypeKind::Char;
+}
+
+bool TypeInfo::isReal() const {
+ return Kind == TypeKind::Real;
+}
+
+bool TypeInfo::isBoolean() const {
+ return Kind == TypeKind::Boolean;
+}
+
+bool TypeInfo::isString() const {
+ return Kind == TypeKind::String;
+}
+
+bool TypeInfo::isChar() const {
+ return Kind == TypeKind::Char;
+}
+
+bool TypeInfo::isVoid() const {
+ return Kind == TypeKind::Void;
+}
+
+TypeSystem::TypeSystem(LLVMContext &Ctx) : Context(Ctx) {
+ registerBuiltins();
+}
+
+void TypeSystem::registerBuiltins() {
+ registerType("INTEGER",
+ Type::getInt64Ty(Context),
+ 8,
+ TypeKind::Integer,
+ true,
+ false,
+ true);
+
+ registerType("REAL",
+ Type::getDoubleTy(Context),
+ 8,
+ TypeKind::Real,
+ true,
+ false,
+ true);
+
+ registerType("BOOLEAN",
+ Type::getInt1Ty(Context),
+ 1,
+ TypeKind::Boolean,
+ true,
+ false,
+ true);
+
+ registerType("STRING",
+ PointerType::getUnqual(Context),
+ 8,
+ TypeKind::String,
+ true,
+ true,
+ true);
+
+ registerType("CHAR",
+ Type::getInt8Ty(Context),
+ 1,
+ TypeKind::Char,
+ true,
+ false,
+ true);
+
+ registerType("VOID",
+ Type::getVoidTy(Context),
+ 0,
+ TypeKind::Void,
+ false,
+ false,
+ true);
+}
+
+const TypeInfo *TypeSystem::resolve(const std::string &TypeName) const {
+ auto It = Types.find(TypeName);
+ if (It == Types.end()) {
+ return nullptr;
+ }
+ return &It->second;
+}
+
+bool TypeSystem::hasType(const std::string &TypeName) const {
+ return resolve(TypeName) != nullptr;
+}
+
+const TypeInfo *TypeSystem::registerType(const std::string &TypeName,
+ Type *LLVMType,
+ uint64_t ElementSize,
+ TypeKind Kind,
+ bool Printable,
+ bool ReferenceLike,
+ bool Builtin) {
+ TypeInfo Info;
+ Info.Name = TypeName;
+ Info.LLVMType = LLVMType;
+ Info.ElementSize = ElementSize;
+ Info.Kind = Kind;
+ Info.Printable = Printable;
+ Info.Builtin = Builtin;
+ Info.ReferenceLike = ReferenceLike;
+
+ auto Result = Types.insert_or_assign(TypeName, std::move(Info));
+ return &Result.first->second;
+}
+
+Type *TypeSystem::getLLVMType(const std::string &TypeName) const {
+ const TypeInfo *Info = resolve(TypeName);
+ return Info ? Info->LLVMType : nullptr;
+}
+
+uint64_t TypeSystem::getElementSize(const std::string &TypeName) const {
+ const TypeInfo *Info = resolve(TypeName);
+ return Info ? Info->ElementSize : 0;
+}
+
+Constant *TypeSystem::getZeroValue(const std::string &TypeName) const {
+ const TypeInfo *Info = resolve(TypeName);
+ if (!Info || !Info->LLVMType || Info->LLVMType->isVoidTy()) {
+ return nullptr;
+ }
+
+ switch (Info->Kind) {
+ case TypeKind::Integer:
+ return ConstantInt::get(Context, APInt(64, 0));
+ case TypeKind::Real:
+ return ConstantFP::get(Context, APFloat(0.0));
+ case TypeKind::Boolean:
+ return ConstantInt::get(Context, APInt(1, 0));
+ case TypeKind::Char:
+ return ConstantInt::get(Context, APInt(8, 0));
+ case TypeKind::String:
+ return ConstantPointerNull::get(cast<PointerType>(Info->LLVMType));
+ case TypeKind::Void:
+ return nullptr;
+ case TypeKind::Custom:
+ return Constant::getNullValue(Info->LLVMType);
+ }
+
+ return Constant::getNullValue(Info->LLVMType);
+}
diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc
index ef3a920..9a8e767 100644
--- a/lib/Lexer/Lexer.cc
+++ b/lib/Lexer/Lexer.cc
@@ -1,9 +1,9 @@
#include "cps/Lexer.h"
+#include <algorithm>
#include <cctype>
#include <cstdio>
-#include <string>
-#include <algorithm>
#include <cstdlib>
+#include <string>
using namespace cps;
@@ -15,43 +15,63 @@ int Lexer::gettok() {
LastChar = getchar();
}
- if (LastChar == '"' || LastChar == '\'') {
- char QuoteType = LastChar;
- StringVal = "";
-
+ if (LastChar == '"') {
+ StringVal.clear();
LastChar = getchar();
-
- while (LastChar != QuoteType && LastChar != EOF && LastChar != '\n') {
- StringVal += LastChar;
+
+ while (LastChar != '"' && LastChar != EOF && LastChar != '\n') {
+ StringVal += static_cast<char>(LastChar);
LastChar = getchar();
}
-
- if (LastChar == QuoteType) {
+
+ if (LastChar == '"') {
LastChar = getchar();
} else {
- fprintf(stderr, "Error: Unterminated string or char literal\n");
+ fprintf(stderr, "Error: Unterminated string literal\n");
}
- return tok_string_literal;
+ return tok_string_literal;
+ }
+
+ if (LastChar == '\'') {
+ int CharCode = getchar();
+ if (CharCode == EOF || CharCode == '\n') {
+ fprintf(stderr, "Error: Unterminated char literal\n");
+ return tok_eof;
+ }
+
+ int ClosingQuote = getchar();
+ if (ClosingQuote != '\'') {
+ fprintf(stderr, "Error: CHAR literal must contain exactly one character\n");
+ while (ClosingQuote != EOF && ClosingQuote != '\n' && ClosingQuote != '\'') {
+ ClosingQuote = getchar();
+ }
+ }
+
+ CharVal = static_cast<char>(CharCode);
+ StringVal.assign(1, CharVal);
+ LastChar = getchar();
+ return tok_char_literal;
}
if (isalpha(LastChar)) {
- IdentifierStr = LastChar;
+ IdentifierStr = static_cast<char>(LastChar);
while (isalnum((LastChar = getchar())) || LastChar == '_')
- IdentifierStr += LastChar;
+ IdentifierStr += static_cast<char>(LastChar);
if (IdentifierStr == "DECLARE") return tok_declare;
if (IdentifierStr == "INTEGER") return tok_integer_kw;
- if (IdentifierStr == "BOOLEAN") return tok_boolean_kw;
- if (IdentifierStr == "REAL") return tok_real_kw;
+ if (IdentifierStr == "BOOLEAN") return tok_boolean_kw;
+ if (IdentifierStr == "REAL") return tok_real_kw;
if (IdentifierStr == "STRING") return tok_string_kw;
+ if (IdentifierStr == "CHAR") return tok_char_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;
-
+
if (IdentifierStr == "IF") return tok_if;
if (IdentifierStr == "THEN") return tok_then;
if (IdentifierStr == "ELSE") return tok_else;
@@ -60,10 +80,10 @@ int Lexer::gettok() {
if (IdentifierStr == "WHILE") return tok_while;
if (IdentifierStr == "DO") return tok_do;
if (IdentifierStr == "ENDWHILE") return tok_endwhile;
-
+
if (IdentifierStr == "REPEAT") return tok_repeat;
if (IdentifierStr == "UNTIL") return tok_until;
-
+
if (IdentifierStr == "FOR") return tok_for;
if (IdentifierStr == "TO") return tok_to;
if (IdentifierStr == "STEP") return tok_step;
@@ -74,7 +94,7 @@ int Lexer::gettok() {
if (IdentifierStr == "DIV") return tok_div;
if (IdentifierStr == "MOD") return tok_mod;
-
+
if (IdentifierStr == "AND") return tok_and;
if (IdentifierStr == "OR") return tok_or;
if (IdentifierStr == "NOT") return tok_not;
@@ -93,7 +113,7 @@ 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;
@@ -104,7 +124,7 @@ int Lexer::gettok() {
std::string NumStr;
bool isReal = false;
do {
- NumStr += LastChar;
+ NumStr += static_cast<char>(LastChar);
LastChar = getchar();
if (LastChar == '.' && !isReal) {
isReal = true;
@@ -112,27 +132,27 @@ int Lexer::gettok() {
LastChar = getchar();
}
} while (isdigit(LastChar));
-
+
if (isReal) {
RealVal = strtod(NumStr.c_str(), nullptr);
return tok_number_real;
- } else {
- NumVal = strtoll(NumStr.c_str(), nullptr, 10);
- return tok_number_int;
}
+
+ NumVal = strtoll(NumStr.c_str(), nullptr, 10);
+ return tok_number_int;
}
if (LastChar == '<') {
LastChar = getchar();
- if (LastChar == '-') { // <-
+ if (LastChar == '-') {
LastChar = getchar();
return tok_assign;
}
- if (LastChar == '=') { // <=
+ if (LastChar == '=') {
LastChar = getchar();
return tok_le;
}
- if (LastChar == '>') { // <>
+ if (LastChar == '>') {
LastChar = getchar();
return tok_ne;
}
@@ -141,7 +161,7 @@ int Lexer::gettok() {
if (LastChar == '>') {
LastChar = getchar();
- if (LastChar == '=') { // >=
+ if (LastChar == '=') {
LastChar = getchar();
return tok_ge;
}
@@ -173,7 +193,7 @@ int Lexer::gettok() {
do {
LastChar = getchar();
} while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');
-
+
if (LastChar != EOF)
return gettok();
} else {
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc
index 9bdd821..322cdb9 100644
--- a/lib/Parser/Parser.cc
+++ b/lib/Parser/Parser.cc
@@ -1,5 +1,6 @@
#include "cps/Parser.h"
#include "cps/FunctionAST.h"
+#include <cstdio>
using namespace cps;
@@ -96,6 +97,41 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() {
return std::make_unique<VariableExprAST>(IdName);
}
+std::string Parser::ParseTypeName(bool AllowVoid) {
+ if (CurTok == tok_integer_kw) {
+ getNextToken();
+ return "INTEGER";
+ }
+ if (CurTok == tok_real_kw) {
+ getNextToken();
+ return "REAL";
+ }
+ if (CurTok == tok_boolean_kw) {
+ getNextToken();
+ return "BOOLEAN";
+ }
+ if (CurTok == tok_string_kw) {
+ getNextToken();
+ return "STRING";
+ }
+ if (CurTok == tok_char_kw) {
+ getNextToken();
+ return "CHAR";
+ }
+ if (CurTok == tok_identifier) {
+ std::string TypeName = Lex.IdentifierStr;
+ if (!AllowVoid && TypeName == "VOID") {
+ fprintf(stderr, "Error: VOID is not allowed here\n");
+ return "";
+ }
+ getNextToken();
+ return TypeName;
+ }
+
+ fprintf(stderr, "Error: Unknown type name\n");
+ return "";
+}
+
std::unique_ptr<ExprAST> Parser::ParseStringBuiltin(const std::string &FuncName) {
getNextToken();
if (CurTok != '(') {
@@ -146,6 +182,11 @@ std::unique_ptr<ExprAST> Parser::ParsePrimary() {
getNextToken();
return Res;
}
+ case tok_char_literal: {
+ auto Res = std::make_unique<CharExprAST>(Lex.CharVal);
+ getNextToken();
+ return Res;
+ }
case tok_length: return ParseStringBuiltin("LENGTH");
case tok_mid: return ParseStringBuiltin("MID");
case tok_right: return ParseStringBuiltin("RIGHT");
@@ -176,6 +217,16 @@ std::unique_ptr<ExprAST> Parser::ParseUnary() {
if (!Operand) return nullptr;
return std::make_unique<UnaryExprAST>(tok_not, std::move(Operand));
}
+
+ if (CurTok == '-') {
+ int Line = Lex.getLine();
+ getNextToken();
+ auto Operand = ParseUnary();
+ if (!Operand) return nullptr;
+ auto Zero = std::make_unique<IntegerExprAST>(0);
+ return std::make_unique<BinaryExprAST>('-', std::move(Zero), std::move(Operand), Line);
+ }
+
return ParsePrimary();
}
@@ -268,26 +319,19 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() {
return nullptr;
}
getNextToken();
-
- if (CurTok != tok_integer_kw) {
- fprintf(stderr, "Error: Only INTEGER arrays supported currently\n");
- return nullptr;
+
+ std::string TypeStr = ParseTypeName(false);
+ if (TypeStr.empty()) {
+ return nullptr;
}
- getNextToken();
- return std::make_unique<ArrayDeclareStmtAST>(Name, std::move(Bounds), "INTEGER");
+ return std::make_unique<ArrayDeclareStmtAST>(Name, std::move(Bounds), TypeStr);
}
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 if (CurTok == tok_string_kw) TypeStr = "STRING";
- else {
- fprintf(stderr, "Error: Unknown type in declaration\n");
+ std::string TypeStr = ParseTypeName(false);
+ if (TypeStr.empty()) {
return nullptr;
}
- getNextToken();
return std::make_unique<DeclareStmtAST>(Name, TypeStr);
}
}
diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc
index d689aa6..05b1e12 100644
--- a/lib/Parser/ParserFunction.cc
+++ b/lib/Parser/ParserFunction.cc
@@ -1,5 +1,6 @@
#include "cps/Parser.h"
#include "cps/FunctionAST.h"
+#include <cstdio>
#include <tuple>
using namespace cps;
@@ -34,15 +35,10 @@ std::vector<std::tuple<std::string, std::string, bool>> Parser::ParsePrototypeAr
}
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;
+ std::string Type = ParseTypeName(false);
+ if (Type.empty()) {
+ fprintf(stderr, "Error: Expected argument type for '%s'\n", Name.c_str());
+ return Args;
}
Args.emplace_back(Name, Type, IsRef);
@@ -58,18 +54,26 @@ std::vector<std::tuple<std::string, std::string, bool>> Parser::ParsePrototypeAr
return Args;
}
-
std::unique_ptr<StmtAST> Parser::ParseFunction() {
getNextToken();
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "Error: Expected function name\n");
+ return nullptr;
+ }
+
std::string Name = Lex.IdentifierStr;
getNextToken();
auto Args = ParsePrototypeArgs();
std::string RetType = "INTEGER";
- if (CurTok == tok_returns) {
- getNextToken();
+ if (CurTok == tok_returns) {
getNextToken();
+ RetType = ParseTypeName(true);
+ if (RetType.empty()) {
+ fprintf(stderr, "Error: Expected return type for function '%s'\n", Name.c_str());
+ return nullptr;
+ }
}
auto Proto = std::make_unique<PrototypeAST>(Name, std::move(Args), RetType);
@@ -80,6 +84,11 @@ std::unique_ptr<StmtAST> Parser::ParseFunction() {
if (Stmt) Body.push_back(std::move(Stmt));
else if (CurTok != tok_eof && CurTok != tok_endfunction) getNextToken();
}
+
+ if (CurTok != tok_endfunction) {
+ fprintf(stderr, "Error: expected ENDFUNCTION\n");
+ return nullptr;
+ }
getNextToken();
return std::make_unique<FunctionDefAST>(std::move(Proto), std::move(Body));
@@ -87,6 +96,11 @@ std::unique_ptr<StmtAST> Parser::ParseFunction() {
std::unique_ptr<StmtAST> Parser::ParseProcedure() {
getNextToken();
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "Error: Expected procedure name\n");
+ return nullptr;
+ }
+
std::string Name = Lex.IdentifierStr;
getNextToken();
@@ -99,6 +113,11 @@ std::unique_ptr<StmtAST> Parser::ParseProcedure() {
if (Stmt) Body.push_back(std::move(Stmt));
else if (CurTok != tok_eof && CurTok != tok_endprocedure) getNextToken();
}
+
+ if (CurTok != tok_endprocedure) {
+ fprintf(stderr, "Error: expected ENDPROCEDURE\n");
+ return nullptr;
+ }
getNextToken();
return std::make_unique<FunctionDefAST>(std::move(Proto), std::move(Body));
@@ -106,6 +125,11 @@ std::unique_ptr<StmtAST> Parser::ParseProcedure() {
std::unique_ptr<StmtAST> Parser::ParseCallStmt() {
getNextToken();
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "Error: Expected callee name after CALL\n");
+ return nullptr;
+ }
+
std::string Callee = Lex.IdentifierStr;
getNextToken();
@@ -115,6 +139,7 @@ std::unique_ptr<StmtAST> Parser::ParseCallStmt() {
while (CurTok != ')') {
auto Arg = ParseExpression();
if (Arg) Args.push_back(std::move(Arg));
+ else return nullptr;
if (CurTok == ')') break;
if (CurTok != ',') {