/**********************************************************************
 *
 *       *** HAPPy Pascal Compiler ***
 *               P-code assmebler
 *
 *           Copyright (c) H.Asano 1992-1994.
 *
 **********************************************************************/

#define EXTERN extern
#define Maxlabel   500                  /* 最大ラベル数               */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "version.h"
#include "hapai.h"

/********* co-operation table **********/
static char cop[] = {
    115/*lod*/, 105/*ldo*/, 125/*str*/, 120/*sro*/,
    130/*sto*/, 110/*chk*/, 135/*ind*/ } ;

/***************************************/
/*            ラベル表                 */
/***************************************/
enum lbst {  entered,                   /* ラベル未登録の状態         */
             defined                    /* ラベル定義済の状態         */
          };

static struct  {
  short     val         ;               /* value                      */
  enum lbst st          ;               /* status {enterd,defined}    */
} labeltab[Maxlabel]    ;

/***************************************/
/*      仮想計算機 記憶装置            */
/***************************************/
static _store store[Maxstore] ;

/***************************************/
/*            変数定義                 */
/***************************************/
static char *PcodeSourceName ;          /* P-codeｿｰｽﾌｧｲﾙ名　　　　　　*/
static char *PcodeObjectName ;          /* P-codeｵﾌﾞｼﾞｪｸﾄﾌｧｲﾙ名       */
static char *CompVersion     ;          /* コンパイラのバージョン     */
static FILE *pcsfile         ;          /* P-codeｿｰｽﾌｧｲﾙﾎﾟｲﾝﾀ         */
static FILE *objfile         ;          /* P-codeｵﾌﾞｼﾞｪｸﾄﾌｧｲﾙﾎﾟｲﾝﾀ    */
static short codesize        ;          /* コードのﾜｰﾄﾞｻｲｽﾞ           */
static short objsize         ;          /* オブジェクト全体のﾜｰﾄﾞｻｲｽﾞ */
static short ch              ;          /* 読込文字                   */
static short intch           ;          /* 読込処理内での読込文字     */
static short  pc             ;          /* program counter            */
static _code  cd             ;          /* P-code                     */
static short entpc           ;          /* ent命令の番地              */
static short start = -1      ;          /* オブジェクト開始の合図     */

/*********************************************************************/

/***************************************/
/*     エラーメッセージ出力処理        */
/***************************************/
static void paerr(short errno)
{
  static struct _errmsg {
       short msgno       ;              /* error message number       */
       char  *errmsg     ;              /* error message              */
     } errtb[]  =  {

   {1,  "命令数が多すぎる"},
   {2,  "オブジェクトファイルがオープンできない"},
   {3,  "オブジェクトファイル出力でエラーが発生した"},
   {4,  "ラベルが多する"},
   {5,  "定数が多すぎる"},
   {6,  "P-codeソースファイルがオープンできない"},
   {7,  "PC.EXEとPA.OVLのバージョンが違う"},
   {8,  "アセンブルリストの出力でエラーが発生した"}
} ;
  short i = -1 ;

     while(errtb[++i].msgno != errno) ; /* search message             */
     fprintf(stderr,"A%03d: %s\n", errno, errtb[i].errmsg);
     exit(3) ;                          /* アセンブルエラーで停止     */
}

/***************************************/
/*      reset() : reset関数            */
/***************************************/
static void reset(char *filename)
{

     pcsfile = fopen(filename,"r") ;
     if(pcsfile == NULL) paerr(6) ;

     intch =  getc(pcsfile)  ;          /* 1文字先読み                */
}

/***************************************/
/*       eoln() : eolnマクロ定義       */
/***************************************/
#define eoln()   (intch == '\n')        /* 改行を読んでいれば真       */

/***************************************/
/* readc() : char型read処理            */
/***************************************/
static short readc(void)
{
  short oldch ;

     oldch    = intch         ;
     intch    = getc(pcsfile) ;
     return(oldch)      ;
}

/***************************************/
/*   readi() : integer型入力処理       */
/***************************************/
static integer readi(void)
{
  integer  ival = 0 ;
  short    sign = 1 ;

     if(intch == ' ')
      while((intch = getc(pcsfile)) == ' '); /* 空白読み飛ばし        */

     if(intch=='-') {                    /* 符号の時 ( + は現れない)  */
      sign = -1              ;           /* 符号に応じた正負          */
      intch  = getc(pcsfile) ;           /* 符号を読み飛ばす          */
     }

     do {
      ival = ival*10 + intch-'0' ;
      intch=getc(pcsfile) ;
     } while(('0' <= intch) && (intch <= '9')) ;

     return(sign*ival) ;
}

