/************************************************************/
/*                                                          */
/*       *** HAPPy Pascal Compiler ***                      */
/*        式のコンパイル処理                                */
/*      void expression(Set fsys) ;                         */
/*                                                          */
/*                 Copyright (c) H.Asano 1992,1994.         */
/*                                                          */
/************************************************************/

#define EXTERN extern
#include "pascomp.h"
#include "pcpcd.h"

extern void gen0(enum pcdmnc) ;
extern void genp(enum pcdmnc,int) ;
extern void gen0t(enum pcdmnc,stp*) ;
extern void gen1t(enum pcdmnc,stp*,int)     ;
extern void gen2t(enum pcdmnc,stp*,int,int) ;
extern void gencompare(enum pcdmnc,char,int) ;
extern void genldc(char,long) ;
extern void genixa(long,int)  ;
extern void genchk(stp*,int,long,long) ;
extern void convertint(stp*)  ;
extern void load(void) ;
extern void loadaddress(void) ;
extern ctp  *searchsection(ctp*) ;
extern ctp  *searchid(Set) ;
extern void insymbol(void) ;
extern void pcerr(int,char*);
extern char *inttoch(long)  ;
extern void skip(Set) ;
extern boolean string(stp*) ;
extern boolean compatible(stp*,stp*) ;
extern void getbounds(stp*,long*,long*) ;
extern int align(stp*,int) ;
extern void conststrings(stp**, union valu*) ;
extern Set  *mkset(Set*,int,...) ;
extern Set  *orset(Set*,Set*) ;
extern void call(Set,ctp*) ;
extern void *Malloc(int)   ;
static void array(Set) ;
static void recordmember(void) ;
static void ptr(void) ;
static void factident(Set) ;
static void factconst(Set) ;
static void factlparent(Set) ;
static void factnot(Set)   ;
static void factset(Set)   ;
static void factset2(Set,stp*,long*,boolean*,boolean*) ;
static void factnil(void)  ;
static void simpleexpression(Set) ;
static void plusminusope(attr,enum operator) ;
static void orope(attr)    ;
static void mulope(attr)   ;
static void rdivope(attr)  ;
static void inope(attr)    ;
static void relope(attr,enum operator)  ;
static void cnvfloat(attr*)   ;

/*******************************************/
/* expression() : 式のコンパイル処理メイン */
/*******************************************/
void expression(Set fsys)
{
  attr lattr ;
  enum operator lop ;
  Set ws ;

     ws = fsys ;
     addset(ws,relop) ;
     simpleexpression(ws) ;

     if(sy == relop) {                  /* 関係演算子の時             */
      if(gattr.typtr)
       if(gattr.typtr->form <= power)   /*  スカラ､範囲型､集合型の時  */
        load() ;                        /*   load命令                 */
       else loadaddress() ;             /*  それ以外は間接参照        */
      lattr = gattr ;                   /* 今の式の属性を退避         */
      lop   = op    ;                   /* 今の演算子を退避           */

      if(lop == inop)                   /* in の時 integerでなければ  */
       if(gattr.typtr && (gattr.typtr->form == scalar) &&
          (gattr.typtr != realptr))    /* inの前の式が順序型の時     */
        convertint(gattr.typtr) ;       /* 必要ならord命令生成        */

      insymbol()    ;
      simpleexpression(fsys) ;          /* 関係演算子の次の単純式の処理*/
      if(gattr.typtr)
       if(gattr.typtr->form <= power)   /* スカラ､範囲型､集合型の時   */
        load() ;                        /*  load命令                  */
       else loadaddress() ;             /* それ以外は間接参照         */

      if((lattr.typtr) && (gattr.typtr))
       if(lop == inop) inope(lattr) ;   /* in 演算子処理              */
       else {
        if(lattr.typtr != gattr.typtr)
         cnvfloat(&lattr) ;             /* realへの変換処理           */

        if(compatible(lattr.typtr,gattr.typtr))  /* 両方の型が同じ    */
         relope(lattr,lop) ;            /* 関係演算子の処理           */
        else pcerr(143,"") ;            /* 演算子の両端の型が不一致   */
       }

      gattr.typtr = boolptr ;
      gattr.kind  = expr    ;           /* これ以降論理型の式とする   */
     }

}

/**************************************/
/*      inope() : in 演算子処理       */
/**************************************/
static void inope(attr fattr)
{
     if(gattr.typtr->form == power)           /* 今の型が集合型          */
      if(compatible(fattr.typtr,gattr.typtr->sf.pw.elset))
                                              /* 底基の型と等しいか      */
       gen0(iINN) ;                           /* inn命令を生成           */
      else {
       pcerr(143,"") ;                        /* 演算子の両端の型が不一致*/
       gattr.typtr = nil ;
      }
     else {
      pcerr(130,"") ;                         /* 式は集合型でない        */
      gattr.typtr = nil  ;
     }
}

