diff options
| author | Nagi5Yeq <wu@x-nagi.com> | 2020-05-31 13:11:44 +0800 |
|---|---|---|
| committer | Nagi5Yeq <wu@x-nagi.com> | 2020-05-31 13:11:44 +0800 |
| commit | 4a5bc55769804d003d6cd9f8c16eefb76bb53d1b (patch) | |
| tree | 365756351275152391a812440f6a76b9f92cc854 | |
| parent | bd44c9eaef1f4dcbbd98d4489885566b6c7e5138 (diff) | |
full support of array, pointer and record stuffs
| -rw-r--r-- | Lexer.l | 3 | ||||
| -rw-r--r-- | Parser.y | 25 | ||||
| -rw-r--r-- | Type.cc | 27 | ||||
| -rw-r--r-- | Type.hh | 11 | ||||
| -rw-r--r-- | TypeIdentifier.cc | 21 | ||||
| -rw-r--r-- | TypeIdentifier.hh | 12 | ||||
| -rw-r--r-- | TypeManager.cc | 19 | ||||
| -rw-r--r-- | TypeManager.hh | 6 | ||||
| -rw-r--r-- | node/ExprNode.cc | 56 | ||||
| -rw-r--r-- | node/ExprNode.hh | 20 | ||||
| -rw-r--r-- | t/trivial.pas | 37 |
11 files changed, 227 insertions, 10 deletions
@@ -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);} @@ -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 @@ -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 @@ -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; |
