M Web Magazine 007 (June 5, 1998 - September 4, 1998)

Parsing M Code

by
Paul Perrin

 

Having worked in M for many years, I have gradually built up a toolkit of useful utilities to help with development and support of M systems. As a freelancer I work on various sites, and do not necessarily have access to the equipment required to load software on to the clients machine. In this case I just retype my utilities right into the system, along with any enhancements that may be useful at that particular site.

One particularly useful bit of code is a parser that scans M source code and breaks it down into individual commands -- this makes it easy to locate calls to labels and other routines, identify operations on particular variables etc... It could also form the basis of a language translator (convert your M to C) or prepasser to enable you to add your own extensions to the M language.

A feature that I particularly like is that because of the nature of M's syntax, the parser uses generic code for almost all commands -- only requiring specific code for comment lines ';' and the arguments for the 'F' command. The rest of the code is based on the structure of M being as follows.

A line is made up:

<optional label><whitespace><optional dots/whitespace><commands>

Commands are made up:

<command name><colon and optional post conditional><space><arguments><space or end of line>

Arguments are:

<argument><comma <argument>

This code was used to generate an array (CALLTREE) listing all the external calls made by various routines, it may not be perfect but you can do what ever you like to improve it. It was written on ISM running under Unix (but I think it is portable). It can be called as D PROC("^ROUTINE") -- if you save it, you can even make it process itself.

 

Download and Installation

Click here to download this routine.

After downloading the archive, unzip it to a subdirectory. Use the Routine Restore command of your M implementation to upload it into the UCI you want to work on.

Once loaded, you D ^PROC(<routine>), where <routine> is the name of the program you want to parse. (Try out D ^PROC("^PROC")).

 

The Source

PROC(RTN)ÞS $ZT="NXT"
ÞF L=1:1 X "S LIN=$T(+"_L_RTN_")" Q:LIN="" D PARSE,TRAPCALL,SHANA
NXTÞQ
PARSEÞS ORIG=LIN
ÞS LBL=$$SKIPTO(.LIN," ")
ÞI LIN="" Q
ÞS LEV=$$SKIPOVER(.LIN,". ")
ÞS LEV=$L(LEV,".")
ÞK CMD
ÞF CMD=1:1 D Q:LIN=""
Þ.S (CMD(CMD,1),CMD(CMD,2),CMD(CMD,3))=""
Þ.S TMP=$$SKIPOVER(.LIN," ")
Þ.I $E(LIN)=";" D Q
Þ..S CMD(CMD,1)=";",CMD(CMD,3)=LIN,LIN=""
Þ.S CMD(CMD,1)=$$SKIPTO(.LIN," :",.TC)
Þ.I LIN="" Q
Þ.I TC=":" S CMD(CMD,2)=$$SKIPTO(.LIN," ")
Þ.I LIN="" Q
Þ.S CMD(CMD,3)=$$SKIPTO(.LIN," ")
Þ.S SLIN=CMD(CMD,3)
Þ.F SCMD=1:1 Q:SLIN="" D
Þ..I $E(CMD(CMD,1))="F" S CMD(CMD,3,SCMD,3)=$$SKIPTO(.SLIN,",",.TC)
Þ..I $E(CMD(CMD,1))'="F" S
CMD(CMD,3,SCMD,3)=$$SKIPTO(.SLIN,":,",.TC)
Þ..S CMD(CMD,3,SCMD,2)=""
Þ..I TC=":" S CMD(CMD,3,SCMD,2)=$$SKIPTO(.SLIN,",")
Þ.I SCMD=2,CMD(CMD,3,1,2)="" K CMD(CMD,3,1) Q
Þ.S CMD(CMD,3)=""
ÞQ
SKIPTO(SOUR,TERMCH,CH)
ÞN DEST,PC,QC
ÞS DEST="",(PC,QC)=0
ÞF D Q:SOUR="" Q:(PC=0)&(QC=0)&(TERMCH[CH)
Þ.S CH=$E(SOUR),SOUR=$E(SOUR,2,$L(SOUR))
Þ.I PC=0,QC=0,TERMCH[CH Q
Þ.I CH="""" S QC=1-QC
Þ.I QC=0 D
Þ..I CH="(" S PC=PC+1
Þ..I CH=")" S PC=PC-1
Þ.S DEST=DEST_CH
ÞQ DEST
SKIPOVER(SOUR,SKIPCH)
ÞN DEST,PC,QC
ÞS DEST="",(PC,QC)=0
ÞF Q:SKIPCH'[$E(SOUR) D Q:SOUR=""
Þ.I $E(SOUR)="""" S QC=1-QC
Þ.I QC=0 D
Þ..I $E(SOUR)="(" S PC=PC+1
Þ..I $E(SOUR)=")" S PC=PC-1
Þ.S DEST=DEST_$E(SOUR)
Þ.S SOUR=$E(SOUR,2,$L(SOUR))
ÞQ DEST
Þ;
ÞSHANA W "+",L,RTN," ",ORIG,!
ÞW LBL," (",LEV,")",!
ÞS (CMD,SCMD)=""
ÞF S CMD=$O(CMD(CMD)) Q:CMD="" D
Þ.W CMD(CMD,1)," - ",CMD(CMD,2)," - ",CMD(CMD,3),!
Þ.F S SCMD=$O(CMD(CMD,3,SCMD)) Q:SCMD="" D
Þ..W $J("",$L(CMD(CMD,1)))," - ",$J("",$L(CMD(CMD,2)))," - "
Þ..W CMD(CMD,3,SCMD,2)," - ",CMD(CMD,3,SCMD,3),!
ÞQ
TRAPCALLÞS (CMD,SCMD)=""
ÞF S CMD=$O(CMD(CMD)) Q:CMD="" D
Þ.I "DG"'[$E(CMD(CMD,1)) Q
Þ.I CMD(CMD,3)["^" S CALLTREE(RTN,$P(CMD(CMD,3),"^",2))="" Q
Þ.F S SCMD=$O(CMD(CMD,3,SCMD)) Q:SCMD="" D
Þ..S TO=CMD(CMD,3,SCMD,3)
Þ..I TO'["^" Q
Þ..S CALLTREE(RTN,$P(TO,"^",2))=""
ÞQ

Click here to download this routine.

 

Contact Information

Paul Perrin is a freelance programmer/consultant. He maintains the MTA UK&I's web page, and writes a regular column in MTA UK&I's M Technology News called "News from the Net".

e-mail: paul@admatic.com
URL: http://www.admatic.com

E&OE

1