summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNagi5Yeq <wu@x-nagi.com>2020-05-30 12:10:38 +0800
committerNagi5Yeq <wu@x-nagi.com>2020-05-30 12:10:38 +0800
commit4c9d2d541c90968db2065260dc94c3be9e8adef9 (patch)
treed9c67d89bb7709bd76ea4809101efbd55dd1a9b0
parent63d2a1c552b0d190a0131c2db2045d154b9ec138 (diff)
use llvm::Function* to call a function for backward compatibility
-rw-r--r--Context.cc13
-rw-r--r--Context.hh8
-rw-r--r--Lexer.l5
-rw-r--r--Parser.y11
-rw-r--r--Type.cc24
-rw-r--r--Type.hh5
-rw-r--r--TypeManager.cc30
-rw-r--r--TypeManager.hh11
-rw-r--r--node/ExprNode.cc7
-rw-r--r--node/FunctionNode.cc16
-rw-r--r--node/FunctionNode.hh4
-rw-r--r--t/trivial.pas18
12 files changed, 113 insertions, 39 deletions
diff --git a/Context.cc b/Context.cc
index 2462b64..b7b5100 100644
--- a/Context.cc
+++ b/Context.cc
@@ -29,17 +29,16 @@ void Context::PushScope(VariableList* scope) { scopes_.push(scope); }
void Context::PopScope() { scopes_.pop(); }
-std::shared_ptr<FunctionType> Context::GetFunctionType(std::string name) {
- decltype(FuncTypes_)::iterator result = FuncTypes_.find(name);
- if (result == FuncTypes_.end()) {
- return nullptr;
+Function Context::FindFunction(std::string name) {
+ decltype(Functions_)::iterator result = Functions_.find(name);
+ if (result == Functions_.end()) {
+ return {nullptr, nullptr};
}
return std::get<1>(*result);
}
-void Context::AddFunctionType(std::string name,
- std::shared_ptr<FunctionType> type) {
- FuncTypes_.insert({name, type});
+void Context ::AddFunction(std::string name, Function func) {
+ Functions_.emplace(name, func);
}
void Context::PushBreakDestination(llvm::BasicBlock* dest) {
diff --git a/Context.hh b/Context.hh
index bc360b4..7829dcf 100644
--- a/Context.hh
+++ b/Context.hh
@@ -11,6 +11,8 @@
#include "VariableList.hh"
namespace pcc {
+using Function = std::pair<std::shared_ptr<FunctionType>, llvm::Function*>;
+
class Context {
public:
Context(const char* name);
@@ -21,8 +23,8 @@ class Context {
VariableList* GetCurrentScope();
void PushScope(VariableList* scope);
void PopScope();
- std::shared_ptr<FunctionType> GetFunctionType(std::string name);
- void AddFunctionType(std::string name, std::shared_ptr<FunctionType> type);
+ Function FindFunction(std::string name);
+ void AddFunction(std::string name, Function func);
// every time we enter a while, repeat or for statement, we push the
// destination of break and continue.
@@ -41,7 +43,7 @@ class Context {
TypeManager TypeManager_;
VariableList globals_;
std::stack<VariableList*> scopes_;
- std::unordered_map<std::string, std::shared_ptr<FunctionType>> FuncTypes_;
+ std::unordered_map<std::string, Function> Functions_;
std::stack<llvm::BasicBlock*> BreakDestinations_;
std::stack<llvm::BasicBlock*> ContinueDestinations_;
// if statments always link then and else block with the endif block, it
diff --git a/Lexer.l b/Lexer.l
index bc35e9f..63808f9 100644
--- a/Lexer.l
+++ b/Lexer.l
@@ -33,7 +33,7 @@ hexadecimal 0[xX][0-9a-fA-F]
integer {decimal}|{octal}|{hexadecimal}
real_exp [0-9]*(\.[0-9]*)?[eE]{decimal}
-real_noexp [0-9]*\.[0-9]*
+real_noexp [0-9]*\.[0-9]+
real {real_exp}|{real_noexp}
@@ -64,6 +64,7 @@ white [\t\f\r ]
":=" {return Parser::make_ASSIGN(loc);}
":" {return Parser::make_COLON(loc);}
";" {return Parser::make_SEMICOLON(loc);}
+".." {return Parser::make_DOTDOT(loc);}
"." {return Parser::make_DOT(loc);}
"," {return Parser::make_COMMA(loc);}
"[" {return Parser::make_LBRACKET(loc);}
@@ -116,6 +117,8 @@ white [\t\f\r ]
"integer" {return Parser::make_INTEGER(loc);}
"real" {return Parser::make_REAL(loc);}
"string" {return Parser::make_STRING(loc);}
+"array" {return Parser::make_ARRAY(loc);}
+"of" {return Parser::make_OF(loc);}
"true" {return Parser::make_BOOLEAN_LITERAL(true, loc);}
"false" {return Parser::make_BOOLEAN_LITERAL(false, loc);}
diff --git a/Parser.y b/Parser.y
index 921e81c..d6f33c9 100644
--- a/Parser.y
+++ b/Parser.y
@@ -41,16 +41,16 @@ YY_DECL;
%define parse.assert
%token FILE_END 0;
-%token COLON SEMICOLON COMMA DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS
+%token COLON SEMICOLON COMMA DOTDOT DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS
%token PROGRAM IDENTIFIER CONST VAR BEGINS ENDS FUNCTION
%token IF THEN ELSE WHILE DO REPEAT UNTIL BREAK CONTINUE
-%token VOID BOOLEAN CHAR INTEGER REAL STRING
+%token VOID BOOLEAN CHAR INTEGER REAL STRING ARRAY OF
%token ADD SUB MUL REAL_DIV DIV MOD LT LE GT GE EQ NE CARET AT
%token AND NOT OR XOR SHL SHR
%token INTEGER_LITERAL REAL_LITERAL STRING_LITERAL BOOLEAN_LITERAL CHAR_LITERAL
%type <std::string> IDENTIFIER program_header
-%type <std::shared_ptr<pcc::Type>> type
+%type <std::shared_ptr<pcc::Type>> type array_type
%type <std::list<Declaration>> var_decls
%type <std::pair<std::list<std::string>, std::shared_ptr<pcc::Type>>> var_decl
%type <std::list<std::string>> vars
@@ -149,6 +149,11 @@ type
| REAL {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::REAL);}
| STRING {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::STRING);}
| CARET type {$$=ctx->GetTypeManager()->GetPointerType($2);}
+ | array_type {$$=$1;}
+ ;
+
+array_type
+ : ARRAY LBRACKET literal DOTDOT literal RBRACKET OF type {$$=ctx->GetTypeManager()->CreateArrayType($8, $3, $5);}
;
/* ==================[function part]================== */
diff --git a/Type.cc b/Type.cc
index 90a498e..14146d4 100644
--- a/Type.cc
+++ b/Type.cc
@@ -276,15 +276,16 @@ Value RealType::CreateUnaryOperation(UnaryOperator op, Value v,
return (this->*operations[ToUnderlying(op)])(v, context);
}
-ArrayType::ArrayType(std::shared_ptr<Type> ElementType, int ElementNumber,
+ArrayType::ArrayType(std::shared_ptr<Type> ElementType, uint64_t ElementNumber,
std::shared_ptr<Type> IndexType, Value start, Value end,
- std::string&& name)
- : Type(std::move(name), llvm::ArrayType::get(ElementType->GetLLVMType(),
- (uint64_t) ElementNumber))
+ std::string&& name, bool IsZeroStarted)
+ : Type(std::move(name),
+ llvm::ArrayType::get(ElementType->GetLLVMType(), ElementNumber))
, ElementType_(ElementType)
, IndexType_(IndexType)
, start_(start)
- , end_(end) {}
+ , end_(end)
+ , IsZeroStarted_(IsZeroStarted) {}
std::shared_ptr<Type> ArrayType::GetElementType() { return ElementType_; }
std::shared_ptr<Type> ArrayType::GetIndexType() { return IndexType_; }
@@ -298,10 +299,15 @@ Value ArrayType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
}
Value ArrayType::CreateArrayAccess(Value v0, Value v1, Context* context) {
- Value indices[2] = {
- llvm::ConstantInt::get(IndexType_->GetLLVMType(), 0, true),
- IndexType_->CreateBinaryOperation(BinaryOperator::SUB, v1, start_,
- context)};
+ Value Zero = llvm::ConstantInt::get(IndexType_->GetLLVMType(), 0, true);
+ Value indices[2] = {Zero};
+ if (IsZeroStarted_ == false) {
+ indices[1] = IndexType_->CreateBinaryOperation(BinaryOperator::SUB, v1,
+ start_, context);
+ } else {
+ // saves a sub
+ indices[1] = v1;
+ }
return context->GetBuilder()->CreateInBoundsGEP(v0, indices);
}
diff --git a/Type.hh b/Type.hh
index 3bfd733..c841b74 100644
--- a/Type.hh
+++ b/Type.hh
@@ -152,9 +152,9 @@ class RealType : public Type {
class ArrayType : public Type {
public:
- ArrayType(std::shared_ptr<Type> ElementType, int ElementNumber,
+ ArrayType(std::shared_ptr<Type> ElementType, uint64_t ElementNumber,
std::shared_ptr<Type> IndexType, Value start, Value end,
- std::string&& name);
+ std::string&& name, bool IsZeroStarted = false);
std::shared_ptr<Type> GetElementType();
std::shared_ptr<Type> GetIndexType();
virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
@@ -165,6 +165,7 @@ class ArrayType : public Type {
std::shared_ptr<Type> ElementType_;
std::shared_ptr<Type> IndexType_;
+ bool IsZeroStarted_;
Value start_, end_;
};
diff --git a/TypeManager.cc b/TypeManager.cc
index c4c9c10..55b172e 100644
--- a/TypeManager.cc
+++ b/TypeManager.cc
@@ -1,5 +1,6 @@
#include "TypeManager.hh"
#include "Context.hh"
+#include "ExprNode.hh"
#include "Log.hh"
namespace pcc {
@@ -195,6 +196,35 @@ std::shared_ptr<PointerType>
return NewType;
}
+std::shared_ptr<ArrayType>
+ TypeManager::CreateArrayType(std::shared_ptr<Type> ElementType,
+ std::shared_ptr<ExprNode> start,
+ std::shared_ptr<ExprNode> end) {
+ llvm::Constant* StartValue = llvm::cast<llvm::Constant>(start->CodeGen());
+ llvm::Constant* EndValue = llvm::cast<llvm::Constant>(end->CodeGen());
+ std::shared_ptr<Type> IndexType = start->GetType();
+ if (IndexType != end->GetType()) {
+ Log(LogLevel::PCC_ERROR,
+ "the start and end indices of an array type must be same "
+ "(start=%s, end=%s)",
+ IndexType->GetCommonName(), end->GetType()->GetCommonName());
+ return nullptr;
+ }
+ if (std::dynamic_pointer_cast<IntegerBaseType>(IndexType) == nullptr) {
+ Log(LogLevel::PCC_ERROR,
+ "array index must have a integer-like type (i.e. integer, char)");
+ return nullptr;
+ }
+ uint64_t StartIndex = StartValue->getUniqueInteger().getZExtValue();
+ uint64_t ElementNumber =
+ EndValue->getUniqueInteger().getZExtValue() - StartIndex + 1;
+ std::shared_ptr<ArrayType> NewType = std::make_shared<ArrayType>(
+ ElementType, ElementNumber, IndexType, StartValue, EndValue,
+ std::string(ElementType->GetCommonName()) + "[]", StartIndex == 0);
+ ArrayTypes_.push_back(NewType);
+ return NewType;
+}
+
std::shared_ptr<FunctionType> TypeManager::CreateFunctionType(
std::shared_ptr<Type> ReturnType,
std::vector<std::shared_ptr<Type>> ArgTypes) {
diff --git a/TypeManager.hh b/TypeManager.hh
index e6cd2c0..ce9cfee 100644
--- a/TypeManager.hh
+++ b/TypeManager.hh
@@ -9,6 +9,8 @@
#include "Type.hh"
namespace pcc {
+class ExprNode;
+
enum class BuiltinType {
VOID,
BOOLEAN,
@@ -24,10 +26,19 @@ class TypeManager {
TypeManager();
std::shared_ptr<Type> GetBuiltinType(BuiltinType type);
+ // if call this function twice with the same ElementType, it will return the
+ // same shared_ptr to the Type.
std::shared_ptr<PointerType>
GetPointerType(std::shared_ptr<Type> ElementType,
const char* CustomName = nullptr);
+ // array types and function types are considered unique, unless use type
+ // alias, you can't get the same type as previous call to this function.
+ std::shared_ptr<ArrayType>
+ CreateArrayType(std::shared_ptr<Type> ElementType,
+ std::shared_ptr<ExprNode> start,
+ std::shared_ptr<ExprNode> end);
+
std::shared_ptr<FunctionType>
CreateFunctionType(std::shared_ptr<Type> ReturnType,
std::vector<std::shared_ptr<Type>> ArgTypes);
diff --git a/node/ExprNode.cc b/node/ExprNode.cc
index 93f0068..f4a26a8 100644
--- a/node/ExprNode.cc
+++ b/node/ExprNode.cc
@@ -95,14 +95,13 @@ FunctionCallNode::FunctionCallNode(Context* context, const std::string& name,
Value FunctionCallNode::CodeGen() {
TypeManager* manager = context_->GetTypeManager();
- std::shared_ptr<FunctionType> type = context_->GetFunctionType(name_);
+ Function function = context_->FindFunction(name_);
+ std::shared_ptr<FunctionType> type = std::get<0>(function);
if (type == nullptr) {
Log(LogLevel::PCC_ERROR, "call to undefined function %s",
name_.c_str());
return nullptr;
}
- llvm::FunctionCallee fp = context_->GetModule()->getOrInsertFunction(
- name_, llvm::cast<llvm::FunctionType>(type->GetLLVMType()));
const std::vector<std::shared_ptr<Type>>& ArgTypes = type->GetArgTypes();
std::vector<Value> ArgValues(args_.size());
auto ArgTypeIt = ArgTypes.begin();
@@ -121,6 +120,6 @@ Value FunctionCallNode::CodeGen() {
++ArgTypeIt, ++ArgValueIt;
}
type_ = type->GetReturnType();
- return context_->GetBuilder()->CreateCall(fp, ArgValues);
+ return context_->GetBuilder()->CreateCall(std::get<1>(function), ArgValues);
}
} // namespace pcc
diff --git a/node/FunctionNode.cc b/node/FunctionNode.cc
index f6810fd..736007b 100644
--- a/node/FunctionNode.cc
+++ b/node/FunctionNode.cc
@@ -12,12 +12,12 @@ namespace pcc {
FunctionNode::FunctionNode(
Context* context, std::string&& name, std::list<Declaration>&& arguments,
std::list<std::shared_ptr<DeclNode>>&& LocalDeclarations,
- std::shared_ptr<Type> type, std::shared_ptr<StatementListNode> body)
+ std::shared_ptr<Type> ReturnType, std::shared_ptr<StatementListNode> body)
: BaseNode(context)
, name_(std::move(name))
, arguments_(std::move(arguments))
, LocalDeclarations_(std::move(LocalDeclarations))
- , type_(type)
+ , ReturnType_(ReturnType)
, locals_(context->GetGlobals())
, body_(body) {
for (auto&& decl : LocalDeclarations_) {
@@ -33,13 +33,13 @@ Value FunctionNode::CodeGen() {
std::transform(arguments_.cbegin(), arguments_.cend(), params.begin(),
[](const Declaration& decl) { return std::get<1>(decl); });
std::shared_ptr<FunctionType> type =
- manager->CreateFunctionType(type_, params);
- context_->AddFunctionType(name_, type);
+ manager->CreateFunctionType(ReturnType_, params);
llvm::FunctionType* LLVMType =
llvm::cast<llvm::FunctionType>(type->GetLLVMType());
llvm::Function* function = llvm::Function::Create(
LLVMType, llvm::GlobalValue::ExternalLinkage, name_, *module);
function->setCallingConv(llvm::CallingConv::C);
+ context_->AddFunction(name_, {type, function});
llvm::BasicBlock* block =
llvm::BasicBlock::Create(GlobalLLVMContext, name_, function);
Log(LogLevel::PCC_INFO, "generating function %s of type %s", name_.c_str(),
@@ -57,17 +57,17 @@ Value FunctionNode::CodeGen() {
decl->CodeGen();
}
Value rv = nullptr;
- bool IsVoid = type_ == manager->GetBuiltinType(BuiltinType::VOID);
+ bool IsVoid = ReturnType_ == manager->GetBuiltinType(BuiltinType::VOID);
if (IsVoid == false) {
// create a variable with the same name as the function for return value
- rv = builder->CreateAlloca(type_->GetLLVMType());
- locals_.Add(name_, {type_, rv});
+ rv = builder->CreateAlloca(ReturnType_->GetLLVMType());
+ locals_.Add(name_, {ReturnType_, rv});
}
// push the function scope variables
context_->PushScope(&locals_);
body_->CodeGen();
if (IsVoid == false) {
- builder->CreateRet(builder->CreateLoad(type_->GetLLVMType(), rv));
+ builder->CreateRet(builder->CreateLoad(ReturnType_->GetLLVMType(), rv));
} else {
builder->CreateRetVoid();
}
diff --git a/node/FunctionNode.hh b/node/FunctionNode.hh
index 415c2cc..d317402 100644
--- a/node/FunctionNode.hh
+++ b/node/FunctionNode.hh
@@ -13,7 +13,7 @@ class FunctionNode : public BaseNode {
FunctionNode(Context* context, std::string&& name,
std::list<Declaration>&& arguments,
std::list<std::shared_ptr<DeclNode>>&& LocalDeclarations,
- std::shared_ptr<Type> type,
+ std::shared_ptr<Type> ReturnType,
std::shared_ptr<StatementListNode> body);
virtual Value CodeGen() override;
@@ -21,7 +21,7 @@ class FunctionNode : public BaseNode {
std::string name_;
std::list<Declaration> arguments_;
std::list<std::shared_ptr<DeclNode>> LocalDeclarations_;
- std::shared_ptr<Type> type_;
+ std::shared_ptr<Type> ReturnType_;
VariableList locals_;
std::shared_ptr<StatementListNode> body_;
};
diff --git a/t/trivial.pas b/t/trivial.pas
index dd98fad..560bb94 100644
--- a/t/trivial.pas
+++ b/t/trivial.pas
@@ -42,6 +42,24 @@ begin
string_test:=s[b-a]
end;
+function array_test():integer;
+var
+ ai:array['a'..'z'] of integer;
+ ac:array[0..25] of char;
+ i:integer;
+ c:char;
+begin
+ i:=0;
+ c:='z';
+ repeat
+ begin
+ ac[i]:=c;
+ ai[c]:=i;
+ i:=i+1;
+ c:=c-1
+ end until i>25;
+end;
+
function pointer_test():integer;
var
a,b:integer;