root/src/assemble.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. printline
  2. getadr
  3. grword
  4. getliteral
  5. getliteralquote
  6. writememory
  7. writestr
  8. writedc
  9. assemble_start
  10. assemble_end
  11. assemble_ds
  12. assemble_dc
  13. assemble_in
  14. assemble_out
  15. assemble_rpush
  16. assemble_rpop
  17. casl2cmd
  18. assemble_comet2cmd
  19. assembletok
  20. assembleline
  21. assemblefile
  22. assemble
  23. addcerrlist_assemble
  24. outassemble

   1 #include "assemble.h"
   2 #include <stdio.h>
   3 #include <stdlib.h>
   4 #include <string.h>
   5 #include <ctype.h>
   6 #include <assert.h>
   7 #include <errno.h>
   8 
   9 /**
  10  * @brief ファイルストリームの現在行を番号付きで表示する
  11  *
  12  * @param *stream ファイルストリーム
  13  * @param *filename ファイル名
  14  * @param lineno 行番号
  15  * @param line 行の文字列
  16  */
  17 void printline(FILE *stream, const char *filename, int lineno, char *line);
  18 
  19 /**
  20  * @brief アドレスを返す
  21  *
  22  * アドレスには、リテラル/10進定数/16進定数/アドレス定数が含まれる
  23  *
  24  * @return アドレス
  25  *
  26  * @param *prog プログラム名
  27  * @param *str アドレスを表す文字列
  28  * @param pass アセンブラが何回目かを表す数
  29  */
  30 WORD getadr(const char *prog, const char *str, PASS pass);
  31 
  32 /**
  33  * @brief 汎用レジスタを表す文字列からレジスタ番号を返す
  34  * @brief 文字列が汎用レジスタを表さない場合は、0xFFFFを返す
  35  * @brief is_xがtrueの場合は指標レジスタとなり、GR0が指定された場合はCOMET IIの仕様によりエラー発生
  36  *
  37  * @return レジスタ番号[0-7]を表すWORD値
  38  *
  39  * @param *str 汎用レジスタを表す文字列。「GR0」「GR1」・・・「GR7」のいずれか
  40  * @param is_x trueの場合は指標レジスタ
  41  */
  42 WORD grword(const char *str, bool is_x);
  43 
  44 /**
  45  * @brief リテラルを返す
  46  *
  47  * リテラルには、10進定数/16進定数/文字定数が含まれる
  48  *
  49  * @param *str リテラル。定数の前に等号(=)をつけて記述される
  50  * @param pass アセンブラが何回目かを表す数
  51  */
  52 WORD getliteral(const char *str, PASS pass);
  53 
  54 /**
  55  * @brief 'ではじまる文字列からWORD値を返す
  56  * @brief 'が閉じていない場合や、2文字以上の場合はエラーを発生させ、0を返す
  57  *
  58  * @return WORD値
  59  *
  60  * @param *str 'ではじまる文字列
  61  */
  62 WORD getliteralquote(const char *str);
  63 
  64 /**
  65  * @brief アドレス値をメモリに書き込む
  66  *
  67  * @param word アドレス値
  68  * @param adr アドレス
  69  * @param pass アセンブラが何回目かを表す数
  70  */
  71 void writememory(WORD word, WORD adr, PASS pass);
  72 
  73 /**
  74  * @brief 文字をメモリに書き込む
  75  *
  76  * @param *str アドレスを表す文字列。リテラル/10進定数/16進定数/アドレス定数が含まれる
  77  * @param pass アセンブラが何回目かを表す数
  78  */
  79 void writestr(const char *str, PASS pass);
  80 
  81 /**
  82  * @brief DC命令を書込
  83  *
  84  * @param str アドレスを表す文字列。10進定数/16進定数/アドレス定数が含まれる
  85  * @param pass アセンブラが何回目かを表す数
  86  */
  87 void writedc(const char *str, PASS pass);
  88 
  89 /**
  90  * @brief アセンブラ命令STARTの処理
  91  * @relatesalso Casl2cmd
  92  *
  93  * @param *cmdl 1行分のラベル・コマンド・オペランド
  94  * @param pass アセンブラが何回目かを表す数
  95  */
  96 void assemble_start(const CMDLINE *cmdl, PASS pass);
  97 
  98 /**
  99  * @brief アセンブラ命令DSの処理
 100  * @relatesalso Casl2cmd
 101  *
 102  * @param *cmdl 1行分のラベル・コマンド・オペランド
 103  * @param pass アセンブラが何回目かを表す数
 104  */
 105 void assemble_ds(const CMDLINE *cmdl, PASS pass);
 106 
 107 /**
 108  * @brief アセンブラ命令ENDの処理
 109  * @relatesalso Casl2cmd
 110  *
 111  * @param *cmdl 1行分のラベル・コマンド・オペランド
 112  * @param pass アセンブラが何回目かを表す数
 113  */
 114 void assemble_end(const CMDLINE *cmdl, PASS pass);
 115 
 116 /**
 117  * @brief アセンブラ命令DCの処理
 118  * @relatesalso Casl2cmd
 119  *
 120  * @param *cmdl 1行分のラベル・コマンド・オペランド
 121  * @param pass アセンブラが何回目かを表す数
 122  */
 123 void assemble_dc(const CMDLINE *cmdl, PASS pass);
 124 
 125 /**
 126  * @brief マクロ命令 "IN IBUF,LEN" をアセンブル
 127  *
 128  * @code
 129  *      PUSH 0,GR1
 130  *      PUSH 0,GR2
 131  *      LAD GR1,IBUF
 132  *      LAD GR2,LEN
 133  *      SVC 1
 134  *      POP GR2
 135  *      POP GR1
 136  * @endcode
 137  * @relatesalso Casl2cmd
 138  *
 139  *
 140  * @param *cmdl 1行分のラベル・コマンド・オペランド
 141  * @param pass アセンブラが何回目かを表す数
 142  */
 143 void assemble_in(const CMDLINE *cmdl, PASS pass);
 144 
 145 /**
 146  * @brief マクロ命令 "OUT OBUF,LEN" をアセンブル
 147  *
 148  * @code
 149  *      PUSH 0,GR1
 150  *      PUSH 0,GR2
 151  *      LAD GR1,OBUF
 152  *      LAD GR2,LEN
 153  *      SVC 2
 154  *      LAD GR1,=#A
 155  *      LAD GR2,=1
 156  *      SVC 2
 157  *      POP GR2
 158  *      POP GR1
 159  * @endcode
 160  * @relatesalso Casl2cmd
 161  *
 162  * @param *cmdl 1行分のラベル・コマンド・オペランド
 163  * @param pass アセンブラが何回目かを表す数
 164  */
 165 void assemble_out(const CMDLINE *cmdl, PASS pass);
 166 
 167 /**
 168  * @brief マクロ命令 "RPUSH" をメモリに書き込む
 169  *
 170  * @code
 171  *       PUSH 0,GR1
 172  *       PUSH 0,GR2
 173  *       PUSH 0,GR3
 174  *       PUSH 0,GR4
 175  *       PUSH 0,GR5
 176  *       PUSH 0,GR6
 177  *       PUSH 0,GR7
 178  * @endcode
 179  * @relatesalso Casl2cmd
 180  *
 181  * @param *cmdl 1行分のラベル・コマンド・オペランド
 182  * @param pass アセンブラが何回目かを表す数
 183  */
 184 void assemble_rpush(const CMDLINE *cmdl, PASS pass);
 185 
 186 /**
 187  * @brief マクロ命令 "RPOP" をメモリに書き込む
 188  *
 189  * @code
 190  *      POP GR7
 191  *      POP GR6
 192  *      POP GR5
 193  *      POP GR4
 194  *      POP GR3
 195  *      POP GR2
 196  *      POP GR1
 197  * @endcode
 198  * @relatesalso Casl2cmd
 199  *
 200  * @param *cmdl 1行分のラベル・コマンド・オペランド
 201  * @param pass アセンブラが何回目かを表す数
 202  */
 203 void assemble_rpop(const CMDLINE *cmdl, PASS pass);
 204 
 205 /**
 206  * @class Casl2cmd
 207  * @brief casl2cmdから関数ポインタで呼び出される関数
 208  */
 209 
 210 /**
 211  * @brief アセンブラ言語CASL IIの命令を処理する。
 212  *
 213  * エラー発生時は、cerrを設定
 214  *
 215  * @relatesalso Casl2cmd
 216  *
 217  * @return 命令が表で定義されている場合はtrue、それ以外の場合はfalseを返す
 218  *
 219  * @param *cmdtbl アセンブラ言語CASL IIの命令表
 220  * @param *cmdl 1行分のラベル・コマンド・オペランド
 221  * @param pass アセンブルが何回目か
 222  */
 223 bool casl2cmd(CMD *cmdtbl, const CMDLINE *cmdl, PASS pass);
 224 
 225 /**
 226  * @brief システムCOMET IIの命令をアセンブルする
 227  *
 228  * @return アセンブル成功時はtrue、失敗時はfalseを返す
 229  *
 230  * @param *cmdl 1行分のラベル・コマンド・オペランド
 231  * @param pass アセンブルが何回目か
 232  */
 233 bool assemble_comet2cmd(const CMDLINE *cmdl, PASS pass);
 234 
 235 /**
 236  * @brief トークンをアセンブルする
 237  *
 238  * @return アセンブル成功時はtrue、失敗時はfalseを返す
 239  *
 240  * @param *cmdl 1行分のラベル・コマンド・オペランド
 241  * @param pass アセンブラが何回目かを表す数
 242  */
 243 bool assembletok(const CMDLINE *cmdl, PASS pass);
 244 
 245 /**
 246  * @brief 1行をアセンブルする
 247  *
 248  * passが1の場合はラベルを登録し、2の場合はラベルからアドレスを読み込む
 249  *
 250  * @return アセンブル成功時はtrue、失敗時はfalseを返す
 251  *
 252  * @param *line 1行分の文字列
 253  * @param pass アセンブラが何回目かを表す数
 254  */
 255 bool assembleline(const char *line, PASS pass);
 256 
 257 /**
 258  * @brief アセンブルのエラー
 259  */
 260 static CERR cerr_assemble[] = {
 261     { 106, "operand mismatch in CASL II command" },
 262     { 107, "no label in START" },
 263     { 108, "not command of operand \"r\"" },
 264     { 109, "not command of operand \"r1,r2\"" },
 265     { 110, "not command of operand \"r,adr[,x]\"" },
 266     { 111, "not command of operand \"adr[,x]\"" },
 267     { 112, "not command of no operand" },
 268     { 113, "operand too many in COMET II command" },
 269     { 119, "out of COMET II memory" },
 270     { 120, "GR0 in operand x" },
 271     { 122, "cannot create hash table" },
 272     { 124, "more than one character in literal" },
 273     { 125, "not GR in operand x" },
 274     { 126, "syntax error in character constant. In CASL II, two consecutive apostrophes ('') represent a single apostrophe (')." },
 275     { 127, "empty character constant" },
 276 };
 277 
 278 /**
 279  * @brief アセンブラ命令
 280  */
 281 static CMD ascmd[] = {
 282     { "START", assemble_start },
 283     { "END", assemble_end },
 284     { "DS", assemble_ds },
 285     { "DC", assemble_dc },
 286     { "", NULL }
 287 };
 288 
 289 /**
 290  * @brief マクロ命令
 291  */
 292 static CMD macrocmd[] = {
 293     { "OUT", assemble_out },
 294     { "IN", assemble_in },
 295     { "RPUSH", assemble_rpush },
 296     { "RPOP", assemble_rpop },
 297     { "", NULL }
 298 };
 299 
 300 ASPTR *asptr = NULL;
 301 
 302 ASMODE asmode = {false, false, false, false, false};
 303 
 304 void printline(FILE *stream, const char *filename, int lineno, char *line)
 305 {
 306     fprintf(stream, "%s:%5d:%s", filename, lineno, line);
 307 }
 308 
 309 WORD getadr(const char *prog, const char *str, PASS pass)
 310 {
 311     WORD adr = 0;
 312 
 313     if(str[0] == '=') {
 314         adr = getliteral(str, pass);
 315     } else if(isdigit(str[0]) || str[0] == '-' || str[0] == '#') {
 316         adr = nh2word(str);
 317     } else {
 318         if(pass == SECOND) {
 319             if((adr = getlabel(prog, str)) == 0xFFFF) {
 320                 adr = getlabel("", str);
 321             }
 322             if(adr == 0xFFFF) {
 323                 setcerr(103, str);    /* label not found */
 324             }
 325         }
 326     }
 327     return adr;
 328 }
 329 
 330 WORD grword(const char *str, bool is_x)
 331 {
 332     WORD r = 0;
 333 
 334     /*  "GR[0-7]" 以外の文字列では、0xFFFFを返して終了 */
 335     if(strlen(str) != 3 ||
 336        strncmp(str, "GR", 2) != 0 ||
 337        str[2] < '0' || str[2] > '0' + (GRSIZE - 1))
 338     {
 339         return 0xFFFF;
 340     }
 341     r = (WORD)(str[2] - '0');
 342     /* GR0は指標レジスタとして用いることができない */
 343     if(is_x == true && r == 0x0) {
 344         setcerr(120, "");    /* GR0 in operand x */
 345         return 0;
 346     }
 347     return r;
 348 }
 349 
 350 WORD getliteral(const char *str, PASS pass)
 351 {
 352     assert(str[0] == '=');
 353     str++;
 354     WORD val = 0;
 355     WORD adr = 0;
 356 
 357     if(str[0] == '\'') {
 358         val = getliteralquote(str);
 359     } else {
 360         val = nh2word(str);
 361     }
 362     if(cerr->num == 0) {
 363         /* PASS FIRSTでは、lptrがまだ確定していない(ENDで初めて確定する)ため、
 364          * 重複排除の登録・検索は行わず、従来通りダミーの書き込みのみ行う */
 365         if(pass == FIRST) {
 366             adr = asptr->lptr;
 367             writememory(val, (asptr->lptr)++, pass);
 368         } else {
 369             /* PASS SECONDでは、lptrはEND処理で正しく確定済みなので、重複排除が有効 */
 370             char llabel[LITERALSIZE + 1];
 371             sprintf(llabel, "=%04X", val);
 372             adr = getlabel("", llabel);
 373             if(adr == 0xFFFF) {
 374                 adr = asptr->lptr;
 375                 writememory(val, (asptr->lptr)++, pass);
 376                 addlabel("", llabel, adr);
 377             }
 378         }
 379     }
 380     return adr;
 381 }
 382 
 383 WORD getliteralquote(const char *str)
 384 {
 385     assert(str[0] == '\'');
 386     size_t len = strlen(str);
 387     WORD val = 0;
 388     if(str[1] == '\'' && len == 2) {
 389         setcerr(127, str);    /* empty character constant */
 390     } else if (len == 1 || str[len - 1] != '\'') {
 391         setcerr(123, str);    /* unclosed quote */
 392     } else if((str[1] != '\'' && len > 3) || (str[1] == '\'' && len > 4)) {
 393         setcerr(124, str);    /* more than one character in literal */
 394     } else if(str[1] == '\'' && len == 3 && str[2] == '\'') {
 395         setcerr(126, str);    /* syntax error in character constant. In CASL II, two consecutive apostrophes ('') represent a single apostrophe ('). */
 396     } else {
 397         val = (WORD)str[1];
 398     }
 399     return val;
 400 }
 401 
 402 void writememory(WORD word, WORD adr, PASS pass)
 403 {
 404     char *n = NULL;
 405 
 406     /* メモリオーバーの場合、エラー発生 */
 407     if(adr >= sys->memsize) {
 408         setcerr(119, (n = word2n(adr)));    /* out of COMET II memory */
 409         FREE(n);
 410         return;
 411     }
 412     (sys->memory)[adr] = word;
 413     if(pass == SECOND && asmode.asdetail == true) {
 414         fprintf(stdout, "\t#%04X\t#%04X\n", adr, word);
 415     }
 416 }
 417 
 418 void writestr(const char *str, PASS pass)
 419 {
 420     assert(str[0] == '\'');
 421 
 422     /* 空文字列(DC '')はエラー */
 423     if(str[1] == '\'' && str[2] == '\0') {
 424         setcerr(127, str);    /* empty character constant */
 425     } else {
 426         int i = 1;
 427         do {
 428             if(str[i] == '\0') {
 429                 /* 閉じクォートがないまま文字列が終了の場合 */
 430                 setcerr(123, str);    /* unclosed quote */
 431                 break;
 432             }
 433             if(str[i] == '\'') {
 434                 if(str[i + 1] != '\0' && str[i + 1] != '\'') {
 435                     setcerr(126, str);    /* syntax error in character constant. In CASL II, two consecutive apostrophes ('') represent a single apostrophe ('). */
 436                     break;
 437                 } else if(str[i + 1] == '\0') {
 438                     break;         /* 正常終了 */
 439                 } else {
 440                     /* エスケープされたアポストロフィ:1文字として書き込み、2文字分進める */
 441                     writememory('\'', (asptr->ptr)++, pass);
 442                     i += 2;
 443                 }
 444             } else {
 445                 writememory(str[i++], (asptr->ptr)++, pass);
 446             }
 447         } while(1);
 448     }
 449 }
 450 
 451 void writedc(const char *str, PASS pass)
 452 {
 453     WORD adr = 0;
 454 
 455     if(*str == '\'') {
 456         writestr(str, pass);
 457     } else {
 458         if(str[0] == '#' || isdigit(str[0]) || str[0] == '-') {
 459             adr = nh2word(str);
 460         } else {
 461             if(pass == SECOND && (adr = getlabel(asptr->prog, str)) == 0xFFFF) {
 462                 adr = getlabel("", str);
 463             }
 464             if(pass == SECOND && adr == 0xFFFF) {
 465                 setcerr(103, str);    /* label not found */
 466             }
 467         }
 468         writememory(adr, (asptr->ptr)++, pass);
 469     }
 470 }
 471 
 472 void assemble_start(const CMDLINE *cmdl, PASS pass)
 473 {
 474     if(cmdl->opd->opdc > 1) {
 475         setcerr(106, "");    /* operand count mismatch */
 476         return;
 477     }
 478     if(!cmdl->label[0]) {
 479         setcerr(107, "");    /* no label in START */
 480         return;
 481     }
 482     /* プログラム名の設定 */
 483     strcpy(asptr->prog, cmdl->label);
 484     /* オペランドがある場合、書き込みと実行の開始アドレスを設定 */
 485     if(cmdl->opd->opdv[0] != NULL) {
 486         asptr->ptr = execptr->start = getadr(asptr->prog, cmdl->opd->opdv[0], pass);
 487     }
 488 }
 489 
 490 void assemble_end(const CMDLINE *cmdl, PASS pass)
 491 {
 492     if(cmdl->opd->opdc > 0) {
 493         setcerr(106, "");    /* operand count mismatch */
 494         return;
 495     }
 496     /* 1回目のアセンブルの場合は、リテラル領域開始アドレスを設定 */
 497     if(pass == FIRST) {
 498         asptr->lptr = asptr->ptr;
 499     }
 500     /* 2回目のアセンブルの場合は、リテラル領域終了アドレスを実行終了アドレスとして設定 */
 501     else if(pass == SECOND) {
 502         execptr->end = asptr->lptr;
 503     }
 504     strcpy(asptr->prog, "");
 505 }
 506 
 507 void assemble_ds(const CMDLINE *cmdl, PASS pass)
 508 {
 509     if(cmdl->opd->opdc != 1) {
 510         setcerr(106, "");    /* operand count mismatch */
 511         return;
 512     }
 513     for(int i = 0; i < atoi(cmdl->opd->opdv[0]); i++) {
 514         writememory(0x0, (asptr->ptr)++, pass);
 515         if(cerr->num > 0) {
 516             break;
 517         }
 518     }
 519 }
 520 
 521 void assemble_dc(const CMDLINE *cmdl, PASS pass)
 522 {
 523     if(cmdl->opd->opdc == 0 || cmdl->opd->opdc >= OPDSIZE) {
 524         setcerr(106, "");    /* operand count mismatch */
 525         return;
 526     }
 527     for(int i = 0; i < cmdl->opd->opdc; i++) {
 528         writedc(cmdl->opd->opdv[i], pass);
 529         if(cerr->num > 0) {
 530             break;
 531         }
 532     }
 533 }
 534 
 535 void assemble_in(const CMDLINE *cmdl, PASS pass)
 536 {
 537     char *line = malloc_chk(LINESIZE + 1, "assemble_in.line");
 538 
 539     if(cmdl->opd->opdc == 0 || cmdl->opd->opdc > 2) {
 540         setcerr(106, "");    /* operand count mismatch */
 541         return;
 542     }
 543     assembleline("    PUSH 0,GR1", pass);
 544     assembleline("    PUSH 0,GR2", pass);
 545     sprintf(line, "    LAD GR1,%s", cmdl->opd->opdv[0]);
 546     assembleline(line, pass);
 547     sprintf(line, "    LAD GR2,%s", cmdl->opd->opdv[1]);
 548     assembleline(line, pass);
 549     assembleline("    SVC 1", pass);
 550     assembleline("    POP GR2", pass);
 551     assembleline("    POP GR1", pass);
 552     FREE(line);
 553 }
 554 
 555 void assemble_out(const CMDLINE *cmdl, PASS pass)
 556 {
 557     char *line = malloc_chk(LINESIZE + 1, "assemble_out.line");
 558 
 559     if(cmdl->opd->opdc == 0 || cmdl->opd->opdc > 2) {
 560         setcerr(106, "");    /* operand count mismatch */
 561         return;
 562     }
 563     assembleline("    PUSH 0,GR1", pass);
 564     assembleline("    PUSH 0,GR2", pass);
 565     sprintf(line, "    LAD GR1,%s", cmdl->opd->opdv[0]);
 566     assembleline(line, pass);
 567     sprintf(line, "    LAD GR2,%s", cmdl->opd->opdv[1]);
 568     assembleline(line, pass);
 569     assembleline("    SVC 2", pass);
 570     assembleline("    LAD GR1,=#A", pass);
 571     assembleline("    LAD GR2,=1", pass);
 572     assembleline("    SVC 2", pass);
 573     assembleline("    POP GR2", pass);
 574     assembleline("    POP GR1", pass);
 575     FREE(line);
 576 }
 577 
 578 void assemble_rpush(const CMDLINE *cmdl, PASS pass)
 579 {
 580     char *line = malloc_chk(LINESIZE + 1, "assemble_rpush.line");
 581 
 582     if(cmdl->opd->opdc > 0) {
 583         setcerr(106, "");    /* operand count mismatch */
 584         return;
 585     }
 586     for(int i = 1; i <= GRSIZE-1; i++) {
 587         sprintf(line, "    PUSH 0,GR%d", i);
 588         assembleline(line, pass);
 589     }
 590     FREE(line);
 591 }
 592 
 593 void assemble_rpop(const CMDLINE *cmdl, PASS pass)
 594 {
 595     char *line = malloc_chk(LINESIZE + 1, "assemble_rpop.line");
 596 
 597     if(cmdl->opd->opdc > 0) {
 598         setcerr(106, "");    /* operand count mismatch */
 599         return;
 600     }
 601     for(int i = GRSIZE-1; i >= 1; i--) {
 602         sprintf(line, "    POP GR%d", i);
 603         assembleline(line, pass);
 604     }
 605     FREE(line);
 606 }
 607 
 608 bool casl2cmd(CMD *cmdtbl, const CMDLINE *cmdl, PASS pass)
 609 {
 610     void (*cmdptr)(const CMDLINE *, PASS) = NULL;
 611 
 612     for(int i = 0; cmdtbl[i].name[0]; i++) {
 613         if(strcmp(cmdl->cmd, cmdtbl[i].name) == 0) {
 614             cmdptr = cmdtbl[i].ptr;
 615             (*cmdptr)(cmdl, pass);
 616             return true;
 617         }
 618     }
 619     return false;
 620 }
 621 
 622 bool assemble_comet2cmd(const CMDLINE *cmdl, PASS pass)
 623 {
 624     WORD cmd = 0;
 625     WORD r_r1 = 0;
 626     WORD x_r2 = 0;
 627     WORD adr = 0;
 628 
 629     /* オペランドなし */
 630     if(cmdl->opd->opdc == 0) {
 631         if((cmd = getcmdcode(cmdl->cmd, NONE)) == 0xFFFF) {
 632             setcerr(112, cmdl->cmd);    /* not command of no operand */
 633             return false;
 634         }
 635         writememory(cmd, (asptr->ptr)++, pass);
 636     }
 637     /* 第1オペランドは汎用レジスタ */
 638     else if((r_r1 = grword(cmdl->opd->opdv[0], false)) != 0xFFFF) {
 639         /* オペランド数1 */
 640         if(cmdl->opd->opdc == 1) {
 641             if((cmd = getcmdcode(cmdl->cmd, R_)) == 0xFFFF) {
 642                 setcerr(108, cmdl->cmd);    /* not command of operand "r" */
 643                 return false;
 644             }
 645             cmd |= (r_r1 << 4);
 646             writememory(cmd, (asptr->ptr)++, pass);
 647         }
 648         /* オペランド数2。第2オペランドは汎用レジスタ */
 649         else if(cmdl->opd->opdc == 2 && (x_r2 = grword(cmdl->opd->opdv[1], false)) != 0xFFFF) {
 650             if((cmd = getcmdcode(cmdl->cmd, R1_R2)) == 0xFFFF) {
 651                 setcerr(109, cmdl->cmd);    /* not command of operand "r1,r2" */
 652                 return false;
 653             }
 654             cmd |= ((r_r1 << 4) | x_r2);               /* 第1オペランド、第2オペランドともに汎用レジスタ */
 655             /* メモリへの書き込み */
 656             writememory(cmd, (asptr->ptr)++, pass);
 657         }
 658         /* オペランド数2または3 */
 659         else if(cmdl->opd->opdc == 2 || cmdl->opd->opdc == 3) {
 660             if((cmd = getcmdcode(cmdl->cmd, R_ADR_X)) == 0xFFFF) {
 661                 setcerr(110, cmdl->cmd);    /* not command of operand "r,adr[,x]" */
 662                 return false;
 663             }
 664             cmd |= (r_r1 << 4);                    /* 第1オペランドは汎用レジスタ */
 665             /* オペランド数3の場合 */
 666             if(cmdl->opd->opdc == 3) {             /* 第3オペランドは指標レジスタとして用いる汎用レジスタ */
 667                 if((x_r2 = grword(cmdl->opd->opdv[2], true)) == 0xFFFF) {
 668                     setcerr(125, cmdl->cmd);    /* not GR in operand x */
 669                     return false;
 670                 }
 671                 cmd |= x_r2;
 672             }
 673             adr = getadr(asptr->prog, cmdl->opd->opdv[1], pass); /* 第2オペランドはアドレス */
 674             /* メモリへの書き込み */
 675             writememory(cmd, (asptr->ptr)++, pass);
 676             writememory(adr, (asptr->ptr)++, pass);
 677         } else {
 678             setcerr(113, cmdl->cmd);    /* operand too many in COMET II command */
 679             return false;
 680         }
 681     }
 682     /* オペランド数1または2。第1オペランドはアドレス */
 683     else if(cmdl->opd->opdc == 1 || cmdl->opd->opdc == 2) {
 684         if((cmd = getcmdcode(cmdl->cmd, ADR_X)) == 0xFFFF) {
 685             setcerr(111, cmdl->cmd);    /* not command of operand "adr[,x]" */
 686             return false;
 687         }
 688         /* オペランド数2の場合 */
 689         if(cmdl->opd->opdc == 2) {             /* 第2オペランドは指標レジスタとして用いる汎用レジスタ */
 690             x_r2 = grword(cmdl->opd->opdv[1], true);
 691             if(cerr->num > 0) {
 692                 return false;
 693             }
 694             cmd |= x_r2;
 695         }
 696         /* CALLの場合はプログラムの入口名を表すラベルを取得 */
 697         /* CALL以外の命令の場合と、プログラムの入口名を取得できない場合は、 */
 698         /* 同一プログラム内のラベルを取得 */
 699         if(pass == SECOND && cmd == 0x8000) {        /* CALL命令 */
 700             adr = getlabel("", cmdl->opd->opdv[0]);
 701         }
 702         if(cmd != 0x8000 || (pass == SECOND && adr == 0xFFFF)) {
 703             adr = getadr(asptr->prog, cmdl->opd->opdv[0], pass);
 704         }
 705         /* メモリへの書込 */
 706         writememory(cmd, (asptr->ptr)++, pass);
 707         writememory(adr, (asptr->ptr)++, pass);
 708     }
 709     return (cerr->num == 0) ? true : false;
 710 }
 711 
 712 bool assembletok(const CMDLINE *cmdl, PASS pass)
 713 {
 714     /* 命令がない場合 */
 715     if(!cmdl->cmd[0]) {
 716         return true;
 717     }
 718     /* アセンブラ命令またはマクロ命令の書込 */
 719     if(casl2cmd(ascmd, cmdl, pass) == false && casl2cmd(macrocmd, cmdl, pass) == false) {
 720         /* 機械語命令の書込 */
 721         if(assemble_comet2cmd(cmdl, pass) == false) {
 722             if(cerr->num == 0) {
 723                 setcerr(113, cmdl->cmd);    /* operand too many in COMET II command */
 724             }
 725         }
 726     }
 727     return (cerr->num == 0) ? true : false;
 728 }
 729 
 730 bool assembleline(const char *line, PASS pass)
 731 {
 732     CMDLINE *cmdl = NULL;
 733     bool stat = true;
 734 
 735     cmdl = linetok(line);
 736     stat = (cerr->num == 0) ? true : false;
 737     if(cmdl != NULL) {
 738         if(stat == true) {
 739             if(pass == FIRST && cmdl->label[0]) {
 740                 stat = addlabel(asptr->prog, cmdl->label, asptr->ptr);
 741             }
 742         }
 743         if(stat == true) {
 744             stat = assembletok(cmdl, pass);
 745         }
 746         FREE(cmdl->label);
 747         if(cmdl->opd != NULL) {
 748             for(int i = 0; i < cmdl->opd->opdc; i++) {
 749                 FREE(cmdl->opd->opdv[i]);
 750             }
 751         }
 752         FREE(cmdl->opd);
 753         FREE(cmdl->cmd);
 754     }
 755     FREE(cmdl);
 756     return stat;
 757 }
 758 
 759 /**
 760  * @brief 指定された名前のファイルをアセンブル
 761  *
 762  * アセンブル完了時はtrue、エラー発生時はfalseを返す
 763  */
 764 bool assemblefile(const char *file, PASS pass)
 765 {
 766     int lineno = 1;
 767     char *line = NULL;
 768     FILE *fp = NULL;
 769 
 770     if((fp = fopen(file, "r")) == NULL) {
 771         cerr->num = errno;
 772         perror(file);
 773         return false;
 774     }
 775     for(line = malloc_chk(LINESIZE + 1, "assemble.line"); fgets(line, LINESIZE, fp); lineno++) {
 776         if((pass == FIRST && asmode.src == true) || (pass == SECOND && asmode.asdetail == true)) {
 777             printline(stdout, file, lineno, line);
 778         }
 779         if(assembleline(line, pass) == false) {
 780             break;
 781         }
 782     }
 783     if(cerr->num > 0) {
 784         fprintf(stderr, "Assemble error - %d: %s\n", cerr->num, cerr->msg);
 785         printline(stderr, file, lineno, line);
 786     }
 787     FREE(line);
 788     fclose(fp);
 789     return (cerr->num == 0) ? true : false;
 790 }
 791 
 792 bool assemble(int filec, char *filev[], WORD adr)
 793 {
 794     int i;
 795     PASS pass;
 796     WORD bp[filec];
 797     bool stat = false;
 798 
 799     asptr = malloc_chk(sizeof(ASPTR), "asptr");    /* アセンブル時のプロパティ用の領域確保 */
 800     asptr->prog = malloc_chk(LABELSIZE + 1, "asptr.prog");
 801     asptr->ptr = adr;
 802     /* アセンブル。ラベル表作成のため、2回行う */
 803     for(pass = FIRST; pass <= SECOND; pass++) {
 804         for(i = 0; i < filec; i++) {
 805             /* データの格納開始位置 */
 806             if(pass == FIRST) {
 807                 bp[i] = asptr->ptr;
 808             } else if(pass == SECOND) {
 809                 asptr->ptr = bp[i];
 810             }
 811             if(execmode.trace == true || execmode.dump == true ||
 812                asmode.src == true || asmode.label == true || asmode.asdetail == true)
 813             {
 814                 fprintf(stdout, "\nAssemble %s (%d)\n", filev[i], pass);
 815             }
 816             /* ファイルをアセンブル */
 817             stat = assemblefile(filev[i], pass);
 818             if(stat == false) {
 819                 goto asfin;
 820             }
 821         }
 822         if(asmode.label == true) {
 823             if(pass == FIRST) {
 824                 printlabel();
 825                 if(asmode.onlylabel == true) {
 826                     break;
 827                 }
 828             }
 829             if(pass == SECOND) {
 830                 printliteral();
 831             }
 832         }
 833     }
 834 asfin:
 835     freelabel();                              /* ラベルハッシュ表を解放 */
 836     FREE(asptr->prog);                        /* アセンブル時のプロパティを解放 */
 837     FREE(asptr);
 838     return stat;
 839 }
 840 
 841 /* assemble.hで定義された関数群 */
 842 void addcerrlist_assemble()
 843 {
 844     addcerrlist_tok();
 845     addcerrlist_word();
 846     addcerrlist_label();
 847     addcerrlist(ARRAYSIZE(cerr_assemble), cerr_assemble);
 848 }
 849 
 850 void outassemble(const char *file)
 851 {
 852     FILE *fp = NULL;
 853 
 854     if((fp = fopen(file, "w")) == NULL) {
 855         perror(file);
 856         exit(1);
 857     }
 858     fwrite(sys->memory, sizeof(WORD), execptr->end, fp);
 859     fclose(fp);
 860 }

/* [<][>][^][v][top][bottom][index][help] */