Multi-Edit's Top Bar Image - Click here to Return to the Home Page spacer image for website layout News regarding our IDE -click this image- Products of MESI Page -click this image- Support Avenues, Forums, Emails etc. -click this image- Purchase Online -click this image- Resources, Downloads, Zips for Mult-Edit -click this image- Company NFO -click this image- Website Sitemap -click this image-

Adding New Language Support to Multi-Edit

Multi-Edit ships with support for many of the most popular programming languages, C/C++, Pascal, Modula-2, DBase and many more but with a little work unsupported languages can easily be added. This document describes all of the language features Multi-Edit supports and how to go about adding these features for an unsupported language.

** If any user has developed support for a previously unsupported language and would like it to become a supported language, send us a copy of your language macro and support files, ie *.TPT etc and we will have it added to a future version of Multi-Edit. Send all such requests to Multi-Edit Development, care of VP Dan Hughes **

As Multi-Edit has evolved over the years, the features users want to change most frequently have been redesigned so that most of the changes could be made without resorting to writing macros and usually consists of filling in entries in dialogs. This idea has been applied to the language support also but with the vast differences between programming languages there are still some areas where macros are required to provide the needed support.

A number of different language features are provided and can be added independent of each other. This means that when adding support for a new language all of these features do not need to be implemented to reap the benefit of a particular feature. Thus the new language support can be added and tested in stages or not even support some features.

The following list of language features are provided in Multi-Edit and are shown from the easiest to implement to the hardest. Not all of these features will be covered in detail here since they are covered fairly well in the online help and the manual.

  • Color syntax and keyword highlighting
  • Code commenting and uncommenting
  • Templates
  • Compiler support and error processing
  • Construct matching
  • Smart indenting
  • Function tagging
  • Properties

The way Multi-Edit supports different languages is through the filename extension. When a file with a specific extension is loaded, a check is done to see if that extension has been defined and if it has the language features associated with it are initialized. The Filename Extension Setup dialog is where the extension specific information is setup and the language associated with that extension is specified. It is also where the templates and compiler entries are associated with a given extension.

The language specific information is mostly defined in the Language Setup dialog accessed from the Tools main or the context menus. Template are created and changed in the Edit Template dialog accessed from the Tools menu as well.

Color syntax and keyword highlighting

The ability to highlight keywords and syntax with color is a very powerful feature. This and the Code commenting feature is the easiest to add. All that is required to add this feature is to create a new language record by doing the following:
  1. From the main menu select Tools | Customize... | Languages...
  2. Select the Insert button and type in the name of the new language.
This will bring up the Language Setup dialog for the new language and the fields can then be filled in with the appropriate data. See the online help for more information about what each field should contain.

When the new language record has been defined it must be associated with a set of file extensions. This is done as follows:

  1. From the main menu select Tools | Customize... | Filename extension...
  2. Select a defined extension and hit the Edit button or Select the Insert button and type a new set of file extensions
  3. Select the ... button by Language and Select the newly defined language from the list.

Code commenting and uncommenting

This feature is automatically added as soon as the comment fields are filled out in the Language Setup dialog. See the online help for more information.

Templates

The new template system that is provided with Multi-Edit allows adding abbreviations for common code fragments and language constructs that fully expand when the space key is pressed. These templates are stored as *.TPT files under the /MEW/CONFIG subdirectory. A specific language template can be defined and associated with an extension just like a language record. This is done as follows:
  1. From the main menu select Tools | Customize... | Filename extensions...
  2. Select the '...' button beside the Template field
  3. Select a defined template and click the Select button or select the Insert button and define a new language template.
There can be only one main language template associated with a set of extensions, but by adding template set names separated by ;'s in the Addon template field, it is possible to allow additional templates to be added to the extension. This is how the Windows API template set would be added.

Also, while in the Extension setup dialog be sure to check the Auto template expansion option to enable template expansion for the specified extension.

To edit or add a new template do the following:

  1. From the main menu select Tools | Edit templates