/***************************************/
/*   readr() : real型入力処理          */
/***************************************/
static float readr(void)
{
  char   buf[20] ;
  short  i = 0   ;

     while(intch == ' ') intch = getc(pcsfile) ;   /* 空白読み飛ばし */
     do {
      buf[i++] = (char)intch ;
      intch = getc(pcsfile) ;
     } while (intch != '\n') ;
     buf[i] = '\0' ;

     return((float)atof(buf)) ;         /* 浮動小数点へ変換           */
}

/***************************************/
/* readln() : EOLまで読み飛ばす処理    */
/***************************************/
static void readln(void)
{
     while(!eoln()) intch = getc(pcsfile) ;
     intch = getc(pcsfile);
}

/***************************************/
/*    オブジェクトファイル書出処理     */
/***************************************/
static void putobject(char *area, short size)
{
      fwrite(area,size,1,objfile) ;
      if(ferror(objfile)) paerr(3) ;    /* 書き込み失敗               */
}

/***************************************/
/*          初期設定処理               */
/***************************************/
static void init(void)
{
  short i;

     for(i=0;i<Maxlabel;i++) {          /* ラベル表 の 初期設定       */
      labeltab[i].val = -1 ;
      labeltab[i].st  = entered;
     }

     reset(PcodeSourceName) ;           /* P-codeｿｰｽﾌｧｲﾙのｵｰﾌﾟﾝ       */

     objfile = fopen(PcodeObjectName,"wb") ;/* ファイルオープン       */
     if(objfile == NULL) paerr(2) ;     /* オープンできない           */

     if(codesize > Maxstore)            /* 記憶装置の大きさより大きい時*/
      paerr(1) ;                        /* ﾌﾟﾛｸﾞﾗﾑ停止                */

     if(strcmp(CompVersion,version))
      paerr(7) ;                        /* バージョン不一致           */

     putobject(version,strlen(version)+1) ; /* バージョン番号書出     */

     objsize = codesize ;
}

/***************************************/
/*    ラベル表登録処理                 */
/***************************************/
static void update(void)
{
   short x         ;                    /*  x: label名                */
   short curr,succ ;

     x=(short)readi()           ;       /* ラベル名を読む             */
     if(x >= Maxlabel) paerr(4) ;       /* ラベル数が多すぎる         */

     if(labeltab[x].val != -1) {        /* 前方参照されている時       */
      curr = labeltab[x].val;
      do {
       succ = store[curr].vo.q;
       store[curr].vo.q = pc  ;
       curr = succ ;
      } while(succ != -1) ;
     }
     labeltab[x].st  = defined    ;
     labeltab[x].val = pc         ;
}

/***************************************/
/*     ラベル値読込処理                */
/***************************************/
static void labelsearch(void)
{
  short x ;

     while(ch != 'L') ch = readc() ;    /* 'L' まで 読み飛ばし        */
     x = (short)readi() ;
     if(x >= Maxlabel) paerr(4) ;       /* ラベル数が多すぎる         */
     if(labeltab[x].st == entered) {    /* 未定義                     */
      cd.q = labeltab[x].val  ;         /* 初期値のまま　-1           */
      labeltab[x].val = pc    ;         /* 今のpcを格納               */
     }
     else cd.q = labeltab[x].val ;      /* 定義済の時                 */
}


/********* typesymbol() : instruction名4文字目によってopを決定する *********/
static void typesymbol(void)
{
   short i;

     switch(ch) {
      case 'i' : return ;       /* 'i' の時は opはそのまま */
      case 'a' : i=0; break;
      case 'r' : i=1; break;
      case 's' : i=2; break;
      case 'b' : i=3; break;
      case 'c' : i=4;
     }
     cd.op=cop[cd.op]+i;             /* opの変更 */
}

/**************************************/
/* PTN0() : オペランドのない命令      */
/**************************************/
static void PTN0(void)
{
}