/*****************************************/
/*  relope() : in 以外の関係演算子処理   */
/*              =  <  >  <>  <=  >=      */
/*****************************************/
static void relope(attr fattr,enum operator fop)
{
  int lsize ;                           /* 比較する大きさ             */
  char typind ;                         /* 比較命令の型               */
  enum pcdmnc pcd ;                     /* 生成P-code                 */

     lsize = fattr.typtr->size ;        /* その型の大きさ             */

     switch(fattr.typtr->form) {        /* 型で振り分ける             */
      case scalar :                     /* スカラー                   */
        if(fattr.typtr == realptr)      typind = 'r' ;  /* real       */
        else if(fattr.typtr == boolptr) typind = 'b' ;  /* boolean    */
        else if(fattr.typtr == charptr) typind = 'c' ;  /* char       */
        else                            typind = 'i' ;  /* integer/列挙型*/
        break ;
      case pointer :                    /* ポインタ型                 */
        if((fop != eqop) && (fop != neop)) /* =  <> 以外              */
         pcerr(131,"") ;                /* 等しいかどうかの判定しか駄目*/
        typind = 'a'   ;
        break ;
      case power   :                    /* 集合型                     */
        if((fop == ltop) || (fop == gtop)) /* <  >  の時              */
         pcerr(132,"") ;                /*  完全包含の判定は駄目      */
        typind = 's'   ;
        break ;
      case arrays :                     /* 配列型                     */
        if(! string(fattr.typtr))       /*  文字列でない時            */
         pcerr(134,"") ;                /*  演算対象の型に誤り        */
         typind = 'm'  ;
         break ;
      case records :                    /* レコード型                 */
        pcerr(134,"")  ;                /*  レコード型は駄目          */
        typind = 'm'   ;
        break          ;
      case files :                      /* ファイル型                 */
        pcerr(133,"")  ;                /*   ファイルの比較は駄目     */
        typind = 'f'   ;
     }

     switch(fop) {                      /* 演算子で生成命令を区別     */
      case ltop : pcd = iLES ; break ;  /* <  les命令                 */
      case leop : pcd = iLEQ ; break ;  /* <= leq命令                 */
      case gtop : pcd = iGRT ; break ;  /* >  grt命令                 */
      case geop : pcd = iGEQ ; break ;  /* >= geq命令                 */
      case neop : pcd = iNEQ ; break ;  /* <> neq命令                 */
      case eqop : pcd = iEQU ;          /* =  neq命令                 */
     }
     gencompare(pcd,typind,lsize)    ;  /* 命令生成                   */
}

/**************************************/
/* cnvfloat() : realへの変換処理      */
/**************************************/
static void cnvfloat(attr *fattr)
{

      if((*fattr).typtr == intptr) {    /* 前の式がinteger            */
       gen0(iFLO) ;                     /*  前の式を realに変換       */
       (*fattr).typtr = realptr ;
      } ;
      if(gattr.typtr == intptr) {       /* 今の式integer              */
       gen0(iFLT) ;                     /*  今の式をrealに変換        */
       gattr.typtr = realptr ;
      }
}

