diff options
| -rw-r--r-- | Lexer.l | 4 | ||||
| -rw-r--r-- | Parser.y | 7 | ||||
| -rw-r--r-- | Type.cc | 11 | ||||
| -rw-r--r-- | Type.hh | 4 | ||||
| -rw-r--r-- | TypeIdentifier.hh | 4 | ||||
| -rw-r--r-- | TypeManager.cc | 14 | ||||
| -rw-r--r-- | TypeManager.hh | 7 | ||||
| -rw-r--r-- | node/BaseNode.cc | 1 | ||||
| -rw-r--r-- | node/ExprNode.cc | 28 | ||||
| -rw-r--r-- | node/FunctionNode.cc | 30 | ||||
| -rw-r--r-- | node/FunctionNode.hh | 12 | ||||
| -rw-r--r-- | t/extern.pas | 15 |
12 files changed, 109 insertions, 28 deletions
@@ -46,7 +46,7 @@ char_value {trival_char}|{escaped_char}|{hex_char}|{oct_char}|\\' char '{char_value}' string '{char_value}+' -identifier [a-z][0-9a-z_]* +identifier [a-z_][0-9a-z_]* white [\t\f\r ] @@ -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_DOTDOTDOT(loc);} ".." {return Parser::make_DOTDOT(loc);} "." {return Parser::make_DOT(loc);} "," {return Parser::make_COMMA(loc);} @@ -99,6 +100,7 @@ white [\t\f\r ] "end" {return Parser::make_ENDS(loc);} "program" {return Parser::make_PROGRAM(loc);} "function" {return Parser::make_FUNCTION(loc);} +"extern" {return Parser::make_EXTERN(loc);} "var" {return Parser::make_VAR(loc);} "const" {return Parser::make_CONST(loc);} "type" {return Parser::make_TYPE(loc);} @@ -43,7 +43,7 @@ YY_DECL; %token FILE_END 0; %token COLON SEMICOLON COMMA DOTDOT DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS -%token PROGRAM IDENTIFIER VAR CONST TYPE BEGINS ENDS FUNCTION +%token PROGRAM IDENTIFIER VAR CONST TYPE BEGINS ENDS FUNCTION EXTERN DOTDOTDOT %token IF THEN ELSE WHILE DO REPEAT UNTIL BREAK CONTINUE %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 @@ -174,7 +174,7 @@ type ; array_type - : ARRAY LBRACKET literal DOTDOT literal RBRACKET OF type {$$=std::make_shared<ArrayTypeIdentifier>(ctx, $8, $3, $5);} + : ARRAY LBRACKET literal DOTDOT literal RBRACKET OF type {$$=std::make_shared<ArrayTypeIdentifier>(ctx, $8, $3, $5);} ; record_type @@ -195,6 +195,9 @@ member_decl function : FUNCTION IDENTIFIER LPARENTHESIS var_decls RPARENTHESIS COLON type SEMICOLON decls statement_block {$$=std::make_shared<pcc::FunctionNode>(ctx, std::move($2), std::move($4), std::move($9), $7, $10);} | FUNCTION IDENTIFIER LPARENTHESIS RPARENTHESIS COLON type SEMICOLON decls statement_block {$$=std::make_shared<pcc::FunctionNode>(ctx, std::move($2), std::list<Declaration>(), std::move($8), $6, $9);} + | EXTERN IDENTIFIER LPARENTHESIS var_decls RPARENTHESIS COLON type {$$=std::make_shared<pcc::ExternNode>(ctx, std::move($2), std::move($4), $7, false);} + | EXTERN IDENTIFIER LPARENTHESIS RPARENTHESIS COLON type {$$=std::make_shared<pcc::ExternNode>(ctx, std::move($2), std::list<Declaration>(), $6, false);} + | EXTERN IDENTIFIER LPARENTHESIS var_decls COMMA DOTDOTDOT RPARENTHESIS COLON type {$$=std::make_shared<pcc::ExternNode>(ctx, std::move($2), std::move($4), $9, true);} ; /* ==================[statements part]================== */ @@ -334,16 +334,17 @@ Value PointerType::CreatePointerSub(Value v0, Value v1, Context* context) { FunctionType::FunctionType(std::shared_ptr<Type> ReturnType, std::vector<std::shared_ptr<Type>> ArgTypes, - std::string&& name) + std::string&& name, bool IsVariadic) : Type(std::move(name), nullptr) , ReturnType_(ReturnType) - , ArgTypes_(ArgTypes) { + , ArgTypes_(ArgTypes) + , IsVariadic_(IsVariadic) { std::vector<llvm::Type*> params(ArgTypes_.size()); std::transform( ArgTypes_.cbegin(), ArgTypes_.cend(), params.begin(), [](std::shared_ptr<Type> decl) { return decl->GetLLVMType(); }); - LLVMType_ = - llvm::FunctionType::get(ReturnType_->GetLLVMType(), params, false); + LLVMType_ = llvm::FunctionType::get(ReturnType_->GetLLVMType(), params, + IsVariadic_); } std::shared_ptr<Type> FunctionType::GetReturnType() { return ReturnType_; } @@ -352,6 +353,8 @@ std::vector<std::shared_ptr<Type>> FunctionType::GetArgTypes() { return ArgTypes_; } +bool FunctionType::IsVariadic() { return IsVariadic_; } + RecordType::RecordType(const std::vector<RecordMember>& members, std::string&& name) : Type(std::move(name), nullptr) { @@ -189,13 +189,15 @@ class FunctionType : public Type { public: FunctionType(std::shared_ptr<Type> ReturnType, std::vector<std::shared_ptr<Type>> ArgTypes, - std::string&& name); + std::string&& name, bool IsVariadic = false); std::shared_ptr<Type> GetReturnType(); std::vector<std::shared_ptr<Type>> GetArgTypes(); + bool IsVariadic(); protected: std::shared_ptr<Type> ReturnType_; std::vector<std::shared_ptr<Type>> ArgTypes_; + bool IsVariadic_; }; using RecordMember = std::pair<std::string, std::shared_ptr<Type>>; diff --git a/TypeIdentifier.hh b/TypeIdentifier.hh index 88b208a..4543774 100644 --- a/TypeIdentifier.hh +++ b/TypeIdentifier.hh @@ -9,8 +9,8 @@ namespace pcc { -// since TypeAlias returns std::shared_ptr<Type> instead of llvm::Value*, we -// won't use CodeGen() override. +// since TypeIdentifier returns std::shared_ptr<Type> instead of llvm::Value*, +// we won't use CodeGen() override. class TypeIdentifier { public: TypeIdentifier(Context* context, std::shared_ptr<Type> type = nullptr); diff --git a/TypeManager.cc b/TypeManager.cc index 977d3bc..9c484e4 100644 --- a/TypeManager.cc +++ b/TypeManager.cc @@ -227,9 +227,10 @@ std::shared_ptr<RecordType> return NewType; } -std::shared_ptr<FunctionType> TypeManager::CreateFunctionType( - std::shared_ptr<Type> ReturnType, - std::vector<std::shared_ptr<Type>> ArgTypes) { +std::shared_ptr<FunctionType> + TypeManager::CreateFunctionType(std::shared_ptr<Type> ReturnType, + std::vector<std::shared_ptr<Type>> ArgTypes, + bool IsVariadic) { decltype(ArgTypes)::const_iterator ArgIt = ArgTypes.cbegin(); std::string name = " (*)("; if (!ArgTypes.empty()) { @@ -240,15 +241,16 @@ std::shared_ptr<FunctionType> TypeManager::CreateFunctionType( } } std::shared_ptr<FunctionType> NewType = std::make_shared<FunctionType>( - ReturnType, ArgTypes, ReturnType->GetCommonName() + name + ")"); + ReturnType, ArgTypes, ReturnType->GetCommonName() + name + ")", + IsVariadic); FunctionTypes_.push_back(NewType); return NewType; } -std::shared_ptr<Type> TypeManager::GetPointerIndexType_() { +std::shared_ptr<Type> TypeManager::GetPointerIndexType() { return PointerIndexType_; } -std::shared_ptr<Type> TypeManager::GetPointerDifferenceType_() { +std::shared_ptr<Type> TypeManager::GetPointerDifferenceType() { return PointerDifferenceType_; } diff --git a/TypeManager.hh b/TypeManager.hh index 099b505..9f778a8 100644 --- a/TypeManager.hh +++ b/TypeManager.hh @@ -25,8 +25,8 @@ class TypeManager { public: TypeManager(); std::shared_ptr<Type> GetBuiltinType(BuiltinType type); - std::shared_ptr<Type> GetPointerIndexType_(); - std::shared_ptr<Type> GetPointerDifferenceType_(); + std::shared_ptr<Type> GetPointerIndexType(); + std::shared_ptr<Type> GetPointerDifferenceType(); // if call this function twice with the same ElementType, it will return the // same shared_ptr to the Type. @@ -46,7 +46,8 @@ class TypeManager { std::shared_ptr<FunctionType> CreateFunctionType(std::shared_ptr<Type> ReturnType, - std::vector<std::shared_ptr<Type>> ArgTypes); + std::vector<std::shared_ptr<Type>> ArgTypes, + bool IsVariadic = false); // binary operators may change type std::pair<std::shared_ptr<Type>, Value> diff --git a/node/BaseNode.cc b/node/BaseNode.cc index 8391322..a923498 100644 --- a/node/BaseNode.cc +++ b/node/BaseNode.cc @@ -14,6 +14,7 @@ ProgramNode::ProgramNode( , functions_(std::move(functions)) {} Value ProgramNode::CodeGen() { + context_->GetModule()->setModuleIdentifier(name_); for (auto&& decl : GlobalDeclarations_) { decl->CodeGen(); } diff --git a/node/ExprNode.cc b/node/ExprNode.cc index 13a85e9..e75eda5 100644 --- a/node/ExprNode.cc +++ b/node/ExprNode.cc @@ -124,7 +124,7 @@ Value ArrayAccessNode::CodeGen() { if (array != nullptr) { std::shared_ptr<Type> IndexType = array->GetIndexType(); Value indices[2] = {llvm::ConstantInt::get( - manager->GetPointerIndexType_()->GetLLVMType(), 0)}; + manager->GetPointerIndexType()->GetLLVMType(), 0)}; if (array->GetIsZeroStarted() == false) { Value ConvertedRight = manager->CreateCast(IndexType, RightType, right, context_); @@ -167,7 +167,7 @@ Value DereferenceNode::CodeGen() { return nullptr; } Value zero = llvm::ConstantInt::get( - context_->GetTypeManager()->GetPointerIndexType_()->GetLLVMType(), 0); + context_->GetTypeManager()->GetPointerIndexType()->GetLLVMType(), 0); type_ = pointer; return context_->GetBuilder()->CreateInBoundsGEP(value, zero); } @@ -201,7 +201,7 @@ Value MemberAccessNode::CodeGen() { int MemberIndex; std::shared_ptr<Type> MemberType; std::tie(MemberIndex, MemberType) = LeftInner->GetMember(rhs_); - llvm::Type* IndexLLLVMType = manager->GetPointerIndexType_()->GetLLVMType(); + llvm::Type* IndexLLLVMType = manager->GetPointerIndexType()->GetLLVMType(); Value indices[2] = {llvm::ConstantInt::get(IndexLLLVMType, 0), llvm::ConstantInt::get(IndexLLLVMType, MemberIndex)}; type_ = manager->GetPointerType(MemberType); @@ -234,21 +234,31 @@ Value FunctionCallNode::CodeGen() { return nullptr; } const std::vector<std::shared_ptr<Type>>& ArgTypes = type->GetArgTypes(); + if (type->IsVariadic() == false && ArgTypes.size() != args_.size()) { + Log(LogLevel ::PCC_ERROR, + "argument number mismatch, %d wanted, %d given", ArgTypes.size(), + args_.size()); + return nullptr; + } std::vector<Value> ArgValues(args_.size()); - auto ArgTypeIt = ArgTypes.begin(); + auto ArgIt = args_.begin(); auto ArgValueIt = ArgValues.begin(); - for (auto&& arg : args_) { - Value argv = arg->CodeGen(); + for (auto&& ArgType : ArgTypes) { + Value argv = (*ArgIt)->CodeGen(); Value ConvertedArgv = - manager->CreateCast(*ArgTypeIt, arg->GetType(), argv, context_); + manager->CreateCast(ArgType, (*ArgIt)->GetType(), argv, context_); if (ConvertedArgv == nullptr) { Log(LogLevel ::PCC_ERROR, "argument type mismatch, the function type is %s, an argument " "of type %s needed", - type->GetCommonName(), (*ArgTypeIt)->GetCommonName()); + type->GetCommonName(), ArgType->GetCommonName()); } *ArgValueIt = ConvertedArgv; - ++ArgTypeIt, ++ArgValueIt; + ++ArgIt, ++ArgValueIt; + } + while (ArgIt != args_.end()) { + *ArgValueIt = (*ArgIt)->CodeGen(); + ++ArgIt, ++ArgValueIt; } type_ = type->GetReturnType(); return context_->GetBuilder()->CreateCall(std::get<1>(function), ArgValues); diff --git a/node/FunctionNode.cc b/node/FunctionNode.cc index 97b1680..4fb5138 100644 --- a/node/FunctionNode.cc +++ b/node/FunctionNode.cc @@ -91,4 +91,34 @@ Value FunctionNode::CodeGen() { return nullptr; } +ExternNode::ExternNode(Context* context, std::string&& name, + std::list<Declaration>&& arguments, + std::shared_ptr<TypeIdentifier> ReturnTypeIdentifier, + bool IsVariadic) + : FunctionNode(context, std::move(name), std::move(arguments), + std::list<std::shared_ptr<DeclNode>>(), ReturnTypeIdentifier, + nullptr) + , IsVariadic_(IsVariadic) {} + +Value ExternNode::CodeGen() { + llvm::Module* module = context_->GetModule(); + llvm::IRBuilder<>* builder = context_->GetBuilder(); + TypeManager* manager = context_->GetTypeManager(); + std::vector<std::shared_ptr<Type>> params(arguments_.size()); + std::transform( + arguments_.cbegin(), arguments_.cend(), params.begin(), + [](const Declaration& decl) { return std::get<1>(decl)->GetType(); }); + std::shared_ptr<Type> ReturnType = ReturnTypeIdentifier_->GetType(); + std::shared_ptr<FunctionType> type = + manager->CreateFunctionType(ReturnType, params, IsVariadic_); + llvm::FunctionType* LLVMType = + llvm::cast<llvm::FunctionType>(type->GetLLVMType()); + llvm::FunctionCallee callee = module->getOrInsertFunction(name_, LLVMType); + llvm::Function* function = llvm::cast<llvm::Function>(callee.getCallee()); + function->setCallingConv(llvm::CallingConv::C); + context_->AddFunction(name_, {type, function}); + Log(LogLevel::PCC_INFO, "extern function %s of type %s", name_.c_str(), + type->GetCommonName()); + return nullptr; +} } // namespace pcc diff --git a/node/FunctionNode.hh b/node/FunctionNode.hh index e939121..6860c45 100644 --- a/node/FunctionNode.hh +++ b/node/FunctionNode.hh @@ -25,6 +25,18 @@ class FunctionNode : public BaseNode { VariableList locals_; std::shared_ptr<StatementListNode> body_; }; + +class ExternNode : public FunctionNode { + public: + ExternNode(Context* context, std::string&& name, + std::list<Declaration>&& arguments, + std::shared_ptr<TypeIdentifier> ReturnTypeIdentifier, + bool IsVariadic); + virtual Value CodeGen() override; + + protected: + bool IsVariadic_; +}; } // namespace pcc #endif diff --git a/t/extern.pas b/t/extern.pas new file mode 100644 index 0000000..0b78e45 --- /dev/null +++ b/t/extern.pas @@ -0,0 +1,15 @@ +program hello_world; + +extern puts(s:string):integer; +extern printf(s:string, ...):integer; +extern __isoc99_scanf(s:string, ...):integer; + +function main():integer; +var + buf:array[0..1023] of char; +begin + puts('Hello, World!'); + printf('Variadic Function Test: %d, %s, %x\nsay something:', 1, 'yes', 0x12345678); + __isoc99_scanf('%s', @buf); + printf('you said: %s\n', @buf) +end; |
