Prism language definition for dBase IV

Completed a fairly complete version of a Prism language file for the dBase IV programming language. Included are dBase commands, program keywords, and selected SQL keywords supported by dBase.

Prism.languages.dbase = {
  // dBase language definition. v0.3, 20170115, Hanna Goodbar
  // Related extensions: prg (dBase program), prs (dBase SQL program)
  'comment': [
    {
      'pattern': /(&&.+)/
    },
    {
      // Comments: at the beginning of a line or on a line preceded by whitespace only.
      // Thanks dBase for making the asterisk both the multiplication symbol and a comment marker.
      'pattern': /(^|^\s+?)\*.+/,
      lookbehind: true
    },
    {
      // Oh yeah, a line beginning with NOTE is also a comment.
      'pattern': /(^|^s+?)NOTE.+/i,
      lookbehind: true
    }
  ],
  'directive': {
    'pattern': /(#\s*)\b(define|else|endif|if|ifdef|ifndef|include|undef)\b/i,
    lookbehind: true,
    alias: 'keyword'
  },
  'string': /"(?:""|[!#$%&'()*,\/:;<=>?^_ +\-.A-Z\d])*"/i,
  'function': /\b\w+(?=\()/,
  'variable': [
    {
      // Variables: m->blah
      'pattern': /(m->\w+)/i
    },
    {
      // Arrays: blah[x]
      'pattern': /\b\w+(?=\[)/
    }
  ],
  'keyword': /\b(\?\??\??|\@|(de)?activate|all|append|application|array|assist|average|bar|begin|bottom|box|browse|calculate|call|cancel|case|change|clear|color|close|command|compile|continue|convert|copy|create|cursor|debug|declare|define|deleted?|dir|display|do|end(case|do|if)|edit|eject|else|end|environment|erase|error|escape|except|exit|export|extended|file|find|for|from|function|gets?|goto|go|help|history|if|import|(re)?index(es)?|input|insert|join|key|keyboard|label|list|load|locate|(un)?lock|logout|loop|macros?|memo|memory|menus?|modify|off?|on|order|otherwise|pack|pad|page|parameters|popups?|(end)?printjob|private|procedure|prompt|protect|public|query|quit|read|readerror|recall|record|release|rename|replace|report|reset|restore|resume|retry|return|rollback|run|save|say|(end)?scan|seek|select(ion)?|set|save|screens?|show|skip|sort|status|store|structure|sum|suspend|tag|talk|text|to|top|total|transaction|type|typeahead|update|use|users|view|wait|when|while|windows?|with|zap)\b/i,
  'number': /\b([\d]+)\b/i,
  'symbol': [
    /(&\w+[.])/
  ],
  'boolean': /(\.[t|f]\.)/i,
  'operator': [
    /\.and\.|\.or\.|\.not\./i,
    /[<>+-\/#\$=^\*\*?]/
  ],
  'punctuation': /[()\[\]{}.,;]/
};
Prism.languages.prg = Prism.languages.dbase;
Prism.languages.prs = Prism.languages.dbase;

An example procedure:


*------------------------------------------------------------------------------
*--                              - ReduceArr -
*-- Reduces duplicated array elements. Creates a new array ARECUCE with
*-- two columns: first is data to be reduced, second is number of
*-- duplicates in old array. WILL ERASE older AREDUCE arrays!!!
*--
*-- 14 Aug 1994    Initial programming
*------------------------------------------------------------------------------
PROCEDURE  ReduceArr
PARAMETERS cArName
PRIVATE    carname, noldrows, nx, ny, xolddata, xnewdata, nnewrows, nz
*- xOldData initialized with data type of array search in loop
*- xNewData initialized with data type of array search in loop
   m->nX = 1                                && old row counter
   m->nY = 1                                && loop counter
   m->nZ = 0                                && new row counter
   m->nOldRows = ArrayRows( "&cArName" )    && number of old rows
   m->nNewRows = 0                          && number of new rows
   if type( "AREDUCE[1,1]" ) # "U"
      release aReduce
   endif
   *-- First pass ------------------------------------------------------
   *-- search old array, count number of "unique" items in order to
   *-- create the new array...
   *-- Second pass -----------------------------------------------------
   *-- create new array, copy unique items to column 1, number of
   *-- duplicates into column 2.
   *--------------------------------------------------------------------
   do while m->nY < 3
      do while m->nX <= nOldRows
         m->xNewData = &cArName[ m->nX ]
         if type( "XOLDDATA" ) = "U"
            do case
               case type( "XNEWDATA" ) = "C"
                    m->xOldData = chr( 255 )
               case type( "XNEWDATA" ) = "N"
                    m->xOldData = -1
               case type( "XNEWDATA" ) = "D"
                    m->xOldData = {  /  /    }
            endcase
         endif
         if m->nY = 2
            if m->xNewData = m->xOldData
               aReduce[ m->nZ, 2 ] = aReduce[ m->nZ, 2 ] + 1
            else
               m->nZ = m->nZ + 1
               aReduce[ m->nZ, 1 ] = m->xNewData
               aReduce[ m->nZ, 2 ] = 1
            endif
         else
            if m->xOldData # m->xNewData
               m->nNewRows = m->nNewRows + 1
            endif
         endif
         m->xOldData = m->xNewData
         m->nX = m->nX + 1
      enddo
      release xOldData
      m->nX = 1
      m->nY = m->nY + 1
      if m->nY = 2
         if type( "AREDUCE[1,1]" ) = "U"
            public array aReduce[ m->nNewRows, 2]
         endif
      endif
   enddo
RETURN


Of special note is comment handling in dBase. From the dBase IV Language Reference:

NOTE/*/&&

NOTE, an asterisk (*), or double ampersand (&&) characters indicate comment lines in a program (.prg) file.

Syntax
NOTE/* <text>
  and
[<command>] && <text>

Usage
NOTE/*/&& inserts comments into program files for documentation and explanatory purposes. Use NOTE and * at the beginning of a line within a program. Use && to insert comments on the same line with a command in a program. You may use the && either after the command and the comment, or at the beginning of a line.

If a NOTE or && ends with a semicolon, dBASE IV reads the next line as part of the comment line. You cannot use a semicolon with NOTE/*. Each line must begin with either NOTE or *.

Examples
This example shows how you might use NOTE:

NOTE This is a simple loop
STORE 1 TO Cnt
DO WHILE Cnt < 100
  STORE Cnt + 1 TO Cnt
ENNDO

This example uses && to put a comment on a program line:

Memvar = 12     && Initializes numeric memvar