This will open the Edit Template dialog for the language specified in the extension setup for the currently loaded window. This is where new templates are added and older templates are modified. The fields in this dialog allow each template to be modified with specifications as to what will be inserted and when it will be expanded. See the online help for more details about all of the fields in the template dialog.

Compiler support and error processing

Compiler support and error processing is setup through the Filename Extension Setup dialog by selecting the Compiler/Program setup button. This will bring up a list of all compiler entries for the specified extension. New entries can easily be added by selecting the Insert button and filling in the dialog. See the online help for more details.

Adding error processing requires a little more work but it is still fairly straight forward. This involves creating a compiler type and specifying a set of regular expressions that will match the lines with errors in the captured compiler output. To do this, select the '...' button by the Program type field in the Compiler/Program Setup dialog mentioned above. This is also covered more thoroughly in the online help.

Construct matching

Construct matching provides the ability to start with the cursor on a opening or closing construct, ie (), {} or begin end, and find (optionally highlighting) the matching construct. This feature can be implemented in two ways, with a macro that does the searching or through the new general purpose LangDoMatch routine.

The macro method requires that a macro be written to locate and match all supported constructs. This is the older method and will not be discussed in detail here.

The new method of adding construct matching is to define a set of global variables that define the patterns to match and then using the general purpose LangDoMatch macro to do the matching. To implement this the following steps that must be done.

  1. Setup the special pattern global variable.
  2. Write a special _xGetMatchPat( ) macro.
  3. Write a xMatch macro which calls the LangDoMatch macro passing the correct parameters depending upon the language Properties.
  4. Setup the Init and Match macro fields in the Language Setup dialog to point to the correct macros.
To setup the special pattern global variables currently requires an xInit macro be written where x is the language prefix, usually the first three letters of the language support macro filename. Eventually, we hope to move this into a dialog and save them in a DB file so that it could be more easily updated.

There are three global variables that must be setup and are shown below using C as the example. See the CInit macro in C.S for more details.

!CMatchExtra - Characters used to specify the start and end of words

This global string variable consists of three parts starting with the \x7F character shown below as %

%B=str where str is a list of all of the characters that can precede a construct word.

%E=str where str is a list of all of the characters that can come after a construct word.

%D=char where char is a character that is used to separate multiple construct patterns. The default is to use the space character as the delimiter but should be changed to something else for languages such as Ada and Visual Basic that use double word constructs.
!CMatchBegPat - Beginning construct patterns to match

This global string variable consists of a series of records using \x7F as the delimiter character, shown below as %, and each record can consists of up to seven fields.

%Str1%Str2... where Str# is the character string of a beginning construct, ie IF or (

%F= Flag where Flag is an optional bit flag used to control how the match routine will work for matching the current construct. See Language.sh for the _mfc_Xxxx flag values.

_mfc_StrOnly - This flags when set will cause the matching routine to exactly match the construct ignoring the characters before and after it.

_mfc_SkipMid - This flag when set changes the meaning of the %M= strings to cause them to be skipped when searching for a match. The %I= field should be used to specify patterns to ignore when a middle pattern is also required. The %I= field is available in Mew80b+ releases.

_mfc_ContMatch - This flag when set will cause matching to continue when the %C= expression is found after a %B= or %E= string was located. When this flag is reset matching will end if the %C= expression is not found after a %B= or %E= string was located.

%B= Str1 Str2 ... where Str# is a %D=char delimited, before and after, list of beginning construct patterns, ie IF or (

%M= Str1 Str2 ... where Str# is a %D=char delimited, before and after, list of middle construct patterns, ie ELSE or blank for ( matching. If the %F= flag has the _mfc_SkipMid bit set then the match routine will cause a found string matching one of the %M= strings to be skipped.

%E= Str1 Str2 ... where Str# is a %D=char delimited, before and after, list of ending construct patterns, ie ENDIF or )

%X=XStr where XStr is a UNIX style regular expression that will match any of the B, M or E string, ie (IF)|(ELSE)|(ENDIF) or [\(\)]

%I=IStr where IStr is an optional %D=char delimited, before and after, list of construct patterns to ignore when doing a match. See VBasic.s or Ada.s for an example of how this would be used. (Available in Mew80b+ releases)

