interp:library "afnix-txt"
Scanning concepts
Text scanning is the ability to extract lexical elements or lexemes from a stream. A scanner or lexical analyzer is the principal object used to perform this task. A scanner is created by adding special object that acts as a pattern matcher. When a pattern is matched, a special object called a lexeme is returned.
Pattern object
A Pattern object is a special object that acts as model for the string to match. There are several ways to build a pattern. The simplest way to build it is with a regular expression. Another type of pattern is a balanced pattern. In its first form, a pattern object can be created with a regular expression object.
# load the text module interp:library "afnix-txt" # create a pattern object const pat (afnix:txt:Pattern "$d+")
In this example, the pattern object is built to detect integer objects.
pat:check "123" # true pat:match "123" # 123
The check method return true if the input string matches the pattern. The match method returns the string that matches the pattern. Since the pattern object can also operates with stream object, the match method is appropriate to match a particular string. The pattern object is, as usual, available with the appropriate predicate.
afnix:txt:pattern-p pat # true
Another form of pattern object is the balanced pattern. A balanced pattern is determined by a starting string and an ending string. There are two types of balanced pattern. One is a single balanced pattern and the other one is the recursive balanced pattern. The single balanced pattern is appropriate for those lexical element that are defined by a character. For example, the classical C-string is a single balanced pattern with the double quote character.
# create a balanced pattern const pat (afnix:txt:Pattern "ELEMENT" "<" ">") pat:check "<xml>" # true pat:match "<xml>" # xml
In the case of the C-string, the pattern might be more appropriately defined with an additional escape character. Such character is used by the pattern matcher to grab characters that might be part of the pattern definition.
# create a balanced pattern const pat (afnix:txt:Pattern "STRING" """ '\') pat:check ""hello"" # true pat:match ""hello"" # "hello"
In this form, a balanced pattern with an escape character is created. The same string is used for both the starting and ending string. Another constructor that takes two strings can be used if the starting and ending strings are different. The last pattern form is the balanced recursive form. In this form, a starting and ending string are used to delimit the pattern. However, in this mode, a recursive use of the starting and ending strings is allowed. In order to have an exact match, the number of starting string must equal the number of ending string. For example, the C-comment pattern can be viewed as recursive balanced pattern.
# create a c-comment pattern const pat (afnix:txt:Pattern "STRING" "/*" "*/" )
Lexeme object
The Lexeme object is the object built by a scanner that contains the matched string. A lexeme is therefore a tagged string. Additionally, a lexeme can carry additional information like a source name and index.
# create an empty lexeme const lexm (afnix:txt:Lexeme) afnix:txt:lexeme-p lexm # true
The default lexeme is created with any value. A value can be set with the set-value method and retrieved with the get-value methods.
lexm:set-value "hello" lexm:get-value # hello
Similar are the set-tag and get-tag methods which operate with an integer. The source name and index are defined as well with the same methods.
# check for the source lexm:set-source "world" lexm:get-source # world # check for the source index lexm:set-index 2000 lexm:get-index # 2000
Text scanning
Text scanning is the ability to extract lexical elements or lexemes from an input stream. Generally, the lexemes are the results of a matching operation which is defined by a pattern object. As a result, the definition of a scanner object is the object itself plus one or several pattern object.
Scanner construction
By default, a scanner is created without pattern objects. The length method returns the number of pattern objects. As usual, a predicate is associated with the scanner object.
# the default scanner const scan (afnix:txt:Scanner) afnix:txt:scanner-p scan # true # the length method scan:length # 0
The scanner construction proceeds by adding pattern objects. Each pattern can be created independently, and later added to the scanner. For example, a scanner that reads real, integer and string can be defined as follow:
# create the scanner pattern const REAL (afnix:txt:Pattern "REAL" [$d+.$d*]) const STRING (afnix:txt:Pattern "STRING" """ '\') const INTEGER (afnix:txt:Pattern "INTEGER" [$d+|"0x"$x+]) # add the pattern to the scanner scanner:add INTEGER REAL STRING
The order of pattern integration defines the priority at which a token is recognized. The symbol name for each pattern is optional since the functional programming permits the creation of patterns directly. This writing style makes the scanner definition easier to read.
Using the scanner
Once constructed, the scanner can be used as is. A stream is generally the best way to operate. If the scanner reaches the end-of-stream or cannot recognize a lexeme, the nil object is returned. With a loop, it is easy to get all lexemes.
while (trans valid (is:valid-p)) {
# try to get the lexeme
trans lexm (scanner:scan is)
# check for nil lexeme and print the value
if (not (nil-p lexm)) (println (lexm:get-value))
# update the valid flag
valid:= (and (is:valid-p) (not (nil-p lexm)))
}
In this loop, it is necessary first to check for the end of the stream. This is done with the help of the special loop construct that initialize the valid symbol. As soon as the the lexeme is built, it can be used. The lexeme holds the value as well as it tag.
Text sorting
Sorting is one the primary function implemented inside the text processing module. There are three sorting functions available in the module.
Ascending and descending order sorting
The sort-ascent function operates with a vector object and sorts the elements in ascending order. Any kind of objects can be sorted as long as they support a comparison method. The elements are sorted in placed by using a quick sort algorithm.
# create an unsorted vector const v-i (Vector 7 5 3 4 1 8 0 9 2 6) # sort the vector in place afnix:txt:sort-ascent v-i # print the vector for (e) (v) (println e)
The sort-descent function is similar to the sort-ascent function except that the object are sorted in descending order.
Lexical sorting
The sort-lexical function operates with a vector object and sorts the elements in ascending order using a lexicographic ordering relation. Objects in the vector must be literal objects or an exception is raised.
Transliteration
Transliteration is the process of changing characters my mapping one to another one. The transliteration process operates with a character source and produces a target character with the help of a mapping table. The transliteration process is not necessarily reversible as often indicated in the literature.
Literate object
The Literate object is a transliteration object that is bound by default with the identity function mapping. As usual, a predicate is associate with the object.
# load the text module interp:library "afnix-txt" # create a transliterate object const tl (afnix:txt:Literate) # check the object afnix:txt:literate-p tl # true
The transliteration process can also operate with an escape character in order to map double character sequence into a single one, as usually found inside programming language.
# create a transliterate object with an escape character const tl (afnix:txt:Literate '\')
Transliteration configuration
The set-map configures the transliteration mapping table while the set-escape-map configure the escape mapping table. The mapping is done by setting the source character and the target character. For instance, if one want to map the tabulation character to a white space, the mapping table is set as follow:
tl:set-map ' ' ' '
The escape mapping table operates the same way. It should be noted that the mapping algorithm translate first the input character, eventually yielding to an escape character and then the escape mapping takes place. Note also that the set-escape method can be used to set the escape character.
tl:set-map ' ' ' '
Transliteration process
The transliteration process is done either with a string or an input stream. In the first case, the translate method operates with a string and returns a translated string. On the other hand, the read method returns a character when operating with a stream.
# set the mapping characters tl:set-map '\h' 'w' tl:set-map '\e' 'o' tl:set-map '\l' 'r' tl:set-map '\o' 'd' # translate a string tl:translate "helo" # word
Text hashing
Text hashing is the ability to generate an almost unique id from a string. Although, there is no guarantee that two different string will not produce the same result -- known as collision -- the sophistication of the hashing function attempt to minimize such eventuality. The hashing process is not reversible. There are several hashing functions available in the public domain. To name a few, MD5 is the message digest 5, and SHA is the secure hash algorithm. The following table illustrates the size of the result with different hashing functions.
| Function | Result size |
| MD-5 | 128 bits |
| SHA-1 | 160 bits |
| SHA-256 | 256 bits |
| SHA-384 | 384 bits |
| SHA-512 | 512 bits |
Hasher object
The Hasher class is a text hashing computation class. The class computes a hash value from a literal object, a buffer or an input stream. Once computed, the hash value is stored as an array of bytes that can be retrieved one by one or at all in the form of a string representation.
Creating a MD5 hasher
The Md5 object is the hasher object that implements the MD-5 algorithm. The constructor does not take any argument.
# get a MD-5 hasher const md (afnix:txt:Md5) # check the object afnix:txt:hasher-p md # true
The compute method computes the hash value. For example, the string "abc" returns the value "900150983CD24FB0D6963F7D28E17F72" which is 16 bytes long.
const hval (md:compute "abc")
Creating a SHA hasher
There are several SHA objects that produces results of different size as indicated in the next table.
| Hasher | Size | Constructor |
| SHA-1 | 160 bits | Sha1 |
| SHA-256 | 256 bits | Sha256 |
| SHA-384 | 384 bits | Sha384 |
| SHA-512 | 512 bits | Sha512 |
The compute method computes the hash value. For example, the string "abc" returns with SHA-1 the value "A9993E364706816ABA3E25717850C26C9CD0D89D" which is here 20 bytes long.
Cipher key
Cipher key management is an important concept in the land of text ciphering. In a simple mode, a key is used by a text cipher to encode some data. Although the key can be any sequence of bytes, it is preferable to have it built with some special algorithms like a text hasher. Most of the time, it is also desirable to have a key that follow simple constraints like size.
Creating a cipher key
The Key class is a cipher key suitable for text cipher. The key can be 128 bits, 192 bits or 256 bits long. By default, a random key is generated, but the key can be also generated from a string message. Internally, the key is generated with the SHA-256 algorithm. By default, the key is 128 bits long.
const key (afnix:txt:Key) assert true (afnix:txt:key-p key)
A random typed key can be created by specifying the key type in the constructor. The type K128, K192 and K256 are currently supported.
const key (afnix:txt:Key afnix:txt:Key:K26) assert true (afnix:txt:key-p key)
The constructor also supports the use of a string message for the generation of the key. The message can also be combined with a key type
# create a message key const key3 (afnix:txt:Key "hello world") assert true (afnix:txt:key-p key3) # create a message key by type const key4 (afnix:txt:Key afnix:txt:Key:K256 "hello world") assert true (afnix:txt:key-p key4)
Key functions
The basic operations associated with a key are the byte extraction as well as the key formating. In normal use, the key object is used directly by the text cipher. However, it might become necessary to access the key value directly. The get-type and get-size methods returns respectively the key type and key size. The format method returns a string representation of the key. The get method returns a key byte by index.
# create a message key const key3 (afnix:txt:Key "hello world") # get the key type and value const type (key3:get-type) const kval (key3:format) # create a message key by type const key4 (afnix:txt:Key type "hello world") assert kval (key4:format)
Stream cipher
A stream cipher is a class that encodes an input stream with a particular algorithm. The stream cipher is symmetric. This means that the data can be coded and later decoded to their original form. Most of the time. a stream cipher requires a key to operate. It is the key, if kept secret, that can ensure the confidentiality of the information being coded.
Cipher base class
The Cipher class is a base class for the stream cipher engine. The class provides a stream method that reads from an input stream and write into an output stream. The Cipher class is an abstract class and cannot be instantiated by itself. The object is actually created by using a cipher algorithm class such like the Aes class.
trans count (cipher:stream os is)
The stream method returns the number of character that have been encoded. Care should be taken that most of the stream cipher operates by block and therefore, will block until a complete block has been read from the input stream, unless the end of stream is read. Furthermore, the coded results does precise how the padding should be made for a particular cipher. It is therefore not recommended to use the stream stream method, but rather use the InputCipher class.
Creating a cipher
A Cipher object can be created with a cipher constructor. As of today, only the advanced encryption standard or AES is supported. The Aes class creates a new cipher that conform to the AES standard.
const cipher (afnix:txt:Aes)
A cipher can be created with a key and eventually a reverse flag. With one argument, the cipher key is associated with the cipher. Such key can be created as indicated in the previous section. The reverse flag is used to determine if the cipher operate in encoding or decoding mode. By default, the cipher operates in coding mode.
# create a key const key (afnix:txt:Key "hello world") # create a direct cipher const aes (afnix:txt:Aes key)
Cipher information
The Cipher class has several methods that provide information about the cipher. This include the cipher name with the get-name method and the cipher block size with the get-size method.
println (aes:get-name)
The cipher operating mode can be found with the get-reverse method. If the get-reverse method returns true, the cipher is operating in decoding mode. Note that a set-reverse method exists also.
Input cipher
In the presence of a Cipher object, it is difficult to read an input stream and encode the character of a block basis. Furthermore, the existence of various method for block padding makes the coding operation even more difficult. For this reason, the InputCipher class provides the necessary method to code or decode an input stream in various mode of operations, including the management of the block padding.
Input cipher mode
The InputCipher class is an input stream that binds an input stream with a cipher. The class acts like an input stream, read the character from the binded input stream and encode or decode them from the binded cipher. The InputCipher defines two modes of operations. In electronic codebook mode or ECB, the character are encoded in a block basis. In cipher block chaining mode, the block are encoded by doing an XOR operation with the previous block. In all cases, a block padding is added, following the recommendation of RFC 2630 and NIST 800-38A.
Creating an input cipher
By default an input cipher is created with a cipher object. Eventually, an input stream and/or the input mode can be specified at the object construction.
# create a key const key (afnix:txt:Key "hello world") # create a direct cipher const aes (afnix:txt:Aes key) # create an input cipher const ic (afnix:txt:InputCipher aes)
In this example, the input cipher is created in ECB mode. The input stream is later associated with the set-is method.
Input cipher operation
The InputCipher class operates with one or several input streams. The set-is method sets the input stream. Read operation can be made with the help of the valid-p predicate.
while (ic:valid-p) (os:write (ic:read))
Since the InputCipher operates like an input stream, the stream can be read as long as the valid-p predicate returns true. Note that the InputCipher manages automatically the padding operation by maintaining internally a buffer with the encoded padded characters. During the decoding phase, the class make sure that the padded characters are removed correctly.
| Symbol | Description |
| afnix-txt | module |
| afnix:txt | nameset |
Pattern
The Pattern class is a pattern matching class based either on regular expression or balanced string. In the regex mode, the pattern is defined with a regex and a matching is said to occur when a regex match is achieved. In the balanced string mode, the pattern is defined with a start pattern and end pattern strings. The balanced mode can be a single or recursive. Additionally, an escape character can be associated with the class. A name and a tag is also bound to the pattern object as a mean to ease the integration within a scanner.
Predicate
Inheritance
Constructors
Constants
Methods
Lexeme
The Lexeme class is a literal object that is designed to hold a matching pattern. A lexeme consists in string (i.e. the lexeme value), a tag and eventually a source name (i.e. file name) and a source index (line number).
Predicate
Inheritance
Constructors
Methods
Scanner
The Scanner class is a text scanner or lexical analyzer that operates on an input stream and permits to match one or several patterns. The scanner is built by adding patterns to the scanner object. With an input stream, the scanner object attempts to build a buffer that match at least one pattern. When such matching occurs, a lexeme is built. When building a lexeme, the pattern tag is used to mark the lexeme.
Predicate
Inheritance
Constructors
Methods
Literate
The Literate class is transliteration mapping class. Transliteration is the process of changing characters my mapping one to another one. The transliteration process operates with a character source and produces a target character with the help of a mapping table. This transliteration object can also operate with an escape table. In the presence of an escape character, an escape mapping table is used instead of the regular one.
Predicate
Inheritance
Constructors
Methods
Functions
Hasher
The Hasher class is a base class that is used to build a message hash. The hash result is stored in an array of bytes and can be retrieved byte by byte or as a formatted printable string. This class does not have a constructor.
Predicate
Inheritance
Methods
Md5
The Md5 class is a hashing class that implements the MD-5 algorithm.
Predicate
Inheritance
Constructors
Sha1
The Sha1 class is a hashing class that implements the SHA-1 algorithm.
Predicate
Inheritance
Constructors
Sha256
The Sha256 class is a hashing class that implements the SHA-256 algorithm.
Predicate
Inheritance
Constructors
Sha384
The Sha384 class is a hashing class that implements the SHA-384 algorithm.
Predicate
Inheritance
Constructors
Sha512
The Sha512 class is a hashing class that implements the SHA-512 algorithm.
Predicate
Inheritance
Constructors
Key
The Key class is a cipher key class that generates random key or message key. The key generation algorithm is based on the SHA-256 algorithm and accept different size. The default key size is 128 bits.
Predicate
Inheritance
Constructors
Constants
Methods
Cipher
The Cipher class is a base class that is used to implement a symmetric block cipher. A reverse flag controls the cipher operation. When false, the cipher operates in encrypt mode. When true, the cipher operates in decrypt mode, that is the reverse mode. This class cannot be instantiated by itself.
Predicate
Inheritance
Methods
Aes
The Aes class is a cipher class that implements the advanced encryption standard or AES block cipher. The AES cipher is a symmetric block cipher.
Predicate
Inheritance
Constructors
InputCipher
The InputCipher class is an stream interface that can stream out an input stream from a cipher. In other word, an input stream is read and block are encoded as long as the input stream read characters. If the cipher is nil, the input cipher simply read the input stream and is therefore transparent. The class acts like an input stream, read the character from the bounded input stream and encode or decode them from the bounded cipher. The InputCipher defines two modes of operations. In electronic codebook mode or ECB, the character are encoded in a block basis. In cipher block chaining mode, the block are encoded by doing an XOR operation with the previous block. In all cases, a block padding is added, following the recommendation of RFC 2630 and NIST 800-38A.
Predicate
Inheritance
Constructors
Constants
Methods