X-Git-Url: http://j8takagi.net/cgi-bin/gitweb.cgi?p=YACASL2.git;a=blobdiff_plain;f=src%2Fassemble.c;h=0c13893117f289731849c70bb5aa5062efe35fd6;hp=25762c32822ea815c7a3cd3bf5ac67fd07e7f50e;hb=62a189b4cdc7045922b132d5ff3371da948f2dbe;hpb=0423c8cffe1e1a480222b0a80ecd31957edec06d diff --git a/src/assemble.c b/src/assemble.c index 25762c3..0c13893 100644 --- a/src/assemble.c +++ b/src/assemble.c @@ -1,6 +1,9 @@ #include "casl2.h" #include "assemble.h" +/* アセンブルモード: src, label, onlylabel, asdetail, onlyassemble */ +ASMODE asmode = {false, false, false, false, false}; + /* 値を格納するポインタ */ WORD ptr; @@ -10,20 +13,21 @@ WORD lptr; /* 他のプログラムで参照する入口名 */ char *prog; -/* 汎用レジスタを表す文字列「GR[0-7]」をWORD値に変換 - is_xがtrueの場合は、指標レジスタとして用いる汎用レジスタ - 文字列が汎用レジスタを表さない場合は、0xFFFFを返す */ +/* 汎用レジスタを表す文字列「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'))) { return 0xFFFF; } r = (WORD)(*(str+2) - '0'); - /* COMET IIの仕様により、GR0は指標レジスタとして用いることはできない */ + /* 指標レジスタとして用いることはできない */ if(is_x == true && r == 0x0) { setcerr(120, NULL); /* GR0 in operand x */ return 0x0; @@ -31,76 +35,37 @@ 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((*str == '#') || isdigit(*str) || *str == '-') { + adr = nh2word(str); } else { - if(pass == SECOND && (adr = getlabel(str, prog)) == 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 */ + setcerr(119, word2n(adr)); /* out of COMET II memory */ } if(cerrno == 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; @@ -112,19 +77,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 = 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), lptr++, pass); } return adr; } @@ -133,21 +91,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(cerrno == 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++), lptr++, pass); + lw = true; } else { - writememory(*(str++), ptr++, pass); + writememory(*(p++), ptr++, pass); } } } @@ -159,12 +125,10 @@ void writeDC(const char *str, PASS pass) 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, prog)) == 0xFFFF) { + if(pass == SECOND && (adr = getlabel(prog, str)) == 0xFFFF) { setcerr(103, str); /* label not found */ } } @@ -172,8 +136,8 @@ void writeDC(const char *str, PASS pass) } } -/* 命令がアセンブラ命令の場合は処理を実行 - 実行に成功した場合はtrue、それ以外の場合はfalseを返す */ +/* 命令がアセンブラ命令の場合は処理を実行 */ +/* 実行に成功した場合はtrue、それ以外の場合はfalseを返す */ bool assemblecmd(const CMDLINE *cmdl, PASS pass) { int i = 0; @@ -182,7 +146,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 } }; @@ -209,7 +173,7 @@ bool assemblecmd(const CMDLINE *cmdl, PASS pass) prog = strdup(cmdl->label); /* オペランドがある場合、実行開始番地を設定 */ if(pass == SECOND && cmdl->opd->opdc == 1) { - if((startptr = getlabel(cmdl->opd->opdv[0], prog)) == 0xFFFF) { + if((startptr = getlabel(prog, cmdl->opd->opdv[0])) == 0xFFFF) { setcerr(103, cmdl->opd->opdv[0]); /* label not found */ } } @@ -254,8 +218,8 @@ bool assemblecmd(const CMDLINE *cmdl, PASS pass) return status; } -/* 命令がマクロ命令の場合はメモリに書込 - 書込に成功した場合はtrue、それ以外の場合はfalseを返す */ +/* 命令がマクロ命令の場合はメモリに書込 */ +/* 書込に成功した場合はtrue、それ以外の場合はfalseを返す */ bool macrocmd(const CMDLINE *cmdl, PASS pass) { int i = 0; @@ -299,9 +263,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; @@ -335,7 +298,7 @@ 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) { status = true; @@ -343,8 +306,7 @@ bool cometcmd(const CMDLINE *cmdl, PASS pass) } /* オペランド数2〜3。第2オペランドはアドレス、 第3オペランドは指標レジスタとして用いる汎用レジスタ */ - else if(cmdl->opd->opdc == 2 || cmdl->opd->opdc == 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) { @@ -355,11 +317,12 @@ 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); + adr = getadr(prog, cmdl->opd->opdv[1], pass); writememory(cmd, ptr++, pass); writememory(adr, ptr++, pass); if(cerrno == 0) { @@ -384,7 +347,15 @@ bool cometcmd(const CMDLINE *cmdl, PASS pass) } cmd |= x; } - adr = getadr(cmdl->opd->opdv[0], pass); + /* CALLの場合はプログラムの入口名を表すラベルを取得 */ + /* CALL以外の命令の場合と、プログラムの入口名を取得できない場合は、 */ + /* 同一プログラム内のラベルを取得 */ + if(pass == SECOND && cmd == 0x8000) { /* CALL命令 */ + adr = getlabel(NULL, cmdl->opd->opdv[0]); + } + if(cmd != 0x8000 || (pass == SECOND && adr == 0xFFFF)) { + adr = getadr(prog, cmdl->opd->opdv[0], pass); + } writememory(cmd, ptr++, pass); writememory(adr, ptr++, pass); if(cerrno == 0) { @@ -427,6 +398,10 @@ bool assembleline(const CMDLINE *cmdl, PASS pass) 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) @@ -451,8 +426,10 @@ bool assemble(const char *file, PASS pass) 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) { @@ -469,7 +446,8 @@ bool assemble(const char *file, PASS pass) } } if(cerrno > 0) { - fprintf(stderr, "Assemble error - %d: %s\n %s:%d: %s\n", cerrno, cerrmsg, file, lineno, line); + fprintf(stderr, "Assemble error - %d: %s\n", cerrno, cerrmsg); + printline(stderr, file, lineno, line); status = false; } fclose(fp);