1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
#pragma once
#include "llvm/Support/SaveAndRestore.h"
#include "cps/Identifier.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "cps/AST.h"
#include "cps/RuntimeCheck.h"
#include "cps/FunctionGen.h"
#include "cps/TypeSystem.h"
#include "cps/ArithmeticHandler.h"
#include "cps/StringHandler.h"
#include "cps/StringConversionHandler.h"
#include <map>
#include <memory>
#include <optional>
#include <string>
namespace cps {
class ArrayHandler;
class FileHandler;
class MemoryHandler;
class ExceptionHandler;
class CastExprAST;
class NewExprAST;
class CodeGen {
std::unique_ptr<llvm::LLVMContext> TheContext;
std::unique_ptr<llvm::Module> TheModule;
std::unique_ptr<llvm::IRBuilder<>> Builder;
int DiagnosticLine = 0;
IdentifierMap<SymbolInfo> Symbols;
IdentifierMap<IdentifierMap<FunctionDefAST*>> ClassMethods;
std::string CurrentClass;
const PrototypeAST *findMethod(const std::string &Class, const std::string &Name) const;
llvm::Value *emitMemberCall(MemberCallExprAST *Call);
llvm::Value *emitMethodCall(const std::string &Class, llvm::Value *Receiver,
const std::string &Name,
const std::vector<std::unique_ptr<ExprAST>> &Args, int Line);
bool typeNeedsConstruction(const std::string &TypeName) const;
bool emitConstruct(const std::string &TypeName, llvm::Value *Addr,
const std::vector<std::unique_ptr<ExprAST>> &Args, int Line);
bool emitDefaultConstruct(const std::string &TypeName, llvm::Value *Addr, int Line);
struct ConstantScope {
unsigned ID;
IdentifierMap<std::optional<SymbolInfo>> Saved;
};
std::vector<ConstantScope> ConstantScopes = {{0, {}}};
unsigned NextScopeID = 1;
void emitScopedBlock(const std::vector<std::unique_ptr<StmtAST>> &Body);
void warnMemberShadow(const std::string &Name, int Line) const;
bool prepareSymbolDeclaration(const std::string &Name, bool IsConstant = false);
bool requireWritable(const SymbolInfo &Info, const std::string &Name);
void emitConstantStmt(ConstantStmtAST *Stmt);
std::unique_ptr<TypeSystem> Types;
std::unique_ptr<ArrayHandler> Arrays;
std::unique_ptr<ExceptionHandler> Exceptions;
std::unique_ptr<RuntimeCheck> RuntimeChecker;
std::unique_ptr<FunctionGen> FuncGen;
std::unique_ptr<ArithmeticHandler> ArithHandler;
std::unique_ptr<StringHandler> StrHandler;
std::unique_ptr<StringConversionHandler> StrConvHandler;
std::unique_ptr<FileHandler> Files;
std::unique_ptr<MemoryHandler> Memory;
llvm::FunctionCallee PrintfFunc;
llvm::FunctionCallee ScanfFunc;
llvm::FunctionCallee MallocFunc;
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
llvm::Value *ScanfStringFormatStr; // %s
llvm::Value *TrueStr; // "TRUE"
llvm::Value *FalseStr; // "FALSE"
llvm::Value *EmptyStringStr; // ""
bool HadError = false;
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;
bool isWholeArrayVar(ExprAST *Expr) const;
const TypeInfo *getExprTypeInfo(ExprAST *Expr) const;
llvm::Value *coerceValueToType(llvm::Value *Val, const TypeInfo *TargetInfo);
llvm::Value *convertNumericValue(llvm::Value *Val, const TypeInfo *Source,
const TypeInfo *Target);
llvm::Value *emitCast(CastExprAST *Cast);
llvm::Value *emitBinaryOp(int Op, llvm::Value *L, const TypeInfo *LT,
llvm::Value *R, const TypeInfo *RT, int Line);
llvm::Value *emitCBinaryOp(int Op, llvm::Value *L, const TypeInfo *Left,
llvm::Value *R, const TypeInfo *Right, int Line);
void emitCOutput(llvm::Value *Val, const TypeInfo *Info, bool AppendNewline);
void emitCInput(llvm::Value *Addr, const TypeInfo *Info);
// TYPE-system registration (Designator.cc) and operators (TypeCheckGen.cc).
void runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statements);
llvm::Value *emitUserKindBinaryOp(int Op, llvm::Value *L, const TypeInfo *LT,
llvm::Value *R, const TypeInfo *RT, int Line);
// An addressable location and the pseudocode type stored there.
struct LValueInfo {
llvm::Value *Addr = nullptr;
std::string TypeName;
};
// Resolves a variable / array element / field chain / deref to an address
// (emitting index and null-pointer checks along the way).
bool emitLValue(ExprAST *E, LValueInfo &Out);
// The rvalue read: load + the STRING null->"" guard.
llvm::Value *loadFromLValue(const LValueInfo &LV);
llvm::Value *emitAllocationSize(ExprAST *Expr);
llvm::Value *emitCall(const std::string &Callee,
const std::vector<std::unique_ptr<ExprAST>> &ArgExprs, int Line);
bool marshalCallArgs(const std::string &Callee,
const std::vector<std::unique_ptr<ExprAST>> &ArgExprs,
int Line,
std::vector<llvm::Value*> &Out);
llvm::Value *symbolAddress(const SymbolInfo &Info);
void emitAssignment(const LValueInfo &Target, ExprAST *Expr,
const SymbolInfo *Symbol = nullptr);
void emitDeclareStmt(DeclareStmtAST *Stmt);
void emitOutputValue(llvm::Value *Val, const TypeInfo *TypeInfo, bool AppendNewline = true);
void emitCaseStmt(CaseStmtAST *Stmt);
void emitIfStmt(IfStmtAST *Stmt);
void emitTryStmt(TryStmtAST *Stmt);
void emitWhileStmt(WhileStmtAST *Stmt);
void emitRepeatStmt(RepeatStmtAST *Stmt);
void emitForStmt(ForStmtAST *Stmt);
public:
CodeGen();
~CodeGen();
void compile(const std::vector<std::unique_ptr<StmtAST>> &Statements);
void print(llvm::raw_ostream &Output);
const llvm::Module &getModule() const { return *TheModule; }
bool hadError() const { return HadError; }
void reportError(const char *Fmt, ...);
static bool isBuiltinName(const std::string &Name);
llvm::Value *emitExpr(ExprAST *Expr);
void emitStmt(StmtAST *Stmt);
// STRING slots zero-init to null; normalize null to "" at load/print sites.
llvm::Value *emitStringNullGuard(llvm::Value *StrVal);
// Name-level admission gate for Enum/Record/Pointer plus the existing
// representation coercion for builtin targets. The ONLY door through
// which assignments, BYVAL args, RETURN values and file/builtin operands
// may produce a typed value. (TypeCheckGen.cc)
llvm::Value *emitCoercedExpr(ExprAST *E, const TypeInfo *TargetInfo);
const TypeInfo *resolveType(const std::string &TypeName) const;
friend class ArrayHandler;
};
}
|