summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Lexer.l4
-rw-r--r--Parser.y7
-rw-r--r--Type.cc11
-rw-r--r--Type.hh4
-rw-r--r--TypeIdentifier.hh4
-rw-r--r--TypeManager.cc14
-rw-r--r--TypeManager.hh7
-rw-r--r--node/BaseNode.cc1
-rw-r--r--node/ExprNode.cc28
-rw-r--r--node/FunctionNode.cc30
-rw-r--r--node/FunctionNode.hh12
-rw-r--r--t/extern.pas15
12 files changed, 109 insertions, 28 deletions
diff --git a/Lexer.l b/Lexer.l
index d3e6f29..861806d 100644
--- a/Lexer.l
+++ b/Lexer.l
@@ -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);}
diff --git a/Parser.y b/Parser.y
index eeda0c7..34d8b03 100644
--- a/Parser.y
+++ b/Parser.y
@@ -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]================== */
diff --git a/Type.cc b/Type.cc
index 7ad0352..6167175 100644
--- a/Type.cc
+++ b/Type.cc
@@ -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) {
diff --git a/Type.hh b/Type.hh
index b686e28..e16b52f 100644
--- a/Type.hh
+++ b/Type.hh
@@ -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;