/***************************************/
/* selector() : 変数の属性を選択する   */
/*      α[･･･]  :  配列変数           */
/*      α^      :  ポインタ変数       */
/*      α.      : レコード変数        */
/***************************************/
void selector(Set fsys, ctp *fcp)
{
  Set ws ;

     gattr.typtr = fcp->idtype ;        /* 型を設定                   */
     gattr.kind  = varbl       ;        /* 種類は 変数                */
     switch(fcp->klass) {               /* 変数の型で振り分ける       */
      case vars :                       /*[変数]                      */
        if(fcp->n.v.vkind == actual) {  /*  実変数                    */
         gattr.access = drct ;
         gattr.vlevel = fcp->n.v.vlev ;
         gattr.dplmt  = fcp->n.v.vaddr;
        }
        else {                          /*  formal (変数引数)         */
         if(gattr.typtr->form != files) /* ﾌｧｲﾙ型はlodaを生成しない   */
          gen2t(iLOD,nilptr,level-fcp->n.v.vlev,fcp->n.v.vaddr) ;
         gattr.access = indrct ;
         gattr.idplmt = 0      ;
         gattr.vlevel = fcp->n.v.vlev ; /* ファイルが変数引数の時の   */
         gattr.dplmt  = fcp->n.v.vaddr; /* ために退避しておく         */
        }                               /* 本当はこのやり方は違反です */
        break ;

      case field :                      /* レコードのフィールド       */
                                        /* with文配下しかこないはず   */
        if(display[disx].occur == crec){/* 固定フィールドの時         */
         gattr.access = drct ;
         gattr.vlevel = display[disx].clev ;
         gattr.dplmt  = display[disx].cdspl+ fcp->n.fldaddr ;
        }
        else {                          /* vrec(可変フィールドの時)   */
         if(level == 1)                 /* 大域変数                   */
          gen1t(iLDO,nilptr,display[disx].vdspl) ;        /* ldo命令  */
         else  gen2t(iLOD,nilptr,0,display[disx].vdspl) ; /* lod命令  */
         gattr.access = indrct ;
         gattr.idplmt = fcp->n.fldaddr ;
        }
       break;

      case func  :                      /* 関数                       */
        gattr.access = drct ;
        gattr.vlevel = fcp->n.pf.sd.d.pflev + 1 ;
        gattr.dplmt  = 0    ;

     }

     ws = selectsys ;
     orset(&ws,&fsys) ;
     if(! inset(ws,sy)) {
      pcerr(59,"") ;                    /* 変数に誤りがある           */
      skip(ws)     ;                    /* fsys+selectsysまで読み飛ばし*/
     }

     while(inset(selectsys,sy)) {       /* [  .  ^  の間処理する      */
      if(sy == lbrack)                  /*  [ の時                    */
       array(fsys) ;                    /*   配列の処理               */
      else if(sy == period)             /*  . の時                    */
       recordmember() ;                 /*   レコードの各要素の処理   */
      else                              /*  ^ の時                    */
       ptr() ;                          /*    ポインタの処理          */

      if(! inset(ws,sy)) {
       pcerr(6,"") ;                    /* 不当な記号が現れた         */
       skip(ws) ;
      }
     }
}

/*****************************************/
/* recordmember() : レコードの要素の処理 */
/*****************************************/
static void recordmember(void)
{
  ctp *lcp ;

     if(gattr.typtr)
      if(gattr.typtr->form != records) {
       pcerr(140,"") ;                  /* 変数の型がレコード型でない */
       gattr.typtr = nil ;              /* 今後のエラー防止のためnilにする*/
      }

     insymbol() ;                       /* 次のsymbol                 */
     if(sy == ident) {                  /*  名前                      */
      if(gattr.typtr) {                 /*  レコードの要素から名前を探す*/
       lcp = searchsection(gattr.typtr->sf.re.fstfld) ;
       if(!lcp) {                       /*  名前がない時              */
        pcerr(152,id) ;                 /*  レコードの欄ではない      */
        gattr.typtr = nil ;             /* 今後のエラー防止のためnilにする*/
       }
       else {                           /* 名前がレコードの欄の時     */
        gattr.typtr = lcp->idtype ;     /*   名前の型                 */
        if(gattr.access==drct)          /* 直接参照の時               */
           gattr.dplmt += lcp->n.fldaddr ;
        else                            /* 間接参照の時(indrct)       */
           gattr.idplmt += lcp->n.fldaddr ;
       }
      }                                 /* end (typtr != nil)         */
      insymbol() ;                      /* 名前の次を読み込む         */
     }
     else pcerr(2,"") ;                 /* 名前がない                 */
}