/**************************************/
/* PTN1() : lod,strのアセンブル       */
/**************************************/
static void PTN1(void)
{
     typesymbol() ;
     cd.p=(char)readi() ;
     cd.q=(short)readi() ;
}

/**************************************/
/* PTN2() : lda,mov,wrsのアセンブル   */
/**************************************/
static void PTN2(void)
{
     cd.p=(char)readi() ;
     cd.q=(short)readi() ;
}

/*********************************************/
/* PTN3() : mst,cui,bas,tra.mms,             */
/*          eol,eof,pge,rln,rdc,rdi,rdr,tgt, */
/*          tgt,tpt,trs,trw,wln,wrb,wrc,wrf, */
/*          wri,wrr のアセンブル             */
/*********************************************/
static void PTN3(void)
{
     cd.p=(char)readi() ;
}

/**************************************/
/* PTN4() : cup,ejpのアセンブル       */
/**************************************/
static void PTN4(void)
{
     cd.p=(char)readi() ;
     labelsearch();
}

/************************************************/
/* PTN5() : equ,neq,geq,grt,leq,lesのアセンブル */
/************************************************/
static void PTN5(void)
{
     switch(ch) {
    /*case 'a' :     ; break ;   何もしない */
      case 'i' : cd.p=1 ; break ;
      case 'r' : cd.p=2 ; break ;
      case 'b' : cd.p=3 ; break ;
      case 's' : cd.p=4 ; break ;
      case 'c' : cd.p=6 ; break ;
      case 'm' : cd.p=5 ;
                 cd.q=(short)readi() ;
     }
}

/**************************************/
/* PTN6() : ldo,sro,indのアセンブル   */
/**************************************/
static void PTN6(void)
{
     typesymbol() ;
     cd.q=(short)readi();
}

/****************************************/
/* PTN7() : inc,dec,nxt,nxdのアセンブル */
/****************************************/
static void PTN7(void)
{
     switch(ch) {
    /*case 'a' :  cd.p=0;    break ;  何もしない */ /* inc,decのみ */
      case 'i' :  cd.p=1;    break ;
      case 'b' :  cd.p=3;    break ;
      case 'c' :  cd.p=6;    break ;
     }
     cd.q = (short)readi() ;
}

/****************************************/
/* PTN8() : ujp,fjp,lapのアセンブル     */
/****************************************/
#define PTN8  labelsearch

/***************************************/
/* PTN9() : lao,new,disのアセンブル    */
/***************************************/
static void PTN9(void)
{
     cd.q=(short)readi();
}

/**************************************/
/* ENT() : entのアセンブル            */
/**************************************/
static void ENT(void)
{
     entpc = pc ;
}

/**************************************/
/* CHK() : chkのアセンブル            */
/**************************************/
static void CHK(void)
{
   integer  lb,ub ;

     typesymbol() ;
     cd.p = (char)readi() ;             /* チェック種別　             */
     lb = readi();                      /* 下限値                     */
     ub = readi();                      /* 上限値                     */
     if(objsize+1>=Maxstore) paerr(5) ; /* 定数格納不可               */
     store[objsize  ].vi = lb ;
     store[objsize+1].vi = ub ;
     cd.q=codesize;
     do {
      cd.q++ ;
     } while((store[cd.q-1].vi != lb) || (store[cd.q].vi != ub)) ;
     if(cd.q   == objsize) objsize++   ;/* 最後に1つだけ定数追加の時  */
     if(cd.q-1 == objsize) objsize += 2;/* 最後に2つの  対数追加の時  */
}

/**************************************/
/* IXA() : ixaのアセンブル            */
/**************************************/
static void IXA(void)
{
  integer low  ;
  short   ixav ;

     low  = readi() ;                     /* 下限値                     */
     ixav = (short)readi() ;              /* ixa値                      */
     if(objsize+1>=Maxstore) paerr(5) ;   /* 定数格納不可               */
     store[objsize  ].vi = low  ;
     store[objsize+1].va = ixav ;         /*  2バイトエリアを使用       */
     cd.q=codesize;
     do {
      cd.q++ ;
     } while((store[cd.q-1].vi != low) || (store[cd.q].va != ixav)) ;
     if(cd.q   == objsize) objsize++   ;/* 最後に1つだけ定数追加の時  */
     if(cd.q-1 == objsize) objsize += 2;/* 最後に2つの  対数追加の時  */
}

