From ad7519d4938f762af3de9755cc2874ecd49efeef Mon Sep 17 00:00:00 2001 From: Nicholas Mosier Date: Thu, 16 Jan 2020 17:05:38 -0500 Subject: [PATCH] fixed array bugs; wrote demo program --- DIARY | 17 ++++ asm/asm-crt.cpp | 145 +++++++++++++++++++++++++++++++++- asm/asm-crt.hpp | 2 +- ast/ast-type.hpp | 7 +- c.ypp | 3 - cgen.cpp | 167 ++++++++++++++++++++++++++------------- cgen.hpp | 6 +- crt-dump.sh | 67 ++++++++++++++++ crt.inc | 141 +++++++++++++++++++++++++++++++++ crt.z80 | 27 +++++++ demo/memcpy.c | 31 ++++++++ demo/memcpy.z80 | 175 +++++++++++++++++++++++++++++++++++++++++ semant.cpp | 49 +++++++++--- tst/semant/memcpy.test | 31 ++++++++ 14 files changed, 794 insertions(+), 74 deletions(-) create mode 100755 crt-dump.sh create mode 100644 crt.inc create mode 100644 crt.z80 create mode 100644 demo/memcpy.c create mode 100644 demo/memcpy.z80 create mode 100644 tst/semant/memcpy.test diff --git a/DIARY b/DIARY index 7604374..f7649bf 100644 --- a/DIARY +++ b/DIARY @@ -127,9 +127,26 @@ structs on [1], [2], [3] share the same unique ID, while [4] has a different uni [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). +01/16/2020 +[1 hr] Wrote script that searches through the TI 84+ CE C runtime (CRT) for given symbols (e.g. sprintf, imulu, etc.) and then prints out the disassembled contents. This script was tricky because the CRT functions use a trampoline (for stability across releases) -- that is, the static address `__sprintf' points to a single jump instruction that jumps to the real implemenation of _sprintf. + +[1 hr] I wrote a new C runtime function 'cdivu' that divides two unsigned chars. (The CRT already on the calculator did not have this, and fast division is non-trivial). I unit-tested this, and it works. + +[2 hr] Wrote program 'memcpy.c' to demonstrate current state of compiler. It contains three functions: + ``` + int main(int argc, char **argv); /* main */ + void *mymemset(void *dst, char c, size_t bytes); /* re-implementation of C memset function */ + void *mymemcpy(void *dst, void *src, size_t bytes); /* re-implementation of C memcpy function */ + ``` + At first, the program wouldn't compile; later, it wouldn't produce correct output and/or crash. I went back and fixed those bugs. This program behave correctly now. + memcpy.c compiles to approximately 170 lines of code (!!!). This should be a very easy to target for optimization. + TODO [ ] typedef [X] ++, -- [ ] +=, *=, etc. [ ] for + +need bdivs, bdivu +add signed/unsigned \ No newline at end of file diff --git a/asm/asm-crt.cpp b/asm/asm-crt.cpp index 4fe096f..799c321 100644 --- a/asm/asm-crt.cpp +++ b/asm/asm-crt.cpp @@ -4,8 +4,6 @@ namespace zc::z80 { - CRT crt; - CRT::CRT(const std::initializer_list& l) { for (const std::string& str : l) { Label *label = new Label(str); @@ -38,5 +36,148 @@ namespace zc::z80 { } } + CRT g_crt {"__longjmp", + "__memchr", + "__memcmp", + "__memcpy", + "__memmove", + "__memset", + "__memclear", + "_printf", + "__setjmp", + "_sprintf", + "__strcat", + "__strchr", + "__strcmp", + "__strcpy", + "__strcspn", + "__strlen", + "__strncat", + "__strncmp", + "__strncpy", + "__strpbrk", + "__strrchr", + "__strspn", + "__strstr", + "_strtok", + "_ret", + "__bldiy", + "__bshl", + "__bshru", + "__bstiy", + "__bstix", + "__case", + "__case16", + "__case16D", + "__case24", + "__case24D", + "__case8", + "__case8D", + "__frameset", + "__frameset0", + "__iand", + "__icmpzero", + "__idivs", + "__idivu", + "__idvrmu", + "__ildix", + "__ildiy", + "__imul_b", + "__imulu", + "__imuls", + "__indcall", + "__ineg", + "__inot", + "__ior", + "__irems", + "__iremu", + "__ishl", + "__ishl_b", + "__ishrs", + "__ishrs_b", + "__ishru", + "__ishru_b", + "__istix", + "__istiy", + "__itol", + "__ixor", + "__ladd", + "__ladd_b", + "__land", + "__lcmps", + "__lcmpu", + "__lcmpzero", + "__ldivs", + "__ldivu", + "__ldvrmu", + "__lldix", + "__lldiy", + "__lmuls", + "__lmulu", + "__lneg", + "__lnot", + "__lor", + "__lrems", + "__lremu", + "__lshl", + "__lshrs", + "__lshru", + "__lstix", + "__lstiy", + "__lsub", + "__lxor", + "__sand", + "__scmpzero", + "__sdivs", + "__sdivu", + "__seqcase", + "__seqcaseD", + "__setflag", + "__sldix", + "__sldiy", + "__smuls", + "__smulu", + "__sneg", + "__snot", + "__sor", + "__srems", + "__sremu", + "__sshl", + "__sshl_b", + "__sshrs", + "__sshrs_b", + "__sshru", + "__sshru_b", + "__sstix", + "__sstiy", + "__stoi", + "__stoiu", + "__sxor", + "__fppack", + "__fadd", + "__fcmp", + "__fdiv", + "__ftol", + "__ultof", + "__ltof", + "__fmul", + "__fneg", + "__fsub", + "_FLTMAX", + "_sqrtf", + "__frbtof", + "__frftob", + "__frftoub", + "__frftoi", + "__frftoui", + "__frftos", + "__frftous", + "__fritof", + "__fruitof", + "__frstof", + "__frubtof", + "__frustof", + "__cdivu", + }; } diff --git a/asm/asm-crt.hpp b/asm/asm-crt.hpp index a766e5a..860ff68 100644 --- a/asm/asm-crt.hpp +++ b/asm/asm-crt.hpp @@ -28,7 +28,7 @@ namespace zc::z80 { const Pair& add(const std::string& name); }; - extern CRT crt; + extern CRT g_crt; } #endif diff --git a/ast/ast-type.hpp b/ast/ast-type.hpp index 70de40b..8c9b33d 100644 --- a/ast/ast-type.hpp +++ b/ast/ast-type.hpp @@ -55,7 +55,9 @@ namespace zc { void Enscope(SemantEnv& env); virtual ASTType *Address() = 0; - virtual ASTType *Dereference(SemantEnv *env = nullptr) = 0; + virtual ASTType *Dereference(SemantEnv *env); + virtual bool decays() const { return false; } + virtual ASTType *Decay() { return this; } virtual int bytes() const = 0; void FrameGen(StackFrame& frame) const; @@ -79,6 +81,7 @@ namespace zc { virtual ASTType *get_containee() const override { return pointee(); } int depth() const { return depth_; } ASTType *pointee() const { return pointee_; } + bool is_void() const { return pointee()->kind() == Kind::TYPE_VOID; } template static PointerType *Create(Args... args) { @@ -544,6 +547,8 @@ namespace zc { virtual ASTType *Address() override; virtual ASTType *Dereference(SemantEnv *env) override { return elem(); } + virtual bool decays() const override { return true; } + virtual ASTType *Decay() override; virtual int bytes() const override; diff --git a/c.ypp b/c.ypp index e8b8be7..675e1c2 100644 --- a/c.ypp +++ b/c.ypp @@ -188,9 +188,6 @@ decl: decl_specs optional_init_declarator_list ';' { declarator->get_declarables($$); zc::Declaration *decl = $1->GetDecl(zc::g_semant_error, declarator); enscope_typedef(decl); - // auto type = zc::ASTType::Create(specs_type, declarator); - // $$->push_back(zc::VarDeclaration::Create(declarator->sym(), false, - // type, @1)); $$->push_back(decl); } diff --git a/cgen.cpp b/cgen.cpp index 1f0f369..d307c3b 100644 --- a/cgen.cpp +++ b/cgen.cpp @@ -47,9 +47,11 @@ namespace zc { Label *label = new Label(std::string("_") + *ext_decl->sym()); LabelValue *label_val = new LabelValue(label); - if (type->kind() == ASTType::Kind::TYPE_FUNCTION) { - /* Functions _always_ behave as lvalues, i.e. they are always treated as addresses. */ - addr_ = val_ = label_val; + if (type->kind() == ASTType::Kind::TYPE_FUNCTION || + type->kind() == ASTType::Kind::TYPE_ARRAY) + { + /* Functions and arrays _always_ behave as addresses */ + addr_ = val_ = label_val; } else { addr_ = label_val; @@ -59,9 +61,14 @@ namespace zc { } VarSymInfo::VarSymInfo(const Value *addr, const VarDeclaration *decl): SymInfo(), addr_(addr) { - auto loc = new MemoryLocation(addr); - auto val = new MemoryValue(loc, decl->bytes()); - val_ = val; + if (decl->type()->kind() == ASTType::Kind::TYPE_FUNCTION || + decl->type()->kind() == ASTType::Kind::TYPE_ARRAY) { + val_ = addr; + } else { + auto loc = new MemoryLocation(addr); + auto val = new MemoryValue(loc, decl->bytes()); + val_ = val; + } } /*** STRING CONSTANTS ***/ @@ -138,7 +145,7 @@ namespace zc { env.ext_env().Exit(); env.ExitScope(); } - + Block *CompoundStat::CodeGen(CgenEnv& env, Block *block, bool new_scope) { if (new_scope) { env.EnterScope(); @@ -702,14 +709,12 @@ namespace zc { case word_size: abort(); case long_size: - /* dec hl - * xor a,a + /* scf * sbc hl,de * sbc a,a * inc a */ - block->instrs().push_back(new DecInstruction(&rv_hl)); - block->instrs().push_back(new XorInstruction(&rv_a, &rv_a)); + block->instrs().push_back(new ScfInstruction()); block->instrs().push_back(new SbcInstruction(&rv_hl, &rv_de)); block->instrs().push_back(new SbcInstruction(&rv_a, &rv_a)); block->instrs().push_back(new IncInstruction(&rv_a)); @@ -798,11 +803,63 @@ namespace zc { case Kind::BOP_DIVIDE: case Kind::BOP_MOD: + block = emit_binop(env, block, this, &rv_bc); + switch (type()->bytes()) { + case byte_size: + emit_crt("__cdivu", block); + if (kind() == Kind::BOP_MOD) { + block->instrs().push_back(new LoadInstruction(&rv_a, &rv_b)); + } + break; + case word_size: abort(); + case long_size: + emit_crt("__idivu", block); + if (kind() == Kind::BOP_MOD) { + block->instrs().push_back(new PushInstruction(&rv_bc)); + block->instrs().push_back(new PopInstruction(&rv_hl)); + } + break; + } + break; + case Kind::BOP_BITWISE_AND: + block = emit_binop(env, block, this, &rv_bc); + switch (type()->bytes()) { + case byte_size: + block->instrs().push_back(new AndInstruction(&rv_a, &rv_b)); + break; + case word_size: abort(); + case long_size: + emit_crt("__iand", block); + break; + } + break; + case Kind::BOP_BITWISE_OR: + block = emit_binop(env, block, this, &rv_bc); + switch (type()->bytes()) { + case byte_size: + block->instrs().push_back(new OrInstruction(&rv_a, &rv_b)); + break; + case word_size: abort(); + case long_size: + emit_crt("__ior", block); + break; + } + break; + case Kind::BOP_BITWISE_XOR: - /* TODO */ - abort(); + block = emit_binop(env, block, this, &rv_bc); + switch (type()->bytes()) { + case byte_size: + block->instrs().push_back(new OrInstruction(&rv_a, &rv_b)); + break; + case word_size: abort(); + case long_size: + emit_crt("__ixor", block); + break; + } + break; case Kind::BOP_COMMA: lhs()->CodeGen(env, block, ExprKind::EXPR_RVALUE); @@ -841,33 +898,26 @@ namespace zc { Block *IdentifierExpr::CodeGen(CgenEnv& env, Block *block, ExprKind mode) { const SymInfo *id_info = env.symtab().Lookup(id()->id()); - switch (mode) { - case ExprKind::EXPR_NONE: abort(); - case ExprKind::EXPR_LVALUE: - { - /* obtain address of identifier */ - const Value *id_addr = dynamic_cast(id_info)->addr(); - block->instrs().push_back(new LeaInstruction(&rv_hl, id_addr)); - } - break; + + if (mode == ExprKind::EXPR_LVALUE || type()->kind() == ASTType::Kind::TYPE_ARRAY) { + /* obtain address of identifier */ + const Value *id_addr = dynamic_cast(id_info)->addr(); + block->instrs().push_back(new LeaInstruction(&rv_hl, id_addr)); + } else { + const Value *id_rval = id_info->val(); + const RegisterValue *rv; - case ExprKind::EXPR_RVALUE: - { - const Value *id_rval = id_info->val(); - const RegisterValue *rv; - switch (type()->bytes()) { - case byte_size: - rv = &rv_a; - break; - case word_size: abort(); - case long_size: - rv = &rv_hl; - break; - default: abort(); - } - block->instrs().push_back(new LoadInstruction(rv, id_rval)); + switch (type()->bytes()) { + case byte_size: + rv = &rv_a; + break; + case word_size: abort(); + case long_size: + rv = &rv_hl; + break; + default: abort(); } - break; + block->instrs().push_back(new LoadInstruction(rv, id_rval)); } return block; @@ -877,10 +927,11 @@ namespace zc { /* push arguments onto stack (1st arg is highest on stack) */ /* codegen params */ - for (ASTExpr *param : params()->vec()) { + for (auto it = params()->vec().rbegin(), end = params()->vec().rend(); it != end; ++it) { + auto param = *it; block = param->CodeGen(env, block, ExprKind::EXPR_RVALUE); const RegisterValue *rv; - switch (param->type()->bytes()) { + switch (param->type()->Decay()->bytes()) { case byte_size: rv = &rv_af; break; @@ -1119,6 +1170,11 @@ namespace zc { } Block *emit_binop(CgenEnv& env, Block *block, ASTBinaryExpr *expr) { + return emit_binop(env, block, expr, &rv_de); + } + + Block *emit_binop(CgenEnv& env, Block *block, ASTBinaryExpr *expr, + const RegisterValue *long_rhs_reg) { Block::InstrVec& instrs = block->instrs(); int bytes = expr->type()->bytes(); int lhs_bytes = expr->lhs()->type()->bytes(); @@ -1150,7 +1206,7 @@ namespace zc { break; case word_size: abort(); case long_size: - block->instrs().push_back(new PopInstruction(&rv_de)); + block->instrs().push_back(new PopInstruction(long_rhs_reg)); break; default: abort(); } @@ -1159,7 +1215,7 @@ namespace zc { } void emit_crt(const std::string& name, Block *block) { - const LabelValue *lv = crt.val(name); + const LabelValue *lv = g_crt.val(name); block->instrs().push_back(new CallInstruction(lv)); } @@ -1397,21 +1453,23 @@ namespace zc { if (next_local_addr_ == nullptr) { next_local_addr_ = &FP_idxval; } + VarSymInfo *info = new VarSymInfo(next_local_addr_, decl); - next_local_addr_ = next_local_addr_->Add(decl->bytes()); + next_local_addr_ = next_local_addr_->Add(decl->type()->bytes()); return info; - } - + } + + void FunctionDef::FrameGen(StackFrame& frame) const { comp_stat()->FrameGen(frame); } - - void CompoundStat::FrameGen(StackFrame& frame) const { - for (const Declaration *decl : *decls()) { - decl->FrameGen(frame); - } - for (const ASTStat *stat : stats()->vec()) { - stat->FrameGen(frame); + + void CompoundStat::FrameGen(StackFrame& frame) const { + for (const Declaration *decl : *decls()) { + decl->FrameGen(frame); + for (const ASTStat *stat : stats()->vec()) { + stat->FrameGen(frame); + } } } @@ -1448,10 +1506,11 @@ namespace zc { env.symtab().AddToScope (sym(), - new ConstSymInfo(VarDeclaration::Create(sym(), true, enum_type(), loc()), - val)); + new ConstSymInfo(val, VarDeclaration::Create(sym(), true, enum_type(), loc()))); } + + void EnumType::Declare(CgenEnv& env) { if (membs()) { diff --git a/cgen.hpp b/cgen.hpp index 1a4780f..f09b360 100644 --- a/cgen.hpp +++ b/cgen.hpp @@ -46,7 +46,7 @@ namespace zc { const Value *val_; SymInfo(): decl_(nullptr), val_(nullptr) {} - SymInfo(const VarDeclaration *decl, const Value *val): decl_(decl), val_(val) {} + SymInfo(const Value *val, const VarDeclaration *decl): decl_(decl), val_(val) {} }; class ConstSymInfo: public SymInfo { @@ -66,6 +66,8 @@ namespace zc { const Value *addr() const { return addr_; } VarSymInfo(const Value *addr, const VarDeclaration *decl); + template + VarSymInfo(const Value *addr, Args... args): SymInfo(args...), addr_(addr) {} VarSymInfo(const ExternalDecl *ext_decl); private: @@ -309,6 +311,8 @@ namespace zc { * Post condition: lhs in %a or %hl; hs in %b or %de, depending on size. */ Block *emit_binop(CgenEnv& env, Block *block, ASTBinaryExpr *expr); + Block *emit_binop(CgenEnv& env, Block *block, ASTBinaryExpr *expr, + const RegisterValue *long_rhs_reg); /** * Emit instructions that move the contents of the zero flag (ZF) into register %a. diff --git a/crt-dump.sh b/crt-dump.sh new file mode 100755 index 0000000..352c99a --- /dev/null +++ b/crt-dump.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +USAGE="usage: $0 [-l lab] [-d dump] [-n lines] symbol" + +LAB=crt.inc +DUMP=ce.asm +LINES=30 + +while getopts "l:d:n:h" opt +do + case $opt in + l) + LAB="$OPTARG" + ;; + d) + DUMP="$OPTARG" + ;; + n) + LINES=$(("$OPTARG")) + ;; + h) + echo $USAGE + exit 0 + ;; + ?) + echo $USAGE + exit 1 + ;; + esac +done + +shift $((OPTIND-1)) +if [[ $# -lt 1 ]] +then + echo $USAGE + exit 1 +fi + +SYM="$1" +shift 1 + +# find symbol in symbol table +ADDR=$((0x`grep -m1 "\<$SYM\>" "$LAB" | grep -o -E "[[:xdigit:]]{7}"`)) + +if [[ 0x$ADDR -eq 0 ]] +then + echo "$0: \"$SYM\" not found" + exit 1 +fi + +echo \"$SYM\" @ $(printf 0x%06x $ADDR) + +# find address in dump +REAL_ADDR=$(grep -m1 "^"`printf %06x $ADDR`":" "$DUMP" | grep -o -E "[[:xdigit:]]+$") + +if [[ 0x$REAL_ADDR -eq 0 ]] +then + echo "$0: error in looking up \"$SYM\"" + exit 1 +fi + +echo \"_$SYM\" @ 0x"$REAL_ADDR" + +# print out dump +REAL_ADDR=$(printf %06x $((0x$REAL_ADDR))) +L=$(awk '/^'$REAL_ADDR':/ { print NR; exit 0 }' "$DUMP") +tail -n +"$L" "$DUMP" | head -n "$LINES" diff --git a/crt.inc b/crt.inc new file mode 100644 index 0000000..37410d5 --- /dev/null +++ b/crt.inc @@ -0,0 +1,141 @@ +__longjmp equ 0000098h +__memchr equ 000009Ch +__memcmp equ 00000A0h +__memcpy equ 00000A4h +__memmove equ 00000A8h +__memset equ 00000ACh +__memclear equ 00000B0h +_printf equ 00000B4h +__setjmp equ 00000B8h +_sprintf equ 00000BCh +__strcat equ 00000C0h +__strchr equ 00000C4h +__strcmp equ 00000C8h +__strcpy equ 00000CCh +__strcspn equ 00000D0h +__strlen equ 00000D4h +__strncat equ 00000D8h +__strncmp equ 00000DCh +__strncpy equ 00000E0h +__strpbrk equ 00000E4h +__strrchr equ 00000E8h +__strspn equ 00000ECh +__strstr equ 00000F0h +_strtok equ 00000F4h +_ret equ 00000F8h +__bldiy equ 00000FCh +__bshl equ 0000100h +__bshru equ 0000104h +__bstiy equ 0000108h +__bstix equ 000010Ch +__case equ 0000110h +__case16 equ 0000114h +__case16D equ 0000118h +__case24 equ 000011Ch +__case24D equ 0000120h +__case8 equ 0000124h +__case8D equ 0000128h +__frameset equ 000012Ch +__frameset0 equ 0000130h +__iand equ 0000134h +__icmpzero equ 0000138h +__idivs equ 000013Ch +__idivu equ 0000140h +__idvrmu equ 0000144h +__ildix equ 0000148h +__ildiy equ 000014Ch +__imul_b equ 0000150h +__imulu equ 0000154h +__imuls equ 0000158h +__indcall equ 000015Ch +__ineg equ 0000160h +__inot equ 0000164h +__ior equ 0000168h +__irems equ 000016Ch +__iremu equ 0000170h +__ishl equ 0000174h +__ishl_b equ 0000178h +__ishrs equ 000017Ch +__ishrs_b equ 0000180h +__ishru equ 0000184h +__ishru_b equ 0000188h +__istix equ 000018Ch +__istiy equ 0000190h +__itol equ 0000194h +__ixor equ 0000198h +__ladd equ 000019Ch +__ladd_b equ 00001A0h +__land equ 00001A4h +__lcmps equ 00001A8h +__lcmpu equ 00001ACh +__lcmpzero equ 00001B0h +__ldivs equ 00001B4h +__ldivu equ 00001B8h +__ldvrmu equ 00001BCh +__lldix equ 00001C0h +__lldiy equ 00001C4h +__lmuls equ 00001C8h +__lmulu equ 00001CCh +__lneg equ 00001D0h +__lnot equ 00001D4h +__lor equ 00001D8h +__lrems equ 00001DCh +__lremu equ 00001E0h +__lshl equ 00001E4h +__lshrs equ 00001E8h +__lshru equ 00001ECh +__lstix equ 00001F0h +__lstiy equ 00001F4h +__lsub equ 00001F8h +__lxor equ 00001FCh +__sand equ 0000200h +__scmpzero equ 0000204h +__sdivs equ 0000208h +__sdivu equ 000020Ch +__seqcase equ 0000210h +__seqcaseD equ 0000214h +__setflag equ 0000218h +__sldix equ 000021Ch +__sldiy equ 0000220h +__smuls equ 0000224h +__smulu equ 0000228h +__sneg equ 000022Ch +__snot equ 0000230h +__sor equ 0000234h +__srems equ 0000238h +__sremu equ 000023Ch +__sshl equ 0000240h +__sshl_b equ 0000244h +__sshrs equ 0000248h +__sshrs_b equ 000024Ch +__sshru equ 0000250h +__sshru_b equ 0000254h +__sstix equ 0000258h +__sstiy equ 000025Ch +__stoi equ 0000260h +__stoiu equ 0000264h +__sxor equ 0000268h +__fppack equ 000026Ch +__fadd equ 0000270h +__fcmp equ 0000274h +__fdiv equ 0000278h +__ftol equ 000027Ch +__ultof equ 0000280h +__ltof equ 0000284h +__fmul equ 0000288h +__fneg equ 000028Ch +__fsub equ 0000290h +_FLTMAX equ 0000294h +_sqrtf equ 0000298h +__frbtof equ 000029Ch +__frftob equ 00002A0h +__frftoub equ 00002A4h +__frftoi equ 00002A8h +__frftoui equ 00002ACh +__frftos equ 00002B0h +__frftous equ 00002B4h +__fritof equ 00002B8h +__fruitof equ 00002BCh +__frstof equ 00002C0h +__frubtof equ 00002C4h +__frustof equ 00002C8h diff --git a/crt.z80 b/crt.z80 new file mode 100644 index 0000000..3458ddc --- /dev/null +++ b/crt.z80 @@ -0,0 +1,27 @@ +; divide unsigned chars +; ARGS: +; - a: numerator +; - b: denominator +; RETV: +; - a: quotient +; - b: remainder +__cdivu: + push de + ld e,c + ld c,a + ld d,b + ld b,8 + xor a,a +__cdivu.loop: + sla c + adc a,a + cp a,d + jr c,_ + sub a,d + inc c +_: djnz __cdivu.loop + ld b,a + ld a,c + ld c,e + pop de + ret \ No newline at end of file diff --git a/demo/memcpy.c b/demo/memcpy.c new file mode 100644 index 0000000..5a57e28 --- /dev/null +++ b/demo/memcpy.c @@ -0,0 +1,31 @@ +typedef long size_t; + +void *mymemset(void *buf, char c, size_t len) { + char *buf_it; + + for (buf_it = buf; len > 0; --len) { + *buf_it++ = c; + } + + return buf; +} + +void *mymemcpy(void *dst, void *src, size_t n) { + char *dst_it, *src_it; + + for (dst_it = dst, src_it = src; n > 0; --n) { + *dst_it++ = *src_it++; + } + + return dst; +} + +int main(int argc, char **argv) { + char dst[10]; + char src[10]; + + mymemset(src, 42, 10); + mymemcpy(dst, src, 10); + + return 0; +} diff --git a/demo/memcpy.z80 b/demo/memcpy.z80 new file mode 100644 index 0000000..8ae445b --- /dev/null +++ b/demo/memcpy.z80 @@ -0,0 +1,175 @@ +#include "ti84pce.inc" + +_indcall .equ __indcall + +.org userMem - 2 +.db tExtTok, tAsm84CeCmp + +_start: + ld hl, 25 + push hl + call _main + pop de + ld iy,flags + ret + +#include "crt.z80" + +_mymemset: + push ix + ld ix,-3 + add ix,sp + ld sp,ix + ld hl,(ix+9) + push hl + lea hl,ix+0 + pop de + ld (hl),de + jp __LABEL_for_cond_0 +__LABEL_for_cond_0: + ld hl,0 + push hl + ld hl,(ix+15) + pop de + scf + sbc hl,de + sbc a,a + inc a + or a,a + jp nz,__LABEL_for_body_2 + jp __LABEL_for_join_3 +__LABEL_for_join_3: + ld hl,(ix+9) + jp __frameunset_mymemset + jp __LABEL__4 +__LABEL__4: + jp __frameunset_mymemset +__LABEL_for_body_2: + ld a,(ix+12) + push af + lea hl,ix+0 + ld de,(hl) + inc de + ld (hl),de + dec de + ex de,hl + pop af + ld (hl),a + jp __LABEL_for_after_1 +__LABEL_for_after_1: + lea hl,ix+15 + ld de,(hl) + dec de + ld (hl),de + ex de,hl + jp __LABEL_for_cond_0 +__frameunset_mymemset: + lea ix,ix+3 + ld sp,ix + pop ix + ret +_mymemcpy: + push ix + ld ix,-6 + add ix,sp + ld sp,ix + ld hl,(ix+12) + push hl + lea hl,ix+0 + pop de + ld (hl),de + ld hl,(ix+15) + push hl + lea hl,ix+3 + pop de + ld (hl),de + jp __LABEL_for_cond_5 +__LABEL_for_cond_5: + ld hl,0 + push hl + ld hl,(ix+18) + pop de + scf + sbc hl,de + sbc a,a + inc a + or a,a + jp nz,__LABEL_for_body_7 + jp __LABEL_for_join_8 +__LABEL_for_join_8: + ld hl,(ix+12) + jp __frameunset_mymemcpy + jp __LABEL__9 +__LABEL__9: + jp __frameunset_mymemcpy +__LABEL_for_body_7: + lea hl,ix+3 + ld de,(hl) + inc de + ld (hl),de + dec de + ex de,hl + ld a,(hl) + push af + lea hl,ix+0 + ld de,(hl) + inc de + ld (hl),de + dec de + ex de,hl + pop af + ld (hl),a + jp __LABEL_for_after_6 +__LABEL_for_after_6: + lea hl,ix+18 + ld de,(hl) + dec de + ld (hl),de + ex de,hl + jp __LABEL_for_cond_5 +__frameunset_mymemcpy: + lea ix,ix+6 + ld sp,ix + pop ix + ret +_main: + push ix + ld ix,-20 + add ix,sp + ld sp,ix + ld hl,10 + push hl + ld hl,42 + push hl + lea hl,ix+10 + push hl + ld hl,_mymemset + push hl + pop iy + call __indcall + pop de + pop de + pop de + ld hl,10 + push hl + lea hl,ix+10 + push hl + lea hl,ix+0 + push hl + ld hl,_mymemcpy + push hl + pop iy + call __indcall + pop de + pop de + pop de + ld hl,0 + jp __frameunset_main + jp __LABEL__10 +__LABEL__10: + jp __frameunset_main +__frameunset_main: + lea ix,ix+20 + ld sp,ix + pop ix + ret diff --git a/semant.cpp b/semant.cpp index 9a04762..1ee000d 100644 --- a/semant.cpp +++ b/semant.cpp @@ -617,8 +617,7 @@ break; case Kind::UOP_DEREFERENCE: - if ((type_ = type->Dereference()) == nullptr) { - env.error()(g_filename, this) << "attempt to dereference non-pointer type" << std::endl; + if ((type_ = type->Dereference(&env)) == nullptr) { type_ = type; } break; @@ -735,7 +734,7 @@ } else { auto var = dynamic_cast(decl); if (var) { - type_ = var->type(); + type_ = var->type();//->Decay(); is_const_ = var->is_const(); } else { env.error()(g_filename, this) << "identifier '" << *id()->id() @@ -814,7 +813,13 @@ } ASTExpr::ExprKind IdentifierExpr::expr_kind() const { - return is_const() ? ExprKind::EXPR_RVALUE : ExprKind::EXPR_LVALUE; + if (is_const()) { + return ExprKind::EXPR_RVALUE; + } else if (type()->kind() == ASTType::Kind::TYPE_ARRAY) { + return ExprKind::EXPR_RVALUE; + } else { + return ExprKind::EXPR_LVALUE; + } } intmax_t IdentifierExpr::int_const() const { @@ -886,11 +891,13 @@ return true; } + bool isvoid = pointee()->kind() == ASTType::Kind::TYPE_VOID; + /* check if `from' is an array. */ const ArrayType *from_arr = dynamic_cast(from); if (from_arr != nullptr) { /* ensure base elements are of same type */ - return from_arr->TypeEq(pointee()); + return from_arr->TypeEq(pointee()) || is_void(); } /* check if this is a function pointer and `from' is a function */ @@ -904,13 +911,8 @@ if (from_ptr == nullptr) { return false; /* can never implicitly cast from non-pointer type to pointer type */ } - - /* 1. Check if coercing to 'void *'. */ - if (pointee()->kind() == ASTType::Kind::TYPE_VOID) { - return true; - } - return false; /* cannot coerce since pointers are non-identical and `to' is not void ptr */ + return from_ptr->is_void() || is_void(); } bool FunctionType::TypeCoerce(const ASTType *from) const { @@ -1050,10 +1052,33 @@ ASTType *ArrayType::Address() { return PointerType::Create(1, this, loc()); } - + + /*** DECAY TYPE ***/ + ASTType *ArrayType::Decay() { + return PointerType::Create(1, get_containee(), loc()); + } /*** DEREFERENCE TYPE ***/ + ASTType *ASTType::Dereference(SemantEnv *env) { + if (env) { + env->error()(g_filename, this) << "attempt to dereference non-pointer type" << std::endl; + } else { + abort(); + } + + return nullptr; + } + + ASTType *PointerType::Dereference(SemantEnv *env) { + if (is_void()) { + if (env) { + env->error()(g_filename, this) << "cannot dereference void pointer" << std::endl; + } else { + abort(); + } + } + if (depth() == 1) { return pointee(); } else { diff --git a/tst/semant/memcpy.test b/tst/semant/memcpy.test new file mode 100644 index 0000000..17e5b7e --- /dev/null +++ b/tst/semant/memcpy.test @@ -0,0 +1,31 @@ +typedef long size_t; + +void *memset(void *buf, char c, size_t len) { + char *buf_it; + + for (buf_it = buf; len > 0; --len) { + *buf_it++ = c; + } + + return buf; +} + +void *memcpy(void *dst, void *src, size_t n) { + char *dst_it, *src_it; + + for (dst_it = dst, src_it = src; n > 0; --n) { + *dst_it++ = *src++; + } + + return dst; +} + +int main(int argc, char **argv) { + char dst[10]; + char src[10]; + + memset(src, 42, 10); + memcpy(dst, src, 10); + + return 0; +}