aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/ArrayHandler.cc4
-rw-r--r--lib/CodeGen/CodeGen.cc3
-rw-r--r--lib/CodeGen/ConstantGen.cc59
-rw-r--r--lib/CodeGen/ControlFlowGen.cc17
-rw-r--r--lib/CodeGen/Designator.cc2
-rw-r--r--lib/CodeGen/ExpressionGen.cc1
-rw-r--r--lib/CodeGen/FunctionGen.cc9
-rw-r--r--lib/CodeGen/StatementGen.cc13
-rw-r--r--lib/CodeGen/ValueTypeGen.cc2
-rw-r--r--lib/Lexer/Lexer.cc1
-rw-r--r--lib/Parser/Parser.cc3
-rw-r--r--lib/Parser/ParserType.cc33
12 files changed, 135 insertions, 12 deletions
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc
index 6a89781..40a330f 100644
--- a/lib/CodeGen/ArrayHandler.cc
+++ b/lib/CodeGen/ArrayHandler.cc
@@ -33,6 +33,8 @@ void ArrayHandler::setupExternalFunctions() {
}
const ArrayMetadata *ArrayHandler::getMetadata(const std::string &Name) const {
+ auto Symbol = Symbols->find(Name);
+ if (Symbol == Symbols->end() || !Symbol->second.IsArray) return nullptr;
auto It = ArrayTable.find(Name);
if (It == ArrayTable.end()) {
return nullptr;
@@ -93,6 +95,8 @@ void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) {
return;
}
+ if (!CG.prepareSymbolDeclaration(Name)) return;
+
std::vector<Value*> Lows;
std::vector<Value*> Highs;
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 6c6f682..b793657 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -117,7 +117,7 @@ void CodeGen::registerSymbol(const std::string &Name,
Value *Storage,
const std::string &TypeName,
bool IsArray) {
- Symbols[Name] = {Storage, TypeName, IsArray};
+ Symbols[Name] = {Storage, TypeName, IsArray, nullptr, ConstantScopes.back().ID};
}
const SymbolInfo *CodeGen::getSymbolInfo(const std::string &Name) const {
@@ -243,6 +243,7 @@ bool CodeGen::marshalCallArgs(const std::string &Callee,
reportError("Unknown variable %s in BYREF call", Var->getName().c_str());
return false;
}
+ if (!requireWritable(*Info, Var->getName())) return false;
// BYREF aliases the storage, so the types must match exactly.
if (!Types->sameType(Info->TypeName, TypeName)) {
reportError("BYREF argument %s to %s must be of type %s (got %s)",
diff --git a/lib/CodeGen/ConstantGen.cc b/lib/CodeGen/ConstantGen.cc
new file mode 100644
index 0000000..e9f81ae
--- /dev/null
+++ b/lib/CodeGen/ConstantGen.cc
@@ -0,0 +1,59 @@
+#include "cps/CodeGen.h"
+
+using namespace llvm;
+using namespace cps;
+
+// Only bindings introduced by constants or hiding constants are restored.
+// Ordinary variables keep the compiler's existing function-wide visibility.
+void CodeGen::emitScopedBlock(const std::vector<std::unique_ptr<StmtAST>> &Body) {
+ ConstantScopes.push_back({NextScopeID++, {}});
+ for (const auto &S : Body) emitStmt(S.get());
+ for (const auto &[Name, Previous] : ConstantScopes.back().Saved) {
+ if (Previous) Symbols[Name] = *Previous;
+ else Symbols.erase(Name);
+ }
+ ConstantScopes.pop_back();
+}
+
+bool CodeGen::prepareSymbolDeclaration(const std::string &Name, bool IsConstant) {
+ auto &Scope = ConstantScopes.back();
+ auto It = Symbols.find(Name);
+ if (It != Symbols.end()) {
+ if ((IsConstant || It->second.ConstantValue) && It->second.ScopeID == Scope.ID) {
+ reportError("Declaration of %s conflicts with an existing declaration in this scope", Name.c_str());
+ return false;
+ }
+ if (IsConstant || It->second.ConstantValue) Scope.Saved.emplace(Name, It->second);
+ } else if (IsConstant) {
+ Scope.Saved.emplace(Name, std::nullopt);
+ }
+ return true;
+}
+
+bool CodeGen::requireWritable(const SymbolInfo &Info, const std::string &Name) {
+ if (!Info.ConstantValue) return true;
+ reportError("Constant %s is not a writable location", Name.c_str());
+ return false;
+}
+
+void CodeGen::emitConstantStmt(ConstantStmtAST *Stmt) {
+ const std::string &Name = Stmt->getName();
+ if (Types->lookupEnumConstant(Name) || Types->resolve(Name)) {
+ reportError("Constant %s conflicts with an enum value or type name", Name.c_str());
+ return;
+ }
+ if (ConstantScopes.back().ID == 0 &&
+ (FuncGen->getSignature(Name) || isBuiltinName(Name))) {
+ reportError("Constant %s conflicts with a function name", Name.c_str());
+ return;
+ }
+ if (!prepareSymbolDeclaration(Name, true)) return;
+ const TypeInfo *Type = getExprTypeInfo(Stmt->getValue());
+ Value *Val = emitExpr(Stmt->getValue());
+ auto *Literal = dyn_cast_or_null<Constant>(Val);
+ if (!Type || !Literal) {
+ reportError("CONSTANT initializer must be a literal");
+ return;
+ }
+ Symbols[Name] = {nullptr, Type->Name, false, Literal, ConstantScopes.back().ID};
+}
diff --git a/lib/CodeGen/ControlFlowGen.cc b/lib/CodeGen/ControlFlowGen.cc
index f9300dd..d34f640 100644
--- a/lib/CodeGen/ControlFlowGen.cc
+++ b/lib/CodeGen/ControlFlowGen.cc
@@ -12,14 +12,14 @@ void CodeGen::emitTryStmt(TryStmtAST *Stmt) {
auto SavedArrays = Arrays->snapshotTable();
Exceptions->pushHandler(CatchBB);
- for (const auto &S : Stmt->getBody()) emitStmt(S.get());
+ emitScopedBlock(Stmt->getBody());
auto *Exception = Exceptions->popHandler();
if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(AfterBB);
Arrays->exchangeTable(SavedArrays);
Builder->SetInsertPoint(CatchBB);
Exceptions->beginCatch(Exception);
- for (const auto &S : Stmt->getCatchBody()) emitStmt(S.get());
+ emitScopedBlock(Stmt->getCatchBody());
Exceptions->endCatch();
if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(AfterBB);
Arrays->exchangeTable(std::move(SavedArrays));
@@ -41,12 +41,12 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
// inside the branch, so a declaration must not survive it.
auto SavedArrays = Arrays->snapshotTable();
Builder->SetInsertPoint(ThenBB);
- for (const auto &S : Stmt->getThenStmts()) emitStmt(S.get());
+ emitScopedBlock(Stmt->getThenStmts());
if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(MergeBB);
Arrays->exchangeTable(SavedArrays);
Builder->SetInsertPoint(ElseBB);
- for (const auto &S : Stmt->getElseStmts()) emitStmt(S.get());
+ emitScopedBlock(Stmt->getElseStmts());
if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(MergeBB);
Arrays->exchangeTable(std::move(SavedArrays));
@@ -71,7 +71,7 @@ void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) {
// Arrays declared in the body are block-scoped (see emitIfStmt).
auto SavedArrays = Arrays->snapshotTable();
Builder->SetInsertPoint(LoopBB);
- for (const auto &S : Stmt->getBody()) emitStmt(S.get());
+ emitScopedBlock(Stmt->getBody());
Arrays->exchangeTable(std::move(SavedArrays));
if (!Builder->GetInsertBlock()->hasTerminator())
@@ -92,7 +92,7 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
// Arrays declared in the body are block-scoped (see emitIfStmt).
auto SavedArrays = Arrays->snapshotTable();
Builder->SetInsertPoint(LoopBB);
- for (const auto &S : Stmt->getBody()) emitStmt(S.get());
+ emitScopedBlock(Stmt->getBody());
Arrays->exchangeTable(std::move(SavedArrays));
if (!Builder->GetInsertBlock()->hasTerminator())
Builder->CreateBr(CondBB);
@@ -115,6 +115,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
reportError("Unknown variable in FOR loop %s", VarName.c_str());
return;
}
+ if (!requireWritable(*Symbol, VarName)) return;
if (Symbol->TypeName != "INTEGER") {
reportError("FOR loop variable %s must be INTEGER", VarName.c_str());
return;
@@ -160,7 +161,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
// Arrays declared in the body are block-scoped (see emitIfStmt).
auto SavedArrays = Arrays->snapshotTable();
Builder->SetInsertPoint(LoopBB);
- for (const auto &S : Stmt->getBody()) emitStmt(S.get());
+ emitScopedBlock(Stmt->getBody());
Arrays->exchangeTable(std::move(SavedArrays));
if (!Builder->GetInsertBlock()->hasTerminator())
Builder->CreateBr(IncBB);
@@ -223,7 +224,7 @@ void CodeGen::emitCaseStmt(CaseStmtAST *Stmt) {
}
}
Builder->SetInsertPoint(Body);
- for (const auto &S : Branch.Body) emitStmt(S.get());
+ emitScopedBlock(Branch.Body);
if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(After);
Arrays->exchangeTable(SavedArrays);
Builder->SetInsertPoint(Next);
diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc
index 6c00524..afaf0a4 100644
--- a/lib/CodeGen/Designator.cc
+++ b/lib/CodeGen/Designator.cc
@@ -54,6 +54,7 @@ bool CodeGen::emitLValue(ExprAST *E, LValueInfo &Out) {
}
return false;
}
+ if (!requireWritable(*Info, Var->getName())) return false;
if (Info->IsArray) {
reportError("Whole array %s is not an assignable location; index it", Var->getName().c_str());
return false;
@@ -84,6 +85,7 @@ bool CodeGen::emitLValue(ExprAST *E, LValueInfo &Out) {
return false;
}
+ if (!requireWritable(*Info, D->getBaseName())) return false;
const auto &Accesses = D->getAccesses();
Value *Addr = Info->Storage;
std::string TypeName = Info->TypeName;
diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc
index 9135d6c..f3dadb7 100644
--- a/lib/CodeGen/ExpressionGen.cc
+++ b/lib/CodeGen/ExpressionGen.cc
@@ -45,6 +45,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
reportError("Unknown variable name %s", Var->getName().c_str());
return nullptr;
}
+ if (Info->ConstantValue) return Info->ConstantValue;
if (Info->IsArray) {
return Info->Storage;
}
diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc
index ca8fa45..957a1f5 100644
--- a/lib/CodeGen/FunctionGen.cc
+++ b/lib/CodeGen/FunctionGen.cc
@@ -178,7 +178,7 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) {
}
Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
- const std::function<void(StmtAST*)> &StmtEmitter) {
+ const std::function<void(StmtAST*)> &StmtEmitter, unsigned ScopeID) {
PrototypeAST *Proto = FuncAST->getProto();
Function *TheFunction = emitPrototype(Proto);
@@ -194,8 +194,15 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
std::map<std::string, SymbolInfo> OldSymbols = Symbols;
Symbols.clear();
+ for (const auto &[Name, Info] : OldSymbols) {
+ if (Info.ConstantValue && Info.ScopeID == 0) Symbols.emplace(Name, Info);
+ }
createArgumentAllocas(TheFunction, Proto->getParams());
+ for (const auto &P : Proto->getParams()) {
+ auto It = Symbols.find(P.Name);
+ if (It != Symbols.end()) It->second.ScopeID = ScopeID;
+ }
for (const auto &Stmt : FuncAST->getBody()) {
StmtEmitter(Stmt.get());
diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc
index 8f8711b..8907cfa 100644
--- a/lib/CodeGen/StatementGen.cc
+++ b/lib/CodeGen/StatementGen.cc
@@ -17,9 +17,12 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
// to the emitting function), mirroring FunctionGen's Symbols handling.
auto SavedArrays = Arrays->exchangeTable({});
+ auto SavedScopes = std::move(ConstantScopes);
+ ConstantScopes = {{NextScopeID++, {}}};
FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) {
this->emitStmt(S);
- });
+ }, ConstantScopes.back().ID);
+ ConstantScopes = std::move(SavedScopes);
Arrays->exchangeTable(std::move(SavedArrays));
if (SavedBlock) Builder->SetInsertPoint(SavedBlock);
@@ -83,6 +86,11 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
return;
}
+ if (auto *Const = dynamic_cast<ConstantStmtAST*>(Stmt)) {
+ emitConstantStmt(Const);
+ return;
+ }
+
if (auto *Decl = dynamic_cast<DeclareStmtAST*>(Stmt)) {
emitDeclareStmt(Decl);
return;
@@ -98,6 +106,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
}
return;
}
+ if (!requireWritable(*Info, Assign->getName())) return;
if (Info->IsArray) {
reportError("Cannot assign array %s without indices", Assign->getName().c_str());
return;
@@ -116,6 +125,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
reportError("Unknown variable name %s", In->getName().c_str());
return;
}
+ if (!requireWritable(*Info, In->getName())) return;
if (Info->IsArray) {
reportError("INPUT for entire array %s is not supported", In->getName().c_str());
return;
@@ -204,6 +214,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
reportError("Unknown variable name %s", Read->getVarName().c_str());
return;
}
+ if (!requireWritable(*Info, Read->getVarName())) return;
if (Info->IsArray) {
reportError("READFILE into entire array %s is not supported", Read->getVarName().c_str());
return;
diff --git a/lib/CodeGen/ValueTypeGen.cc b/lib/CodeGen/ValueTypeGen.cc
index 70def81..1ee4a2d 100644
--- a/lib/CodeGen/ValueTypeGen.cc
+++ b/lib/CodeGen/ValueTypeGen.cc
@@ -256,6 +256,8 @@ void CodeGen::emitDeclareStmt(DeclareStmtAST *Stmt) {
return;
}
+ if (!prepareSymbolDeclaration(Stmt->getName())) return;
+
Function *TheFunction = Builder->GetInsertBlock()->getParent();
AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Info->LLVMType, Stmt->getName());
diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc
index fcc9a40..59247cf 100644
--- a/lib/Lexer/Lexer.cc
+++ b/lib/Lexer/Lexer.cc
@@ -70,6 +70,7 @@ int Lexer::readToken() {
while (isalnum((LastChar = Input.get())) || LastChar == '_')
IdentifierStr += static_cast<char>(LastChar);
+ if (IdentifierStr == "CONSTANT") return tok_constant;
if (IdentifierStr == "DECLARE") return tok_declare;
if (IdentifierStr == "INTEGER") return tok_integer_kw;
if (IdentifierStr == "BOOLEAN") return tok_boolean_kw;
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc
index 58422fc..d8fecdc 100644
--- a/lib/Parser/Parser.cc
+++ b/lib/Parser/Parser.cc
@@ -45,7 +45,7 @@ std::vector<std::unique_ptr<StmtAST>> Parser::Parse() {
void Parser::syncToStatementStart() {
while (CurTok != tok_eof) {
switch (CurTok) {
- case tok_declare: case tok_identifier: case tok_input: case tok_output:
+ case tok_constant: case tok_declare: case tok_identifier: case tok_input: case tok_output:
case tok_case: case tok_endcase: case tok_otherwise:
case tok_if: case tok_while: case tok_repeat: case tok_for:
case tok_function: case tok_procedure: case tok_call: case tok_return:
@@ -98,6 +98,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() {
getNextToken();
return nullptr;
}
+ if (CurTok == tok_constant) return ParseConstant();
if (CurTok == tok_declare) {
return ParseDeclare();
}
diff --git a/lib/Parser/ParserType.cc b/lib/Parser/ParserType.cc
index 6c7703c..918b7f6 100644
--- a/lib/Parser/ParserType.cc
+++ b/lib/Parser/ParserType.cc
@@ -297,3 +297,36 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() {
return std::make_unique<DeclareStmtAST>(Name, TypeStr);
}
}
+
+std::unique_ptr<StmtAST> Parser::ParseConstant() {
+ int Line = Lex.getLine();
+ getNextToken();
+ if (CurTok != tok_identifier) {
+ fprintf(stderr, "error: Expected identifier after CONSTANT at line %d\n", Line);
+ return nullptr;
+ }
+ std::string Name = Lex.IdentifierStr;
+ getNextToken();
+ if (CurTok != tok_eq) {
+ fprintf(stderr, "error: Expected '=' in CONSTANT declaration at line %d\n", Line);
+ return nullptr;
+ }
+ getNextToken();
+ bool Negative = CurTok == '-';
+ if (Negative) getNextToken();
+ bool Numeric = CurTok == tok_number_int || CurTok == tok_number_real;
+ bool Literal = Numeric || CurTok == tok_true || CurTok == tok_false ||
+ CurTok == tok_string_literal || CurTok == tok_char_literal;
+ if (!Literal || (Negative && !Numeric)) {
+ fprintf(stderr, "error: CONSTANT initializer must be a literal at line %d\n", Line);
+ return nullptr;
+ }
+ auto Value = ParsePrimary();
+ if (!Value) return nullptr;
+ if (Negative) Value = std::make_unique<UnaryExprAST>('-', std::move(Value));
+ if (GetTokPrecedence() >= 0) {
+ fprintf(stderr, "error: CONSTANT initializer must be a literal, not an expression, at line %d\n", Line);
+ return nullptr;
+ }
+ return std::make_unique<ConstantStmtAST>(std::move(Name), std::move(Value));
+}