$title ('codemacro module 1')
cm1:
do;

/*

  modified  7/24/81  R. Silberstein

*/

/*    This is the module to build new instructions
      which is not present in the already existing
      system. */

$include (:f1:macro.lit)
$include (:f1:equals.lit)
$include (:f1:struc.lit)
$include (:f1:cmacd.lit)
$include (:f1:ermod.lit)
$include (:f1:scan.ext)
$include (:f1:ermod.ext)
$include (:f1:cm2.ext)
$include (:f1:cm.lit)
$include (:f1:global.ext)

$eject

/* Subroutines: */

more$left$on$line: PROC byte;
  if accum(0) <> cr then return true;
                    else return false;
end$proc more$left$on$line;

modrm$rout: PROC;
dcl nopar byte;
  if token.type = number then$do
    call put$b(mmodrm1);
    if token.value > 7 then$do
      cm$error=true; /* legal values are 0,1,..  .,7   */
      return;
    else$do
      call put$b(token.value);
    end$if;
  else$do
    if token.type = ident then$do
      if legal$parameter(acclen,.accum(0),.nopar) then$do
        call put$b(mmodrm2);
        call put$b(nopar);
      else$do /* error, parameter mismatch */
        cm$error=true;
        return;
      end$if;
    else$do /* error, expected parameter */
      cm$error=true;
      return;
    end$if;
  end$if;
  call scan;
  if accum(0) <> comma then$do
    /* error, expected comma */
    cm$error=true;
    return;
  end$if;
  call scan;
  if token.type = ident then$do
    if legal$parameter(acclen,.accum(0),.nopar) then$do
      call put$b(nopar);
      call scan;
      return;
    else$do /* error, parameter mismatch */
      cm$error=true;
      return;
    end$if;
  else$do /* error, expected parameter */
    cm$error=true;
    return;
  end$if;
end$proc modrm$rout;

db$dw$common$rout: PROC(directive);
  dcl (directive,nopar) byte;
  if token.type = number then$do
    call put$b(directive);
    if directive = mdwn then$do
      call put$w(token.value);
    else$do
      if token.value > 0ffh then cm$error=true;
                            else call put$b(token.value);
    end$if;
    call scan;
    return;
  else$do
    if token.type = ident then$do
      if legal$parameter(acclen,.accum(0),.nopar) then$do
        call put$b(directive+1); 
        call put$b(nopar);
        call scan;
        return;
      else$do /* error, parameter mismatch */
        cm$error=true;
        return;
      end$if;
    else$do /* error, expected parameter */
      cm$error=true;
      return;
    end$if;
  end$if;
end$proc db$dw$common$rout;

d$s$rb$rw$rout: PROC(directive);
  dcl (directive,nopar) byte;
  if token.type = ident then$do
    if legal$parameter(acclen,.accum(0),.nopar) then$do
      call put$b(directive);
      call put$b(nopar);
      call scan;
      return;
    else$do /* error, parameter mismatch */
      cm$error=true;
      return;
    end$if;
  else$do /* error, expected parameter */
    cm$error=true;
    return;
  end$if;
end$proc d$s$rb$rw$rout;

nosegfix$rout: PROC;
  dcl nopar byte;
  call put$b(mnosegfix);
  do case legal$seg$reg;
    do; /* error, no segment register specified */
      cm$error=true;
      return;
    end;
    call put$b(res);
    call put$b(rcs);
    call put$b(rss);
    call put$b(rds);
  end$case;
  call scan;
  if accum(0) <> comma then$do
   /* error, expected comma */
   cm$error=true;
   return;
  end$if;
  call scan; /* skip comma */
  if legal$parameter(acclen,.accum(0),.nopar) then$do
    call put$b(nopar);
    call scan;
  else$do
    cm$error=true;
    return;
  end$if;
end$proc nosegfix$rout;

dbit$rout: PROC;
  call put$b(mdbit);
end$proc dbit$rout;