/**************************************/
/* LCA() : lcaのアセンブル            */
/**************************************/
/* lca '文字列'\n という形式とする。最後が改行で終わる。最初の ' と
  改行の前の ' は P-codeソースを読む人間にわかりやすいようについているだけ */

static void LCA(void)
{
     cd.q=objsize;
     readc() ;                          /* 最初の ' を読み飛ばす      */
     while(!eoln()) {                   /* 改行までの文字列を格納     */
      if(objsize+1>=Maxstore) paerr(5); /* 定数格納不可               */
      store[objsize++].vc = readc() ;
     }
     objsize-- ;                        /* 最後の ' を捨てる          */
}

/**************************************/
/*   checkConst() : 定数格納チェック  */
/**************************************/
static void checkConst(void)
{
     if(cd.q==objsize) {
      if(objsize+1>=Maxstore) paerr(5); /* 定数格納不可               */
      objsize++ ;
     }
}

/**************************************/
/* LDC() : ldcのアセンブル            */
/**************************************/
static void LDC(void)
{
  integer inumber ;
  float   rnumber ;
  long    s       ;

     switch(ch) {
      case 'i' : cd.p=1 ;               /* integer type               */
                 inumber = readi() ;
                 if(labs(inumber) < (long)Largeint)
                  cd.q = (short)inumber;
                 else {                 /* 大きな数の時               */
                  cd.op = 66 ;          /* lci命令に変更              */
                  store[objsize].vi = inumber ;
                  cd.q = codesize ;
                  while(store[cd.q].vi != inumber) cd.q++ ;
                  checkConst() ;        /* 定数格納チェック           */
                 }
                 break ;

      case 'c' : cd.p=6 ;               /* char type                  */
                 while(readc() != '\'');/*  最初の ' を見つける       */
                 cd.q=readc() ;         /*  文字を読み込む            */
                 break ;                /*  最後の ' は無視する       */

      case 'b' : cd.p=3;                /* boolean                    */
                 cd.q=(short)readi() ;
                 break;

      case 's' : cd.p = 4;              /* set type                   */
                 s=0;
                 while(readc() != '(') ;
                 while(readc() != ')') addset(s,(short)readi())  ;
                 store[objsize].vs = s ;
                 cd.q = codesize ;
                 while(store[cd.q].vs != s) cd.q++ ;
                 checkConst() ;         /* 定数格納チェック           */
                 break ;

      case 'r' : cd.p = 2 ;
                 rnumber = readr() ;
                 store[objsize].vr = rnumber ;
                 inumber = store[objsize].vi ;
                 /* 浮動小数点の形で比較を行うと思わぬ落とし穴があるので
                   ビット列の比較をするために、union型のviから数を得る*/
                 cd.q = codesize ;
                 while(store[cd.q].vi != inumber) cd.q++ ;
                 checkConst() ;         /* 定数格納チェック           */
                 break ;

    /*case 'n' : cd.p=0 ; */            /* ldc nil                    */
              /* cd.q=0 ; */
     }
}

/**************************************/
/* ORD() : ordのアセンブル            */
/**************************************/
static void ORD(void)
{
     switch(ch) {
      case 'b' : cd.p=3 ; break ;
      case 'c' : cd.p=6 ;
     }
}

/**************************************/
/* RET() : retのアセンブル            */
/**************************************/
static void RET(void)
{
     switch(ch) {
    /*case 'p' :     ; break ;  何もしない */
      case 'i' : cd.p=1 ; break ;
      case 'r' : cd.p=2 ; break ;
      case 'c' : cd.p=3 ; break ;
      case 'b' : cd.p=4 ; break ;
      case 'a' : cd.p=5 ; break ;
     }
}

/**************************************/
/* STO() : stoのアセンブル            */
/**************************************/
#define STO  typesymbol