/*****************************************/
/*      array() : 配列の処理             */
/*****************************************/
static void array(Set fsys)
{
  attr lattr ;                          /* 1つ前の属性                */
  long lmin,lmax ;
  int lsize ;
  int incsize ;
  Set  ws    ;

     do {                               /* 多次元配列のための繰り返し */
      lattr = gattr ;
      if(lattr.typtr)
       if(lattr.typtr->form != arrays) {
        pcerr(138,"") ;                 /* 変数の型は配列でない       */
        lattr.typtr = nil ;
        gattr.typtr = nil ;             /* loadaddressをさせない      */
       }
      loadaddress() ;
      insymbol() ;
      mkset(&ws, comma,rbrack, -1) ;
      orset(&ws, &fsys) ;
      expression(ws)    ;               /* 添え字の式の処理           */

      if(gattr.typtr) {
       if(gattr.typtr->form != scalar)
        pcerr(113,"") ;                 /* 添え字の型はスカラか範囲型 */
       lsize = lattr.typtr->sf.ar.aeltype->size ;
       lsize = align(gattr.typtr,lsize) ; /* 境界合わせ               */
      }
      if(lattr.typtr) {
       if(compatible(lattr.typtr->sf.ar.inxtype,
                     gattr.typtr)) {    /* 添え字の型と等しい         */
        if(lattr.typtr->sf.ar.inxtype) {
         getbounds(lattr.typtr->sf.ar.inxtype,&lmin,&lmax);
         if(gattr.typtr)
          if(gattr.kind == cst) {       /* 添え字が定数の時           */
           if((lmin<=gattr.cval.ival) && (gattr.cval.ival<=lmax)) {
            incsize = (int)(gattr.cval.ival-lmin)*lsize ; /* 増分量   */
            if(incsize) gen1t(iINC,nilptr,incsize);
           }
           else pcerr(148,"") ;        /* 添え字の定数が範囲内にない  */
          }
          else {                        /* 添え字が式の時             */
           load() ;                     /* 添え字式をload             */
           convertint(gattr.typtr) ;    /* 必要ならord命令生成        */
           if(debug) genchk(intptr,1,lmin,lmax) ; /* chk命令生成      */
           genixa(lmin,lsize) ;               /* lxa命令の生成        */
          }
        }
       }
       else pcerr(139,"") ;            /* 添え字の型が宣言と一致しない*/

       gattr.typtr  = lattr.typtr->sf.ar.aeltype ; /* 要素の型        */
       gattr.kind   = varbl ;
       gattr.access = indrct ;
       gattr.idplmt = 0 ;
      }

     } while(sy == comma) ;

     if(sy == rbrack) insymbol() ;
     else pcerr(12,"") ;                /* ] がない                   */
}

/*******************************************/
/* ptr() : ポインタ参照,バッファ変数の処理 */
/*******************************************/
static void ptr(void)
{
     if(gattr.typtr)
      if(gattr.typtr->form == pointer) { /* ポインタ型の時            */
       load() ;
       gattr.typtr = gattr.typtr->sf.pt.eltype ; /* 指し示すものの型  */
       if(debug)                        /* デバッグコンパイルの時     */
        gen0(iCKA) ;                    /* CKA命令                    */
       gattr.kind   = varbl ;
       gattr.access = indrct ;          /* 間接参照                   */
       gattr.idplmt = 0      ;
      }
      else if(gattr.typtr->form == files){/* ファイル型の時           */
       if(gattr.access == indrct)       /* ファイル変数が変数引数の時 */
        gen2t(iLOD,nilptr,level-gattr.vlevel,gattr.dplmt) ;
       gattr.typtr = gattr.typtr->sf.fi.filtype ; /* ファイルの基の型 */
      }
      else pcerr(141,"") ;              /* ファイル型か指標型でない   */

      insymbol() ;
}

/**************************************/
/* factor() : 式の因子(factor)の処理  */
/**************************************/
static void factor(Set fsys)
{
  Set ws ;

     if(! inset(facbegsys,sy)) {
      pcerr(58,"") ;                    /* 項に誤りがある             */
      ws = fsys ;
      orset(&ws, &facbegsys) ;
      skip(ws) ;                        /* fsys+factbegsysまで読み飛ばし*/
      gattr.typtr = nil ;
     }

     while(inset(facbegsys,sy)) {
      switch(sy) {
       case ident       :               /* 名前の時                   */
              factident(fsys) ;
              break ;
       case intconst    :               /* 整数定数                   */
       case realconst   :               /* 実数定数                   */
       case stringconst :               /* 文字列                     */
              factconst(fsys) ;
              break ;
       case lparent     :               /* (                          */
              factlparent(fsys) ;
              break ;
       case notsy       :               /* not                        */
              factnot(fsys) ;
              break ;
       case lbrack      :               /* [    集合の始まり記号      */
              factset(fsys) ;
              break ;
       case nilsy       :               /* nil                        */
              factnil() ;
              break ;
      }
      if(! inset(fsys,sy)) {
       pcerr(6,"") ;                    /* 不当な記号が現れた         */
       skip(ws)    ;                    /* fsys+factbegsysまで読み飛ばし*/
      }
     }
}

