CONTENTS Syntax parser example code. COPYIGHT ©1999 Dietmar Eilert. All Rights Reserved. Dietmar Eilert Mies-v-d-Rohe-Str.31, 52074 Aachen, Germany Phone: +49-(0)179-5987061 German/English E-Mail: Dietmar.Eilert@post.rwth-aachen.de E-Mail: dietmar_eilert@yahoo.de (alternative address) WWW: http://members.tripod.com/golded Mirror: http://members.xoom.com/golded ABOUT The source drawer containes three fully compilable shared libraries implemented for DICE demonstrating how one can write a syntax parser library (library code & description based on Matt Dillon's example library): Some knowledge in shared libraries is required to understand the code. The basic thing to remember is (1) that a shared library is NOT a normal C program, and (2) the interface calls MUST be reentrant, i.e. multiple tasks can make a library call simultaniously. BASICS Syntax parsers are libraries, loaded by the editor at run time. They parse the lines of a text and return syntax descriptions to the editor. Syntax parsers do not contain rendering code: The editor is responsible for rendering to the display (and for briefing the syntax parser if the user modifies the text). Syntax parsers have to implement a fixed set of library functions used by the editor. These functions are described in "autodoc/scanlib.doc". The most important function is ParseLine(): it is called by the editor to obtain syntax desciptions while refreshing the display: The editor will pass a text line to the parser, the parser returns a syntax description. This basic mechanism is supplemented by additional library calls to support high performance syntax parsing (simple parsers may choose to ignore most of them). Two classes of syntax parsers are supported: 1. Context parser Context parsers understand complex syntax elements consisting of multiple lines (e.g. a C parser recognizing comments). Context parsers are the most complex parsers because they have to process every action performed by the editor: deleting the first line of a file might influence highlighting of the last line. The editor will keep the parser up-to-date by "sending" notifies (ie. calling a parser function). A context parsers should use a syntax chache in order to speed up parsing: results of prior parser passes should be cached for each line. Context parsers tend to be slow. A context parser example is available as example_context. 2. Non-context parser Non-context parsers examine single lines only. They are unable to recognize syntax elements consisting of multiple lines. Non-context parsers are considerably less complex than context parsers. Some of them will use a syntax cache (consuming memory), some of them are fast enough to provide real-time parsing. Two examples found in the source drawer are non-context parsers highlighting C++ comments (C++ comments are introduced by a "//" and terminated by the end of the line): the first example "example_cached" uses a cache, the second example "example_simple" doesn't use a cache. Generic syntax parsers Syntax scanners made for a specific language (for example a C++ syntax parsers) usually have built-in rules and a built-in dictionary for finding keywords. However, the editor also supports generic configurable syntax scanners not made for a specific language by providing a standard configuration dialog. In this dialog, the user can specify keywords and other language elements. These configuration details are passed to the syntax parser when it is started. Parser specify the configurable elements in their properties flag field. This information is evaluated by the editor to present the user with the correct configuration dialog. Parsers may also provide their own setup dialog overriding the built-in configuration dialog. FILES source/example: DEFS.H parser independant header stuff (do not change) LIB.C parser independant basic code (do not change) INIT.C parser independant initialization (do not change) TAG.A parser dependant code FUNCS.C parser dependant code DEFS.H, LIB.C and INIT.C are parser independant modules. Do not change these files. FUNCS.C is the parser code decribed by scanlib.doc. TAG.A is the startup code with only one modifications required if used for other projects: the name of the library. "TAG.A contains a subset of the standard startup code LIB/AMIGA/C.A and assumes non-resident compilation (i.e. you cannot use the -r option). This isn't a problem since the -r option doesn't gain you anything as far as shared libraries go. The individual library interface routines are declared with the LibCall macro, defined in DEFS.H, which ensures the small-data pointer is set up for all interface calls allowing use of the small-data model" (Matt Dillon).