# Lexer matching case insensitive

**URL:** <https://racket.discourse.group/t/lexer-matching-case-insensitive/2543>\
**Category:** General\
**Tags:** question, lexer\
**Created:** [November 27, 2023, 12:55pm UTC](https://racket.discourse.group/t/lexer-matching-case-insensitive/2543 "2023-11-27T12:55:04Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://racket.discourse.group/u/ceving)\
**Post date:** [November 27, 2023, 12:55pm UTC](https://racket.discourse.group/t/lexer-matching-case-insensitive/2543/1 "2023-11-27T12:55:04Z")

</div>

The [original SRE specification](https://www.khoury.northeastern.edu/~shivers/papers/sre.txt) contains the definition of `uncase`:

> UNCASE is a regexp operator producing a regexp that matches any  
> case permutation of any string that matches (: \<sre\> ...).  
> For example, the regexp
> 
> ```scheme
> (uncase "foo")
> 
> ```
> 
> matches the strings foo, foO, fOo, fOO, Foo, ...

I can not find it in [parser-tools-lib](https://docs.racket-lang.org/parser-tools/Lexers.html#%28mod-path._parser-tools%2Flex-sre%29).

How to match case-insensitive instead?

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [November 27, 2023, 1:24pm UTC](https://racket.discourse.group/t/lexer-matching-case-insensitive/2543/2 "2023-11-27T13:24:35Z")

</div>

Something like:

```scheme
(define-lex-abbrevs
  [letter     
   (union (char-range #\a #\z) (char-range #\A #\Z))]
  [digit      
   (char-range #\0 #\9)]
  [identifier 
   (concatenation letter 
                  (repetition 0 +inf.0 (union letter digit)))]
   etc

```

If you need to case-insensitive keywords (reserved identifiers),  
you can do something like:

```scheme
; Reserved keywords in Pacal ignore case.
; Thus the "PrOgRaM" and "program" are 
; the same keyword. Since the lexer has
; no builtin support for matching mixed case
; strings, we define our own lexer 
; transformation, mixed, that turns
; (mixed "foo") into
; (concatenation 
; (union #\f #\F) (union #\o #\o) (union #\o #\o))
; Remember to use string-downcase on the 
; resulting lexeme.

(require (for-syntax syntax/parse))
(define-lex-trans mixed
  (λ (stx)
    (syntax-parse stx
      [(_ datum)
       (define str (string-downcase (syntax->datum #'datum)))
       (define STR (string-upcase str))
       #`(concatenation
          #,@(for/list ([c (in-string str)]
                        [C (in-string STR)])
               #`(union #,c #,C)))])))

```

```scheme
; The following lexer transformation turns
; (union-mixed "foo" "bar") into
; (union (mixed "foo") (mixed "bar"))

(define-lex-trans union-mixed
  (λ (stx)
    (syntax-parse stx
      [(_ str ...)
       #`(union (mixed str) ...)])))

```

And now we can use this as a rule in the lexer:

```scheme
  [reserved
     (union-mixed
      "div" "or" "and" "not" "if" "for" "to" "downto"
      "then" "else" "of" "while" "do" "begin" "end" 
      "read" "readln" "write" "writeln"
      "var" "const" "array" "type" "bindable"
      "procedure" "function" "program")]

```

---

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://racket.discourse.group/u/ceving)\
**Post date:** [November 27, 2023, 3:01pm UTC](https://racket.discourse.group/t/lexer-matching-case-insensitive/2543/3 "2023-11-27T15:01:22Z")

</div>

Thanks! The mixed case is what I need. Works fine!
