#|-------------------- 1.1 |# "./agrep.meta" 541
;; -*- Hen -*-
((egg "agrep.egg") ; This should never change
; List here all the files that should be bundled as part of your egg.
(files "agrep.setup" "agrep.scm" "skeleton.h" "engine.scm" "agrep.meta" "tests/run.scm")
; Your egg's license:
(license "GPL-3")
; Pick one from the list of categories (see below) for your egg and
; enter it here.
(category data)
; A list of eggs agrep depends on.
(needs easyffi datatype)
(test-depends test)
(doc-from-wiki)
(author "Ivan Raikov")
(synopsis "Approximate grep."))
#|-------------------- 1.1 |# "./agrep.scm" 10478
;;
;; Approximate grep library. Code ported from the Caml agrep library by
;; Xavier Leroy.
;;
;;
;; Copyright 2009-2010 Ivan Raikov and the Okinawa Institute of Science and
;; Technology.
;;
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; A full copy of the GPL license can be found at
;; .
;;
(module agrep
(string-match
substring-match
errors-substring-match
pattern
string->pattern
iso8859_15_case_insensitive
iso8859_15_accent_insensitive
iso8859_15_case_and_accent_insensitive
)
(import scheme chicken)
(require-extension datatype )
(require-library srfi-1 srfi-4 srfi-13 srfi-14)
(import (only srfi-1 every fold)
(only srfi-4 make-u32vector u32vector? )
(only srfi-13 string-length)
srfi-14)
(include "engine.scm")
;; Deep syntax for patterns
(define-datatype pattern pattern?
(CBase (len integer?) (bm u32vector?))
(CAnd (p1 pattern?) (p2 pattern?))
(COr (p1 pattern?) (p2 pattern?)))
;; String matching
(define (string-match pat text #!key (numerrs 0) (wholeword #f))
(if (negative? numerrs) (error 'string-match "numerrs < 0"))
(let recur ((pat pat))
(cases pattern pat
(CBase (len bm)
(agrep-match text 0 (string-length text) len bm numerrs wholeword))
(CAnd (p1 p2)
(and (recur p1) (recur p2)))
(Cor (p1 p2)
(or (recur p1) (recur p2))))))
(define (substring-match pat text pos len #!key (numerrs 0) (wholeword #f))
(if (or (< pos 0) (< (string-length text) (+ pos len)))
(error 'substring-match "invalid pos len arguments" pos len))
(if (negative? numerrs) (error 'string-match "numerrs < 0"))
(let recur ((pat pat))
(cases pattern pat
(CBase (plen bm)
(agrep-match text pos len plen bm numerrs wholeword))
(CAnd (p1 p2)
(and (recur p1) (recur p2)))
(Cor (p1 p2)
(or (recur p1) (recur p2))))))
(define (errors-substring-match pat text pos len #!key (numerrs 0) (wholeword #f))
(if (or (< pos 0) (< (string-length text) (+ pos len)))
(error 'substring-match "invalid pos len arguments" pos len))
(if (negative? numerrs) (error 'string-match "numerrs < 0"))
(let recur ((pat pat))
(cases pattern pat
(CBase (plen bm)
(agrep-match text pos len plen bm numerrs wholeword))
(CAnd (p1 p2)
(max (recur p1) (recur p2)))
(Cor (p1 p2)
(min (recur p1) (recur p2))))))
;; Shallow syntax for patterns
(define-datatype simple-pattern simple-pattern?
(Char (c char?))
(String (s string?))
(Charset (cs char-set?))
(Wildcard))
(define-datatype complex-pattern complex-pattern?
(Simple (ps (lambda (x) (every simple-pattern? x))))
(PAnd (p1 complex-pattern?) (p2 complex-pattern?))
(POr (p1 complex-pattern?) (p2 complex-pattern?)))
;; Compilation of shallow syntax into deep syntax
(define (add-char transl bm len c r)
(if (not transl)
(let ((t (char->integer c)))
(agrep-set-bit bm len t r))
(let ((t (transl c)))
(agrep-set-bit bm len t r))))
(define (simple-pattern-len sp)
(fold (lambda (p len)
(cases simple-pattern p
(Char (c) (+ 1 len))
(String (s) (+ (string-length s) len))
(Charset (cs) (+ 1 len))
(Wildcard () len)))
0 sp))
(define (compile-simple-pattern sp #!key (transl #f) (nentries 257))
(let* ((len (simple-pattern-len sp))
(bm (agrep-alloc-bitmatrix len (+ 1 nentries))))
(let fill ((pos 0) (sp sp))
(if (pair? sp)
(cases simple-pattern (car sp)
(Char (c)
(add-char transl bm len c pos)
(fill (+ 1 pos) (cdr sp)))
(String (s)
(let ((pos1 (fold (lambda (c pos) (add-char transl bm len c pos)
(+ 1 pos))
pos (string->list s))))
(fill pos1 (cdr sp))))
(Charset (cs)
(for-each (lambda (c) (add-char transl bm len c pos))
(char-set->list cs))
(fill (+ 1 pos) (cdr sp)))
(Wildcard ()
(agrep-set-bit bm len nentries pos)
(fill pos (cdr sp))))
'()))
(CBase len bm)))
(define (compile-pattern pat #!key (transl #f) (nentries 257))
(cases complex-pattern pat
(Simple (sp) (compile-simple-pattern sp transl: transl nentries: nentries))
(PAnd (p1 p2) (CAnd (compile-pattern p1 transl: transl nentries: nentries)
(compile-pattern p2 transl: transl nentries: nentries)))
(POr (p1 p2) (COr (compile-pattern p1 transl: transl nentries: nentries)
(compile-pattern p2 transl: transl nentries: nentries)))))
;; From concrete syntax to shallow abstract syntax
(define (parse-pattern s)
(define (parse-class cls lst)
(cond ((null? lst)
(error 'parse-pattern "syntax error"))
((eq? (car lst) #\])
(values cls (cdr lst)))
((and (eq? (car lst) #\\) (pair? (cdr lst)))
(parse-class (char-set-union cls (char-set (cadr lst))) (cddr lst)))
((and (pair? (cdr lst)) (pair? (cddr lst))
(eq? (cadr lst) #\-) (not (eq? (caddr lst) #\])))
(let ((l (char->integer (car lst))) (u (char->integer (caddr lst))))
(values (char-set-union cls (ucs-range->char-set l u)) (cdddr lst))))
(else
(values (char-set-union cls (char-set (car lst))) (cdr lst)))))
(define (parse-char-class lst)
(let ((cls (char-set)))
(cond ((and (pair? lst) (eq? (car lst) #\^))
(let-values (((cls j) (parse-class cls (cdr lst))))
(values (char-set-complement cls) j)))
(else
(parse-class cls lst)))))
(define (parse-simple-list sl lst)
(if (null? lst) (values sl lst)
(case (car lst)
((#\) #\| #\&) (values sl lst))
((#\()
(error 'parse-pattern "syntax error" lst))
((#\?)
(parse-simple-list (cons (Charset char-set:full) sl) (cdr lst)))
((#\*)
(parse-simple-list (cons (Wildcard) sl) (cdr lst)))
((#\\)
(parse-simple-list (cons (Char (cadr lst)) sl) (cddr lst)))
((#\[)
(let-values (((cls lst1) (parse-char-class (cdr lst))))
(parse-simple-list (cons (Charset cls) sl) lst1)))
(else
(parse-simple-list (cons (Char (car lst)) sl) (cdr lst))))))
(define (parse-base lst)
(if (null? lst) (values (Simple '()) lst)
(let ((s (car lst)))
(case s
((#\) #\| #\&) (values (Simple '()) lst))
((#\()
(let-values (((p lst1) (parse-or (cdr lst))))
(values p lst1)))
(else
(let-values (((sl lst1) (parse-simple-list '() lst)))
(values (Simple (reverse sl)) lst1)))))))
(define (parse-ands p1 lst)
(if (null? lst) (values p1 lst)
(let ((s (car lst)))
(case s
((#\) #\|) (values p1 lst))
((#\&)
(let-values (((p2 lst2) (parse-base (cdr lst) )))
(parse-ands (PAnd p1 p2) lst2)))
(else (error 'parse-pattern "syntax error" lst))))))
(define (parse-and lst)
(let-values (((p1 lst1) (parse-base lst)))
(parse-ands p1 lst1)))
(define (parse-ors p1 lst1)
(if (null? lst1) (values p1 lst1)
(let ((s (car lst1)))
(case s
((#\)) (values p1 lst1))
((#\|) (let-values (((p2 lst2) (parse-and (cdr lst1))))
(parse-ors (POr p1 p2) lst2)))
(else (error 'parse-pattern "syntax error in pattern" lst1))))))
(define (parse-or lst)
(let-values (((p1 lst1) (parse-and lst)))
(parse-ors p1 lst1)))
(let ((lst (string->list s)))
(let-values (((p lst1) (parse-or lst)))
(assert (null? lst1))
p)))
(define (pattern s #!key (transl #f))
(compile-pattern (parse-pattern (string->list s)) transl: transl))
(define (string->pattern s #!key (transl #f))
(compile-pattern (Simple (list (String s))) transl: transl))
;; Translation tables for ISO 8859-15 (Latin 1 with Euro)
(define iso8859_15_case_insensitive
(let ((case_insensitive
(list->vector (string->list "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\t\n\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u0020\u0021\u0022\u0023\u0024\u0025\u0026\u0027\u0028\u0029\u0030\u0031 !\"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0127\u0128\u0129\u0130\u0131\u0132\u0133\u0134\u0135\u0136\u0137\u0138\u0139\u0140\u0141\u0142\u0143\u0144\u0145\u0146\u0147\u0148\u0149\u0150\u0151\u0152\u0153\u0154\u0155\u0156\u0157\u0158\u0159 ¡¢£¤¥¨§¨©ª«¬®¯°±²³¸µ¶·¸¹º»½½ÿ¿àáâãäåæçèéêëìíîïðñòóôõö×øùúûüýþßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"))))
(lambda (c) (vector-ref case_insensitive (char->integer c)))
))
(define iso8859_15_accent_insensitive
(let ((accent_insensitive
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\t\n\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u0020\u0021\u0022\u0023\u0024\u0025\u0026\u0027\u0028\u0029\u0030\u0031 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0127\u0128\u0129\u0130\u0131\u0132\u0133\u0134\u0135\u0136\u0137\u0138\u0139\u0140\u0141\u0142\u0143\u0144\u0145\u0146\u0147\u0148\u0149\u0150\u0151\u0152\u0153\u0154\u0155\u0156\u0157\u0158\u0159 ¡¢£¤¥S§s©ª«¬®¯°±²³Zµ¶·z¹º»OoY¿AAAAAAACEEEEIIIIÐNOOOOO×OUUUUYÞsaaaaaaaceeeeiiiiðnooooo÷ouuuuyþy"))
(lambda (c) (vector-ref accent_insensitive (char->integer c)))
))
(define iso8859_15_case_and_accent_insensitive
(let ((case_and_accent_insensitive
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\t\n\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u0020\u0021\u0022\u0023\u0024\u0025\u0026\u0027\u0028\u0029\u0030\u0031 !\"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0127\u0128\u0129\u0130\u0131\u0132\u0133\u0134\u0135\u0136\u0137\u0138\u0139\u0140\u0141\u0142\u0143\u0144\u0145\u0146\u0147\u0148\u0149\u0150\u0151\u0152\u0153\u0154\u0155\u0156\u0157\u0158\u0159 ¡¢£¤¥s§s©ª«¬®¯°±²³zµ¶·z¹º»ooy¿aaaaaaaceeeeiiiiðnooooo×ouuuuyþsaaaaaaaceeeeiiiiðnooooo÷ouuuuyþy"))
(lambda (c) (vector-ref case_and_accent_insensitive (char->integer c)))
))
)
#|-------------------- 1.1 |# "./agrep.setup" 464
;; -*- Hen -*-
(define (dynld-name fn)
(make-pathname #f fn ##sys#load-dynamic-extension))
(compile -O -d2 -I. -s agrep.scm -X easyffi -j agrep)
(compile -O2 -d0 -s agrep.import.scm)
(install-extension
; Name of your extension:
'agrep
; Files to install for your extension:
`(,(dynld-name "agrep") ,(dynld-name "agrep.import")
)
; Assoc list with properties for your extension:
`((version 1.1)
(documentation "agrep.html")))
#|-------------------- 1.1 |# "./engine.scm" 9014
;;
;; Chicken agrep library interface. Code ported from the Caml agrep
;; library by Xavier Leroy.
;;
;;
;; Copyright 2009-2010 Ivan Raikov and the Okinawa Institute of Science and
;; Technology.
;;
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; A full copy of the GPL license can be found at
;; .
;;
(import scheme chicken foreign srfi-4)
;; Error handling, initialization and finalization
;; The following three functions are borrowed from the
;; Chicken-specific parts of SWIG
#>
static void chicken_Panic (C_char *) C_noret;
static void chicken_Panic (C_char *msg)
{
C_word *a = C_alloc (C_SIZEOF_STRING (strlen (msg)));
C_word scmmsg = C_string2 (&a, msg);
C_halt (scmmsg);
exit (5); /* should never get here */
}
static void chicken_ThrowException(C_word value) C_noret;
static void chicken_ThrowException(C_word value)
{
char *aborthook = C_text("\003sysabort");
C_word *a = C_alloc(C_SIZEOF_STRING(strlen(aborthook)));
C_word abort = C_intern2(&a, aborthook);
abort = C_block_item(abort, 0);
if (C_immediatep(abort))
chicken_Panic(C_text("`##sys#abort' is not defined"));
C_save(value);
C_do_apply(1, abort, C_SCHEME_UNDEFINED);
}
void chicken_agrep_exception (int code, int msglen, const char *msg)
{
C_word *a;
C_word scmmsg;
C_word list;
a = C_alloc (C_SIZEOF_STRING (msglen) + C_SIZEOF_LIST(2));
scmmsg = C_string2 (&a, (char *) msg);
list = C_list(&a, 2, C_fix(code), scmmsg);
chicken_ThrowException(list);
}
<#
; Include into generated code, but don't parse:
#>
#include
#include
#include
typedef unsigned char uchar;
typedef unsigned int uint;
#define BITS_PER_WORD (8 * sizeof(unsigned int))
#define Setbit(ptr,nbit) \
((ptr)[(nbit) / BITS_PER_WORD] |= (1UL << ((nbit) % BITS_PER_WORD)))
unsigned char word_constituent[256] = {
/* 0 - 31 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/* ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
/* @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ */
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
/* ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ \127 */
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
/* 128-159 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/* ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ */
0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,0,
/* À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
/* à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1
};
/* Specialized versions of string matching code */
#undef WHOLE_WORD
#define FUNCTION_NAME match_0errs
#define NERRS 0
#include "skeleton.h"
#undef FUNCTION_NAME
#undef NERRS
#define FUNCTION_NAME match_1errs
#define NERRS 1
#include "skeleton.h"
#undef FUNCTION_NAME
#undef NERRS
#define FUNCTION_NAME match_2errs
#define NERRS 2
#include "skeleton.h"
#undef FUNCTION_NAME
#undef NERRS
#define FUNCTION_NAME match_3errs
#define NERRS 3
#include "skeleton.h"
#undef FUNCTION_NAME
#undef NERRS
#define WHOLE_WORD
#define FUNCTION_NAME match_word_0errs
#define NERRS 0
#include "skeleton.h"
#undef FUNCTION_NAME
#undef NERRS
#define FUNCTION_NAME match_word_1errs
#define NERRS 1
#include "skeleton.h"
#undef FUNCTION_NAME
#undef NERRS
#define FUNCTION_NAME match_word_2errs
#define NERRS 2
#include "skeleton.h"
#undef FUNCTION_NAME
#undef NERRS
#define FUNCTION_NAME match_word_3errs
#define NERRS 3
#include "skeleton.h"
#undef FUNCTION_NAME
#undef NERRS
<#
(define BITS-PER-WORD (foreign-value "BITS_PER_WORD" int))
;; Allocate bit matrix object
(define (agrep-alloc-bitmatrix patlen nentries)
(let* ((nwords (fx/ (fx+ patlen (fx- BITS-PER-WORD 1)) BITS-PER-WORD))
(size (+ nwords nentries)))
(make-u32vector size 0)))
(define agrep-set-bit
(foreign-lambda* void ((u32vector matrix)
(unsigned-int v_patlen)
(unsigned-int v_index)
(unsigned-int v_bitnum))
#<
void *stat_alloc (size_t size)
{
void *p;
if ((p = malloc (size)) == NULL)
{
chicken_agrep_exception (ENOMEM, 25, "unable to allocate memory");
}
return p;
}
void stat_free (void *p)
{
if (p == NULL)
{
chicken_agrep_exception (EINVAL, 18, "null pointer freed");
}
free (p);
}
/* General code: arbitrary errors, arbitrary pattern length */
uint match_general(uint * table, uint m,
uint nerrs, int wholeword,
uchar * text, size_t length)
{
uint nwords, n, j;
uint ** R;
uint * Rpbefore;
uint Found_offset, Found_mask;
uint * Ssharp;
uint * Rc, * Rp;
uint carry;
uint match_empty;
int retcode;
nwords = (m + BITS_PER_WORD - 1) / BITS_PER_WORD;
R = stat_alloc((nerrs + 1) * sizeof(uint *));
for (n = 0; n <= nerrs; n++)
R[n] = stat_alloc(nwords * sizeof(uint));
Rpbefore = stat_alloc(nwords * sizeof(uint));
/* Initialize Found */
Found_offset = m / BITS_PER_WORD;
Found_mask = 1UL << (m % BITS_PER_WORD);
/* Initialize R */
for (n = 0; n <= nerrs; n++)
{
memset(R[n], 0, nwords * sizeof(uint));
for (j = 0; j <= n; j++) Setbit(R[n], j);
}
/* Initialize Ssharp & match_empty */
Ssharp = table + 256 * nwords;
match_empty = 1;
/* Main loop */
for (/*nothing*/; length > 0; length--, text++) {
uint * S = table + (*text) * nwords;
if (wholeword)
match_empty = word_constituent[text[0]] ^ word_constituent[text[1]];
/* Special case for 0 errors */
Rc = R[0];
carry = match_empty;
for (j = 0; j < nwords; j++) {
uint Rcbefore = Rc[j];
uint toshift = Rcbefore & S[j];
Rc[j] = (toshift << 1) | (Rcbefore & Ssharp[j]) | carry;
carry = toshift >> (BITS_PER_WORD - 1);
Rpbefore[j] = Rcbefore;
}
if (Rc[Found_offset] & Found_mask && match_empty)
{ retcode = 0; goto exit; }
/* General case for > 0 errors */
for (n = 1; n <= nerrs; n++) {
Rp = Rc;
Rc = R[n];
carry = match_empty;
for (j = 0; j < nwords; j++) {
uint Rcbefore = Rc[j];
uint toshift = (Rcbefore & S[j]) | Rpbefore[j] | Rp[j];
Rc[j] = (toshift << 1)
| Rpbefore[j]
| (Rcbefore & Ssharp[j])
| carry;
carry = toshift >> (BITS_PER_WORD - 1);
Rpbefore[j] = Rcbefore;
}
if (Rc[Found_offset] & Found_mask && match_empty)
{ retcode = n; goto exit; }
}
}
/* Not found */
retcode = C_WORD_MAX;
/* Cleanup */
exit:
for (n = 0; n <= nerrs; n++) stat_free(R[n]);
stat_free(R);
stat_free(Rpbefore);
return retcode;
}
<#
(define agrep-match
(foreign-primitive scheme-object ((c-string v_text)
(unsigned-int v_ofs)
(unsigned-int v_len)
(unsigned-int v_patlen)
(u32vector v_table)
(unsigned-int v_nerrs)
(bool v_wholeword))
#<= 1
ulong R1, R0before;
#endif
#if NERRS >= 2
ulong R2, R1before;
#endif
#if NERRS == 3
ulong R3, R2before;
#endif
ulong Found, Ssharp;
#ifdef WHOLE_WORD
ulong word_boundary;
#endif
Ssharp = table[256];
Found = 1UL << pattern_length;
R0 = 1;
#if NERRS >= 1
R1 = 3;
#endif
#if NERRS >= 2
R2 = 7;
#endif
#if NERRS == 3
R3 = 0xF;
#endif
for (/*nothing*/; length > 0; length--, text++) {
ulong S = table[*text];
#if NERRS >= 1
R0before = R0;
#endif
#if NERRS >= 2
R1before = R1;
#endif
#if NERRS == 3
R2before = R2;
#endif
#ifdef WHOLE_WORD
word_boundary = word_constituent[text[0]] ^ word_constituent[text[1]];
# define MATCH_EMPTY word_boundary
#else
# define MATCH_EMPTY 1
#endif
R0 = ((R0 & S) << 1) | (R0 & Ssharp) | MATCH_EMPTY;
#if NERRS >= 1
R1 = (((R1 & S) | R0before | R0) << 1)
| R0before
| (R1 & Ssharp)
| MATCH_EMPTY;
#endif
#if NERRS >= 2
R2 = (((R2 & S) | R1before | R1) << 1)
| R1before
| (R2 & Ssharp)
| MATCH_EMPTY;
#endif
#if NERRS == 3
R3 = (((R3 & S) | R2before | R2) << 1)
| R2before
| (R3 & Ssharp)
| MATCH_EMPTY;
#endif
if ((R0 & Found) && MATCH_EMPTY) return (0);
#if NERRS >= 1
if ((R1 & Found) && MATCH_EMPTY) return (1);
#endif
#if NERRS >= 2
if ((R2 & Found) && MATCH_EMPTY) return (2);
#endif
#if NERRS == 3
if ((R3 & Found) && MATCH_EMPTY) return (3);
#endif
}
return (C_WORD_MAX);
}
#undef MATCH_EMPTY