/**************************************/
/*     factident() : 名前因子の処理   */
/**************************************/
static void factident(Set fsys)
{
  ctp *lcp ;
  Set ws ;

     mkset(&ws, konst,vars,field,func,-1) ; /* 名前を､定数･変数･フィールド･ */
     lcp = searchid(ws) ;                   /* 関数の中から探す             */
     insymbol() ;

     if(lcp->klass == func) {
      call(fsys,lcp) ;                  /* 関数の時､関数呼び出し      */
      gattr.kind = expr ;
      if(gattr.typtr)
       if(gattr.typtr->form == subrange) /* 範囲型の時                */
        gattr.typtr = gattr.typtr->sf.su.rangetype ; /* 基の型        */
    }
    else if(lcp->klass == konst) {      /* 定数の時                   */
     gattr.typtr = lcp->idtype ;
     gattr.kind  = cst ;
     gattr.cval  = lcp->n.values ;      /*  値を入れる                */
    }
    else {                              /* 変数､レコードフィールドの時*/
     selector(fsys,lcp) ;               /* 属性選択                   */
     if(gattr.typtr)
      if(gattr.typtr->form == subrange) /* 範囲型の時                 */
       gattr.typtr = gattr.typtr->sf.su.rangetype ; /* 基の型         */
    }
}

/**************************************/
/*     factconst() : 定数因子の処理   */
/**************************************/
static void factconst(Set fsys)
{
  stp *lsp,*lsp1 ;

     gattr.kind = cst ;
     switch(sy) {
      case intconst :                   /* 整数定数                   */
        gattr.typtr = intptr ;
        gattr.cval  = val    ;          /* 値を設定                   */
        break ;

      case realconst :                  /* 実数定数                   */
        gattr.typtr = realptr ;
        gattr.cval   = val    ;
        break ;

      case stringconst :                /* 文字列                     */
        conststrings(&(gattr.typtr),&(gattr.cval));/*文字列定数の処理 */
     }
     insymbol() ;
}

/**************************************/
/*   factlparent() : (〜)の処理       */
/**************************************/
static void factlparent(Set fsys)
{
  Set ws ;

     insymbol() ;
     ws = fsys  ;
     addset(ws,rparent) ;
     expression(ws) ;                   /* )が出てくるまで式の処理    */
     if(sy == rparent) insymbol() ;
     else pcerr(4,"")             ;     /* ) がない                   */
}

/**************************************/
/*     factnot() : not の処理         */
/**************************************/
static void factnot(Set fsys)
{
     insymbol()   ;
     factor(fsys) ;                     /* notの次の因子の解析        */
     load()       ;                     /* load命令の出力             */
     if(gattr.typtr != boolptr) {
      pcerr(135,"not") ;                /*  論理型でないといけない    */
      gattr.typtr = nil  ;              /*  次のエラーをださないためnil*/
     }
     gen0(iNOT)   ;                     /* not命令の出力              */
}

/**************************************/
/*     factset() : 集合の処理         */
/**************************************/
static void factset(Set fsys)
{
  stp *lsp ;
  csp *lvp ;
  long    csetpart;                     /* 集合の定数要素パート       */
  boolean varpart ;                     /* 変数要素がある時 true      */
  boolean cstpart ;                     /* 定数要素がある時 true      */
  boolean test   ;
  Set ws  ;

     insymbol() ;
     csetpart= 0         ;              /* 固定要素集合のクリア       */
     varpart = false     ;
     cstpart = false     ;
     lsp = (stp*)Malloc(sizeof(stp)) ;  /* 集合の型を作成             */
     lsp->form          = power  ;
     lsp->size         = setsize ;
     lsp->assignflag   = true    ;
     lsp->sf.pw.packed = both    ;
     lsp->sf.pw.elset  = nil     ;
     lsp->sf.pw.elmin  = setlow  ;
     lsp->sf.pw.elmax  = sethigh ;

     if(sy == rbrack) {                 /* 空集合の時                 */
      gattr.typtr = lsp ;
      gattr.kind  = cst ;
      insymbol() ;
     }

     else {                             /* 要素がある時               */
      do {
       mkset(&ws,comma,rbrack,period2,-1);
       orset(&ws,&fsys) ;
       expression(ws)   ;               /* 要素                       */
       if(gattr.typtr)
        if((gattr.typtr->form != scalar)/* 要素が順序型かチェック     */
        || (gattr.typtr == realptr)) {
         pcerr(136,"") ;                /*  要素記述は順序型のこと　  */
         gattr.typtr = nil ;
        }
        else {
         if(!lsp->sf.pw.elset)          /* 集合の型がない時           */
          lsp->sf.pw.elset = gattr.typtr ;/* 要素の型を集合の型とする */
         if(compatible(lsp->sf.pw.elset,gattr.typtr)){   /* 要素の型  */
          if(sy == period2)
           factset2(fsys,lsp,&csetpart,&cstpart,&varpart);/* ..の処理 */
          else {                        /* 通常の集合要素の処理       */
           if(gattr.kind == cst)        /* 要素が定数                 */
            if((gattr.cval.ival < (long)lsp->sf.pw.elmin) || /* 集合の*/
               (gattr.cval.ival > (long)lsp->sf.pw.elmax))   /* 範囲  */
             pcerr(607,inttoch((long)lsp->sf.pw.elmax)) ;/* 範囲内にない*/
            else {
             csetpart |=(1L << gattr.cval.ival);/* 集合の定数要素を加える*/
             cstpart = true ;
            }
           else {                       /* 要素が変数の時             */
            load() ;                    /* 要素値をload               */
            convertint(gattr.typtr) ;   /* 必要ならord命令生成        */
            if(debug)
             genchk(intptr,111,         /* 式がHAPPyの集合範囲に入るか*/
             (long)lsp->sf.pw.elmin,(long)lsp->sf.pw.elmax) ;
                                        /*  集合要素の範囲チェック    */
            gen0(iSGS) ;                /* sgs命令(要素1個の集合作成) */
            if(varpart) gen0(iUNI)  ;   /* uni命令(変数の集合に加える)*/
            else varpart = true     ;   /* 初めて変数が現れた時 trueに*/
           }
          }
         }
         else pcerr(137,"") ;           /* 集合の要素の型が不一致     */
        }

       if(test=(sy==comma)) insymbol(); /* , なら次の要素を読む       */
      } while(test) ;                   /* , ならば次の要素の処理     */

      if(sy == rbrack) insymbol() ;     /* ] ならば次のsymbolを読む   */
      else pcerr(12,"") ;               /* ] がない                   */

      gattr.typtr = lsp ;               /* 集合の型を入れる           */
     }

     lvp = (csp*)Malloc(sizeof(csp)) ;  /* 集合定数のエリア確保       */
     lvp->cclass = pset ;
     lvp->c.pval = csetpart ;
     gattr.cval.valp = lvp  ;

     if(varpart && cstpart) {           /* 変数要素と定数要素両方あり */
       genldc('s',(long)nil) ;          /* ldcs命令                   */
       gen0(iUNI) ;                     /* uni命令                    */
       gattr.kind = expr ;
      }
}