%C=CStr where CStr is an optional UNIX style regular expression to search for after a %B= or %E= match was found. What happens when a match is found is determined by the value of the _mfc_ContMatch bit of the %F= flag. See VBasic.s for an example of how this would be used.

% The ending delimiter is required
!CMatchEndPat - Ending construct patterns to match

This global string variable serves the same functions as the !CMatchBegPat except that it is used to specify ending patterns.

%Str1%Str2... where Str# is the character string of a ending construct, ie ENDIF or )

%F= Flag where Flag is an optional bit flag used to control how the match routine will work for matching the current construct. Used exactly as described above.

%B= Str1 Str2 ... where Str# is a %D=char delimited, before and after, list of ending construct patterns, ie ENDIF or ).

%M= Str1 Str2 ... where Str# is an optional %D=char delimited, before and after, list of middle construct patterns, ie ELSE or blank for ( matching. If the %F= flag has the _mfc_SkipMid bit set then the match routine will cause a found string matching one of the %M= strings to be skipped.

%E= Str1 Str2 ... where Str# is a space delimited, before and after, list of ending construct patterns, ie IF or (

%X=XStr where XStr is a UNIX style regular expression that will match any of the B or E string, ie (IF)|(ENDIF) or [\(\)]

%I=IStr where IStr is an optional %D=char delimited, before and after, list of construct patterns to ignore when doing a match. See VBasic.s or Ada.s for an example of how this would be used. (Available in Mew80b+ releases)

%C=CStr where CStr is an optional UNIX style regular expression to search for after a %B= or %E= match was found. What happens when a match is found is determined by the value of the _mfc_ContMatch bit of the %F= flag. See VBasic.s for an example of how this would be used.

% The ending delimiter is required
Before we go into more detail, lets explain how the matching feature works. When the match routine is run either from a key, toolbar or menu, the Match macro looks in the language record specified by the current file's extension for the macro in the Match field. If an entry is found, the specified macro is executed. This is usually a macro that calls the LangDoMatch routine with the language prefix specified /LP= and possibly some other parameters to specify if highlighting is to be done or not.

