summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNagi5Yeq <wu@x-nagi.com>2020-05-31 13:11:44 +0800
committerNagi5Yeq <wu@x-nagi.com>2020-05-31 13:11:44 +0800
commit4a5bc55769804d003d6cd9f8c16eefb76bb53d1b (patch)
tree365756351275152391a812440f6a76b9f92cc854
parentbd44c9eaef1f4dcbbd98d4489885566b6c7e5138 (diff)
full support of array, pointer and record stuffs
-rw-r--r--Lexer.l3
-rw-r--r--Parser.y25
-rw-r--r--Type.cc27
-rw-r--r--Type.hh11
-rw-r--r--TypeIdentifier.cc21
-rw-r--r--TypeIdentifier.hh12
-rw-r--r--TypeManager.cc19
-rw-r--r--TypeManager.hh6
-rw-r--r--node/ExprNode.cc56
-rw-r--r--node/ExprNode.hh20
-rw-r--r--t/trivial.pas37
11 files changed, 227 insertions, 10 deletions
diff --git a/Lexer.l b/Lexer.l
index 39603e2..d3e6f29 100644
--- a/Lexer.l
+++ b/Lexer.l
@@ -28,7 +28,7 @@ namespace pcc {
decimal ([1-9][0-9]*)|0
octal 0[0-7]*
-hexadecimal 0[xX][0-9a-fA-F]
+hexadecimal 0[xX][0-9a-fA-F]+
integer {decimal}|{octal}|{hexadecimal}
@@ -120,6 +120,7 @@ white [\t\f\r ]
"string" {return Parser::make_STRING(loc);}
"array" {return Parser::make_ARRAY(loc);}
"of" {return Parser::make_OF(loc);}
+"record" {return Parser::make_RECORD(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 6f2b9a2..eeda0c7 100644
--- a/Parser.y
+++ b/Parser.y
@@ -45,7 +45,7 @@ YY_DECL;
%token COLON SEMICOLON COMMA DOTDOT DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS
%token PROGRAM IDENTIFIER VAR CONST TYPE BEGINS ENDS FUNCTION
%token IF THEN ELSE WHILE DO REPEAT UNTIL BREAK CONTINUE
-%token VOID BOOLEAN CHAR INTEGER REAL STRING ARRAY OF
+%token VOID BOOLEAN CHAR INTEGER REAL STRING ARRAY OF RECORD
%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
@@ -57,9 +57,9 @@ YY_DECL;
%type <std::list<std::string>> vars
%type <std::list<pcc::Constant>> const_decls
%type <pcc::Constant> const_decl
-%type <std::list<pcc::Declaration>> type_decls
-%type <pcc::Declaration> type_decl
-%type <std::shared_ptr<TypeIdentifier>> type array_type
+%type <std::list<pcc::Declaration>> type_decls member_decls
+%type <pcc::Declaration> type_decl member_decl
+%type <std::shared_ptr<TypeIdentifier>> type array_type record_type
%type <bool> BOOLEAN_LITERAL
%type <char> CHAR_LITERAL
@@ -169,6 +169,7 @@ type
| STRING {$$=std::make_shared<TrivialTypeIdentifier>(ctx, ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::STRING));}
| CARET type {$$=std::make_shared<PointerTypeIdentifier>(ctx, $2);}
| array_type {$$=$1;}
+ | record_type {$$=$1;}
| IDENTIFIER {$$=std::make_shared<AliasTypeIdentifier>(ctx, std::move($1));}
;
@@ -176,6 +177,19 @@ array_type
: ARRAY LBRACKET literal DOTDOT literal RBRACKET OF type {$$=std::make_shared<ArrayTypeIdentifier>(ctx, $8, $3, $5);}
;
+record_type
+ : RECORD member_decls ENDS {$$=std::make_shared<pcc::RecordTypeIdentifier>(ctx, std::move($2));}
+ ;
+
+member_decls
+ : member_decls SEMICOLON member_decl {$$=std::move($1); $$.push_back($3);}
+ | member_decl {$$.push_back($1);}
+ ;
+
+member_decl
+ : IDENTIFIER COLON type {$$={$1, $3};}
+ ;
+
/* ==================[function part]================== */
function
@@ -266,7 +280,8 @@ lvalue
: IDENTIFIER {$$=std::make_shared<pcc::IdentifierNode>(ctx, $1);}
| lvalue LBRACKET expression RBRACKET {$$=std::make_shared<pcc::ArrayAccessNode>(ctx, $1, $3);}
| rvalue LBRACKET expression RBRACKET {$$=std::make_shared<pcc::PointerAccessNode>(ctx, $1, $3);}
- | standalone DOT IDENTIFIER
+ | lvalue DOT IDENTIFIER {$$=std::make_shared<pcc::MemberAccessNode>(ctx, $1, std::move($3));}
+ | standalone CARET {$$=std::make_shared<pcc::DereferenceNode>(ctx, $1);}
;
function_call
diff --git a/Type.cc b/Type.cc
index 95e529d..7ad0352 100644
--- a/Type.cc
+++ b/Type.cc
@@ -1,6 +1,7 @@
#include <llvm/IR/InstrTypes.h>
#include "Context.hh"
+#include "Log.hh"
#include "Type.hh"
namespace pcc {
@@ -350,4 +351,30 @@ std::shared_ptr<Type> FunctionType::GetReturnType() { return ReturnType_; }
std::vector<std::shared_ptr<Type>> FunctionType::GetArgTypes() {
return ArgTypes_;
}
+
+RecordType::RecordType(const std::vector<RecordMember>& members,
+ std::string&& name)
+ : Type(std::move(name), nullptr) {
+ int i = 0;
+ for (auto&& member : members) {
+ members_.insert({std::get<0>(member), {i++, std::get<1>(member)}});
+ }
+ std::vector<llvm::Type*> MemberTypes(members.size());
+ std::transform(
+ members.cbegin(), members.cend(), MemberTypes.begin(),
+ [](const std::pair<std::string, std::shared_ptr<Type>>& member) {
+ return std::get<1>(member)->GetLLVMType();
+ });
+ LLVMType_ = llvm::StructType::create(MemberTypes, "record", false);
+}
+
+std::pair<int, std::shared_ptr<Type>>
+ RecordType::GetMember(const std::string& name) {
+ decltype(members_.end()) result = members_.find(name);
+ if (result == members_.end()) {
+ Log(LogLevel::PCC_ERROR, "the member %s doesn't exist", name.c_str());
+ return {0, nullptr};
+ }
+ return std::get<1>(*result);
+}
} // namespace pcc
diff --git a/Type.hh b/Type.hh
index e11a9ea..b686e28 100644
--- a/Type.hh
+++ b/Type.hh
@@ -197,6 +197,17 @@ class FunctionType : public Type {
std::shared_ptr<Type> ReturnType_;
std::vector<std::shared_ptr<Type>> ArgTypes_;
};
+
+using RecordMember = std::pair<std::string, std::shared_ptr<Type>>;
+
+class RecordType : public Type {
+ public:
+ RecordType(const std::vector<RecordMember>& members, std::string&& name);
+ std::pair<int, std::shared_ptr<Type>> GetMember(const std::string& name);
+
+ protected:
+ std::map<std::string, std::pair<int, std::shared_ptr<Type>>> members_;
+};
} // namespace pcc
#endif // PCC_TYPE_H
diff --git a/TypeIdentifier.cc b/TypeIdentifier.cc
index 8f6894b..3a249da 100644
--- a/TypeIdentifier.cc
+++ b/TypeIdentifier.cc
@@ -54,4 +54,23 @@ std::shared_ptr<Type> ArrayTypeIdentifier::GetType() {
}
return type_;
}
-} // namespace pcc \ No newline at end of file
+
+RecordTypeIdentifier::RecordTypeIdentifier(Context* context,
+ std::list<Declaration>&& members)
+ : TypeIdentifier(context)
+ , members_(std::move(members)) {}
+
+std::shared_ptr<Type> RecordTypeIdentifier::GetType() {
+ if (type_ == nullptr) {
+ std::vector<RecordMember> MemberTypes(members_.size());
+ std::transform(members_.cbegin(), members_.cend(), MemberTypes.begin(),
+ [](const Declaration& member) {
+ return std::make_pair(
+ std::get<0>(member),
+ std::get<1>(member)->GetType());
+ });
+ type_ = context_->GetTypeManager()->CreateRecordType(MemberTypes);
+ }
+ return type_;
+}
+} // namespace pcc
diff --git a/TypeIdentifier.hh b/TypeIdentifier.hh
index c939dcc..88b208a 100644
--- a/TypeIdentifier.hh
+++ b/TypeIdentifier.hh
@@ -1,8 +1,11 @@
#ifndef PCC_TYPEIDENTIFIER_HH
#define PCC_TYPEIDENTIFIER_HH
+#include <list>
+
#include "Context.hh"
#include "Type.hh"
+#include "VariableList.hh"
namespace pcc {
@@ -57,6 +60,15 @@ class ArrayTypeIdentifier : public TypeIdentifier {
std::shared_ptr<ExprNode> start_;
std::shared_ptr<ExprNode> end_;
};
+
+class RecordTypeIdentifier : public TypeIdentifier {
+ public:
+ RecordTypeIdentifier(Context* context, std::list<Declaration>&& members);
+ virtual std::shared_ptr<Type> GetType() override;
+
+ protected:
+ std::list<Declaration> members_;
+};
} // namespace pcc
#endif // !PCC_TYPEIDENTIFIER_HH
diff --git a/TypeManager.cc b/TypeManager.cc
index 4a510eb..977d3bc 100644
--- a/TypeManager.cc
+++ b/TypeManager.cc
@@ -205,11 +205,28 @@ std::shared_ptr<ArrayType>
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);
+ std::string(ElementType->GetCommonName()) + "[" +
+ std::to_string(ElementNumber) + "]",
+ StartIndex == 0);
ArrayTypes_.push_back(NewType);
return NewType;
}
+std::shared_ptr<RecordType>
+ TypeManager::CreateRecordType(const std::vector<RecordMember>& members) {
+ std::string name = "record {";
+ std::vector<RecordMember>::const_iterator MemberIt = members.cbegin();
+ name.append(std::get<1>(*MemberIt)->GetCommonName());
+ for (++MemberIt; MemberIt != members.cend(); ++MemberIt) {
+ name.append(", ");
+ name.append(std::get<1>(*MemberIt)->GetCommonName());
+ }
+ std::shared_ptr<RecordType> NewType =
+ std::make_shared<RecordType>(members, name + "}");
+ RecordTypes_.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 13a98a1..099b505 100644
--- a/TypeManager.hh
+++ b/TypeManager.hh
@@ -34,8 +34,11 @@ class TypeManager {
GetPointerType(std::shared_ptr<Type> ElementType,
const char* CustomName = nullptr);
- // array types and function types are considered unique, unless use type
+ // record, array 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<RecordType>
+ CreateRecordType(const std::vector<RecordMember>& members);
+
std::shared_ptr<ArrayType>
CreateArrayType(std::shared_ptr<Type> ElementType,
std::shared_ptr<ExprNode> start,
@@ -63,6 +66,7 @@ class TypeManager {
std::map<std::shared_ptr<Type>, std::shared_ptr<PointerType>> PointerTypes_;
std::vector<std::shared_ptr<FunctionType>> FunctionTypes_;
std::vector<std::shared_ptr<ArrayType>> ArrayTypes_;
+ std::vector<std::shared_ptr<RecordType>> RecordTypes_;
// if we are porting to some 64-bit machines, we can change these types to
// 64-bit type, in order to make pointers behave correctly
diff --git a/node/ExprNode.cc b/node/ExprNode.cc
index e15d39e..13a85e9 100644
--- a/node/ExprNode.cc
+++ b/node/ExprNode.cc
@@ -152,6 +152,62 @@ Value ArrayAccessNode::CodeGen() {
return nullptr;
}
+DereferenceNode::DereferenceNode(Context* context,
+ std::shared_ptr<ExprNode> lhs)
+ : ExprNode(context)
+ , lhs_(lhs) {}
+
+Value DereferenceNode::CodeGen() {
+ Value value = lhs_->CodeGen();
+ std::shared_ptr<PointerType> pointer =
+ std::dynamic_pointer_cast<PointerType>(lhs_->GetType());
+ if (pointer == nullptr) {
+ Log(LogLevel::PCC_ERROR, "type %s is not a valid type for dereference",
+ lhs_->GetType()->GetCommonName());
+ return nullptr;
+ }
+ Value zero = llvm::ConstantInt::get(
+ context_->GetTypeManager()->GetPointerIndexType_()->GetLLVMType(), 0);
+ type_ = pointer;
+ return context_->GetBuilder()->CreateInBoundsGEP(value, zero);
+}
+
+MemberAccessNode::MemberAccessNode(Context* context,
+ std::shared_ptr<ExprNode> lhs,
+ std::string&& rhs)
+ : ExprNode(context)
+ , lhs_(lhs)
+ , rhs_(std::move(rhs)) {}
+
+Value MemberAccessNode::CodeGen() {
+ llvm::IRBuilder<>* builder = context_->GetBuilder();
+ TypeManager* manager = context_->GetTypeManager();
+ Value left = lhs_->CodeGen();
+ std::shared_ptr<PointerType> LeftType =
+ std::dynamic_pointer_cast<PointerType>(lhs_->GetType());
+ if (LeftType == nullptr) {
+ Log(LogLevel::PCC_ERROR,
+ "type %s is not a valid type for member access",
+ lhs_->GetType()->GetCommonName());
+ return nullptr;
+ }
+ std::shared_ptr<RecordType> LeftInner =
+ std::dynamic_pointer_cast<RecordType>(LeftType->GetElementType());
+ if (LeftInner == nullptr) {
+ Log(LogLevel::PCC_ERROR, "type %s is not a record type",
+ LeftType->GetElementType()->GetCommonName());
+ return nullptr;
+ }
+ int MemberIndex;
+ std::shared_ptr<Type> MemberType;
+ std::tie(MemberIndex, MemberType) = LeftInner->GetMember(rhs_);
+ llvm::Type* IndexLLLVMType = manager->GetPointerIndexType_()->GetLLVMType();
+ Value indices[2] = {llvm::ConstantInt::get(IndexLLLVMType, 0),
+ llvm::ConstantInt::get(IndexLLLVMType, MemberIndex)};
+ type_ = manager->GetPointerType(MemberType);
+ return builder->CreateInBoundsGEP(left, indices);
+}
+
IdentifierNode::IdentifierNode(Context* context, const std::string& name)
: ExprNode(context)
, name_(name) {}
diff --git a/node/ExprNode.hh b/node/ExprNode.hh
index bf24f4d..aeb3ef8 100644
--- a/node/ExprNode.hh
+++ b/node/ExprNode.hh
@@ -84,6 +84,26 @@ class ArrayAccessNode : public ExprNode {
std::shared_ptr<ExprNode> rhs_;
};
+class DereferenceNode : public ExprNode {
+ public:
+ DereferenceNode(Context* context, std::shared_ptr<ExprNode> lhs);
+ virtual Value CodeGen() override;
+
+ protected:
+ std::shared_ptr<ExprNode> lhs_;
+};
+
+class MemberAccessNode : public ExprNode {
+ public:
+ MemberAccessNode(Context* context, std::shared_ptr<ExprNode> lhs,
+ std::string&& rhs);
+ virtual Value CodeGen() override;
+
+ protected:
+ std::shared_ptr<ExprNode> lhs_;
+ std::string rhs_;
+};
+
class IdentifierNode : public ExprNode {
public:
IdentifierNode(Context* context, const std::string& name);
diff --git a/t/trivial.pas b/t/trivial.pas
index 5d20d5f..2795e2e 100644
--- a/t/trivial.pas
+++ b/t/trivial.pas
@@ -175,11 +175,46 @@ type
a1=integer;
a2=array[0..9] of a1;
a3=array[0..9] of a2;
+ rt=record
+ m1:integer;
+ m2:array[1..10] of integer;
+ m3:real
+ end;
var
i:a1;
arr:a3;
+ p:^a2;
+ arr2:array[0..9] of array[0..99] of array[0..9] of integer;
+ r:rt;
begin
i:=4;
arr[i][i]:=i;
- alias_test:=arr[i][i]*i;
+ p:=@arr[i];
+ p[0][i]:=p[0][i]+1;
+ arr2[0][1][2]:=123;
+ alias_test:=arr2[0][1][2]+arr[i][i]*i;
+end;
+
+function record_test():integer;
+type
+ t1=record
+ m1:integer;
+ m2:char;
+ m3:array[2..6] of real;
+ m4: array[1..2] of record
+ m1:array[0..2] of integer;
+ m2:boolean
+ end
+ end;
+var
+ a:t1;
+ pa:^t1;
+begin
+ a.m1:=2;
+ a.m2:='t';
+ a.m3[2]:=6.66;
+ pa:=@a;
+ pa[0].m3[6]:=7.77;
+ pa^.m4[1].m1[2]:=1234;
+ record_test:=a.m3[6]+pa^.m3[a.m1]+a.m4[1].m1[2];
end;