field$descr$rout: PROC;
dcl nopar byte,cm$b$var based cmpt byte;
do forever;
  if token.type <> number or token.value > 0fh then$do
    /* error, expected numberdef. */
    cm$error=true;
    return;
  end$if;
  call put$b(mnumberbits);
  call put$b(token.value);
  call scan;
  if accum(0) <> leftpar then$do
    /* error, expected left paranthesis */
    cm$error=true;
    return;
  end$if;
  call scan; /* skip left paranthesis */
  if token.type = ident then$do
    if not legal$parameter(acclen,.accum(0),.nopar) then$do
      /* error, parameter mismatch */
      cm$error=true;
      return;
    end$if;
    cmpt=cmpt-2;
    cm$b$var=cm$b$var-1; /* it was a parameter, not a number */
    cmpt=cmpt+2;
    call put$b(nopar);
    call scan;
    if accum(0) <> leftpar then$do
      /* error, expected left paranthesis */
      cm$error=true;
      return;
    end$if;
    call scan; /* skip left paranthesis */
  end$if;
  if token.type <> number or token.value > 0ffh then$do
    /* error, expected numberdef.(byte) or parameter */
    cm$error=true;
    return;
  end$if;
  call put$b(token.value);
  call scan;
  if accum(0) <> rightpar then$do
    /* error,expected right paranthesis */
    cm$error=true;
    return;
  end$if;
  call scan; /* skip right paranthesis */
  cmpt=cmpt-4;
  if cm$b$var = mformalbits and
     accum(0) = rightpar then call scan;
  cmpt=cmpt+4;
  if accum(0) <> comma then return;
  call scan;
end$forever;
end$proc field$descr$rout;

enddbit$rout: PROC;
  call put$b(mendbit);
end$proc enddbit$rout;

endm$rout: PROC;
  call put$b(mendm);
end$proc endm$rout;

$eject

/* level 1 in the syntax-tree of codemacrobuilding */

COMMON$CM$ROUT: PROC (TYPE);
  DECLARE TYPE BYTE;
  if pass = 1 then$do
    call skip$rest$of$line;
    return;
  end$if;
  cm$error=false;
  if not codemacro$flag then$do
    /* error, codemacro directive outside codemacrobodydef. */
    cm$error=true;
  end$if;
  DO CASE TYPE;
    call db$dw$common$rout(mdbn);
    call db$dw$common$rout(mdwn);
    call d$s$rb$rw$rout(mddf);
    call d$s$rb$rw$rout(msegfix);
    call nosegfix$rout;
    call modrm$rout;
    call d$s$rb$rw$rout(mrelb);
    call d$s$rb$rw$rout(mrelw);
    DO;
      call dbit$rout;
      call field$descr$rout;
      call enddbit$rout;
    END;
  END$CASE;
  if cm$error or more$left$on$line then$do
    /* error */
    global$cm$error=true;
    call errmsg(codemacroerr);
  end$if;
  call skip$rest$of$line;
END COMMON$CM$ROUT;

codemacro$rout: PROC public;
  if pass = 1 then$do
    codemacro$flag=true;
    call skip$rest$of$line;
    return;
  end$if;
  cm$error=false;
  global$cm$error=false;
  if codemacro$flag then$do
    /* error, nested codemacrodefinition */
    cm$error=true;
  end$if;
  call init$cm$rout; /* clearing all temp. working storages */
  codemacro$flag=true;
  if not name$rout then$do
    /* error, expected codemacroname */
    cm$error=true;
  end$if;
  call formal$list$rout;
  if cm$error or more$left$on$line$ then$do
    /* error */
    global$cm$error=true;
    call errmsg(codemacroerr);
  end$if;
  call skip$rest$of$line;
end$proc codemacro$rout;

db$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (0);
end$proc db$cm$rout;

dw$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (1);
end$proc dw$cm$rout;

dd$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (2);
end$proc dd$cm$rout;

segfix$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (3);
end$proc segfix$cm$rout;

nosegfix$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (4);
end$proc nosegfix$cm$rout;

modrm$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (5);
end$proc modrm$cm$rout;

relb$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (6);
end$proc relb$cm$rout;

relw$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (7);
end$proc relw$cm$rout;

dbit$cm$rout: PROC public;
  CALL COMMON$CM$ROUT (8);
end$proc dbit$cm$rout;

end$cm$rout: PROC public;
  if pass = 1 then$do
    call skip$rest$of$line;
    codemacro$flag=false;
    return;
  end$if;
  cm$error=false;
  if not codemacro$flag then$do
    /* error, terminating a not yet started codemacro */
    cm$error=true;
  end$if;
  call endm$rout;
  if pass = 0 then  call terminate$cm$rout;
  if cm$error or more$left$on$line or cm$list$overflow then$do
    /* error */
    call errmsg(codemacroerr);
  end$if;
  call skip$rest$of$line;
  global$cm$error=false;
  codemacro$flag=false;
end$proc end$cm$rout;

end$module cm1;