The first thing that LangDoMatch does is call a special macro for the specified language called _xGetMatchPat, x being the language prefix passed as the /LP= parameter. This macro is to provide special character processing for the specific language. This can be as simple as setting Return_Str to "" and returning (ie. no special processing), or checking if the current character is one of the special characters and returning the character surrounded by the \x7F delimiters characters, or searching for special characters on the current line and then returning the delimited character. This macro is usually used to process single character and possible double characters (such as comment characters /*) but can also be used to reposition the cursor on another word that is supported. See Fortran.s or Ada.s for an example of the word repositioning feature. The main LangDoMatch will then process whole words if the _xGetMatchPat returns "" or the special character can not be matched.

If the _xGetMatchPat returns a pattern then the LangDoMatch routine searches the special MatchBegPat global variable for a beginning pattern match. If one is found, it will parse out the fields of that record. It will then use the specified regular expression to do a forward search. When a match is found, the found string is compared to the begin, middle and end patterns of the specified record. What happens next depends upon which string the found string is found in. If it is found in the begin string a match count is incremented by one, since a nested construct is found and the search is continued. If the end string contains the found pattern then the count is decremented by one and will exit the search loop when it reaches 0, ie the ending construct was found. If the middle string contains the found string then the search is repeated unless the count is at 1, ie still inside the first construct and thus a middle construct match.

If the original pattern was not found in the MatchBegPat global variable then the MatchEndPat global is "search" and the same process as above happens except for searching backwards for matching patterns.

If the _xGetMatchPat returns "" or the pattern can not be matched, the word the cursor is sitting on is read using the begin and end word string to delimit the word. The above process is then repeated with the word instead of a character pattern. Thus if the new language is to only support words then the _xGetMatchpat can always return "".

When a matching construct is found it will be highlighted if the appropriate parameters are passed. See the LangDoMatch macro in Language.S for more details.

After the xInit, _xGetMatchPat and xMatch macros are written, the xInit macro needs to be specified in the Init macro field and the xMatch macro in the Match field of the Language Setup dialog.

Smart indenting

Smart indenting is the ability to position the cursor in the correct column to continue typing code after the Enter key is pressed. Since this feature is very language dependent a macro must be written which, when called by the CR system macro, should check the context of the cursor and reposition the cursor on the next line in the correct position.

We have developed two different type routines that should handle most languages and they can be seen in the C.s and Pascal.S files. The C.s macro, CIndent, checks the line ending characters of previous lines to determine the indent level of the next line where the Pascal.s macro, PasIndent, checks the first word on previous lines to do likewise.

To implement the indent macro for the new language, determine which type of routine the new language is most like and start with a copy of one of the supplied macros and change it to implement the specific cases.

When you have the macro written and tested it is installed by doing the following:

  1. From the main menu select Tools | Customize... | Filename extension...
  2. Select the specific extensions and hit the Edit button.
  3. Set Indent style to Smart.
  4. Exit dialog by hitting OK
  5. From the main menu select Tools | Customize... | Languages...
  6. Select the new language entry and hit the Edit button.
  7. Enter the macro name in the Indent macros field, ie C^CIndent
Note: Select Indent style "Auto" if a language indent macro has not been written. This will cause the cursor to line up with the first word on the previous line.

Function tagging

This feature requires a macro be written to scan the source file for the function declaration and/or variable names and writes them to a tag file in a specific format. The MeTags macro must then be patched to support the new language. This will not be covered in this document since this is rather involved. We hope to eventually make this easier to add in the future.

Properties

The properties feature is not really a separate feature in itself but is used to support some of the other features. The Set Properties button in the Language Setup dialog, when pressed, will run the macro specified in the Config macro field. This macro should display a dialog that presents the user with configuration options that are supported in the new language support. Examples of this can be seen in the C and Pascal support where the indent style and auto highlighting of closing ')' can be enabled or changed.

If the new language is to support properties then a set of macros needs to be written to support them. These macros are described below using C as the example. Replace the leading C with the first three characters from the name of the new language macro file and make the needed changes for the specific properties.


void CSetProperties(
      str GStr    = Parse_Str( "/GSTR=", MParm_Str ),
      str Parameter = MParm_Str
)
/******************************************************************************

  Function: Set C and CMAC specific properties.  Should only be run by the
            LangSetProperties macro.

  Entry   : str GStr     - Name of global string containing properties (/GSTR=)
            str ParmStr  - Misc parameters
              /L=str       - Language name to show on title bar

  Exit    : None

  Note:
    This macro displays a dialog of all of the available properties that can
    be set for the specified language.  This macro should save the changed
    properties data in the global variable specified by GStr before exiting so
    that the Language Setup dialog can update the db record for the specified
    language.
********************************************************************( ldh )***/


int CGetProperties( struct tCProperties rCP )
/******************************************************************************

  Function: Get the specific language properties for the current file.
  Entry   : struct rCP   - A structure to fill with the properties.
  Exit    : int
              True         - Properties fill from Db
              False        - Properties set to internal defaults

  Note:
    This macro is called by all the other macros when they need to query a
    specific property.  A structure should be define that contains entries for
    all of the supported properties.
********************************************************************( ldh )***/


void CIndentTmp(
      str Set  = Parse_Str( "/S=", MParm_Str ),
      str Name = Parse_Str( "/N=", MParm_Str )
)
/******************************************************************************
  Function: Insert the indent style template Name from the template set Set.
  Entry   : str Set      - The template set
            str Name     - The template name
  Exit    : None
  Note:
    This macro would only be written and used if the new language allows
    templates to adjust indent style based upon a property setting.  When this
    is used the template must be setup to call this macro to determine the
    indent style and the name of a template that will expand to the selected
    indent style.  See C.TPT for examples.
********************************************************************( ldh )***/

** If any user has developed support for a previously unsupported language and would like it to become a supported language, send us a copy of your language macro and support files, ie *.TPT etc and we will have it added to a future version of Multi-Edit. Send all such requests to Multi-Edit Development, care of VP Dan Hughes **