/****************************************/
/*  loadelement() :  集合の 範囲要素load*/
/****************************************/
static void loadelement(stp *fsp,boolean *varpart,int kind)
{
  int pope ;                            /* mms命令の p オペランド
                                            0 下限 上限  チェックなし
                                            1 下限 上限  チェックあり
                                            2 上限 下限  チェックなし
                                            3 上限 下限  チェックあり */
    /* debugオプション指定時に chk命令以外でチェックさせるのは
       このmms命令のみ。統一がとれていないけど、暫定的にこのようにした*/

     pope = kind + (int)(debug) ;
     load() ;                           /* 要素式をload               */
     convertint(gattr.typtr)    ;       /* 必要ならord命令生成        */
     genp(iMMS,pope)            ;       /* mms命令生成                */
     if(*varpart) gen0(iUNI)    ;       /* uni命令(変数の集合に加える)*/
     else *varpart = true       ;
}

/****************************************/
/*  factset2() :  集合の 範囲要素の処理 */
/*                 順序式..順序式       */
/****************************************/
static void factset2(Set fsys,stp *fsp,
              long *csetpart,boolean *cstpart,boolean *varpart)
{
  attr lattr,lattr2 ;
  short m    ;
  Set ws     ;

     lattr = gattr ;
     if(gattr.kind != cst) {            /* 定数以外 ･･･ 式            */
      load() ;                          /* 要素式をload               */
      convertint(gattr.typtr) ;         /* 必要ならord命令生成        */
      insymbol() ;                      /* 次の要素を読む             */
      mkset(&ws,comma,rbrack,-1);
      orset(&ws,&fsys);
      expression(ws)  ;                 /* 次の要素の処理             */
      if(gattr.typtr)
       if(compatible(gattr.typtr,lattr.typtr))/* 前の要素との型チェック*/
        loadelement(fsp,varpart,0) ;    /* 上限式load&mms             */
       else pcerr(137,"") ;             /* 集合の要素の型が不一致     */
     }
     else {                             /* 最初の要素が定数の時       */
      insymbol() ;                      /* 次の要素を読む             */
      mkset(&ws,comma,rbrack,-1);
      orset(&ws,&fsys);
      expression(ws)  ;                 /* 次の要素の処理             */
      if(gattr.typtr)
       if(compatible(gattr.typtr,lattr.typtr)) {/* 前の要素との型チェック*/
        if(gattr.kind == cst) {         /* 上限値が定数               */
         if(lattr.cval.ival <= gattr.cval.ival)   /*上限値の方が大きい*/
          if((lattr.cval.ival >= (long)fsp->sf.pw.elmin) &&/* 要素の範囲*/
             (gattr.cval.ival <= (long)fsp->sf.pw.elmax)){ /*   チェック*/
           for(m=(short)lattr.cval.ival;m<=(short)gattr.cval.ival;m++)
            *csetpart |=(1L << m);      /* 集合の定数要素を加える     */
           *cstpart = true ;
          }
          else
           pcerr(607,inttoch((long)fsp->sf.pw.elmax)) ;/* 範囲内にない*/
        }
        else {                          /* 定数..式                   */
         load() ;                       /* 上限式をload               */
         convertint(gattr.typtr) ;      /* 必要ならord命令生成        */
         gattr = lattr    ;
         loadelement(fsp,varpart,2) ;   /* 下限定数load&mms           */
        }
       }
       else pcerr(137,"") ;             /* 集合の要素の型が不一致     */
     }
}

