FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious exampleNext example

Debugging models via the Remote Invocation Protocol

Description
This model implements a debugger for Mosel models that are executing remotely, including
  • an interactive command interpreter supporting navigation commands like end, cont(inue), next, step, continue up to, and display commands such as model status, listing symbols, or help
  • evaluation of expressions
  • handling of breakpoints
  • navigating in the stack
Further explanation of this example: 'Mosel Language Reference', Appendix B Remote Invocation Protocol


Source Files
By clicking on a file name, a preview is opened at the bottom of this page.
mdbg.mos[download]





mdbg.mos

(!*******************************************************
  * Mosel Example Programs                              *
  * ======================                              *
  *                                                     *
  * file mdbg.mos                                       *
  * `````````````                                       *
  * Example for the use of the Mosel language           *
  * (use of the Remote Invocation Protocol)             *
  *                                                     *
  * Implements a debugger written in Mosel              *
  *                                                     *
  * (c) 2015 Fair Isaac Corporation                     *
  *     author: Y. Colombani, 2015                      *
  *******************************************************!)

model mdbg

uses 'mmjobs','mmsystem'

parameters
 SRC="qsort.mos"
end-parameters

declarations
 LINEMASK=16777215
 FILESHIFT=-24
 EVENT_DBG=32770

 MO:Mosel
 M:Model

 lineset:range
 modset:range
 s_src=record
	 fname:string
         nbl:integer
	 lines:array(lineset) of text
        end-record
 s_msrc=record
	  nbi:integer
	  lndx:array(lineset) of integer
          src:array(modset) of s_src
	end-record
 allmods:range
 allsrc:dynamic array(allmods) of s_msrc
end-declarations

forward procedure intcmd(stat:integer)
forward procedure cmdprint(m:integer,toprint:text)
forward procedure cmdbreak(m:integer,toprint:text)
forward procedure cmdstack(m:integer,args:text)
forward procedure cmdstat
forward procedure cmdfct(m:integer,fct:text)
forward procedure cmdinfo(m:integer,args:text)
forward procedure cmdlsloc(m:integer,args:text)
forward procedure cmdlsattr
forward procedure lslib
forward function dbgopcode(v:real):integer
forward function dbgoparg(v:real):integer
forward function loadfile(f:string):s_src
forward procedure showlocation(m:integer)
forward procedure loadsrc(m:integer)
forward procedure lndxlist(m:integer)
forward function vers2str(sv:string):string
forward function vers2str(v:integer):string
forward function str2date(sd:string):string
forward function getndx(v:integer):integer
forward procedure showsign(typs:array(range) of string, fctsign:string)
forward procedure showtyp(typs:array(range) of string, args:string, ta:textarea)
forward procedure showhelp

if connect(MO,"")<0 then
 exit(1)
end-if
nid:=getid(MO)
setcontrol(MO,"realfmt","%g")
setcontrol(MO,"zerotol","1e-13")
setcontrol(MO,"lang","en")

fcopy(SRC,"rmt:["+nid+"]tmp:src")
if compile(MO,"G","tmp:src","tmp:bimfile")<>0 then
 writeln("Compilation failed")
 exit(1)
end-if

load(MO,M,"tmp:bimfile")

loadsrc(0)

! switch model to debug mode
setcontrol(M,"runmode","1")
run(M)

! execution will stop just before 1st statement
repeat
 wait
 ev:=getnextevent
 if ev.class=EVENT_DBG then
  case dbgopcode(ev.value) of
   1: do		! submodel starting
       writeln("model ",dbgoparg(ev.value)," starting")
      end-do
   2: do		! submodel ending
       writeln("model ",dbgoparg(ev.value)," ending")
       if exists(allsrc(dbgoparg(ev.value))) then
        delcell(allsrc(dbgoparg(ev.value)))
       end-if
      end-do
   3: intcmd(dbgoparg(ev.value))	! Interruption
   else
    writeln("Unexpected DBG event: ",dbgopcode(ev.value),"-",dbgoparg(ev.value))
  end-case
 end-if
until ev.class=EVENT_END
reset(M)

!**********************************
! Interactive command interpreter
!**********************************
! Model flow control is achieved using the 'dbgctrl' parameter that
! can be set using 'setcontrol':
! dbgctrl=B => suspend execution
! dbgctrl=E => terminate execution
! Following can be used only on a suspended model:
! dbgctrl=C => continue
! dbgctrl=N [s] => next statement (on submodel 's')
! dbgctrl=S [s] => step into (on submodel 's')
! dbgctrl=F [s] => continue up to end of routine (on submodel 's')
! dbgctrl=T s lndx => continue up to 'lndx' on submodel 's'

! Other useful parameters:
! flushdso => force unloading of unused modules
! realfmt=string => change format used for displaying reals
! zerotol=real => zero tolerance for real comparison
procedure intcmd(stat:integer)
 declarations
  l:text
  RT_OK=0
  RT_ENDING=2
  RT_BREAK=14
  RT_NIFCT=15
 end-declarations

 case stat of
  RT_OK     : showlocation(0)
  RT_ENDING : writeln("Ending...")
  RT_BREAK  : do writeln("Breakpoint at:"); showlocation(0); end-do
  RT_NIFCT  : do writeln("In NIFct:"); showlocation(0); end-do
  else
   write("Stat: ",stat," at:")
   showlocation(0)
 end-case
 repeat
  write("> "); fflush
  nbc:=readtextline(l)
  trim(l,SYS_RIGHT)
  if nbc<=0 or l="end" then
   setcontrol(M,"dbgctrl","E")
   break
  elif l="cont" then
   setcontrol(M,"dbgctrl","C")
   break
  elif l="next" then
   setcontrol(M,"dbgctrl","N")
   break
  elif l="step" then
   setcontrol(M,"dbgctrl","S")
   break
  elif l="fin" then
   setcontrol(M,"dbgctrl","F")
   break
  elif startswith(l,"to ") then
   setcontrol(M,"dbgctrl","T 0 "+copytext(l,4,l.size))
   break
  elif startswith(l,"info") then
   cmdinfo(0,copytext(l,5,l.size))
  elif startswith(l,"lsloc") then
   cmdlsloc(0,copytext(l,6,l.size))
  elif l="lsattr" then
   cmdlsattr
  elif l="list" then
   lndxlist(0)
  elif l="lslib" then
   lslib
  elif l="flushdso" then
   setcontrol(MO,"flushdso","")
  elif startswith(l,"print ") then
   cmdprint(0,copytext(l,7,l.size))
  elif startswith(l,"break") then
   cmdbreak(0,copytext(l,6,l.size))
  elif startswith(l,"stack") then
   cmdstack(0,copytext(l,6,l.size))
  elif l="status" then
   cmdstat
  elif startswith(l,"fct ") then
   cmdfct(0,copytext(l,4,l.size))
  elif l="help" then
   showhelp
  else
   writeln("Unknown command (try 'help')")
  end-if
 until false
end-procedure

!******************
!* Command 'print'
!******************
! Request 'eval' (evaluate an expression):
!   mcmd:eval@M[.s] lab:expr lab:expr...
! M: master model
! s: submodel (0<=>master model)
! if 'lab'=='.' => label is expression itself
! expression may be ended with 1 or several data amount limit(s)
! [ maxelt ] : return at most 'maxelt' entries
! [ maxelt skip ] : return at most 'maxelt' entries after skipping 'skip'
procedure cmdprint(m:integer,toprint:text)
 trim(toprint)

(!
 declarations
  v:text
 end-declarations
 
 setparam("ioctrl",true)
 initialisations from "rmt:["+nid+"]mcmd:eval-t@1."+m+" v:"+toprint
  v
 end-initialisations
 setparam("ioctrl",false)
 if getparam("iostatus")=0 then
  writeln(" ",v)
 else
  writeln("Evaluation failed or value cannot be displayed")
 end-if
!)
  fflush
  fcopy("rmt:["+nid+"]mcmd:eval-t@1."+m+" :"+toprint,0,"",F_APPEND+F_LINBUF)
end-procedure

!******************
!* Command 'break'
!******************
! Request 'dbgbrkp' (get/set/update/delete breakpoint):
!   mcmd:dbgbrkp@M[.s]
!   mcmd:dbgbrkp@M[.s] lndx
!   mcmd:dbgbrkp@M[.s] lndx cond
! M: master model
! s: submodel (0<=>master model)
! no parameter: return list of breakpoints
! lndx: delete breakpoint. if lndx=*: delete all breakpoints
! lndx cond: add or modify breakpoint at lndx (cond='*' <=> no cond)
procedure cmdbreak(m:integer,args:text)
 declarations
  Rlndx:range
  lndx:dynamic array(Rlndx) of integer
  cond:dynamic array(Rlndx) of string
 end-declarations

 trim(args)
 setparam("ioctrl",true)
 initialisations from "bin:rmt:["+nid+"]mcmd:dbgbrkp@1."+m+" "+args
  Rlndx
  lndx
  cond
 end-initialisations
 setparam("ioctrl",false)
 if getparam("iostatus")=0 then
  loadsrc(m)
  forall(b in Rlndx) do
   l:=bittest(allsrc(m).lndx(lndx(b)),LINEMASK)
   f:=bitshift(allsrc(m).lndx(lndx(b)),FILESHIFT)
   write("Break at (",lndx(b),") ",allsrc(m).src(f).fname,":",l)
   if cond(b)<>"" then
    writeln(" if ",cond(b))
   else
    writeln
   end-if
  end-do
 else
  writeln("Failed to set breakpoint")
 end-if
end-procedure

!******************
!* Command 'stack'
!******************
! Request 'dbgstlev' (get/set stack level):
!   mcmd:dbgstlev@M[.s]
!   mcmd:dbgstlev@M[.s] stlev [maxlev]
! M: master model
! s: submodel (0<=>master model)
! stlev=='*' => get current stack level
! stlev>=0 => set stack level
! if 'maxlev' not provided => maxlev=10
procedure cmdstack(m:integer,args:text)
 declarations
  Rlndx:range
  lndx:dynamic array(Rlndx) of integer
 end-declarations

 trim(args)
 setparam("ioctrl",true)
 initialisations from "bin:rmt:["+nid+"]mcmd:dbgstlev@1."+m+" "+args
  Rlndx
  lndx
 end-initialisations
 setparam("ioctrl",false)
 if getparam("iostatus")=0 then
  loadsrc(m)
  forall(b in Rlndx) do
   write(" ",b,": ")
   i:=lndx(b)
   if i<0 then
    writeln("no location information")
   else
    l:=bittest(allsrc(m).lndx(i),LINEMASK)
    f:=bitshift(allsrc(m).lndx(i),FILESHIFT)
    if l=0 then
     writeln("in package ",allsrc(m).src(f).fname)
    else
     writeln(allsrc(m).src(f).fname,":",l," ",allsrc(m).src(f).lines(l))
    end-if 
   end-if 
  end-do
 else
  writeln("Failed to get stack trace")
 end-if
end-procedure

!***************************************
!* Display status of all running models
!***************************************
! Request 'dbgstat' (status and location):
!   mcmd:dbgstat@M
!   mcmd:dbgstat@M.s
! M: master model (if no submodel => status of all running models)
! s: submodel (0<=>master model)
procedure cmdstat
 declarations
  Rid:range
  id,stat,stlev,lndx:array(Rid) of integer
 end-declarations

 initialisations from "bin:rmt:["+nid+"]mcmd:dbgstat@1"
  Rid
  id
  stat
  stlev
  lndx
 end-initialisations

 forall(j in Rid) do
  m:=id(j)
  i:=lndx(j)
  if stat(j)=2 then
   writeln("[",m,"] ending")
  elif stat(j)=15 then
   writeln("[",m,"] in native function")
  elif i<0 then
   writeln("[",m,"] no location information")
  else
   loadsrc(m)
   l:=bittest(allsrc(m).lndx(i),LINEMASK)
   f:=bitshift(allsrc(m).lndx(i),FILESHIFT)
   if l=0 then
    writeln("[",m,"] in package ",allsrc(m).src(f).fname)
   else
    writeln("[",m,"] ",allsrc(m).src(f).fname,":",l," ",allsrc(m).src(f).lines(l))
   end-if
  end-if
 end-do
end-procedure

!*****************
!* Command 'fct'
!*****************
! Request 'dbgflndx' (line index of a subroutine):
!   mcmd:dbgflndx@M[.s] [fctname|*]
! M: master model
! s: submodel (0<=>master model)
! several line indices are returned if the function is overloaded
! with option 'N', result is sorted by function names
! with option 'L', result is sorted by line indices
procedure cmdfct(m:integer,fct:text)

 declarations
  Rsign:range
  sign:array(Rsign) of string
  lndx:array(Rsign) of integer
  elndx:array(Rsign) of integer
  name:array(Rsign) of string
 end-declarations

 setparam("ioctrl",true)
 initialisations from "bin:rmt:["+nid+"]mcmd:dbgflndx-N@1."+m+fct
  Rsign
  sign
  lndx
  name
  elndx
 end-initialisations
 setparam("ioctrl",false)
 trim(fct)
 if getparam("iostatus")=0 then
  forall(i in Rsign)
   if elndx(i)>lndx(i) then
    writeln(" ",name(i),"(",sign(i),") -> ",lndx(i),":",elndx(i))
   else
    writeln(" ",name(i),"(",sign(i),") -> ",lndx(i))
   end-if
 else
  writeln("Subroutine '",fct,"' not found")
 end-if
end-procedure

!******************
!* Command 'info'
!******************
! Request 'info' (model/package/module/Mosel information):
!   mcmd:info@M[.s]
!   mcmd:info
!   mcmd:info modulename
! M: master model
! s: submodel (0<=>master model)
! 1st form is for a loaded model/package
! 2d form returns Mosel information
! 3d form is used for a module (the module is loaded if necessary)
procedure cmdinfo(m:integer,args:text)
 declarations
  fmt:integer
  hdr:array(Rhdr:range) of string
  deps:array(Rdeps:range) of string
  depsvers,depstyp:array(Rdeps) of integer
  typs:array(Rtyps:range) of string
  typscod:array(Rtyps) of integer
  parms,parmsdesc:array(Rparms:range) of string
  parmsval:array(Rparms) of integer
  consts:array(Rconsts:range) of string
  conststyp:array(Rconsts) of integer
  cstint:array(Rcstint:range) of integer
  cststr:array(Rcststr:range) of string
  cstdbl:array(Rcstdbl:range) of real
  vars:array(Rvars:range) of string
  varstyp,varsopt:array(Rvars) of integer
  arrndx:array(Rarrndx:range) of string
  fct,fctsign:array(Rfct:range) of string
  fcttyp:array(Rfct) of integer
  dtyp:array(Rdtyp:range) of string
  dtyptyp:array(Rdtyp) of integer
  recsstart:array(Rrecsstart:range) of integer
  recfield:array(Rrecfield:range) of string
  recftype:array(Rrecfield) of integer
  iodrv,iodrvinfo:array(Riodrv:range) of string
  annsident:array(Rannsident:range) of string
  annsstart:array(Rannsstart:range) of integer
  anns: array(Ranns:range) of string

	! Format decoding
  SYMB_FMT_MOD=0
  SYMB_FMT_PKG=1
  SYMB_FMT_DSO=2
  SYMB_FMT_MOS=3
  SYMB_MSK_FMT=3

	! Format options (for models/packages)
  SYMB_FMT_CRYPTED=4
  SYMB_FMT_SIGNED=8
  SYMB_FMT_VERIFIED=16
  SYMB_FMT_UNVERIFIED=32

	! Basic types
  SYMB_TYP_NOT=0
  SYMB_TYP_INT=1
  SYMB_TYP_REAL=2
  SYMB_TYP_STRING=3
  SYMB_TYP_BOOL=4
  SYMB_TYP_MPVAR=5
  SYMB_TYP_LINCTR=6

	! Masks for type decoding
  SYMB_MSK_TYP=4095	! 0xFFF		12 bits [ 0-11]
  SYMB_MSK_STR=61440	! 0xF000	 4 bits [12-15]
  SYMB_MSK_OPT=983040	! 0xF0000	 4 bits [16-19]
  SYMB_MSK_NDX=-1048576	! 0xFFF00000	12 bits [20-31]

	! Shift length for type decoding
  SYMB_SHT_STR=12
  SYMB_SHT_OPT=16
  SYMB_SHT_NDX=20

	! Entity structure
  SYMB_STR_SCA=0	! (0<<SYMB_SHT_STR)
  SYMB_STR_ARR=4096	! (1<<SYMB_SHT_STR)
  SYMB_STR_SET=8192	! (2<<SYMB_SHT_STR)
  SYMB_STR_LST=12288	! (3<<SYMB_SHT_STR)
  SYMB_STR_REC=16384	! (4<<SYMB_SHT_STR)
  SYMB_STR_PROB=20480	! (5<<SYMB_SHT_STR)
  SYMB_STR_CSREF=24576	! (6<<SYMB_SHT_STR)
  SYMB_STR_UNION=28672	! (7<<SYMB_SHT_STR)
  SYMB_STR_PROC=32768	! (8<<SYMB_SHT_STR)

	! Parameter flags
  SYMB_OPT_READ=65536	! (1<<SYMB_SHT_OPT)
  SYMB_OPT_WRITE=131072	! (2<<SYMB_SHT_OPT)

	! variable/subroutine flags (to tag requirements)
  SYMB_OPT_REQMT=65536	! (1<<SYMB_SHT_OPT)
  SYMB_OPT_PTR=131072	! (2<<SYMB_SHT_OPT) subroutines
  SYMB_OPT_CONST=131072	! (2<<SYMB_SHT_OPT) variables
  SYMB_OPT_PRIV=262144	! (4<<SYMB_SHT_OPT)

	! Flags for varsopt
  SYM_VOPT_DENSE=1      ! => range for a set
  SYM_VOPT_HMAP=2       ! if not dense

	! Native type properties
  SYMB_MTP_CREAT=1
  SYMB_MTP_DELET=2
  SYMB_MTP_TOSTR=4
  SYMB_MTP_FRSTR=8
  SYMB_MTP_PRTBL=16
  SYMB_MTP_RFCNT=32
  SYMB_MTP_COPY=64
  SYMB_MTP_APPND=128
  SYMB_MTP_ORSET=256
  SYMB_MTP_PROB=512
  SYMB_MTP_CMP=1024
  SYMB_MTP_SHARE=2048
  SYMB_MTP_TFBIN=4096
  SYMB_MTP_ORD=8192
  SYMB_MTP_CONST=16384
  SYMB_MTP_ANDX=32768
 
 end-declarations

 trim(args)
 if args.size=0 then
  fname:="rmt:["+nid+"]mcmd:info-t@1"
 elif args="*" then
  fname:="rmt:["+nid+"]mcmd:info-t"
 else
  fname:="rmt:["+nid+"]mcmd:info-t "+args
 end-if
 setparam("ioctrl",true)
! fcopy(fname,"")
 initialisations from fname
  fmt
  Rhdr hdr
  Rdeps deps depsvers depstyp
  Rtyps typs typscod
  Rparms parms parmsval parmsdesc
  Rconsts consts conststyp
  Rcstint cstint
  Rcststr cststr
  Rcstdbl cstdbl
  Rvars vars varstyp varsopt
  Rarrndx arrndx
  Rfct fct fctsign fcttyp
  Rdtyp dtyp dtyptyp
  Rrecsstart recsstart
  Rrecfield recfield recftype
  Riodrv iodrv iodrvinfo
  Rannsident annsident
  Rannsstart annsstart
  Ranns anns
 end-initialisations
 setparam("ioctrl",false)
 if getparam("iostatus")=0 then

 					!------------------- Header ----------
  case bittest(fmt,SYMB_MSK_FMT) of
   SYMB_FMT_MOD,SYMB_FMT_PKG: do		! Model or Package
	 writeln(if(bittest(fmt,SYMB_MSK_FMT)=SYMB_FMT_MOD,"Model ","Package "),
	 				hdr(0)," version ",vers2str(hdr(4)))
	 writeln(" sys.com:  ",hdr(1))
	 writeln(" date:",str2date(hdr(6)))
	 writeln(" usr.com:  ",hdr(2))
	 write(" security: ")
	 if bittest(fmt,SYMB_FMT_CRYPTED+SYMB_FMT_SIGNED)=0 then
	  writeln("none")
	 else
	  if bittest(fmt,SYMB_FMT_CRYPTED)<>0 then write(" encrypted"); end-if
	  if bittest(fmt,SYMB_FMT_SIGNED)<>0 then
	   write(" signed ",hdr(3))
	   if bittest(fmt,SYMB_FMT_VERIFIED)<>0 then write(" verified")
	   elif bittest(fmt,SYMB_FMT_UNVERIFIED)<>0 then write(" unverified")
	   else write(" unchecked")
	   end-if
	  end-if
	  writeln
	 end-if
	 if Rdeps.size>0 then
	  j:=0
	  forall(i in Rdeps) do
	   if depstyp(i)=0 and j=0 then
	    write(" modules:")
	    j:=1
	   elif depstyp(i)<2 and j<2 then
	    if i>0 then writeln; end-if
	    write(" pkg. req.:")
	    j:=2
	   elif depstyp(i)>1 and j<3 then
	    if i>0 then writeln; end-if
	    write(" pkg. imp.:")
	    j:=3
	   end-if
	   write(" ",deps(i)," (",vers2str(depsvers(i)),")")
	  end-do
	  writeln
	 end-if
	end-do
   SYMB_FMT_DSO: do				! Module
         writeln("Module ",hdr(0)," version ",vers2str(hdr(4))," (",hdr(1),")")
	 writeln(" file:",hdr(5)+"/"+hdr(0)+".dso")
	 writeln(" date:",str2date(hdr(6)))
	 writeln(" priority:",hdr(7))
	 if Rdeps.size>0 then
	  write(" modules:")
	  forall(i in Rdeps) do
	   write(" ",deps(i))
	  end-do
	  writeln
	 end-if
	end-do
   SYMB_FMT_MOS: do				! Mosel core functionality
	 writeln("Mosel ",hdr(7),"-bit version ",vers2str(hdr(4)))
	 writeln(" Link date: ",hdr(2))
	 writeln(" Libpath: ",hdr(5))
	 writeln(" dsopath: ",hdr(1))
	end-do
  end-case
  writeln

 					!------------------- Constants --------
  if Rconsts.size>0 then
   writeln("Constants:")
   forall(i in Rconsts) do
    write(" ",consts(i),"=")
    j:=getndx(conststyp(i))-1
    case bittest(conststyp(i),SYMB_MSK_TYP) of
     SYMB_TYP_INT: write(cstint(j))
     SYMB_TYP_REAL: write(cstdbl(j))
     SYMB_TYP_STRING: write(cststr(j))
     SYMB_TYP_BOOL: write(if(cstint(j)<>0,"true","false"))
    end-case
    if bittest(conststyp(i),SYMB_OPT_PRIV)<>0 then
     writeln(" [priv]")
    else
     writeln
    end-if
   end-do
   writeln
  end-if

 					!------------------- Types ------------
  if Rdtyp.size>0 then
   writeln("Types:")
   forall(i in Rdtyp) do
    type:=bittest(dtyptyp(i),SYMB_MSK_TYP)
    if type=0 then	! dso type
     write(" ",dtyp(i)," (")
     flag:=bitshift(dtyptyp(i),-SYMB_SHT_STR)
     if bittest(flag,SYMB_MTP_PROB)<>0 then
      write("problem")
      if bittest(flag,SYMB_MTP_CREAT)<>0 then write(",create"); end-if
     else
      if bittest(flag,SYMB_MTP_CREAT)<>0 then write("create"); end-if
     end-if
     if bittest(flag,SYMB_MTP_DELET)<>0 then write(",delete"); end-if
     if bittest(flag,SYMB_MTP_RFCNT)<>0 then write(",refcnt"); end-if
     if bittest(flag,SYMB_MTP_TOSTR)<>0 then write(",tostring"); end-if
     if bittest(flag,SYMB_MTP_PRTBL)<>0 then write("+"); end-if
     if bittest(flag,SYMB_MTP_FRSTR)<>0 then write(",fromstring"); end-if
     if bittest(flag,SYMB_MTP_ORSET)<>0 then write(",reset"); end-if
     if bittest(flag,SYMB_MTP_COPY)<>0 then write(",copy"); end-if
     if bittest(flag,SYMB_MTP_APPND)<>0 then write("+"); end-if
     if bittest(flag,SYMB_MTP_CMP)<>0 then write(",cmp"); end-if
     if bittest(flag,SYMB_MTP_TFBIN)<>0 then write(",bin"); end-if
     if bittest(flag,SYMB_MTP_SHARE)<>0 then write(",share"); end-if
     if bittest(flag,SYMB_MTP_ORD)<>0 then write(",ord"); end-if
     if bittest(flag,SYMB_MTP_CONST)<>0 then write(",const"); end-if
     if bittest(flag,SYMB_MTP_ANDX)<>0 then write(",indexer"); end-if
     writeln(")")
    else
     write(" ",dtyp(i),if(bittest(dtyptyp(i),SYMB_OPT_PRIV)<>0,"[priv]",""),"=")
     if bittest(typscod(type),SYMB_MSK_STR)=SYMB_STR_REC then
      j:=getndx(typscod(type))
      writeln("record")
      forall(k in recsstart(j)..(recsstart(j+1)-1))
       writeln("      ",recfield(k),":",
                        typs(bittest(recftype(k),SYMB_MSK_TYP)),
                        if(bittest(recftype(k),SYMB_OPT_PRIV)<>0," [priv]",""))
      writeln("    end-record")
     elif bittest(typscod(type),SYMB_MSK_STR)=SYMB_STR_UNION then
      j:=getndx(typscod(type))
      write(typs(recftype(recsstart(j))))
      forall(k in recsstart(j)+1..(recsstart(j+1)-1))
       write(" or ",if(recftype(k)=0,"any",typs(recftype(k))))
      writeln
     elif bittest(typscod(type),SYMB_MSK_STR)=SYMB_STR_PROB then
      writeln("problem:",typs(type))
     elif bittest(typscod(type),SYMB_MSK_STR)=SYMB_STR_PROC then
      j:=recsstart(getndx(typscod(type)))
      if bittest(typscod(type),SYMB_MSK_TYP)=0 then
       write("procedure",recfield(j),")")
       showsign(typs,recfield(j))
      else
       write("function")
       showsign(typs,recfield(j))
       write(":",typs(bittest(typscod(type),SYMB_MSK_TYP)))
      end-if
      writeln
     else
      writeln(typs(type))
     end-if
    end-if
   end-do
   writeln
  end-if

 					!------------------- Parameters -------
  if Rparms.size>0 then
   writeln("Control Parameters:")
   forall(i in Rparms) do
    type:=parmsval(i)
    write(" ",parms(i)," (",typs(bittest(type,SYMB_MSK_TYP)))
    if bittest(type,SYMB_OPT_READ)<>0 then
     if bittest(type,SYMB_OPT_WRITE)<>0 then write(",read/write")
     else write(",read only"); end-if
    else
     if bittest(type,SYMB_OPT_WRITE)<>0 then write(",write only"); end-if
    end-if
    if parmsdesc(i)<>"" then
     write(",",parmsdesc(i),")")
    else
     write(")")
    end-if

    j:=getndx(type)-1
    if j>=0 then
     case bittest(type,SYMB_MSK_TYP) of
      SYMB_TYP_INT: writeln("=",cstint(j))
      SYMB_TYP_REAL: writeln("=",cstdbl(j))
      SYMB_TYP_STRING: writeln("=",cststr(j))
      SYMB_TYP_BOOL: writeln("=",if(cstint(j)<>0,"true","false"))
     end-case
    else
     writeln
    end-if
   end-do
   writeln
  end-if

 					!------------------- Variables --------
  if Rvars.size>0 then
   writeln("Variables:")
   forall(i in Rvars) do
    write(" ",vars(i),":")
    if bittest(varstyp(i),SYMB_OPT_CONST)<>0 then write("constant "); end-if
    case bittest(varstyp(i),SYMB_MSK_STR) of
     SYMB_STR_ARR: do
         if bittest(varsopt(i),SYM_VOPT_DENSE)=0 then
          if bittest(varsopt(i),SYM_VOPT_HMAP)=0 then
	   write("dynamic ")
          else
	   write("hashmap ")
	  end-if
	 end-if
	 j:=getndx(varstyp(i))
	 if j>0 then
	  write("array (",arrndx(j-1),") of ")
	 else
	  write("array of ")
	 end-if
	end-do
     SYMB_STR_SET:
	if bittest(varsopt(i),SYM_VOPT_DENSE)<>0 then
         write("range set of ")
	else
         write("set of ")
	end-if
     SYMB_STR_LST: write("list of ")
    end-case
    writeln(typs(bittest(varstyp(i),SYMB_MSK_TYP)),if(bittest(varstyp(i),SYMB_OPT_REQMT)<>0," [reqmt]",""),if(bittest(varstyp(i),SYMB_OPT_PRIV)<>0," [priv]",""))
   end-do
   writeln
  end-if

 					!------------------- Subroutines ------
  if Rfct.size>0 then
   writeln("Procedures and Functions:")
   forall(i in Rfct) do
    write(" ",if(bittest(fcttyp(i),SYMB_MSK_TYP)=0,"procedure ","function "),fct(i))
    showsign(typs,fctsign(i))
    if bittest(fcttyp(i),SYMB_MSK_TYP)<>0 then
     write(":",typs(bittest(fcttyp(i),SYMB_MSK_TYP)))
    end-if
    if bittest(fcttyp(i),SYMB_OPT_REQMT)<>0 then write(" [reqmt]"); end-if
    if bittest(fcttyp(i),SYMB_OPT_PRIV)<>0 then write(" [priv]"); end-if
    if bittest(fcttyp(i),SYMB_OPT_PTR)<>0 then write(" [ptr]"); end-if
    writeln
   end-do
   writeln
  end-if

 					!------------------- IO drivers -------
  if Riodrv.size>0 then
   writeln("I/O drivers:")
   forall(i in Riodrv) do
    writeln(" ",iodrv(i),":",iodrvinfo(i))
   end-do
   writeln
  end-if

 					!------------------- Annotations ------
  if Rannsident.size>0 then
   writeln("Annotations:")
   forall(i in Rannsident) do
    writeln(" ",if(annsident(i)<>"",annsident(i),"[global]"),"->")
    forall(k in annsstart(i)..(annsstart(i+1)-1)|not isodd(k)) do
     writeln("   ",anns(k),":",anns(k+1))
    end-do
   end-do
   writeln
  end-if
 else
  writeln("Operation failed")
 end-if
end-procedure

!******************
!* Command 'lsloc'
!******************
! Request 'lsloc' (list of local variables):
!   mcmd:info@M[.s]
! M: master model
! s: submodel (0<=>master model)
procedure cmdlsloc(m:integer,args:text)
 declarations
  typs:array(Rtyps:range) of string
  typscod:array(Rtyps) of integer
  vars:array(Rvars:range) of string
  varstyp:array(Rvars) of integer
  arrndx:array(Rarrndx:range) of string

	! Basic types
  SYMB_TYP_NOT=0
  SYMB_TYP_INT=1
  SYMB_TYP_REAL=2
  SYMB_TYP_STRING=3
  SYMB_TYP_BOOL=4
  SYMB_TYP_MPVAR=5
  SYMB_TYP_LINCTR=6

	! Masks for type decoding
  SYMB_MSK_TYP=4095	! 0xFFF		12 bits [ 0-11]
  SYMB_MSK_STR=61440	! 0xF000	 4 bits [12-15]
  SYMB_MSK_OPT=983040	! 0xF0000	 4 bits [16-19]
  SYMB_MSK_NDX=-1048576	! 0xFFF00000	12 bits [20-31]

	! Shift length for type decoding
  SYMB_SHT_STR=12
  SYMB_SHT_OPT=16
  SYMB_SHT_NDX=20

	! Entity structure
  SYMB_STR_SCA=0	! (0<<SYMB_SHT_STR)
  SYMB_STR_ARR=4096	! (1<<SYMB_SHT_STR)
  SYMB_STR_SET=8192	! (2<<SYMB_SHT_STR)
  SYMB_STR_LST=12288	! (3<<SYMB_SHT_STR)
  SYMB_STR_REC=16384	! (4<<SYMB_SHT_STR)
  SYMB_STR_PROB=20480	! (5<<SYMB_SHT_STR)
  SYMB_STR_CSREF=24576	! (6<<SYMB_SHT_STR)
  SYMB_STR_UNION=28672	! (7<<SYMB_SHT_STR)
  SYMB_STR_PROC=32768	! (8<<SYMB_SHT_STR)

 end-declarations

 setparam("ioctrl",true)
! fcopy(fname,"")
 initialisations from "rmt:["+nid+"]mcmd:lsloc-t@1"
  Rtyps typs typscod
  Rvars vars varstyp
  Rarrndx arrndx
 end-initialisations
 setparam("ioctrl",false)
 if getparam("iostatus")=0 then
 					!------------------- Variables --------
  if Rvars.size>0 then
   writeln("Variables:")
   forall(i in Rvars) do
    write(" ",vars(i),":")
    case bittest(varstyp(i),SYMB_MSK_STR) of
     SYMB_STR_ARR: do
	 j:=getndx(varstyp(i))
	 if j>0 then
	  write("array (",arrndx(j-1),") of ")
	 else
	  write("array of ")
	 end-if
	end-do
     SYMB_STR_SET: write("set of ")
     SYMB_STR_LST: write("list of ")
    end-case
    writeln(typs(bittest(varstyp(i),SYMB_MSK_TYP)))
   end-do
   writeln
  end-if
 else
  writeln("Operation failed")
 end-if
end-procedure

!******************
!* Command 'lsattr'
!******************
! Request 'lsattr' (list of attributes):
!   mcmd:lsattr@M[.s]
! M: master model
! s: submodel (0<=>master model)
procedure cmdlsattr
 declarations
  typs:array(Rtyps:range) of string
  attrs:array(Rattrs:range) of string
  attrsntyp:array(Rattrs) of integer
  attrsatyp:array(Rattrs) of integer
 end-declarations

 setparam("ioctrl",true)
 initialisations from "rmt:["+nid+"]mcmd:lsattr-t@1"
  Rattrs attrs attrsntyp attrsatyp
 end-initialisations
 ! Get the type names (from lsloc)
 initialisations from "rmt:["+nid+"]mcmd:lsloc-t@1"
  Rtyps typs
 end-initialisations
 setparam("ioctrl",false)

 lasttyp:=0;
 forall(a in Rattrs) do
  if attrsntyp(a)<>lasttyp then
   writeln(typs(attrsntyp(a)),":")
   lasttyp:=attrsntyp(a)
  end-if
  writeln("  ",attrs(a),":",typs(attrsatyp(a)))
 end-do
end-procedure

!******************
!* Command 'lslib'
!******************
! Request 'lslib' (list of available libraries [packages+modules]):
!   mcmd:lslib
! with option 'p', packages are listed with their full path
procedure lslib
 declarations
  pkgs:array(Rpkgs:range) of string
  dsos:array(Rdsos:range) of string
 end-declarations

 initialisations from "rmt:["+nid+"]mcmd:lslib-pt"
  Rpkgs
  pkgs
  Rdsos
  dsos
 end-initialisations

 if pkgs.size>0 then
  writeln(" Packages:")
  forall(p in Rpkgs)
   writeln("   ",pkgs(p))
 end-if

 if pkgs.size>0 then
  writeln(" Modules:")
  forall(p in Rdsos)
   writeln("   ",dsos(p))
 end-if
end-procedure

!**********************************************
!* Return operation code of a dbg event value
!**********************************************
function dbgopcode(v:real):integer
 returned:=bitshift(integer(v),-16)
end-function

!**********************************************
!* Return operation arg of a dbg event value
!**********************************************
function dbgoparg(v:real):integer
 returned:=bittest(integer(v),65535)
end-function

!**********************
!* Load a source file
!**********************
function loadfile(f:string):s_src
 declarations
  l:text
 end-declarations
 returned.fname:=f
 setparam("ioctrl",true)
  fopen(f,F_INPUT+F_SILENT)
 setparam("ioctrl",false)
 if getparam("iostatus")=0 then
  while(readtextline(l)>=0) do
   returned.nbl+=1
   trim(l,SYS_RIGHT)
   returned.lines(returned.nbl):=l
  end-do
  fclose(F_INPUT)
 end-if
end-function

!***************************************
!* Display current location of a model
!***************************************
! Request 'dbgstat' (status and location):
!   mcmd:dbgstat@M
!   mcmd:dbgstat@M.s
! M: master model (if no submodel => status of all running models)
! s: submodel (0<=>master model)
procedure showlocation(m:integer)
 declarations
  Rid:range
  id,stat,stlev,lndx:array(Rid) of integer
 end-declarations
 
 initialisations from "bin:rmt:["+nid+"]mcmd:dbgstat@1."+m
  Rid
  id
  stat
  stlev
  lndx
 end-initialisations
 i:=lndx(0)
 if stat(0)=2 then
  writeln("[",m,"] ending")
 elif i<0 then
  writeln("[",m,"] no location information")
 else
  loadsrc(m)
  l:=bittest(allsrc(m).lndx(i),LINEMASK)
  f:=bitshift(allsrc(m).lndx(i),FILESHIFT)
  if l=0 then
   writeln("[",m,"] in package ",allsrc(m).src(f).fname)
  else
   writeln("[",m,"] ",allsrc(m).src(f).fname,":",l," ",allsrc(m).src(f).lines(l))
  end-if
 end-if
end-procedure

!***************************
!* Load source for a model
!***************************
! Request 'dbglndx' (all line indices):
!   mcmd:dbglndx@M[.s]
! M: master model
! s: submodel (0<=>master model)
procedure loadsrc(m:integer)
 declarations
  lines:array(Rlines:range) of integer
  files:array(Rfiles:range) of string
 end-declarations

 if not exists(allsrc(m)) then
  initialisations from "bin:rmt:["+nid+"]mcmd:dbglndx@1."+m
   Rfiles
   files
   Rlines
   lines
  end-initialisations

  allsrc(m).nbi:=Rlines.size
  forall(i in Rlines) allsrc(m).lndx(i):=lines(i)
  forall(f in Rfiles) do
   allsrc(m).src(f):=loadfile(files(f))
  end-do
 end-if
end-procedure

!**********************************************************
!* Display correspondance between line indices and source
!**********************************************************
procedure lndxlist(m:integer)
 loadsrc(m)
 forall(i in 0..allsrc(m).nbi-1) do
  l:=bittest(allsrc(m).lndx(i),LINEMASK)
  f:=bitshift(allsrc(m).lndx(i),FILESHIFT)
  if l=0 then
   writeln("package ",allsrc(m).src(f).fname)
  else
   writeln(i,":",allsrc(m).src(f).fname,'-',l," ",allsrc(m).src(f).lines(l))
  end-if
 end-do
end-procedure

!***************************************
!* Convert a version number to a string
!***************************************
function vers2str(sv:string):string
 returned:=vers2str(integer(sv))
end-function

function vers2str(v:integer):string
 m0:=v mod 1000
 v:=v div 1000
 m1:=v mod 1000
 v:=v div 1000
 returned:=string(v)+"."+m1+"."+m0
end-function

!************************************
!* Convert a Unix time into a string
!************************************
function str2date(sd:string):string
 dt:=datetime(integer(sd))
 returned:=string(dt)
end-function

!***************************************
!* Return index value of an identifier
!***************************************
function getndx(v:integer):integer
 declarations
  SYMB_SHT_NDX=20
 end-declarations
 returned:=bitshift(v,-SYMB_SHT_NDX)
end-function

!*****************************************
!* Display the signature of a subroutine
!*****************************************
procedure showsign(typs:array(range) of string, fctsign:string)
 declarations
  ta:textarea
 end-declarations
 if fctsign<>"" then
  write("(");
  ta.start:=1
  ta.succ:=1
  showtyp(typs,fctsign,ta)
  while(ta.succ<fctsign.size) do
   write(",")
   showtyp(typs,fctsign,ta)
  end-do
  write(")");
 end-if
end-procedure

!*********************************
!* Display a subroutine argument
!*********************************
procedure showtyp(typs:array(range) of string, args:string, ta:textarea)
 ta.start:=ta.succ
 ta.succ:=ta.succ+1
 case getchar(args,ta.start) of
  105: write("integer")	! 'i'
  114: write("real")	! 'r'
  83: write("string")	! 'S'
  115: write("string")	! 's'
  98: write("boolean")	! 'b'
  118:write("mpvar")	! 'v'
  99: write("linctr")	! 'c'
  73: write("range")	! 'I'
  97: write("array")	! 'a'
  101:write("set")	!' e'
  108:write("list")	! 'l'
  117:write("union")	! 'u'
  102:write("subroutine")!'f'
  33: do		! '!'
	 i:=findtext(args,"!",ta.succ)
	 write(copytext(args,ta.succ,i-1))
	 ta.succ:=i+1
	end-do
  124: do		! '|'
	 i:=findtext(args,"|",ta.succ)
	 write(copytext(args,ta.succ,i-1))
	 ta.succ:=i+1
	end-do
  37: do		! '%'
	 i:=integer("0x"+substr(args,ta.succ,ta.succ+2))
	 write(typs(i))
	 ta.succ:=ta.succ+3
	end-do
  65: do		! 'A'
	 write("array (")
	 while(getchar(args,ta.succ)<>46) do
	  showtyp(typs,args,ta)
	 end-do
	 ta.succ:=ta.succ+1
	 write(") of ")
	 showtyp(typs,args,ta)
	end-do
  69: do		! 'E'
	 write("set of ")
	 showtyp(typs,args,ta)
	end-do
  76: do		! 'L'
	 write("list of ")
	 showtyp(typs,args,ta)
	end-do
  70: do		! 'F'
	if getchar(args,ta.succ)=40 then
	 write("procedure")
	 i:=ta.succ+1
	else
	 write("function")
	 i:=findtext(args,"(",ta.succ)+1
	end-if
	j:=findtext(args,")",i)
	if j>i then
	 showsign(typs,substr(args,i,j-1))
	end-if
	if i>ta.succ+1 then
	 write(":")
	 showtyp(typs,args,ta)
	end-if
	ta.succ:=j+1
      end-do
  42: write("...")	! '*'
  else
   write("?")
 end-case
end-procedure

!*************************
!* Display some help
!*************************
procedure showhelp
 write(`
Available commands:
  cont   : continue execution
  end    : abort execution
  next   : continue to next statement
  step   : step into
  fin    : continue up to end of routine
  to lndx: continue up to given line index
  list   : display all line indices of current model
  fct fname: display line indices of given function
  lslib  : list available modules and packages
  info [mod|*]: symbols of the model, a module (mod) or Mosel (*)
  lsattr : list of attributes
  lsloc  : list of current local symbols
  flushdso: unload unused modules
  print expr: evaluate expression
  break  : list breakpoints
  break lndx|*: remove breakpoints at line index lndx (*=> all breakpoints)
  break lndx cond|*: set/change breakpoint at line index lndx
  status : report status of all running models
  stack [stlev [maxlev]]: set/check stack level
`)
end-procedure

end-model

Back to examples browserPrevious exampleNext example