Some Simple Examples PreviousNext

First some simple examples to get the flavor of how one uses gelex. The following gelex input specifies a scanner which whenever it encounters the string "foo" will replace it with the string "bar":

%{
class FOOBAR

inherit

    YY_COMPRESSED_SCANNER_SKELETON

create

    make
%}

%%

foo     output ("bar")

%%

end

This description file is made up of three sections separated by %% marks. The text enclosed within the two signs %{ and %} in the first section is Eiffel text which is copied verbatim to gelex output class file. It specifies that the name of the generated class is FOOBAR and that its creation procedure is make, a routine inherited from class YY_COMPRESSED_SCANNER_SKELETON. This class contains the pattern-matching engine - a Deterministic Finite Automaton (or DFA for short) - which is optimized in terms of memory space, hence the name of the class. It also provides numerous facilities such as routine scan for analyzing a given input text. The second section, enclosed within the two %% marks, contains the only rule of this description file. foo is the pattern of this rule and the output instruction is the action. By default, any text not matched by a gelex scanner is copied to the standard output, so the net effect of this scanner is to copy its input file to the standard output with each occurrence of "foo" replaced with "bar". The third section of the file, after the second %% mark, is Eiffel text which is copied verbatim at the end of the generated class. In this example, it just contains the end of the class keyword.

Here's another simple example:

%{
class WC

inherit

    YY_COMPRESSED_SCANNER_SKELETON

create

    make
%}

%%

\n      nb_lines := nb_lines + 1; nb_characters := nb_characters + 1
.       nb_characters := nb_characters + 1

%%

feature -- Access

    nb_lines: INTEGER
    nb_characters: INTEGER
            -- Number of lines and characters

feature -- Analysis

    analyze 
            -- Count the number of characters and lines
            -- in input file and display the results.
        do
            nb_lines := 1
            nb_characters := 0
            scan
            print ("Number of lines = ")
            print (nb_lines)
            print ('%N')
            print ("Number of characters = ")
            print (nb_characters)
            print ('%N')
        end

end

This scanner counts the number of characters and the number of lines in its input (it produces no output other than the final report on the counts). The first section of the scanner description is similar to the one described in the first example. The generated class is named after the Unix command wc which counts the number of characters, words and lines in given files. There are two rules, one which matches a newline (\n) and increments both the line count and the character count, and one which matches any character other than a newline (indicated by the . regular expression).

A somewhat more complicated example:

%{
note

    description: "Scanner for a toy Eiffel-like language"

class EIFFEL_SCANNER

inherit

    YY_COMPRESSED_SCANNER_SKELETON

    KL_SHARED_ARGUMENTS
        export {NONE} all end

    KL_SHARED_STANDARD_FILES
        export {NONE} all end

create

    make
%}

DIGIT    [0-9]
ID       [a-z][a-z0-9_]*

%%

{DIGIT}+    {
                 io.put_string ("An integer: ")
                 io.put_integer (text.to_integer)
                 io.put_new_line
            }
{DIGIT}+"."{DIGIT}*  {
                 io.put_string ("A real: ")
                 io.put_real (text.to_real)
                 io.put_new_line
            }
class|inherit|feature|do|if|then|else|end    {
                 io.put_string ("A keyword: ")
                 io.put_string (text)
                 io.put_new_line
            }
{ID}        {
                 io.put_string ("An identifier: ")
                 io.put_string (text)
                 io.put_new_line
            }
"+"|"-"|"*"|"/"|"^"    {
                 io.put_string ("An operator: ")
                 io.put_character (text_item (1))
                 io.put_new_line
            }
"--".*           -- Ignore comments
[ \t\n\r]+       -- Ignore separators
.           {
                 io.put_string ("Unrecognized character: ")
                 io.put_character (text_item (1))
                 io.put_new_line
            }

%%

feature -- Scanning

    scan_file 
            -- Scan file whose name has been given as argument.
            -- Scan standard input if no argument has been given.
        local
            l_file: KL_TEXT_INPUT_FILE
            l_input: KI_TEXT_INPUT_STREAM
        do
            if Arguments.argument_count >= 1 then
                create l_file.make (Arguments.argument (1))
                l_file.open_read
                l_input := l_file
            else
                l_input := std.input
            end
            set_input_buffer (new_file_buffer (l_input))
            scan
        end

end

This is the beginnings of a simple scanner for a language like Eiffel. It identifies different types of tokens and reports on what it has seen. The details of this example will be explained in the rest of the documentation.


Copyright © 1998-2019, Eric Bezault
mailto:
ericb@gobosoft.com
http:
//www.gobosoft.com
Last Updated: 17 January 2019

HomeTocPreviousNext