X-Git-Url: http://j8takagi.net/cgi-bin/gitweb.cgi?p=YACASL2.git;a=blobdiff_plain;f=src%2Fassemble.c;h=c9f1345c00a65b0c815fed3ee7c3e2414917b66d;hp=3549c610fa6a0121a22697a7378d4aa6b2d35f04;hb=4ee27a568fb9222907a566e59aaefe248f08a8e4;hpb=44cde08e6cf148928a219593c78a57abfd89b424 diff --git a/src/assemble.c b/src/assemble.c index 3549c61..c9f1345 100644 --- a/src/assemble.c +++ b/src/assemble.c @@ -1,26 +1,58 @@ #include "casl2.h" #include "assemble.h" -/* 値を格納するポインタ */ -WORD ptr; +/* アセンブルモード: src, label, onlylabel, asdetail, onlyassemble */ +ASMODE asmode = {false, false, false, false, false}; -/* リテラル(=付きの値)を格納するポインタ */ -WORD lptr; +/* アセンブル時のプロパティ */ +ASPROP *asprop; -/* 汎用レジスタを表す文字列「GR[0-7]」をWORD値に変換 - is_xがtrueの場合は、指標レジスタとして用いる汎用レジスタ - 文字列が汎用レジスタを表さない場合は、0xFFFFを返す */ +/* アセンブルのエラー定義 */ +CERR cerr_assemble[] = { + { 101, "label already defined" }, + { 102, "label table is full" }, + { 103, "label not found" }, + { 104, "label length is too long" }, + { 105, "no command in the line" }, + { 106, "operand mismatch in assemble command" }, + { 107, "no label in START" }, + { 108, "not command of operand \"r\"" }, + { 109, "not command of operand \"r1,r2\"" }, + { 110, "not command of operand \"r,adr[,x]\"" }, + { 111, "not command of operand \"adr[,x]\"" }, + { 112, "not command of no operand" }, + { 113, "operand too many in COMET II command" }, + { 117, "operand too many in DC" }, + { 118, "operand length too long" }, + { 119, "out of COMET II memory" }, + { 120, "GR0 in operand x" }, + { 121, "cannot get operand token" }, + { 122, "cannot create hash table" }, + { 123, "unclosed quote" }, + { 124, "more than one character in literal" }, + { 125, "not GR in operand x" }, +}; + +bool addcerrlist_assemble() +{ + return addcerrlist(ARRAYSIZE(cerr_assemble), cerr_assemble); +} + +/* 汎用レジスタを表す文字列「GR[0-7]」から、レジスタ番号[0-7]をWORD値で返す */ +/* 文字列が汎用レジスタを表さない場合は、0xFFFFを返す */ +/* is_xがtrueの場合は指標レジスタ。GR0は、COMET IIの仕様により、エラー発生 */ WORD getgr(const char *str, bool is_x) { assert(str != NULL); WORD r; + /* 「GR[0-7]」以外の文字列では、0xFFFFを返して終了 */ if(!(strlen(str) == 3 && strncmp(str, "GR", 2) == 0 && - (*(str+2) >= '0' && *(str+2) <= '7'))) + (*(str+2) >= '0' && *(str+2) <= '0' + GRSIZE))) { return 0xFFFF; } r = (WORD)(*(str+2) - '0'); - /* COMET IIの仕様により、GR0は指標レジスタとして用いることはできない */ + /* GR0は指標レジスタとして用いることができない */ if(is_x == true && r == 0x0) { setcerr(120, NULL); /* GR0 in operand x */ return 0x0; @@ -28,76 +60,38 @@ WORD getgr(const char *str, bool is_x) return r; } -/* 10進定数をWORD値に変換 */ -WORD getint(const char *str) -{ - assert(isdigit(*str) || *str == '-'); - char *check; - int n; - /* WORD値に変換 */ - n = strtol(str, &check, 10); - if(*check != '\0') { - setcerr(114, str); /* not integer */ - return 0x0; - } - /* nが-32768〜32767の範囲にないときは、その下位16ビットを格納 */ - if(n < -32768 || n > 32767) { - n = n % 32768; - } - return (WORD)n; -} - -/* 16進定数をWORD値に変換 */ -WORD gethex(const char *str) -{ - assert(*str == '#'); - WORD adr = 0x0; - char *check; - str++; - if(*str == '-' || strlen(str) > 4) { - setcerr(116, str-1); /* out of hex range */ - return 0; - } - /* WORD値に変換 */ - adr = (WORD)strtol(str, &check, 16); - if(*check != '\0') { - setcerr(115, str-1); /* not hex */ - return 0x0; - } - return adr; -} - -/* アドレスを返す - アドレスには、リテラル/10進定数/16進定数/アドレス定数が含まれる */ -WORD getadr(const char *str, PASS pass) +/* アドレスを返す */ +/* アドレスには、リテラル/10進定数/16進定数/アドレス定数が含まれる */ +WORD getadr(const char *prog, const char *str, PASS pass) { WORD adr = 0x0; if(*str == '=') { adr = getliteral(str, pass); - } else if(*str == '#') { - adr = gethex(str); - } else if(isdigit(*str) || *str == '-') { - adr = getint(str); + } else if(isdigit(*str) || *str == '-' || *str == '#') { + adr = nh2word(str); } else { - if(pass == SECOND && (adr = getlabel(str)) == 0xFFFF) { - setcerr(103, str); /* label not found */ + if(pass == SECOND && (adr = getlabel(prog, str)) == 0xFFFF) { + if(prog != NULL) { + setcerr(103, str); /* label not found */ + } } } return adr; } -/* WORD値wordをアドレスadrに書込 - 書込に成功した場合はtrue、失敗した場合はfalseを返す */ +/* WORD値wordをアドレスadrに書込 */ +/* 書込に成功した場合はtrue、失敗した場合はfalseを返す */ bool writememory(WORD word, WORD adr, PASS pass) { bool status = false; + /* COMET IIメモリオーバーの場合 */ - if(adr >= MEMSIZE) { - setcerr(119, wtoa(adr)); /* out of COMET II memory */ + if(adr >= memsize) { + setcerr(119, word2n(adr)); /* out of COMET II memory */ } - if(cerrno == 0) { + if(cerr->num == 0) { memory[adr] = word; - if(pass == SECOND && asdetailmode == true) { + if(pass == SECOND && asmode.asdetail == true) { fprintf(stdout, "\t#%04X\t#%04X\n", adr, word); } status = true; @@ -109,19 +103,12 @@ bool writememory(WORD word, WORD adr, PASS pass) /* リテラルには、10進定数/16進定数/文字定数が含まれる */ WORD getliteral(const char *str, PASS pass) { - WORD adr = lptr, word = 0x0; + WORD adr = asprop->lptr; assert(*str == '='); - str++; - if(*str == '\'') { /* 文字定数 */ + if(*(++str) == '\'') { /* 文字定数 */ writestr(str, true, pass); } else { - if(*str == '#') { /* 16進定数 */ - word = gethex(str); - } else if(isdigit(*str) || *str == '-') { /* 10進定数 */ - word = getint(str); - } - /* リテラル領域に書込 */ - writememory(word, lptr++, pass); + writememory(nh2word(str), (asprop->lptr)++, pass); } return adr; } @@ -130,21 +117,29 @@ WORD getliteral(const char *str, PASS pass) /* DC命令とリテラルで使い、リテラルの場合はリテラル領域に書込 */ void writestr(const char *str, bool literal, PASS pass) { - assert(cerrno == 0); - assert(*str == '\''); - str++; - while(*str != '\0') { - if(*str == '\'') { - if(*(str+1) != '\'') { - break; - } - str++; + assert(cerr->num == 0 && *str == '\''); + const char *p = str + 1; + bool lw = false; + + for(; ;) { + /* 閉じ「'」がないまま文字列が終了した場合 */ + if(*p == '\0') { + setcerr(123, str); /* unclosed quote */ + break; + } + /* 「'」の場合、次の文字が「'」でない場合は正常終了 */ + if(*p == '\'' && *(++p) != '\'') { + break; + } else if(literal == true && lw == true) { + setcerr(124, str); /* more than one character in literal */ + break; } /*リテラルの場合はリテラル領域に書込 */ if(literal == true) { - writememory(*(str++), lptr++, pass); + writememory(*(p++), (asprop->lptr)++, pass); + lw = true; } else { - writememory(*(str++), ptr++, pass); + writememory(*(p++), (asprop->ptr)++, pass); } } } @@ -153,24 +148,22 @@ void writestr(const char *str, bool literal, PASS pass) void writeDC(const char *str, PASS pass) { WORD adr = 0x0; - if(*str == '\''){ + if(*str == '\'') { writestr(str, false, pass); } else { - if(*str == '#') { - adr = gethex(str); - } else if(isdigit(*str) || *str == '-') { - adr = getint(str); + if(*str == '#' || isdigit(*str) || *str == '-') { + adr = nh2word(str); } else { - if(pass == SECOND && (adr = getlabel(str)) == 0xFFFF) { + if(pass == SECOND && (adr = getlabel(asprop->prog, str)) == 0xFFFF) { setcerr(103, str); /* label not found */ } } - writememory(adr, ptr++, pass); + writememory(adr, (asprop->ptr)++, pass); } } -/* 命令がアセンブラ命令の場合は処理を実行 - 実行に成功した場合はtrue、それ以外の場合はfalseを返す */ +/* 命令がアセンブラ命令の場合は処理を実行 */ +/* 実行に成功した場合はtrue、それ以外の場合はfalseを返す */ bool assemblecmd(const CMDLINE *cmdl, PASS pass) { int i = 0; @@ -179,7 +172,7 @@ bool assemblecmd(const CMDLINE *cmdl, PASS pass) CMDARRAY ascmd[] = { { START, 0, 1, "START" }, { END, 0, 0, "END" }, - { DC, 0, OPDSIZE, "DC" }, + { DC, 1, OPDSIZE, "DC" }, { DS, 1, 1, "DS" }, { 0, 0, 0, NULL } }; @@ -202,9 +195,11 @@ bool assemblecmd(const CMDLINE *cmdl, PASS pass) setcerr(107, NULL); /* no label in START */ return false; } - /* オペランドがある場合、実行開始番地を設定 */ + /* プログラム名の設定 */ + asprop->prog = strdup(cmdl->label); + /* オペランドがある場合、実行開始番地を設定 */ if(pass == SECOND && cmdl->opd->opdc == 1) { - if((startptr = getlabel(cmdl->opd->opdv[0])) == 0xFFFF) { + if((progprop->start = getlabel(asprop->prog, cmdl->opd->opdv[0])) == 0xFFFF) { setcerr(103, cmdl->opd->opdv[0]); /* label not found */ } } @@ -213,18 +208,19 @@ bool assemblecmd(const CMDLINE *cmdl, PASS pass) case END: /* リテラル領域の設定 */ if(pass == FIRST) { - lptr = ptr; + asprop->lptr = asprop->ptr; } /* 実行終了番地と次のプログラムの実行開始番地を設定 */ else if(pass == SECOND) { - endptr = lptr; + progprop->end = asprop->lptr; } + asprop->prog = NULL; status = true; break; case DS: for(i = 0; i < atoi(cmdl->opd->opdv[0]); i++) { - writememory(0x0, ptr++, pass); - if(cerrno > 0) { + writememory(0x0, (asprop->ptr)++, pass); + if(cerr->num > 0) { return false; } } @@ -233,7 +229,7 @@ bool assemblecmd(const CMDLINE *cmdl, PASS pass) case DC: for(i = 0; i < cmdl->opd->opdc; i++) { writeDC(cmdl->opd->opdv[i], pass); - if(cerrno > 0) { + if(cerr->num > 0) { return false; } } @@ -242,14 +238,14 @@ bool assemblecmd(const CMDLINE *cmdl, PASS pass) default: return false; } - if(cerrno > 0) { + if(cerr->num > 0) { status = false; } return status; } -/* 命令がマクロ命令の場合はメモリに書込 - 書込に成功した場合はtrue、それ以外の場合はfalseを返す */ +/* 命令がマクロ命令の場合はメモリに書込 */ +/* 書込に成功した場合はtrue、それ以外の場合はfalseを返す */ bool macrocmd(const CMDLINE *cmdl, PASS pass) { int i = 0; @@ -293,9 +289,8 @@ bool macrocmd(const CMDLINE *cmdl, PASS pass) return status; } - -/* 機械語命令の書込 - 書込に成功した場合はtrue、それ以外の場合はfalseを返す */ +/* 機械語命令の書込 */ +/* 書込に成功した場合はtrue、それ以外の場合はfalseを返す */ bool cometcmd(const CMDLINE *cmdl, PASS pass) { WORD cmd, adr, r1, r2, x; @@ -307,7 +302,7 @@ bool cometcmd(const CMDLINE *cmdl, PASS pass) setcerr(112, cmdl->cmd); /* not command of no operand */ return false; } - if(writememory(cmd, ptr++, pass) == true) { + if(writememory(cmd, (asprop->ptr)++, pass) == true) { status = true; } } @@ -320,7 +315,7 @@ bool cometcmd(const CMDLINE *cmdl, PASS pass) return false; } cmd |= (r1 << 4); - if(writememory(cmd, ptr++, pass) == true) { + if(writememory(cmd, (asprop->ptr)++, pass) == true) { status = true; } } @@ -329,16 +324,15 @@ bool cometcmd(const CMDLINE *cmdl, PASS pass) if((cmd = getcmdcode(cmdl->cmd, R1_R2)) == 0xFFFF) { setcerr(109, cmdl->cmd); /* not command of operand "r1,r2" */ return false; - } + } cmd |= ((r1 << 4) | r2); - if(cerrno == 0 && writememory(cmd, ptr++, pass) == true) { + if(cerr->num == 0 && writememory(cmd, (asprop->ptr)++, pass) == true) { status = true; } } - /* オペランド数2〜3。第2オペランドはアドレス、 - 第3オペランドは指標レジスタとして用いる汎用レジスタ */ - else if(cmdl->opd->opdc == 2 || cmdl->opd->opdc == 3) - { + /* オペランド数2〜3。第2オペランドはアドレス、 */ + /* 第3オペランドは指標レジスタとして用いる汎用レジスタ */ + else if(cmdl->opd->opdc == 2 || cmdl->opd->opdc == 3) { if((cmd = getcmdcode(cmdl->cmd, R_ADR_X_)) == 0xFFFF && (cmd = getcmdcode(cmdl->cmd, R_ADR_X)) == 0xFFFF) { @@ -349,39 +343,48 @@ bool cometcmd(const CMDLINE *cmdl, PASS pass) /* オペランド数3 */ if(cmdl->opd->opdc == 3) { if((x = getgr(cmdl->opd->opdv[2], true)) == 0xFFFF) { + setcerr(125, cmdl->cmd); /* not GR in operand x */ return false; } cmd |= x; } - adr = getadr(cmdl->opd->opdv[1], pass); - writememory(cmd, ptr++, pass); - writememory(adr, ptr++, pass); - if(cerrno == 0) { + adr = getadr(asprop->prog, cmdl->opd->opdv[1], pass); + writememory(cmd, (asprop->ptr)++, pass); + writememory(adr, (asprop->ptr)++, pass); + if(cerr->num == 0) { status = true; } } else { - setcerr(113, cmdl->cmd); /* command not defined */ + setcerr(113, cmdl->cmd); /* operand too many in COMET II command */ return false; } } /* オペランド数1〜2。第1オペランドはアドレス */ else if(cmdl->opd->opdc == 1 || cmdl->opd->opdc == 2) { - if((cmd = getcmdcode(cmdl->cmd, ADR_X)) == 0xFFFF) { + if((cmd = getcmdcode(cmdl->cmd, ADR_X)) == 0xFFFF) { setcerr(111, cmdl->cmd); /* not command of operand "adr[,x]" */ return false; } /* オペランド数2の場合、第2オペランドは指標レジスタとして用いる汎用レジスタ */ if(cmdl->opd->opdc == 2) { x = getgr(cmdl->opd->opdv[1], true); - if(cerrno > 0) { + if(cerr->num > 0) { return false; } cmd |= x; } - adr = getadr(cmdl->opd->opdv[0], pass); - writememory(cmd, ptr++, pass); - writememory(adr, ptr++, pass); - if(cerrno == 0) { + /* CALLの場合はプログラムの入口名を表すラベルを取得 */ + /* CALL以外の命令の場合と、プログラムの入口名を取得できない場合は、 */ + /* 同一プログラム内のラベルを取得 */ + if(pass == SECOND && cmd == 0x8000) { /* CALL命令 */ + adr = getlabel(NULL, cmdl->opd->opdv[0]); + } + if(cmd != 0x8000 || (pass == SECOND && adr == 0xFFFF)) { + adr = getadr(asprop->prog, cmdl->opd->opdv[0], pass); + } + writememory(cmd, (asprop->ptr)++, pass); + writememory(adr, (asprop->ptr)++, pass); + if(cerr->num == 0) { status = true; } } @@ -400,27 +403,31 @@ bool assembleline(const CMDLINE *cmdl, PASS pass) } } /* アセンブラ命令の処理 */ - else if(cerrno == 0 && assemblecmd(cmdl, pass) == true) { + else if(cerr->num == 0 && assemblecmd(cmdl, pass) == true) { ; } /* マクロ命令の書込 */ - else if(cerrno == 0 && macrocmd(cmdl, pass) == true) { + else if(cerr->num == 0 && macrocmd(cmdl, pass) == true) { ; } /* 機械語命令の書込 */ - else if(cerrno == 0 && cometcmd(cmdl, pass) == true) { + else if(cerr->num == 0 && cometcmd(cmdl, pass) == true) { ; } - else if(cerrno == 0) { - setcerr(113, cmdl->cmd); /* command not defined */ + else if(cerr->num == 0) { + setcerr(113, cmdl->cmd); /* operand too many in COMET II command */ } /* エラーが発生していないか確認 */ - if(cerrno == 0) { + if(cerr->num == 0) { status = true; } return status; } +void printline(FILE *stream, const char *filename, int lineno, char *line) { + fprintf(stream, "%s:%5d:%s", filename, lineno, line); +} + /* 指定された名前のファイルをアセンブル */ /* 2回実行される */ bool assemble(const char *file, PASS pass) @@ -430,27 +437,27 @@ bool assemble(const char *file, PASS pass) CMDLINE *cmdl; char *line; FILE *fp; - - if(create_cmdtype_code() == false) { - return false; - } + + addcerrlist_assemble(); if((fp = fopen(file, "r")) == NULL) { perror(file); return false; } for(; ;) { - cmdl = malloc(sizeof(CMDLINE)); - line = malloc(LINESIZE+1); + cmdl = malloc_chk(sizeof(CMDLINE), "cmdl"); + line = malloc_chk(LINESIZE + 1, "line"); if((line = fgets(line, LINESIZE, fp)) == NULL) { break; } lineno++; - if((pass == FIRST && srcmode == true) || (pass == SECOND && asdetailmode == true)) { - fprintf(stdout, "%s:%d:%s", file, lineno, line); + if((pass == FIRST && asmode.src == true) || + (pass == SECOND && asmode.asdetail == true)) + { + printline(stdout, file, lineno, line); } if((cmdl = linetok(line)) != NULL) { if(pass == FIRST && cmdl->label != NULL) { - if(addlabel(cmdl->label, ptr) == false) { + if(addlabel(asprop->prog, cmdl->label, asprop->ptr) == false) { break; } } @@ -458,12 +465,13 @@ bool assemble(const char *file, PASS pass) break; } } - if(cerrno > 0) { + if(cerr->num > 0) { break; } } - if(cerrno > 0) { - fprintf(stderr, "Assemble error - %d: %s\n %s:%d: %s\n", cerrno, cerrmsg, file, lineno, line); + if(cerr->num > 0) { + fprintf(stderr, "Assemble error - %d: %s\n", cerr->num, cerr->msg); + printline(stderr, file, lineno, line); status = false; } fclose(fp);