/**************************************/
/*     factnil() : nil の処理         */
/**************************************/
static void factnil(void)
{
     gattr.typtr      = nilptr ;        /* nil 型                     */
     gattr.kind       = cst    ;
     gattr.cval.ival  = 0      ;
     insymbol()                ;
}

/**************************************/
/*    term() : 式の項(term)の処理     */
/**************************************/
static void term(Set fsys)
{
  attr lattr ;                          /* 1つ前の項の属性            */
  enum operator lop ;                   /* 1つ前の演算子              */
  Set ws ;

     ws = fsys ;
     addset(ws,mulop) ;
     factor(ws) ;                       /* 因子の処理                 */

     while(sy == mulop) {               /* * / div mod and の時       */
      load() ;                          /* 今の項をload               */
      lattr = gattr ;                   /* 今の項の属性を退避         */
      lop   = op    ;                   /* 今の演算子を退避           */
      insymbol() ;
      factor(ws) ;                      /* 次の項の処理               */
      load() ;                          /* その項をload               */
      if((lattr.typtr) && (gattr.typtr))
       switch(lop) {                    /* 演算子で振り分ける         */
        case mul  : mulope(lattr) ;     /*  * 演算子処理              */
                    break         ;
        case rdiv : rdivope(lattr) ;    /*  / 演算子処理              */
                    break          ;
        case idiv  :                    /*  div 演算子                */
        case imod  :                    /*  mod 演算子                */
          if((lattr.typtr == intptr) &&
             (gattr.typtr == intptr))   /*  div/mod の対象はinteger   */
           (lop==idiv) ? gen0(iDVI) : gen0(iMOD);/*dvi / mod命令を生成*/
          else {
           pcerr(134,"") ;              /* 演算対象の型に誤り         */
           gattr.typtr = nil ;
          }
          break ;
        case andop :                    /*  and 演算子                */
          if((lattr.typtr == boolptr) &&
             (gattr.typtr == boolptr))  /*  and の対象はboolean       */
           gen0(iAND) ;                 /*   and命令を生成            */
          else {
           pcerr(135,"and") ;           /* 論理型でない               */
           gattr.typtr = nil ;
          }
       }
      else gattr.typtr = nil ;
     }
}

/**************************************/
/*      mulope() : *  演算子処理      */
/**************************************/
static void mulope(attr fattr)
{
     if((fattr.typtr == intptr) &&      /*  * の両端がinteger         */
        (gattr.typtr == intptr))
      gen0(iMPI) ;                      /* mpi命令の生成              */
     else {
      cnvfloat(&fattr) ;                /* realへの変換処理           */
      if((fattr.typtr == realptr) &&
         (gattr.typtr == realptr))      /* 両端ともrealになっていれば */
       gen0(iMPR) ;                     /*  mpr命令を生成             */
      else if((gattr.typtr->form == power)        /* 集合型で         */
        && compatible(fattr.typtr,gattr.typtr)) { /* 型が適合する     */
        if(fattr.typtr->sf.pw.packed != both) /* 前の式の詰めあり/なし*/
         gattr.typtr->sf.pw.packed = fattr.typtr->sf.pw.packed   ;
       gen0(iINT) ;                     /* int命令を生成              */
      }
      else {                            /* 型が適合しない             */
       pcerr(134,"") ;                  /* 演算対象の型に誤り         */
       gattr.typtr = nil;
      }
     }
}

/**************************************/
/*      rdivope() : /  演算子処理     */
/**************************************/
static void rdivope(attr fattr)
{
     cnvfloat(&fattr) ;                 /* realへの変換処理           */
     if((fattr.typtr == realptr) &&
        (gattr.typtr == realptr))       /* 両端ともrealになっていれば */
      gen0(iDVR) ;                      /*  dvr命令を生成             */
      else {
       pcerr(134,"") ;                  /* 演算対象の型に誤り         */
       gattr.typtr = nil ;
      }
}