/**********************************************************************/
/*                   P-code ニーモニック表                            */
/**********************************************************************/
static char instr[][4] =
{
   /*          x0    x1    x2    x3    x4    x5    x6    x7    x8    x9  */
   /* 0x */  "lod","ldo","str","sro","sto","chk","ind","ldc","lda","dec",
   /* 1x */  "inc","mst","cup","ent","ret","...","ixa","equ","neq","geq",
   /* 2x */  "grt","leq","les","ujp","fjp","xjp","ejp","lap","adi","adr",
   /* 3x */  "sbi","sbr","sgs","flt","flo","trc","ngi","ngr","sqi","sqr",
   /* 4x */  "abi","abr","not","and","ior","dif","int","uni","inn","mod",
   /* 5x */  "odd","mpi","mpr","dvi","dvr","mov","lca","lao","stp","ord",
   /* 6x */  "chr","ujc","mms","msi","cui","bas","...","cka","tra","rou",
   /* 7x */  "nxt","nxd","...","...","...","new","dis","pge","eof","eol",
   /* 8x */  "rst","rwt","get","put","wrs","wrb","wri","wrr","wrc","wrf",
   /* 9x */  "wln","rdi","rdr","rdc","rln","trs","trw","tgt","tpt","atn",
   /*10x */  "sin","cos","exp","log","sqt"
} ;

/******* ニーモニック対応のエントリ表 ********/
static struct entry {
       void (*func)(void) ;
} OP[] = {
   /*          x0    x1    x2    x3    x4    x5    x6    x7    x8    x9  */
   /* 0x */   PTN1, PTN6 ,PTN1, PTN6, STO , CHK , PTN6, LDC , PTN2, PTN7,
   /* 1x */   PTN7, PTN3, PTN4, ENT , RET , PTN0, IXA , PTN5, PTN5, PTN5,
   /* 2x */   PTN5, PTN5, PTN5, PTN8, PTN8, PTN0, PTN4, PTN8, PTN0, PTN0,
   /* 3x */   PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0,
   /* 4x */   PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0, PTN0,
   /* 5x */   PTN0, PTN0, PTN0, PTN0, PTN0, PTN2, LCA , PTN9, PTN0, ORD ,
   /* 6x */   PTN0, PTN0, PTN3, PTN0, PTN3, PTN3, PTN0, PTN0, PTN3, PTN0,
   /* 7x */   PTN7, PTN7, PTN0, PTN0, PTN0, PTN9, PTN9, PTN3, PTN3, PTN3,
   /* 8x */   PTN0, PTN0, PTN0, PTN0, PTN2, PTN3, PTN3, PTN3, PTN3, PTN3,
   /* 9x */   PTN3, PTN3, PTN3, PTN3, PTN3, PTN3, PTN3, PTN3, PTN3, PTN0,
   /*10x */   PTN0, PTN0, PTN0, PTN0, PTN0
} ;

/***************************************/
/*     1行アセンブル処理               */
/***************************************/
static void assemble(void)
{
   char name[4];

     *name     = (char)readc()  ;       /* 1文字目 */
     *(name+1) = (char)readc()  ;       /* 2文字目 */
     *(name+2) = (char)readc()  ;       /* 3文字目 */
     *(name+3) = '\0'     ;
     if(!eoln()) ch=readc();
      /* そこで行が終わってなければ次の文字を読む */

     cd.op = -1 ;
     while(strcmp(instr[++cd.op],name)) ;/* instructionよりopを決定   */
         /* このようなリニアサーチはスピードが遅いので改良しよう      */

     cd.p   =  0 ;
     cd.q   =  0 ;
     OP[cd.op].func() ;                 /* opに対応したアセンブル     */

     store[pc++].vo = cd ;              /* メモリに格納               */
}

