summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Lexer.l11
-rw-r--r--Parser.y37
-rw-r--r--Type.hh4
-rw-r--r--TypeManager.cc25
-rw-r--r--node/ExprNode.cc4
-rw-r--r--node/StatementNode.cc104
-rw-r--r--node/StatementNode.hh35
-rw-r--r--t/1.pas18
-rw-r--r--t/trivial.pas66
9 files changed, 250 insertions, 54 deletions
diff --git a/Lexer.l b/Lexer.l
index 531878d..4e91dda 100644
--- a/Lexer.l
+++ b/Lexer.l
@@ -24,7 +24,7 @@ namespace pcc {
%option never-interactive
%option nounistd
%option case-insensitive
-%option noyywrap nounput noinput batch
+%option noyywrap nounput noinput batch debug
decimal ([1-9][0-9]*)|0
octal 0[0-7]*
@@ -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 ]
@@ -65,6 +65,7 @@ white [\t\f\r ]
":" {return Parser::make_COLON(loc);}
";" {return Parser::make_SEMICOLON(loc);}
"." {return Parser::make_DOT(loc);}
+"," {return Parser::make_COMMA(loc);}
"[" {return Parser::make_LBRACKET(loc);}
"]" {return Parser::make_RBRACKET(loc);}
"(" {return Parser::make_LPARENTHESIS(loc);}
@@ -100,6 +101,8 @@ white [\t\f\r ]
"else" {return Parser::make_ELSE(loc);}
"while" {return Parser::make_WHILE(loc);}
"do" {return Parser::make_DO(loc);}
+"repeat" {return Parser::make_REPEAT(loc);}
+"until" {return Parser::make_UNTIL(loc);}
"integer" {return Parser::make_INTEGER(loc);}
"boolean" {return Parser::make_BOOLEAN(loc);}
"char" {return Parser::make_CHAR(loc);}
@@ -158,9 +161,7 @@ white [\t\f\r ]
namespace pcc {
int Driver::StartLexer(std::string& filename) {
- if(CurrentLogLevel==LogLevel::PCC_DEBUG){
- yy_flex_debug = 1;
- }
+ yy_flex_debug = (CurrentLogLevel==LogLevel::PCC_DEBUG);
yyin = std::fopen(filename.c_str(), "r");
if (yyin == NULL) {
Log(LogLevel::PCC_ERROR, "Failed to open file %s", filename.c_str());
diff --git a/Parser.y b/Parser.y
index 603b4ae..8f1f196 100644
--- a/Parser.y
+++ b/Parser.y
@@ -43,7 +43,7 @@ YY_DECL;
%token FILE_END 0;
%token COLON SEMICOLON COMMA DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS
%token PROGRAM IDENTIFIER CONST VAR BEGINS ENDS FUNCTION
-%token IF THEN ELSE WHILE DO
+%token IF THEN ELSE WHILE DO REPEAT UNTIL
%token BOOLEAN CHAR INTEGER REAL STRING
%token ADD SUB MUL REAL_DIV DIV MOD LT LE GT GE EQ NE
%token AND NOT OR XOR
@@ -76,6 +76,7 @@ YY_DECL;
%type <std::shared_ptr<pcc::BaseNode>> statement open_statement closed_statement normal_statement
%type <std::shared_ptr<pcc::EmptyStatementNode>> empty_statement
%type <std::shared_ptr<pcc::AssignStatementNode>> assign_statement
+%type <std::shared_ptr<pcc::RepeatStatementNode>> repeat_statement
%%
@@ -95,7 +96,7 @@ global_decls
;
global_decl
- : VAR var_decls {$$=std::make_shared<pcc::VarDeclNode>(ctx, nullptr, $2);}
+ : VAR var_decls SEMICOLON {$$=std::make_shared<pcc::VarDeclNode>(ctx, nullptr, $2);}
;
functions
@@ -106,12 +107,12 @@ functions
/* ==================[var part]================== */
var_decls
- : var_decls var_decl {$$=$1; auto NewChilds=std::get<0>($2); for(auto& name: NewChilds){$$.push_back({name, std::get<1>($2)});}}
- | var_decl {auto NewChilds=std::get<0>($1); for(auto& name: NewChilds){$$.push_back({name, std::get<1>($1)});}}
+ : var_decls SEMICOLON var_decl {$$=$1; auto NewChilds=std::get<0>($3); for(auto& name: NewChilds){$$.push_back({name, std::get<1>($3)});}}
+ | var_decl {auto NewChilds=std::get<0>($1); for(auto& name: NewChilds){$$.push_back({name, std::get<1>($1)});}}
;
var_decl
- : vars COLON type SEMICOLON {$$={$1,$3};}
+ : vars COLON type {$$={$1,$3};}
;
vars
@@ -132,6 +133,8 @@ type
function
: FUNCTION IDENTIFIER LPARENTHESIS var_decls RPARENTHESIS COLON type SEMICOLON
local_decls statement_block {$$=std::make_shared<pcc::FunctionNode>(ctx, $2, $4, $9, $7, $10);}
+ | FUNCTION IDENTIFIER LPARENTHESIS RPARENTHESIS COLON type SEMICOLON
+ local_decls statement_block {$$=std::make_shared<pcc::FunctionNode>(ctx, $2, std::list<Declaration>(), $8, $6, $9);}
;
local_decls
@@ -140,7 +143,7 @@ local_decls
;
local_decl
- : VAR var_decls {$$=std::make_shared<pcc::VarDeclNode>(ctx, nullptr, $2);}
+ : VAR var_decls SEMICOLON {$$=std::make_shared<pcc::VarDeclNode>(ctx, nullptr, $2);}
;
/* ==================[statements part]================== */
@@ -156,21 +159,22 @@ statement
;
open_statement
- : IF expression THEN statement
- | IF expression THEN closed_statement ELSE open_statement
- | WHILE expression DO open_statement
+ : IF expression THEN statement {$$=std::make_shared<pcc::IfStatementNode>(ctx, $2, $4, nullptr);}
+ | IF expression THEN closed_statement ELSE open_statement {$$=std::make_shared<pcc::IfStatementNode>(ctx, $2, $4, $6);}
+ | WHILE expression DO open_statement {$$=std::make_shared<pcc::WhileStatementNode>(ctx, $2, $4);}
;
closed_statement
- : normal_statement {$$=$1;}
- | IF expression THEN closed_statement ELSE closed_statement
- | WHILE expression DO closed_statement
+ : normal_statement {$$=$1;}
+ | IF expression THEN closed_statement ELSE closed_statement {$$=std::make_shared<pcc::IfStatementNode>(ctx, $2, $4, $6);}
+ | WHILE expression DO closed_statement {$$=std::make_shared<pcc::WhileStatementNode>(ctx, $2, $4);}
;
normal_statement
: statement_block {$$=$1;}
| empty_statement {$$=$1;}
| assign_statement {$$=$1;}
+ | repeat_statement {$$=$1;}
| expression {$$=$1;}
;
@@ -179,7 +183,11 @@ statement_block
;
empty_statement
- : {$$=std::make_shared<pcc::EmptyStatementNode>(ctx);}
+ : {$$=std::make_shared<pcc::EmptyStatementNode>(ctx);}
+ ;
+
+repeat_statement
+ : REPEAT statement UNTIL expression {$$=std::make_shared<pcc::RepeatStatementNode>(ctx, $4, $2);}
;
assign_statement
@@ -234,6 +242,7 @@ l2_operator
l3_operator
: MUL {$$=pcc::BinaryOperator::MUL;}
| DIV {$$=pcc::BinaryOperator::DIV;}
+ | REAL_DIV {$$=pcc::BinaryOperator::REAL_DIV;}
| MOD {$$=pcc::BinaryOperator::MOD;}
| AND {$$=pcc::BinaryOperator::AND;}
;
@@ -276,7 +285,7 @@ namespace pcc {
{
std::stringstream loc;
loc<<l;
- Log(LogLevel::PCC_ERROR, "error on %s: %s", loc.str().c_str(), m.c_str());
+ Log(LogLevel::PCC_ERROR, "error at %s: %s", loc.str().c_str(), m.c_str());
}
}
diff --git a/Type.hh b/Type.hh
index ebda567..44c9a29 100644
--- a/Type.hh
+++ b/Type.hh
@@ -29,7 +29,9 @@ enum class BinaryOperator {
OR,
XOR,
ARRAY_ACCESS,
- BINARYOP_NUMBER
+ BINARYOP_NUMBER,
+ REAL_DIV // the difference between REAL_DIV and DIV is handled in
+ // TypeManager, thus we don't need to create instruction for this.
};
enum class UnaryOperator { POS, NEG, NOT, UNARYOP_NUMEBR };
diff --git a/TypeManager.cc b/TypeManager.cc
index c721df8..d74f3f0 100644
--- a/TypeManager.cc
+++ b/TypeManager.cc
@@ -89,17 +89,18 @@ std::pair<std::shared_ptr<Type>, Value>
std::dynamic_pointer_cast<RealType>(RightType);
Value ConvertedLeft, ConvertedRight;
std::shared_ptr<Type> CommonType;
- if (LeftType != RightType) {
+ if (op == BinaryOperator::REAL_DIV) {
+ // we can only set the CommonType to real for REAL_DIV on builtin types,
+ // for other types, REAL_DIV and DIV are unavaliable.
+ CommonType = builtins_[ToUnderlying(BuiltinType::REAL)];
+ op = BinaryOperator::DIV;
+ } else if (LeftType != RightType) {
// we can cast the boolean, char, integer and real.
- if (LeftRealType != nullptr && RightIntegerBaseType != nullptr) {
- ConvertedLeft = left;
- ConvertedRight =
- builder->CreateSIToFP(right, LeftType->GetLLVMType());
+ if (op == BinaryOperator::REAL_DIV) {
+ CommonType = builtins_[ToUnderlying(BuiltinType::REAL)];
+ } else if (LeftRealType != nullptr && RightIntegerBaseType != nullptr) {
CommonType = LeftType;
} else if (RightRealType != nullptr && LeftIntegerBaseType != nullptr) {
- ConvertedLeft =
- builder->CreateSIToFP(left, RightType->GetLLVMType());
- ConvertedRight = right;
CommonType = RightType;
} else if (LeftIntegerBaseType != nullptr &&
RightIntegerBaseType != nullptr) {
@@ -107,10 +108,6 @@ std::pair<std::shared_ptr<Type>, Value>
RightIntegerBaseType->GetWidth()
? LeftType
: RightType);
- ConvertedLeft =
- builder->CreateSExt(left, CommonType->GetLLVMType());
- ConvertedRight =
- builder->CreateSExt(right, CommonType->GetLLVMType());
} else {
Log(LogLevel::PCC_ERROR,
"can not apply binary operator on two different type %s and %s",
@@ -118,10 +115,10 @@ std::pair<std::shared_ptr<Type>, Value>
return {nullptr, nullptr};
}
} else {
- ConvertedLeft = left;
- ConvertedRight = right;
CommonType = LeftType;
}
+ ConvertedLeft = CreateCast(CommonType, LeftType, left, context);
+ ConvertedRight = CreateCast(CommonType, RightType, right, context);
Value result = CommonType->CreateBinaryOperation(op, ConvertedLeft,
ConvertedRight, context);
if (result == nullptr) {
diff --git a/node/ExprNode.cc b/node/ExprNode.cc
index 6127f6f..4183120 100644
--- a/node/ExprNode.cc
+++ b/node/ExprNode.cc
@@ -90,8 +90,8 @@ Value FunctionCallNode::CodeGen() {
name_.c_str());
return nullptr;
}
- llvm::FunctionCallee fp =
- context_->GetModule()->getOrInsertFunction(name_, type->GetLLVMType());
+ 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();
diff --git a/node/StatementNode.cc b/node/StatementNode.cc
index fd8ee94..e29398d 100644
--- a/node/StatementNode.cc
+++ b/node/StatementNode.cc
@@ -29,4 +29,108 @@ Value AssignStatementNode::CodeGen() {
context_->GetBuilder()->CreateStore(RightValue, LeftValue);
return nullptr;
}
+
+IfStatementNode::IfStatementNode(Context* context,
+ std::shared_ptr<ExprNode> expr,
+ std::shared_ptr<BaseNode> ThenPart,
+ std::shared_ptr<BaseNode> ElsePart)
+ : BaseNode(context)
+ , expr_(expr)
+ , ThenPart_(ThenPart)
+ , ElsePart_(ElsePart) {}
+
+Value IfStatementNode::CodeGen() {
+ llvm::IRBuilder<>* builder = context_->GetBuilder();
+ TypeManager* manager = context_->GetTypeManager();
+ std::shared_ptr<Type> boolean =
+ manager->GetBuiltinType(BuiltinType::BOOLEAN);
+ llvm::Function* body = builder->GetInsertBlock()->getParent();
+ llvm::BasicBlock* ThenBlock =
+ llvm::BasicBlock::Create(GlobalLLVMContext, "then", body);
+ llvm::BasicBlock* EndBlock =
+ llvm::BasicBlock::Create(GlobalLLVMContext, "endif");
+ Value ExprValue = manager->CreateCast(boolean, expr_->GetType(),
+ expr_->CodeGen(), context_);
+ if (ElsePart_ != nullptr) {
+ llvm::BasicBlock* ElseBlock =
+ llvm::BasicBlock::Create(GlobalLLVMContext, "else");
+ builder->CreateCondBr(ExprValue, ThenBlock, ElseBlock);
+ builder->SetInsertPoint(ThenBlock);
+ ThenPart_->CodeGen();
+ builder->CreateBr(EndBlock);
+ body->getBasicBlockList().push_back(ElseBlock);
+ builder->SetInsertPoint(ElseBlock);
+ ElsePart_->CodeGen();
+ builder->CreateBr(EndBlock);
+ body->getBasicBlockList().push_back(EndBlock);
+ builder->SetInsertPoint(EndBlock);
+ return nullptr;
+ }
+ builder->CreateCondBr(ExprValue, ThenBlock, EndBlock);
+ builder->SetInsertPoint(ThenBlock);
+ ThenPart_->CodeGen();
+ builder->CreateBr(EndBlock);
+ body->getBasicBlockList().push_back(EndBlock);
+ builder->SetInsertPoint(EndBlock);
+ return nullptr;
+}
+
+WhileStatementNode::WhileStatementNode(Context* context,
+ std::shared_ptr<ExprNode> expr,
+ std::shared_ptr<BaseNode> WhileBody)
+ : BaseNode(context)
+ , expr_(expr)
+ , WhileBody_(WhileBody) {}
+
+Value WhileStatementNode::CodeGen() {
+ llvm::IRBuilder<>* builder = context_->GetBuilder();
+ TypeManager* manager = context_->GetTypeManager();
+ std::shared_ptr<Type> boolean =
+ manager->GetBuiltinType(BuiltinType::BOOLEAN);
+ llvm::Function* body = builder->GetInsertBlock()->getParent();
+ llvm::BasicBlock* StartBlock =
+ llvm::BasicBlock::Create(GlobalLLVMContext, "start", body);
+ llvm::BasicBlock* LoopBlock =
+ llvm::BasicBlock::Create(GlobalLLVMContext, "loop");
+ llvm::BasicBlock* EndBlock =
+ llvm::BasicBlock::Create(GlobalLLVMContext, "done");
+ builder->SetInsertPoint(StartBlock);
+ Value ExprValue = manager->CreateCast(boolean, expr_->GetType(),
+ expr_->CodeGen(), context_);
+ builder->CreateCondBr(ExprValue, LoopBlock, EndBlock);
+ body->getBasicBlockList().push_back(LoopBlock);
+ builder->SetInsertPoint(LoopBlock);
+ WhileBody_->CodeGen();
+ builder->CreateBr(StartBlock);
+ body->getBasicBlockList().push_back(EndBlock);
+ builder->SetInsertPoint(EndBlock);
+ return nullptr;
+}
+
+RepeatStatementNode::RepeatStatementNode(Context* context,
+ std::shared_ptr<ExprNode> expr,
+ std::shared_ptr<BaseNode> RepeatBody)
+ : BaseNode(context)
+ , expr_(expr)
+ , RepeatBody_(RepeatBody) {}
+
+Value RepeatStatementNode::CodeGen() {
+ llvm::IRBuilder<>* builder = context_->GetBuilder();
+ TypeManager* manager = context_->GetTypeManager();
+ std::shared_ptr<Type> boolean =
+ manager->GetBuiltinType(BuiltinType::BOOLEAN);
+ llvm::Function* body = builder->GetInsertBlock()->getParent();
+ llvm::BasicBlock* LoopBlock =
+ llvm::BasicBlock::Create(GlobalLLVMContext, "loop", body);
+ llvm::BasicBlock* EndBlock =
+ llvm::BasicBlock::Create(GlobalLLVMContext, "done");
+ builder->SetInsertPoint(LoopBlock);
+ RepeatBody_->CodeGen();
+ Value ExprValue = manager->CreateCast(boolean, expr_->GetType(),
+ expr_->CodeGen(), context_);
+ builder->CreateCondBr(ExprValue, EndBlock, LoopBlock);
+ body->getBasicBlockList().push_back(EndBlock);
+ builder->SetInsertPoint(EndBlock);
+ return nullptr;
+}
} // namespace pcc
diff --git a/node/StatementNode.hh b/node/StatementNode.hh
index 68c808f..1bd0cb6 100644
--- a/node/StatementNode.hh
+++ b/node/StatementNode.hh
@@ -25,6 +25,41 @@ class AssignStatementNode : public BaseNode {
std::shared_ptr<ExprNode> lhs_;
std::shared_ptr<ExprNode> rhs_;
};
+
+class IfStatementNode : public BaseNode {
+ public:
+ IfStatementNode(Context* context, std::shared_ptr<ExprNode> expr,
+ std::shared_ptr<BaseNode> ThenPart,
+ std::shared_ptr<BaseNode> ElsePart);
+ virtual Value CodeGen() override;
+
+ protected:
+ std::shared_ptr<ExprNode> expr_;
+ std::shared_ptr<BaseNode> ThenPart_;
+ std::shared_ptr<BaseNode> ElsePart_;
+};
+
+class WhileStatementNode : public BaseNode {
+ public:
+ WhileStatementNode(Context* context, std::shared_ptr<ExprNode> expr,
+ std::shared_ptr<BaseNode> WhileBody);
+ virtual Value CodeGen() override;
+
+ protected:
+ std::shared_ptr<ExprNode> expr_;
+ std::shared_ptr<BaseNode> WhileBody_;
+};
+
+class RepeatStatementNode : public BaseNode {
+ public:
+ RepeatStatementNode(Context* context, std::shared_ptr<ExprNode> expr,
+ std::shared_ptr<BaseNode> RepeatBody);
+ virtual Value CodeGen() override;
+
+ protected:
+ std::shared_ptr<ExprNode> expr_;
+ std::shared_ptr<BaseNode> RepeatBody_;
+};
} // namespace pcc
#endif
diff --git a/t/1.pas b/t/1.pas
deleted file mode 100644
index 0b2228f..0000000
--- a/t/1.pas
+++ /dev/null
@@ -1,18 +0,0 @@
-program a;
-
-function test(a:integer;b:char;c:real;):integer;
-var
- d:integer;
- e:char;
- f:string;
-begin
- a:=1;
- b:='a';
- c:=3.5;
- a:=b*(c-b+6)--4;
- d:=a*a-b-(5+c);
- e:='\x03';
- f:='a normal test \'\\\0\023';
- f[4];
- test:=e+d;
-end;
diff --git a/t/trivial.pas b/t/trivial.pas
new file mode 100644
index 0000000..1a433c5
--- /dev/null
+++ b/t/trivial.pas
@@ -0,0 +1,66 @@
+program a;
+
+function arithmetic_test(a:integer;b:char;c:real):integer;
+var
+ d:integer;
+ e:char;
+ f:real;
+begin
+ a:=1; d:=-2;
+ b:='B'; e:='\x46';
+ c:=1.5; f:=-3.14;
+
+ a:=a+b-c+d;
+ b:=b*c-d*e;
+ c:=c+d*e+f;
+
+ b:=1; e:=2;
+ a:=1/2+b/e;
+ d:=1 div 2 + b div e;
+ arithmetic_test:=a+d
+end;
+
+function string_test():char;
+var
+ s:string;
+ a,b:char;
+begin
+ s='hello world';
+ a:=s[3];
+ b:=s[6];
+ string_test:=s[b-a]
+end;
+
+function recursion_test(x:integer):integer;
+begin
+ if (x=0) or (x=1) then
+ recursion_test:=1
+ else
+ recursion_test:=recursion_test(x-1)+recursion_test(x-2)
+end;
+
+function branch_test(a:integer):integer;
+var
+ b,c:integer;
+begin
+ b:=3;
+ if a<b then
+ if a>b then
+ c:=1
+ else
+ c:=0
+ else
+ c:=-1;
+ while b>0 do
+ begin
+ a:=a*b;
+ b:=b-1
+ end;
+ repeat
+ begin
+ a:=a*c;
+ b:=b+1
+ end
+ until b>5;
+ branch_test:=a;
+end;