/*********************************************/
/*     simpleexpression() : 単純式の処理     */
/*********************************************/
static void simpleexpression(Set fsys)
{
  boolean sign = false ;
  boolean neg ;
  attr lattr ;
  enum operator lop ;
  Set ws ;

     sign = (op==plus) || (op==minus) ; /* + か - の時 真             */
     if(sign) {
      neg = (op == minus)    ;          /* - の時 true                */
      insymbol() ;
     }

     ws = fsys ;
     addset(ws,addop) ;
     term(ws) ;                         /* 項の処理                   */

     if(sign) {                         /* + -  がついていた時        */
       if(gattr.typtr==intptr) {
        if(neg)
         if(gattr.kind==cst)            /* 定数の時は 値を反転する    */
          gattr.cval.ival = -gattr.cval.ival ;
         else {                          /* 変数の時                   */
          load() ;
          gen0(iNGI)  ;                  /* ngi 命令の出力             */
         }
       }
       else if(gattr.typtr==realptr) {  /* 実数は定数でもngr命令      */
        if(neg) {
         load() ;
         gen0(iNGR) ;                   /* ngr 命令の出力             */
        }
       }
       else {                           /* 整数､実数以外に符号がついている*/
        pcerr(134,"") ;                 /* 演算対象の型に誤り         */
        gattr.typtr = nil ;             /* 今後のためにnilとする      */
       }
     }

     while(sy ==addop) {
      load()        ;
      lattr = gattr ;                   /* 今の属性を退避             */
      lop   = op    ;                   /* 今の演算子を退避           */
      insymbol()    ;
      term(ws)      ;                   /* 項の処理                   */

      if((lattr.typtr) && (gattr.typtr))
       switch(lop) {                    /* 前の演算子で振り分ける    */
        case plus  :
        case minus : plusminusope(lattr,lop);
                     break           ;  /* + -  の演算子処理          */
        case orop  : load()          ;
                     orope(lattr)    ;  /* or     演算子処理          */
                     break           ;
       }
      else gattr.typtr = nil    ;
     }
}

/**************************************/
/* plusminusope() : + -  演算子処理   */
/**************************************/
static void plusminusope(attr fattr,enum operator fop)
{
     if((fattr.typtr == intptr) &&      /* 前と今の式が両方ともinteger*/
        (gattr.typtr == intptr))        /*   であれば                 */
      if((gattr.kind == cst) &&
         (gattr.cval.ival <= 32767)) {
        (fop == plus)
          ? gen1t(iINC,intptr,(int)gattr.cval.ival)
          : gen1t(iDEC,intptr,(int)gattr.cval.ival) ;
         gattr.kind = expr ;
      }
      else {
       load() ;
       (fop == plus) ? gen0(iADI) : gen0(iSBI) ; /* adi/sbi命令を生成 */
      }
     else {
      load() ;
      cnvfloat(&fattr) ;                /* realに変換                 */
      if((fattr.typtr == realptr) &&    /* 前と今の式が両方ともreal   */
         (gattr.typtr == realptr))      /*   になっていれば           */
       (fop == plus) ? gen0(iADR) : gen0(iSBR) ; /* adr/sbr命令を生成 */
      else if((fattr.typtr->form == power)       /* 前の式が集合型で  */
         && compatible(fattr.typtr,gattr.typtr)){/* 基底の型が同じ    */
       if(fattr.typtr->sf.pw.packed != both)  /* 前の式の詰めあり/なし*/
        gattr.typtr->sf.pw.packed = fattr.typtr->sf.pw.packed   ;
       load() ;
       (fop == plus) ? gen0(iUNI) : gen0(iDIF) ; /* uni/dif命令を生成 */
      }
      else {                            /* 型が適合しない             */
       pcerr(134,"") ;                  /* 演算対象の型に誤り         */
       gattr.typtr = nil;
      }
     }
}

/**************************************/
/*      orope() : or 演算子処理       */
/**************************************/
static void orope(attr fattr)
{
      if((fattr.typtr == boolptr) &&    /* 前と今の式が両方ともboolean*/
         (gattr.typtr == boolptr))      /*   であれば                 */
       gen0(iIOR) ;                     /*   ior命令を生成            */
      else {
       pcerr(135,"or") ;              /*  演算対象は論理型でないと駄目*/
       gattr.typtr = nil ;
      }
}