/********** generate() :  行の最初に呼ばれる処理 **********/
static void generate(void)
{
   short i     ;                        /* 作業カウンタ               */
   char progname[33] ;                  /* プログラム名               */
   char filename[33] ;                  /* ファイル名                 */
   short fileadr       ;                /* ファイルアトレス           */
   short filesize      ;                /* バッファ変数の大きさ       */

     for(;;) {
      ch=readc();                       /* 行の最初の文字を読む       */
      switch(ch) {
       case ' ' : assemble();           /* 通常命令 その行をアセンブル*/
                  break     ;
 
       case ';' :                       /* 注釈行を無視               */
                  break ;
 
       case 'L' : update()  ;           /* label登録                  */
                  break ;
 
       case 'V' : store[entpc].vo.p = (unsigned char)readi() ;
                  store[entpc].vo.q = (short)        readi() ;
                  break ;
 
       case 'F' :                       /* ファイルアドレス           */
                  readc() ;             /* 空白を読み飛ばす           */
                  i=0 ;
                  while((ch=readc()) != ' ') /* ファイル名取得        */
                   filename[i++] = (char)ch ;
                  filename[i++] = '\0'  ;
                  readc() ;                       /*  空白を読み飛ばす*/
                  fileadr = (short)readi() ;      /* ファイルアトレス */
                  putobject((char*)&fileadr,sizeof(fileadr));/* 書出  */
                  filesize = (short)readi();      /* バッファサイズ   */
                  putobject((char*)&filesize,sizeof(filesize));/* 書出*/
                  putobject(filename,i) ;         /* ファイル名書出   */
                  break ;

       case 'N' :                       /* プログラム名               */
                  readc() ;             /* 空白を読み飛ばす           */
                  i=0 ;
                  while(!eoln())        /* プログラム名取得           */
                   progname[i++] = (char)readc() ;
                  progname[i++] = '\0' ;
                  putobject(progname,i);/* 書出                       */
                  break ;

       case 'Q' : return ;              /* アセンブル終わり           */
      }
      readln() ;                        /* 行の残りを読み飛ばし       */
     }
}


/*****************************************/
/* assemblelist() : アセンブルリスト出力 */
/*****************************************/
static void assemblelist(void)
{
     reset(PcodeSourceName) ;           /* P-codeｿｰｽﾌｧｲﾙのｵｰﾌﾟﾝ       */

     printf("\n ADDR   OP   P      Q    P-code source statement\n");
     printf(  "================================================\n");

     pc  = 0 ;

     for(;;) {
      ch=readc();                       /* 行の最初の文字             */
      switch(ch) {
       case ' ' :  printf(" %4d: %3d %3d %6d    %c",
                     pc++, store[pc].vo.op, store[pc].vo.p ,
                     store[pc].vo.q,ch);
                   break;
       case ';' :
       case 'L' :
       case 'V' :
       case 'F' :
       case 'N' :  printf("\t\t\t %c",ch) ;
                   break;
       case 'Q' :  printf("\t\t\t Q\n") ;
                   if(codesize != objsize)
                   printf(" %4d:\n   〜: constant data\n %4d:\n",
                     codesize,objsize-1) ;
                   fclose(pcsfile) ;   /* ソースファイルのクローズ   */
                   return;
      }
      while(!eoln()) putc(readc(),stdout) ;
      printf("\n") ;
      if(ferror(stdout)) paerr(8) ;     /* 出力でエラーが発生した     */
      readln()     ;
     }
}

/***************************************/
/* main() : P-codeアセンブラメイン処理 */
/***************************************/
short main(short argc,char *argv[])
{
     codesize  = atoi(argv[1]) ;        /* 命令コードの数             */
     PcodeSourceName = argv[2] ;        /* P-codeソースファイル名     */
     PcodeObjectName = argv[3] ;        /* P-codeオブジェクトファイル名*/
     CompVersion     = argv[4] ;        /* コンパイラのバージョン     */
     init();                            /* 各種初期設定               */
     generate();                        /* アセンブル                 */
     fclose(pcsfile)  ;                 /* ソースファイルのクローズ   */

     for(pc=0;pc<codesize;pc++) {       /* qｵﾍﾟﾗﾝﾄﾞの補正処理         */
      cd.op = store[pc].vo.op ;
      if((/*lao*/ cd.op==57)||(/*ldox*/cd.op==1 || (105<=cd.op && cd.op<=109))
                            ||(/*srox*/cd.op==3 || (120<=cd.op && cd.op<=124)))
       store[pc].vo.q += objsize ;
     }

     putobject((char*)&start,sizeof(start)) ; /* オブジェクト開始合図 */
     putobject((char*)store,objsize*sizeof(_store)) ; /* オブジェクト出力*/
     if(fflush(objfile) == EOF) paerr(3) ;
     if(fclose(objfile) == EOF) paerr(3) ;
                 /* クローズできなければ書き込み失敗の可能性がある    */

     fputs(         " *** Assemble completed. ***\n",stderr);
     fprintf(stderr," *** code = %5d words  constant data = %5d words ***\n",
                                codesize,       objsize-codesize);

     if(argc==6) assemblelist();        /* アセンブルリストの出力     */

     return(0) ;                        /* 正常終了                   */
}
