diff --git a/DIARY b/DIARY index f89e427..7604374 100644 --- a/DIARY +++ b/DIARY @@ -119,9 +119,17 @@ structs on [1], [2], [3] share the same unique ID, while [4] has a different uni that these operators are working. Interestingly, there is no penalty for pre- vs. post-increment/decrement on chars (single-byte values); however, there _is_ a penalty for post-inc'ing/dec'ing ints. +[6 hrs] Added typedefs. TODO + +[1 hr] Added for loop. + +01/15/2020 +[1 hr] Wrote tests for loop; fixed binary operation bug (invalid 'case' fallthrough in switch statement, leading to incorrect type being assigned). Added comma operator (the one that separates + expressions). TODO [ ] typedef [X] ++, -- [ ] +=, *=, etc. -[ ] for \ No newline at end of file +[ ] for + diff --git a/ast/ast-expr.cpp b/ast/ast-expr.cpp index 3bd9667..b79f129 100644 --- a/ast/ast-expr.cpp +++ b/ast/ast-expr.cpp @@ -167,6 +167,7 @@ namespace zc { case Kind::BOP_TIMES: return l * r; case Kind::BOP_DIVIDE: return l / r; case Kind::BOP_MOD: return l % r; + case Kind::BOP_COMMA: return r; } } diff --git a/ast/ast-expr.hpp b/ast/ast-expr.hpp index 7795459..9d44434 100644 --- a/ast/ast-expr.hpp +++ b/ast/ast-expr.hpp @@ -84,7 +84,8 @@ namespace zc { BOP_MINUS, BOP_TIMES, BOP_DIVIDE, - BOP_MOD + BOP_MOD, + BOP_COMMA }; Kind kind() const { return kind_; } bool is_logical() const; @@ -206,9 +207,7 @@ namespace zc { virtual void TypeCheck(SemantEnv& env) override; - virtual Block *CodeGen(CgenEnv& env, Block *block, ExprKind mode) override { - abort(); - } + virtual Block *CodeGen(CgenEnv& env, Block *block, ExprKind mode) override { return block; } protected: NoExpr(const SourceLoc& loc): ASTExpr(loc) {} diff --git a/ast/ast-stat.hpp b/ast/ast-stat.hpp index b04e854..39bfda8 100644 --- a/ast/ast-stat.hpp +++ b/ast/ast-stat.hpp @@ -176,16 +176,6 @@ namespace zc { SelectionStat(args...), cond_(cond), if_body_(if_body), else_body_(else_body) {} }; -#if 0 - class SwitchStat: public SelectionStat { - public: - - private: - ASTExpr *control_; - - }; -#endif - /* NOTE: Abstract */ class IterationStat: public ASTStat { public: @@ -226,6 +216,30 @@ namespace zc { WhileStat(Args... args): IterationStat(args...) {} }; + class ForStat: public IterationStat { + public: + ASTExpr *init() const { return init_; } + ASTExpr *after() const { return after_; } + + /* Semantic Analysis */ + virtual void TypeCheck(SemantEnv& env) override; + + /* Code Generation */ + virtual Block *CodeGen(CgenEnv& env, Block *block) override; + virtual void FrameGen(StackFrame& env) const override; + + template + static ForStat *Create(Args... args) { return new ForStat(args...); } + + private: + ASTExpr *init_; + ASTExpr *after_; + + template + ForStat(ASTExpr *init, ASTExpr *cond, ASTExpr *after, Args... args): + IterationStat(cond, args...), init_(init), after_(after) {} + }; + class GotoStat: public ASTStat { public: Identifier *label_id() const { return label_id_; } diff --git a/c.l b/c.l index 043886a..9257429 100644 --- a/c.l +++ b/c.l @@ -63,6 +63,7 @@ E [Ee][+-]?{D}+ "if" { return IF; } "else" { return ELSE; } "while" { return WHILE; } +"for" { return FOR; } "auto" { return AUTO; } "register" { return REGISTER; } diff --git a/c.ypp b/c.ypp index 9490e58..e8b8be7 100644 --- a/c.ypp +++ b/c.ypp @@ -104,6 +104,7 @@ %token IF %token ELSE %token WHILE +%token FOR /* STORAGE CLASS SPECS */ %token AUTO REGISTER STATIC EXTERN TYPEDEF @@ -378,6 +379,9 @@ iteration_stat: WHILE '(' exp ')' stat { $$ = zc::WhileStat::Create($3, $5, @3); } + | FOR '(' optional_exp ';' optional_exp ';' optional_exp ')' stat { + $$ = zc::ForStat::Create($3, $5, $7, $9, @1); + } ; exp_stat: optional_exp ';' { $$ = zc::ExprStat::Create($1, @1); } ; @@ -385,7 +389,8 @@ optional_exp: /* empty */ { $$ = zc::NoExpr::Create(@$); @$ = 0; } | exp { $$ = $1; } ; exp: assignment_exp { $$ = $1; } - ; /* incomplete */ + | exp ',' assignment_exp { $$ = zc::BinaryExpr::Create(zc::BinaryExpr::Kind::BOP_COMMA, $1, $3, @1); } + ; assignment_exp: conditional_exp { $$ = $1; } | unary_exp '=' conditional_exp { $$ = zc::AssignmentExpr::Create($1, $3, @1); } ; /* incomplete */ @@ -537,6 +542,8 @@ equality_operator: relational_operator: '<' { $$ = zc::BinaryExpr::Kind::BOP_LT; } | LEQ { $$ = zc::BinaryExpr::Kind::BOP_LEQ; } + | '>' { $$ = zc::BinaryExpr::Kind::BOP_GT; } + | GEQ { $$ = zc::BinaryExpr::Kind::BOP_GEQ; } ; /* incomplete */ additive_operator: '+' { $$ = zc::BinaryExpr::Kind::BOP_PLUS; } diff --git a/cgen.cpp b/cgen.cpp index d675407..1f0f369 100644 --- a/cgen.cpp +++ b/cgen.cpp @@ -158,30 +158,6 @@ namespace zc { return block; } - -#if 0 - void ASTType::CodeGen(CgenEnv& env) { - SymInfo *info = env.ext_env().frame().next_local(this); - - if (sym() != nullptr) { - /* if this type is bounded to a symbol, declare that symbol */ - env.symtab().AddToScope(sym(), info); - } - } -#endif - -#if 0 - void EnumType::CodeGen(CgenEnv& env) { - for (auto memb : *membs()) { - const auto imm = new ImmediateValue(memb->eval(), bytes()); - auto info = new ConstSymInfo(this, imm); - env.symtab().AddToScope(memb->sym(), info); - } - - ASTType::CodeGen(env); - } -#endif - Block *ReturnStat::CodeGen(CgenEnv& env, Block *block) { /* generate returned expression * For now, assume result will be in %a or %hl. */ @@ -258,7 +234,7 @@ namespace zc { env.stat_stack().Push(stat_info); pred_block = pred()->CodeGen(env, pred_block, ASTExpr::ExprKind::EXPR_RVALUE); - emit_nonzero_test(env, block, pred()->type()->bytes()); + emit_nonzero_test(env, pred_block, pred()->type()->bytes()); /* CHANGED */ pred_block->transitions().vec().push_back(new JumpTransition(body_block, Cond::NZ)); pred_block->transitions().vec().push_back(new JumpTransition(join_block, Cond::ANY)); @@ -272,6 +248,42 @@ namespace zc { return join_block; } + Block *ForStat::CodeGen(CgenEnv& env, Block *block) { + Label *cond_label = new_label("for_cond"); + Block *cond_block = new Block(cond_label); + BlockTransition *cond_trans = new JumpTransition(cond_block, Cond::ANY); + + Label *after_label = new_label("for_after"); + Block *after_block = new Block(after_label); + BlockTransition *after_trans = new JumpTransition(after_block, Cond::ANY); + + Label *body_label = new_label("for_body"); + Block *body_block = new Block(body_label); + BlockTransition *body_trans = new JumpTransition(body_block, Cond::NZ); + + Label *join_label = new_label("for_join"); + Block *join_block = new Block(join_label); + BlockTransition *join_trans = new JumpTransition(join_block, Cond::ANY); + + StatInfo *stat_info = new StatInfo(this, after_block, join_block); + env.stat_stack().Push(stat_info); + + block = init()->CodeGen(env, block, ASTExpr::ExprKind::EXPR_RVALUE); + block->transitions().vec().push_back(cond_trans); + block = pred()->CodeGen(env, cond_block, ASTExpr::ExprKind::EXPR_RVALUE); + emit_nonzero_test(env, block, pred()->type()->bytes()); + block->transitions().vec().push_back(body_trans); + block->transitions().vec().push_back(join_trans); + block = body()->CodeGen(env, body_block); + block->transitions().vec().push_back(after_trans); + block = after()->CodeGen(env, after_block, ASTExpr::ExprKind::EXPR_RVALUE); + block->transitions().vec().push_back(cond_trans); + + env.stat_stack().Pop(); + + return join_block; + } + Block *BreakStat::CodeGen(CgenEnv& env, Block *block) { StatInfo *stat_info = env.stat_stack().Find([](auto info){return info->stat()->can_break(); }); block->transitions().vec().push_back(new JumpTransition(stat_info->exit(), Cond::ANY)); @@ -600,7 +612,7 @@ namespace zc { case Kind::BOP_EQ: case Kind::BOP_NEQ: - emit_binop(env, block, this); + block = emit_binop(env, block, this); switch (lhs()->type()->bytes()) { case byte_size: block->instrs().push_back(new CompInstruction(&rv_a, &rv_b)); @@ -617,7 +629,7 @@ namespace zc { break; case Kind::BOP_LT: - emit_binop(env, block, this); + block = emit_binop(env, block, this); switch (lhs()->type()->bytes()) { case byte_size: /* cp a,b @@ -644,7 +656,7 @@ namespace zc { break; case Kind::BOP_LEQ: - emit_binop(env, block, this); + block = emit_binop(env, block, this); switch (lhs()->type()->bytes()) { case byte_size: /* scf @@ -674,7 +686,7 @@ namespace zc { break; case Kind::BOP_GT: - emit_binop(env, block, this); + block = emit_binop(env, block, this); switch (lhs()->type()->bytes()) { case byte_size: /* dec a @@ -706,7 +718,7 @@ namespace zc { break; case Kind::BOP_GEQ: - emit_binop(env, block, this); + block = emit_binop(env, block, this); switch (lhs()->type()->bytes()) { case byte_size: /* cp a,b @@ -734,7 +746,7 @@ namespace zc { break; case Kind::BOP_PLUS: - emit_binop(env, block, this); + block = emit_binop(env, block, this); switch (type()->bytes()) { case byte_size: /* add a,b */ @@ -749,7 +761,7 @@ namespace zc { break; case Kind::BOP_MINUS: - emit_binop(env, block, this); + block = emit_binop(env, block, this); switch (type()->bytes()) { case byte_size: /* sub a,b */ @@ -767,7 +779,7 @@ namespace zc { break; case Kind::BOP_TIMES: - emit_binop(env, block, this); + block = emit_binop(env, block, this); switch (type()->bytes()) { case byte_size: /* ld c,a @@ -791,6 +803,11 @@ namespace zc { case Kind::BOP_BITWISE_XOR: /* TODO */ abort(); + + case Kind::BOP_COMMA: + lhs()->CodeGen(env, block, ExprKind::EXPR_RVALUE); + rhs()->CodeGen(env, block, mode); + break; } return block; @@ -1101,7 +1118,7 @@ namespace zc { } } - void emit_binop(CgenEnv& env, Block *block, ASTBinaryExpr *expr) { + Block *emit_binop(CgenEnv& env, Block *block, ASTBinaryExpr *expr) { Block::InstrVec& instrs = block->instrs(); int bytes = expr->type()->bytes(); int lhs_bytes = expr->lhs()->type()->bytes(); @@ -1137,6 +1154,8 @@ namespace zc { break; default: abort(); } + + return block; } void emit_crt(const std::string& name, Block *block) { @@ -1407,6 +1426,10 @@ namespace zc { body()->FrameGen(frame); } + void ForStat::FrameGen(StackFrame& frame) const { + body()->FrameGen(frame); + } + void VarDeclaration::FrameGen(StackFrame& frame) const { frame.add_local(this); } diff --git a/cgen.hpp b/cgen.hpp index 31309da..1a4780f 100644 --- a/cgen.hpp +++ b/cgen.hpp @@ -308,7 +308,7 @@ namespace zc { * Generic emission routine for performing binary operation on two integers. * Post condition: lhs in %a or %hl; hs in %b or %de, depending on size. */ - void emit_binop(CgenEnv& env, Block *block, ASTBinaryExpr *expr); + Block *emit_binop(CgenEnv& env, Block *block, ASTBinaryExpr *expr); /** * Emit instructions that move the contents of the zero flag (ZF) into register %a. diff --git a/semant.cpp b/semant.cpp index a5d1159..9a04762 100644 --- a/semant.cpp +++ b/semant.cpp @@ -452,6 +452,15 @@ env.stat_stack().Pop(); } + void ForStat::TypeCheck(SemantEnv& env) { + env.stat_stack().Push(this); + init()->TypeCheck(env); + pred()->TypeCheck(env); + after()->TypeCheck(env); + body()->TypeCheck(env); + env.stat_stack().Pop(); + } + void GotoStat::TypeCheck(SemantEnv& env) { env.ext_env().LabelRef(label_id()); } @@ -700,6 +709,11 @@ type_ = IntegralType::Create(IntegralType::IntKind::SPEC_CHAR, loc()); } } + break; + + case Kind::BOP_COMMA: + type_ = rhs()->type(); + break; } } @@ -785,6 +799,9 @@ case Kind::BOP_DIVIDE: case Kind::BOP_MOD: return ExprKind::EXPR_RVALUE; + + case Kind::BOP_COMMA: + return ExprKind::EXPR_LVALUE; } } diff --git a/tst/semant/for-break.test b/tst/semant/for-break.test new file mode 100644 index 0000000..4121163 --- /dev/null +++ b/tst/semant/for-break.test @@ -0,0 +1,9 @@ +int main(int argc, char **argv) { + for (; argc > 0; --argc) { + if (argc == 1) { + break; + } + } + + return argc; +} diff --git a/tst/semant/for.test b/tst/semant/for.test new file mode 100644 index 0000000..0ede287 --- /dev/null +++ b/tst/semant/for.test @@ -0,0 +1,9 @@ +int main(int argc, char **argv) { + int i, j; + + for (i = 0, j = 0; i < 10; ++i) { + j = j + argc; + } + + return j; +}